@peac/adapter-eat 0.12.6

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 ADDED
@@ -0,0 +1,190 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2025-2026 PEAC Protocol Contributors
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @peac/adapter-eat
2
+
3
+ EAT (Entity Attestation Token, RFC 9711) passport decoder and PEAC claim mapper with privacy-first defaults.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @peac/adapter-eat
9
+ ```
10
+
11
+ ## What It Does
12
+
13
+ `@peac/adapter-eat` is a Layer 4 adapter that decodes COSE_Sign1 structures (RFC 9052) containing Entity Attestation Token payloads and maps them into Interaction Record format claims. It verifies Ed25519 signatures, enforces a 64 KB size limit before CBOR decode to prevent denial-of-service, and hashes all claim values with SHA-256 by default so that no raw attestation data leaks into PEAC receipts.
14
+
15
+ ## How Do I Use It?
16
+
17
+ ### Decode and verify an EAT passport
18
+
19
+ ```typescript
20
+ import { decodeEatPassport } from '@peac/adapter-eat';
21
+
22
+ const result = await decodeEatPassport(coseBytes, publicKey);
23
+
24
+ if (result.verified) {
25
+ console.log('Claims:', result.claims);
26
+ console.log('Algorithm:', result.headers.alg); // -8 (EdDSA)
27
+ }
28
+ ```
29
+
30
+ ### Map EAT claims to PEAC receipt claims
31
+
32
+ ```typescript
33
+ import { decodeEatPassport, mapEatClaims } from '@peac/adapter-eat';
34
+
35
+ const result = await decodeEatPassport(coseBytes, publicKey);
36
+ if (result.verified) {
37
+ // Privacy-first: all values are SHA-256 hashed by default
38
+ const mapped = await mapEatClaims(result.claims);
39
+ console.log('Type:', mapped.type); // 'org.peacprotocol/attestation'
40
+ console.log('Pillars:', mapped.pillars); // ['identity']
41
+ console.log('Values:', mapped.values); // Map<number, string> with hashed values
42
+
43
+ // Opt in to raw values when needed
44
+ const raw = await mapEatClaims(result.claims, { includeRawClaims: true });
45
+ }
46
+ ```
47
+
48
+ ## Integrates With
49
+
50
+ - `@peac/kernel` (Layer 0): Wire constants and types
51
+ - `@peac/schema` (Layer 1): Interaction Record format claim schemas
52
+ - `@peac/crypto` (Layer 2): Ed25519 signature verification and SHA-256 hashing
53
+ - `@peac/protocol` (Layer 3): Receipt issuance with mapped EAT claims
54
+
55
+ ## For Agent Developers
56
+
57
+ If you are building an agent that needs to verify device or entity attestations:
58
+
59
+ - Use `decodeEatPassport()` to decode and verify COSE_Sign1 tokens from hardware or software attestation sources
60
+ - Use `mapEatClaims()` to convert verified attestations into PEAC receipt claims with privacy-safe defaults
61
+ - Only Ed25519 (COSE algorithm -8) is supported; all other algorithms are rejected
62
+ - See the [llms.txt](https://github.com/peacprotocol/peac/blob/main/llms.txt) for a concise protocol overview
63
+
64
+ ## License
65
+
66
+ Apache-2.0
67
+
68
+ ---
69
+
70
+ PEAC Protocol is an open source project stewarded by Originary and community contributors.
71
+
72
+ [Docs](https://www.peacprotocol.org) | [GitHub](https://github.com/peacprotocol/peac) | [Originary](https://www.originary.xyz)
@@ -0,0 +1,24 @@
1
+ /**
2
+ * EAT Claim Mapper: maps EAT claims to Wire 0.2 receipt claims
3
+ *
4
+ * Privacy-first: all claim values are SHA-256 hashed by default.
5
+ * Callers opt in to raw value inclusion via `includeRawClaims` option.
6
+ * This prevents accidental PII leakage from EAT attestations into PEAC receipts.
7
+ *
8
+ * References:
9
+ * - RFC 9711 (Entity Attestation Token)
10
+ * - Wire 0.2 spec: kind, type, pillars, extensions
11
+ */
12
+ import type { EatClaims, ClaimMapperOptions, MappedEatClaims } from './types.js';
13
+ /**
14
+ * Map EAT claims to Wire 0.2 receipt claims.
15
+ *
16
+ * Privacy-first: claim values are SHA-256 hashed unless their integer key
17
+ * appears in `options.includeRawClaims`. This prevents accidental PII leakage.
18
+ *
19
+ * @param claims - Decoded EAT claims map
20
+ * @param options - Mapper configuration
21
+ * @returns Mapped claims suitable for Wire 0.2 receipt issuance
22
+ */
23
+ export declare function mapEatClaims(claims: EatClaims, options?: ClaimMapperOptions): Promise<MappedEatClaims>;
24
+ //# sourceMappingURL=claim-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim-mapper.d.ts","sourceRoot":"","sources":["../src/claim-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AA0CjF;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,eAAe,CAAC,CA+B1B"}
package/dist/index.cjs ADDED
@@ -0,0 +1,262 @@
1
+ 'use strict';
2
+
3
+ var cbor = require('cbor');
4
+ var crypto = require('@peac/crypto');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var cbor__default = /*#__PURE__*/_interopDefault(cbor);
9
+
10
+ // src/types.ts
11
+ var COSE_ALG = {
12
+ /** EdDSA (Ed25519 or Ed448) */
13
+ EdDSA: -8
14
+ };
15
+ var EAT_CLAIM_KEY = {
16
+ iss: 1,
17
+ sub: 2,
18
+ aud: 3,
19
+ exp: 4,
20
+ nbf: 5,
21
+ iat: 6,
22
+ cti: 7,
23
+ nonce: 10,
24
+ ueid: 256,
25
+ sueids: 257,
26
+ oemid: 258,
27
+ hwmodel: 259,
28
+ hwversion: 260,
29
+ swname: 271,
30
+ swversion: 272,
31
+ oemueid: 273,
32
+ secboot: 262,
33
+ dbgstat: 263,
34
+ location: 264,
35
+ profile: 265,
36
+ submods: 266,
37
+ uptime: 261,
38
+ intuse: 267,
39
+ dloas: 268,
40
+ manifests: 269,
41
+ measurements: 270
42
+ };
43
+ var EAT_SIZE_LIMIT = 65536;
44
+ var cborDecode = cbor__default.default.decode;
45
+ var cborEncode = cbor__default.default.encode;
46
+ var EatAdapterError = class extends Error {
47
+ constructor(message, code) {
48
+ super(message);
49
+ this.code = code;
50
+ this.name = "EatAdapterError";
51
+ }
52
+ };
53
+ function decodeCoseSign1(data) {
54
+ let decoded;
55
+ try {
56
+ decoded = cborDecode(data);
57
+ } catch {
58
+ throw new EatAdapterError("EAT token is not valid CBOR", "E_EAT_INVALID_CBOR");
59
+ }
60
+ if (!Array.isArray(decoded) || decoded.length !== 4) {
61
+ throw new EatAdapterError(
62
+ "EAT token is not a valid COSE_Sign1 structure (expected 4-element array)",
63
+ "E_EAT_INVALID_COSE"
64
+ );
65
+ }
66
+ const [protectedBytes, unprotectedMap, payload, signature] = decoded;
67
+ if (!(protectedBytes instanceof Uint8Array)) {
68
+ throw new EatAdapterError(
69
+ "COSE_Sign1 protected header must be a byte string",
70
+ "E_EAT_INVALID_COSE"
71
+ );
72
+ }
73
+ if (payload === null) {
74
+ throw new EatAdapterError(
75
+ "Detached COSE_Sign1 payload (null) is not supported; EAT tokens require an attached payload",
76
+ "E_EAT_INVALID_COSE"
77
+ );
78
+ }
79
+ if (!(payload instanceof Uint8Array)) {
80
+ throw new EatAdapterError("COSE_Sign1 payload must be a byte string", "E_EAT_INVALID_COSE");
81
+ }
82
+ if (!(signature instanceof Uint8Array)) {
83
+ throw new EatAdapterError("COSE_Sign1 signature must be a byte string", "E_EAT_INVALID_COSE");
84
+ }
85
+ if (signature.length !== 64) {
86
+ throw new EatAdapterError(
87
+ `COSE_Sign1 signature has unexpected length ${signature.length} (expected 64 for Ed25519)`,
88
+ "E_EAT_INVALID_COSE"
89
+ );
90
+ }
91
+ return {
92
+ protected: protectedBytes,
93
+ unprotected: unprotectedMap instanceof Map ? unprotectedMap : /* @__PURE__ */ new Map(),
94
+ payload,
95
+ signature
96
+ };
97
+ }
98
+ function decodeProtectedHeaders(protectedBytes) {
99
+ if (protectedBytes.length === 0) {
100
+ throw new EatAdapterError("COSE_Sign1 protected headers are empty", "E_EAT_INVALID_COSE");
101
+ }
102
+ let headerMap;
103
+ try {
104
+ headerMap = cborDecode(protectedBytes);
105
+ } catch {
106
+ throw new EatAdapterError(
107
+ "COSE_Sign1 protected headers are not valid CBOR",
108
+ "E_EAT_INVALID_COSE"
109
+ );
110
+ }
111
+ if (!(headerMap instanceof Map)) {
112
+ throw new EatAdapterError(
113
+ "COSE_Sign1 protected headers must be a CBOR map",
114
+ "E_EAT_INVALID_COSE"
115
+ );
116
+ }
117
+ const alg = headerMap.get(1);
118
+ if (typeof alg !== "number") {
119
+ throw new EatAdapterError(
120
+ "COSE_Sign1 protected headers missing algorithm (label 1)",
121
+ "E_EAT_INVALID_COSE"
122
+ );
123
+ }
124
+ if (alg !== COSE_ALG.EdDSA) {
125
+ throw new EatAdapterError(
126
+ `Unsupported COSE algorithm ${alg}; only EdDSA (-8) is supported`,
127
+ "E_EAT_UNSUPPORTED_ALG"
128
+ );
129
+ }
130
+ const kid = headerMap.get(4);
131
+ return {
132
+ alg,
133
+ kid: kid instanceof Uint8Array || typeof kid === "string" ? kid : void 0
134
+ };
135
+ }
136
+ function decodeEatClaims(payload) {
137
+ if (payload.length === 0) {
138
+ return /* @__PURE__ */ new Map();
139
+ }
140
+ let decoded;
141
+ try {
142
+ decoded = cborDecode(payload);
143
+ } catch {
144
+ throw new EatAdapterError("EAT payload is not valid CBOR", "E_EAT_INVALID_CBOR");
145
+ }
146
+ if (decoded instanceof Map) {
147
+ return decoded;
148
+ }
149
+ if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
150
+ const map = /* @__PURE__ */ new Map();
151
+ for (const [k, v] of Object.entries(decoded)) {
152
+ const numKey = Number(k);
153
+ map.set(Number.isInteger(numKey) ? numKey : k, v);
154
+ }
155
+ return map;
156
+ }
157
+ throw new EatAdapterError("EAT payload must be a CBOR map", "E_EAT_INVALID_CBOR");
158
+ }
159
+ function buildSigStructure(protectedBytes, payload, externalAad = new Uint8Array(0)) {
160
+ const sigStructure = ["Signature1", protectedBytes, externalAad, payload];
161
+ return cborEncode(sigStructure);
162
+ }
163
+ async function decodeEatPassport(data, publicKey) {
164
+ if (data.length > EAT_SIZE_LIMIT) {
165
+ throw new EatAdapterError(
166
+ `EAT token is ${data.length} bytes, exceeding ${EAT_SIZE_LIMIT} byte limit`,
167
+ "E_EAT_SIZE_EXCEEDED"
168
+ );
169
+ }
170
+ if (data.length === 0) {
171
+ throw new EatAdapterError("EAT token is empty", "E_EAT_INVALID_CBOR");
172
+ }
173
+ const coseSign1 = decodeCoseSign1(data);
174
+ const headers = decodeProtectedHeaders(coseSign1.protected);
175
+ const claims = decodeEatClaims(coseSign1.payload);
176
+ let signatureValid;
177
+ if (publicKey !== void 0) {
178
+ if (publicKey.length !== 32) {
179
+ throw new EatAdapterError(
180
+ `Ed25519 public key must be 32 bytes, got ${publicKey.length}`,
181
+ "E_EAT_SIGNATURE_FAILED"
182
+ );
183
+ }
184
+ const sigStructureBytes = buildSigStructure(coseSign1.protected, coseSign1.payload);
185
+ try {
186
+ signatureValid = await crypto.ed25519Verify(coseSign1.signature, sigStructureBytes, publicKey);
187
+ } catch {
188
+ throw new EatAdapterError("Ed25519 signature verification failed", "E_EAT_SIGNATURE_FAILED");
189
+ }
190
+ if (!signatureValid) {
191
+ throw new EatAdapterError(
192
+ "COSE_Sign1 Ed25519 signature is invalid",
193
+ "E_EAT_SIGNATURE_FAILED"
194
+ );
195
+ }
196
+ }
197
+ return { headers, claims, signatureValid };
198
+ }
199
+ var DEFAULT_TYPE = "org.peacprotocol/attestation";
200
+ var DEFAULT_PILLARS = ["identity"];
201
+ var CLAIM_LABEL_NAMES = {
202
+ [EAT_CLAIM_KEY.iss]: "iss",
203
+ [EAT_CLAIM_KEY.sub]: "sub",
204
+ [EAT_CLAIM_KEY.aud]: "aud",
205
+ [EAT_CLAIM_KEY.exp]: "exp",
206
+ [EAT_CLAIM_KEY.nbf]: "nbf",
207
+ [EAT_CLAIM_KEY.iat]: "iat",
208
+ [EAT_CLAIM_KEY.cti]: "cti",
209
+ [EAT_CLAIM_KEY.nonce]: "nonce",
210
+ [EAT_CLAIM_KEY.ueid]: "ueid",
211
+ [EAT_CLAIM_KEY.sueids]: "sueids",
212
+ [EAT_CLAIM_KEY.oemid]: "oemid",
213
+ [EAT_CLAIM_KEY.hwmodel]: "hwmodel",
214
+ [EAT_CLAIM_KEY.hwversion]: "hwversion",
215
+ [EAT_CLAIM_KEY.swname]: "swname",
216
+ [EAT_CLAIM_KEY.swversion]: "swversion",
217
+ [EAT_CLAIM_KEY.secboot]: "secboot",
218
+ [EAT_CLAIM_KEY.dbgstat]: "dbgstat"
219
+ };
220
+ function serializeClaimValue(value) {
221
+ if (value instanceof Uint8Array) {
222
+ return Array.from(value).map((b) => b.toString(16).padStart(2, "0")).join("");
223
+ }
224
+ if (typeof value === "string") return value;
225
+ if (typeof value === "number") return String(value);
226
+ if (typeof value === "boolean") return String(value);
227
+ return JSON.stringify(value);
228
+ }
229
+ async function mapEatClaims(claims, options = {}) {
230
+ const { includeRawClaims = [], type = DEFAULT_TYPE, pillars = DEFAULT_PILLARS } = options;
231
+ const rawSet = new Set(includeRawClaims);
232
+ const attestationClaims = {};
233
+ for (const [key, value] of claims) {
234
+ if (typeof key !== "number") continue;
235
+ const labelName = CLAIM_LABEL_NAMES[key] ?? `claim_${key}`;
236
+ const serialized = serializeClaimValue(value);
237
+ if (rawSet.has(key)) {
238
+ attestationClaims[labelName] = serialized;
239
+ } else {
240
+ attestationClaims[labelName] = `sha256:${await crypto.sha256Hex(serialized)}`;
241
+ }
242
+ }
243
+ const issValue = claims.get(EAT_CLAIM_KEY.iss);
244
+ const subValue = claims.get(EAT_CLAIM_KEY.sub);
245
+ return {
246
+ kind: "evidence",
247
+ type,
248
+ pillars,
249
+ attestation_claims: attestationClaims,
250
+ eat_iss: typeof issValue === "string" ? issValue : void 0,
251
+ eat_sub: typeof subValue === "string" ? subValue : void 0
252
+ };
253
+ }
254
+
255
+ exports.COSE_ALG = COSE_ALG;
256
+ exports.EAT_CLAIM_KEY = EAT_CLAIM_KEY;
257
+ exports.EAT_SIZE_LIMIT = EAT_SIZE_LIMIT;
258
+ exports.EatAdapterError = EatAdapterError;
259
+ exports.decodeEatPassport = decodeEatPassport;
260
+ exports.mapEatClaims = mapEatClaims;
261
+ //# sourceMappingURL=index.cjs.map
262
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/passport.ts","../src/claim-mapper.ts"],"names":["cbor","ed25519Verify","sha256Hex"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * EAT (Entity Attestation Token) and COSE types\n *\n * References:\n * - RFC 9711 (Entity Attestation Token)\n * - RFC 9052 Section 4.2 (COSE_Sign1)\n * - RFC 9053 (COSE Initial Algorithms)\n * - RFC 8949 (CBOR)\n */\n\n/**\n * COSE_Sign1 structure per RFC 9052 Section 4.2.\n *\n * COSE_Sign1 = [\n * protected : bstr, -- Serialized protected headers (CBOR-encoded map)\n * unprotected : map, -- Unprotected headers (CBOR map, may be empty)\n * payload : bstr / nil, -- Payload bytes\n * signature : bstr -- Signature bytes\n * ]\n */\nexport interface CoseSign1 {\n protected: Uint8Array;\n unprotected: Map<number, unknown>;\n payload: Uint8Array;\n signature: Uint8Array;\n}\n\n/**\n * Decoded COSE protected headers.\n *\n * COSE header parameter labels (integer keys per RFC 9052 Section 3.1):\n * 1 = alg (algorithm)\n * 4 = kid (key identifier)\n */\nexport interface CoseProtectedHeaders {\n alg: number;\n kid?: Uint8Array | string;\n}\n\n/** COSE algorithm identifiers per RFC 9053 Table 2 */\nexport const COSE_ALG = {\n /** EdDSA (Ed25519 or Ed448) */\n EdDSA: -8,\n} as const;\n\n/**\n * EAT standard claim keys (CBOR integer labels per RFC 9711 Section 4).\n *\n * Many of these inherit from CWT (RFC 8392) claim labels.\n */\nexport const EAT_CLAIM_KEY = {\n iss: 1,\n sub: 2,\n aud: 3,\n exp: 4,\n nbf: 5,\n iat: 6,\n cti: 7,\n nonce: 10,\n ueid: 256,\n sueids: 257,\n oemid: 258,\n hwmodel: 259,\n hwversion: 260,\n swname: 271,\n swversion: 272,\n oemueid: 273,\n secboot: 262,\n dbgstat: 263,\n location: 264,\n profile: 265,\n submods: 266,\n uptime: 261,\n intuse: 267,\n dloas: 268,\n manifests: 269,\n measurements: 270,\n} as const;\n\n/**\n * Decoded EAT claims (CBOR map with integer or string keys).\n *\n * The decoder preserves the raw CBOR map. The claim mapper extracts\n * specific claims by integer key.\n */\nexport type EatClaims = Map<number | string, unknown>;\n\n/** Result of decoding and verifying an EAT passport */\nexport interface EatPassportResult {\n /** Decoded protected headers */\n headers: CoseProtectedHeaders;\n /** Raw EAT claims map */\n claims: EatClaims;\n /** Whether the Ed25519 signature is valid (only present if publicKey provided) */\n signatureValid?: boolean;\n}\n\n/** Options for the claim mapper */\nexport interface ClaimMapperOptions {\n /**\n * Claim keys whose raw values should be included in the mapped output.\n * By default, all claim values are hashed (SHA-256 digest) for privacy.\n * List specific integer keys here to include their raw values.\n */\n includeRawClaims?: number[];\n /** Receipt type (reverse-DNS or URI). Defaults to 'org.peacprotocol/attestation' */\n type?: string;\n /** Pillars to include on the receipt. Defaults to ['identity'] */\n pillars?: string[];\n}\n\n/** Mapped Wire 0.2 claims from an EAT passport */\nexport interface MappedEatClaims {\n kind: 'evidence';\n type: string;\n pillars?: string[];\n /** Hashed or raw claim values, keyed by claim label */\n attestation_claims: Record<string, string>;\n /** Original issuer from EAT (if present) */\n eat_iss?: string;\n /** Original subject from EAT (if present) */\n eat_sub?: string;\n}\n\n/** Size limit for EAT tokens (64 KB, consistent with carrier transport limits) */\nexport const EAT_SIZE_LIMIT = 65_536;\n","/**\n * EAT Passport Decoder\n *\n * Decodes COSE_Sign1 structures containing EAT (Entity Attestation Token)\n * payloads per RFC 9711. Optionally verifies Ed25519 signatures per\n * RFC 9052 Section 4.4 (Sig_structure construction).\n *\n * References:\n * - RFC 9052 Section 4.2 (COSE_Sign1 structure)\n * - RFC 9052 Section 4.4 (Signing and Verification Process)\n * - RFC 9053 Table 2 (EdDSA algorithm identifier: -8)\n * - RFC 9711 (Entity Attestation Token)\n * - RFC 8949 (CBOR encoding)\n *\n * Security:\n * - 64 KB size limit enforced BEFORE CBOR decode (DoS prevention)\n * - Only Ed25519 (COSE alg -8) supported; all others rejected\n * - No network I/O\n */\n\nimport cbor from 'cbor';\n\nconst cborDecode = cbor.decode;\nconst cborEncode = cbor.encode;\nimport { ed25519Verify } from '@peac/crypto';\nimport type { CoseSign1, CoseProtectedHeaders, EatClaims, EatPassportResult } from './types.js';\nimport { COSE_ALG, EAT_SIZE_LIMIT } from './types.js';\n\n/** Error class for EAT adapter failures */\nexport class EatAdapterError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'EatAdapterError';\n }\n}\n\n/**\n * Decode a COSE_Sign1 array from raw CBOR bytes.\n *\n * Validates the COSE_Sign1 structure per RFC 9052 Section 4.2:\n * [protected, unprotected, payload, signature]\n *\n * @param data - Raw CBOR bytes\n * @returns Parsed COSE_Sign1 structure\n * @throws EatAdapterError on invalid CBOR or COSE structure\n */\nfunction decodeCoseSign1(data: Uint8Array): CoseSign1 {\n let decoded: unknown;\n try {\n decoded = cborDecode(data);\n } catch {\n throw new EatAdapterError('EAT token is not valid CBOR', 'E_EAT_INVALID_CBOR');\n }\n\n // COSE_Sign1 is a CBOR array of exactly 4 elements\n if (!Array.isArray(decoded) || decoded.length !== 4) {\n throw new EatAdapterError(\n 'EAT token is not a valid COSE_Sign1 structure (expected 4-element array)',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n const [protectedBytes, unprotectedMap, payload, signature] = decoded;\n\n if (!(protectedBytes instanceof Uint8Array)) {\n throw new EatAdapterError(\n 'COSE_Sign1 protected header must be a byte string',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (payload === null) {\n throw new EatAdapterError(\n 'Detached COSE_Sign1 payload (null) is not supported; EAT tokens require an attached payload',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (!(payload instanceof Uint8Array)) {\n throw new EatAdapterError('COSE_Sign1 payload must be a byte string', 'E_EAT_INVALID_COSE');\n }\n\n if (!(signature instanceof Uint8Array)) {\n throw new EatAdapterError('COSE_Sign1 signature must be a byte string', 'E_EAT_INVALID_COSE');\n }\n\n // Ed25519 signatures are exactly 64 bytes\n if (signature.length !== 64) {\n throw new EatAdapterError(\n `COSE_Sign1 signature has unexpected length ${signature.length} (expected 64 for Ed25519)`,\n 'E_EAT_INVALID_COSE'\n );\n }\n\n return {\n protected: protectedBytes,\n unprotected: unprotectedMap instanceof Map ? unprotectedMap : new Map<number, unknown>(),\n payload,\n signature,\n };\n}\n\n/**\n * Decode and validate COSE protected headers.\n *\n * @param protectedBytes - CBOR-encoded protected headers\n * @returns Decoded headers with algorithm and optional kid\n * @throws EatAdapterError if algorithm is not EdDSA (-8)\n */\nfunction decodeProtectedHeaders(protectedBytes: Uint8Array): CoseProtectedHeaders {\n if (protectedBytes.length === 0) {\n throw new EatAdapterError('COSE_Sign1 protected headers are empty', 'E_EAT_INVALID_COSE');\n }\n\n let headerMap: unknown;\n try {\n headerMap = cborDecode(protectedBytes);\n } catch {\n throw new EatAdapterError(\n 'COSE_Sign1 protected headers are not valid CBOR',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (!(headerMap instanceof Map)) {\n throw new EatAdapterError(\n 'COSE_Sign1 protected headers must be a CBOR map',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n // Label 1 = alg\n const alg = headerMap.get(1);\n if (typeof alg !== 'number') {\n throw new EatAdapterError(\n 'COSE_Sign1 protected headers missing algorithm (label 1)',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (alg !== COSE_ALG.EdDSA) {\n throw new EatAdapterError(\n `Unsupported COSE algorithm ${alg}; only EdDSA (-8) is supported`,\n 'E_EAT_UNSUPPORTED_ALG'\n );\n }\n\n // Label 4 = kid (optional)\n const kid = headerMap.get(4);\n\n return {\n alg,\n kid: kid instanceof Uint8Array || typeof kid === 'string' ? kid : undefined,\n };\n}\n\n/**\n * Decode EAT claims from COSE payload bytes.\n *\n * @param payload - CBOR-encoded payload\n * @returns EAT claims as a Map\n * @throws EatAdapterError if payload is not valid CBOR\n */\nfunction decodeEatClaims(payload: Uint8Array): EatClaims {\n if (payload.length === 0) {\n return new Map();\n }\n\n let decoded: unknown;\n try {\n decoded = cborDecode(payload);\n } catch {\n throw new EatAdapterError('EAT payload is not valid CBOR', 'E_EAT_INVALID_CBOR');\n }\n\n if (decoded instanceof Map) {\n return decoded as EatClaims;\n }\n\n // Some CBOR decoders return plain objects for empty maps or when\n // configured without Map preference. Convert to Map for consistency.\n if (typeof decoded === 'object' && decoded !== null && !Array.isArray(decoded)) {\n const map = new Map<number | string, unknown>();\n for (const [k, v] of Object.entries(decoded as Record<string, unknown>)) {\n const numKey = Number(k);\n map.set(Number.isInteger(numKey) ? numKey : k, v);\n }\n return map;\n }\n\n throw new EatAdapterError('EAT payload must be a CBOR map', 'E_EAT_INVALID_CBOR');\n}\n\n/**\n * Construct the Sig_structure for COSE_Sign1 verification per RFC 9052 Section 4.4.\n *\n * Sig_structure1 = [\n * context : \"Signature1\",\n * body_protected : bstr,\n * external_aad : bstr,\n * payload : bstr\n * ]\n *\n * @param protectedBytes - Serialized protected headers\n * @param payload - Payload bytes\n * @param externalAad - External additional authenticated data (defaults to empty)\n * @returns CBOR-encoded Sig_structure bytes\n */\nfunction buildSigStructure(\n protectedBytes: Uint8Array,\n payload: Uint8Array,\n externalAad: Uint8Array = new Uint8Array(0)\n): Uint8Array {\n const sigStructure = ['Signature1', protectedBytes, externalAad, payload];\n return cborEncode(sigStructure);\n}\n\n/**\n * Decode an EAT passport from COSE_Sign1 CBOR bytes.\n *\n * Enforces a 64 KB size limit before CBOR decode (DoS prevention).\n * Validates COSE_Sign1 structure per RFC 9052 Section 4.2.\n * Optionally verifies Ed25519 signature per RFC 9052 Section 4.4.\n *\n * @param data - Raw COSE_Sign1 CBOR bytes\n * @param publicKey - Optional Ed25519 public key (32 bytes) for signature verification\n * @returns Decoded EAT passport with headers, claims, and optional signature validity\n * @throws EatAdapterError on size, CBOR, COSE, or algorithm errors\n */\nexport async function decodeEatPassport(\n data: Uint8Array,\n publicKey?: Uint8Array\n): Promise<EatPassportResult> {\n // Size limit: 64 KB enforced BEFORE any CBOR decode\n if (data.length > EAT_SIZE_LIMIT) {\n throw new EatAdapterError(\n `EAT token is ${data.length} bytes, exceeding ${EAT_SIZE_LIMIT} byte limit`,\n 'E_EAT_SIZE_EXCEEDED'\n );\n }\n\n if (data.length === 0) {\n throw new EatAdapterError('EAT token is empty', 'E_EAT_INVALID_CBOR');\n }\n\n // Step 1: Decode COSE_Sign1 structure\n const coseSign1 = decodeCoseSign1(data);\n\n // Step 2: Decode and validate protected headers\n const headers = decodeProtectedHeaders(coseSign1.protected);\n\n // Step 3: Decode EAT claims from payload\n const claims = decodeEatClaims(coseSign1.payload);\n\n // Step 4: Optionally verify Ed25519 signature\n let signatureValid: boolean | undefined;\n if (publicKey !== undefined) {\n if (publicKey.length !== 32) {\n throw new EatAdapterError(\n `Ed25519 public key must be 32 bytes, got ${publicKey.length}`,\n 'E_EAT_SIGNATURE_FAILED'\n );\n }\n\n const sigStructureBytes = buildSigStructure(coseSign1.protected, coseSign1.payload);\n\n try {\n signatureValid = await ed25519Verify(coseSign1.signature, sigStructureBytes, publicKey);\n } catch {\n throw new EatAdapterError('Ed25519 signature verification failed', 'E_EAT_SIGNATURE_FAILED');\n }\n\n if (!signatureValid) {\n throw new EatAdapterError(\n 'COSE_Sign1 Ed25519 signature is invalid',\n 'E_EAT_SIGNATURE_FAILED'\n );\n }\n }\n\n return { headers, claims, signatureValid };\n}\n","/**\n * EAT Claim Mapper: maps EAT claims to Wire 0.2 receipt claims\n *\n * Privacy-first: all claim values are SHA-256 hashed by default.\n * Callers opt in to raw value inclusion via `includeRawClaims` option.\n * This prevents accidental PII leakage from EAT attestations into PEAC receipts.\n *\n * References:\n * - RFC 9711 (Entity Attestation Token)\n * - Wire 0.2 spec: kind, type, pillars, extensions\n */\n\nimport { sha256Hex } from '@peac/crypto';\nimport { EAT_CLAIM_KEY } from './types.js';\nimport type { EatClaims, ClaimMapperOptions, MappedEatClaims } from './types.js';\n\nconst DEFAULT_TYPE = 'org.peacprotocol/attestation';\nconst DEFAULT_PILLARS = ['identity'];\n\n/** Well-known EAT claim labels (integer to string name) */\nconst CLAIM_LABEL_NAMES: Record<number, string> = {\n [EAT_CLAIM_KEY.iss]: 'iss',\n [EAT_CLAIM_KEY.sub]: 'sub',\n [EAT_CLAIM_KEY.aud]: 'aud',\n [EAT_CLAIM_KEY.exp]: 'exp',\n [EAT_CLAIM_KEY.nbf]: 'nbf',\n [EAT_CLAIM_KEY.iat]: 'iat',\n [EAT_CLAIM_KEY.cti]: 'cti',\n [EAT_CLAIM_KEY.nonce]: 'nonce',\n [EAT_CLAIM_KEY.ueid]: 'ueid',\n [EAT_CLAIM_KEY.sueids]: 'sueids',\n [EAT_CLAIM_KEY.oemid]: 'oemid',\n [EAT_CLAIM_KEY.hwmodel]: 'hwmodel',\n [EAT_CLAIM_KEY.hwversion]: 'hwversion',\n [EAT_CLAIM_KEY.swname]: 'swname',\n [EAT_CLAIM_KEY.swversion]: 'swversion',\n [EAT_CLAIM_KEY.secboot]: 'secboot',\n [EAT_CLAIM_KEY.dbgstat]: 'dbgstat',\n};\n\n/**\n * Serialize a claim value to a deterministic string for hashing.\n * Handles Uint8Array (hex), numbers, strings, and falls back to JSON.\n */\nfunction serializeClaimValue(value: unknown): string {\n if (value instanceof Uint8Array) {\n return Array.from(value)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n if (typeof value === 'string') return value;\n if (typeof value === 'number') return String(value);\n if (typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\n/**\n * Map EAT claims to Wire 0.2 receipt claims.\n *\n * Privacy-first: claim values are SHA-256 hashed unless their integer key\n * appears in `options.includeRawClaims`. This prevents accidental PII leakage.\n *\n * @param claims - Decoded EAT claims map\n * @param options - Mapper configuration\n * @returns Mapped claims suitable for Wire 0.2 receipt issuance\n */\nexport async function mapEatClaims(\n claims: EatClaims,\n options: ClaimMapperOptions = {}\n): Promise<MappedEatClaims> {\n const { includeRawClaims = [], type = DEFAULT_TYPE, pillars = DEFAULT_PILLARS } = options;\n\n const rawSet = new Set(includeRawClaims);\n const attestationClaims: Record<string, string> = {};\n\n for (const [key, value] of claims) {\n if (typeof key !== 'number') continue;\n\n const labelName = CLAIM_LABEL_NAMES[key] ?? `claim_${key}`;\n const serialized = serializeClaimValue(value);\n\n if (rawSet.has(key)) {\n attestationClaims[labelName] = serialized;\n } else {\n attestationClaims[labelName] = `sha256:${await sha256Hex(serialized)}`;\n }\n }\n\n // Extract standard identifiers (if present and opted-in to raw)\n const issValue = claims.get(EAT_CLAIM_KEY.iss);\n const subValue = claims.get(EAT_CLAIM_KEY.sub);\n\n return {\n kind: 'evidence',\n type,\n pillars,\n attestation_claims: attestationClaims,\n eat_iss: typeof issValue === 'string' ? issValue : undefined,\n eat_sub: typeof subValue === 'string' ? subValue : undefined,\n };\n}\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @peac/adapter-eat
3
+ *
4
+ * EAT (Entity Attestation Token, RFC 9711) passport decoder and
5
+ * PEAC Wire 0.2 claim mapper.
6
+ *
7
+ * Decodes COSE_Sign1 structures (RFC 9052) with Ed25519 signatures,
8
+ * extracts EAT claims, and maps them to Wire 0.2 receipt claims
9
+ * with privacy-first defaults (SHA-256 hashing of claim values).
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ export type { CoseSign1, CoseProtectedHeaders, EatClaims, EatPassportResult, ClaimMapperOptions, MappedEatClaims, } from './types.js';
14
+ export { COSE_ALG, EAT_CLAIM_KEY, EAT_SIZE_LIMIT } from './types.js';
15
+ export { decodeEatPassport, EatAdapterError } from './passport.js';
16
+ export { mapEatClaims } from './claim-mapper.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGrE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.mjs ADDED
@@ -0,0 +1,251 @@
1
+ import cbor from 'cbor';
2
+ import { ed25519Verify, sha256Hex } from '@peac/crypto';
3
+
4
+ // src/types.ts
5
+ var COSE_ALG = {
6
+ /** EdDSA (Ed25519 or Ed448) */
7
+ EdDSA: -8
8
+ };
9
+ var EAT_CLAIM_KEY = {
10
+ iss: 1,
11
+ sub: 2,
12
+ aud: 3,
13
+ exp: 4,
14
+ nbf: 5,
15
+ iat: 6,
16
+ cti: 7,
17
+ nonce: 10,
18
+ ueid: 256,
19
+ sueids: 257,
20
+ oemid: 258,
21
+ hwmodel: 259,
22
+ hwversion: 260,
23
+ swname: 271,
24
+ swversion: 272,
25
+ oemueid: 273,
26
+ secboot: 262,
27
+ dbgstat: 263,
28
+ location: 264,
29
+ profile: 265,
30
+ submods: 266,
31
+ uptime: 261,
32
+ intuse: 267,
33
+ dloas: 268,
34
+ manifests: 269,
35
+ measurements: 270
36
+ };
37
+ var EAT_SIZE_LIMIT = 65536;
38
+ var cborDecode = cbor.decode;
39
+ var cborEncode = cbor.encode;
40
+ var EatAdapterError = class extends Error {
41
+ constructor(message, code) {
42
+ super(message);
43
+ this.code = code;
44
+ this.name = "EatAdapterError";
45
+ }
46
+ };
47
+ function decodeCoseSign1(data) {
48
+ let decoded;
49
+ try {
50
+ decoded = cborDecode(data);
51
+ } catch {
52
+ throw new EatAdapterError("EAT token is not valid CBOR", "E_EAT_INVALID_CBOR");
53
+ }
54
+ if (!Array.isArray(decoded) || decoded.length !== 4) {
55
+ throw new EatAdapterError(
56
+ "EAT token is not a valid COSE_Sign1 structure (expected 4-element array)",
57
+ "E_EAT_INVALID_COSE"
58
+ );
59
+ }
60
+ const [protectedBytes, unprotectedMap, payload, signature] = decoded;
61
+ if (!(protectedBytes instanceof Uint8Array)) {
62
+ throw new EatAdapterError(
63
+ "COSE_Sign1 protected header must be a byte string",
64
+ "E_EAT_INVALID_COSE"
65
+ );
66
+ }
67
+ if (payload === null) {
68
+ throw new EatAdapterError(
69
+ "Detached COSE_Sign1 payload (null) is not supported; EAT tokens require an attached payload",
70
+ "E_EAT_INVALID_COSE"
71
+ );
72
+ }
73
+ if (!(payload instanceof Uint8Array)) {
74
+ throw new EatAdapterError("COSE_Sign1 payload must be a byte string", "E_EAT_INVALID_COSE");
75
+ }
76
+ if (!(signature instanceof Uint8Array)) {
77
+ throw new EatAdapterError("COSE_Sign1 signature must be a byte string", "E_EAT_INVALID_COSE");
78
+ }
79
+ if (signature.length !== 64) {
80
+ throw new EatAdapterError(
81
+ `COSE_Sign1 signature has unexpected length ${signature.length} (expected 64 for Ed25519)`,
82
+ "E_EAT_INVALID_COSE"
83
+ );
84
+ }
85
+ return {
86
+ protected: protectedBytes,
87
+ unprotected: unprotectedMap instanceof Map ? unprotectedMap : /* @__PURE__ */ new Map(),
88
+ payload,
89
+ signature
90
+ };
91
+ }
92
+ function decodeProtectedHeaders(protectedBytes) {
93
+ if (protectedBytes.length === 0) {
94
+ throw new EatAdapterError("COSE_Sign1 protected headers are empty", "E_EAT_INVALID_COSE");
95
+ }
96
+ let headerMap;
97
+ try {
98
+ headerMap = cborDecode(protectedBytes);
99
+ } catch {
100
+ throw new EatAdapterError(
101
+ "COSE_Sign1 protected headers are not valid CBOR",
102
+ "E_EAT_INVALID_COSE"
103
+ );
104
+ }
105
+ if (!(headerMap instanceof Map)) {
106
+ throw new EatAdapterError(
107
+ "COSE_Sign1 protected headers must be a CBOR map",
108
+ "E_EAT_INVALID_COSE"
109
+ );
110
+ }
111
+ const alg = headerMap.get(1);
112
+ if (typeof alg !== "number") {
113
+ throw new EatAdapterError(
114
+ "COSE_Sign1 protected headers missing algorithm (label 1)",
115
+ "E_EAT_INVALID_COSE"
116
+ );
117
+ }
118
+ if (alg !== COSE_ALG.EdDSA) {
119
+ throw new EatAdapterError(
120
+ `Unsupported COSE algorithm ${alg}; only EdDSA (-8) is supported`,
121
+ "E_EAT_UNSUPPORTED_ALG"
122
+ );
123
+ }
124
+ const kid = headerMap.get(4);
125
+ return {
126
+ alg,
127
+ kid: kid instanceof Uint8Array || typeof kid === "string" ? kid : void 0
128
+ };
129
+ }
130
+ function decodeEatClaims(payload) {
131
+ if (payload.length === 0) {
132
+ return /* @__PURE__ */ new Map();
133
+ }
134
+ let decoded;
135
+ try {
136
+ decoded = cborDecode(payload);
137
+ } catch {
138
+ throw new EatAdapterError("EAT payload is not valid CBOR", "E_EAT_INVALID_CBOR");
139
+ }
140
+ if (decoded instanceof Map) {
141
+ return decoded;
142
+ }
143
+ if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
144
+ const map = /* @__PURE__ */ new Map();
145
+ for (const [k, v] of Object.entries(decoded)) {
146
+ const numKey = Number(k);
147
+ map.set(Number.isInteger(numKey) ? numKey : k, v);
148
+ }
149
+ return map;
150
+ }
151
+ throw new EatAdapterError("EAT payload must be a CBOR map", "E_EAT_INVALID_CBOR");
152
+ }
153
+ function buildSigStructure(protectedBytes, payload, externalAad = new Uint8Array(0)) {
154
+ const sigStructure = ["Signature1", protectedBytes, externalAad, payload];
155
+ return cborEncode(sigStructure);
156
+ }
157
+ async function decodeEatPassport(data, publicKey) {
158
+ if (data.length > EAT_SIZE_LIMIT) {
159
+ throw new EatAdapterError(
160
+ `EAT token is ${data.length} bytes, exceeding ${EAT_SIZE_LIMIT} byte limit`,
161
+ "E_EAT_SIZE_EXCEEDED"
162
+ );
163
+ }
164
+ if (data.length === 0) {
165
+ throw new EatAdapterError("EAT token is empty", "E_EAT_INVALID_CBOR");
166
+ }
167
+ const coseSign1 = decodeCoseSign1(data);
168
+ const headers = decodeProtectedHeaders(coseSign1.protected);
169
+ const claims = decodeEatClaims(coseSign1.payload);
170
+ let signatureValid;
171
+ if (publicKey !== void 0) {
172
+ if (publicKey.length !== 32) {
173
+ throw new EatAdapterError(
174
+ `Ed25519 public key must be 32 bytes, got ${publicKey.length}`,
175
+ "E_EAT_SIGNATURE_FAILED"
176
+ );
177
+ }
178
+ const sigStructureBytes = buildSigStructure(coseSign1.protected, coseSign1.payload);
179
+ try {
180
+ signatureValid = await ed25519Verify(coseSign1.signature, sigStructureBytes, publicKey);
181
+ } catch {
182
+ throw new EatAdapterError("Ed25519 signature verification failed", "E_EAT_SIGNATURE_FAILED");
183
+ }
184
+ if (!signatureValid) {
185
+ throw new EatAdapterError(
186
+ "COSE_Sign1 Ed25519 signature is invalid",
187
+ "E_EAT_SIGNATURE_FAILED"
188
+ );
189
+ }
190
+ }
191
+ return { headers, claims, signatureValid };
192
+ }
193
+ var DEFAULT_TYPE = "org.peacprotocol/attestation";
194
+ var DEFAULT_PILLARS = ["identity"];
195
+ var CLAIM_LABEL_NAMES = {
196
+ [EAT_CLAIM_KEY.iss]: "iss",
197
+ [EAT_CLAIM_KEY.sub]: "sub",
198
+ [EAT_CLAIM_KEY.aud]: "aud",
199
+ [EAT_CLAIM_KEY.exp]: "exp",
200
+ [EAT_CLAIM_KEY.nbf]: "nbf",
201
+ [EAT_CLAIM_KEY.iat]: "iat",
202
+ [EAT_CLAIM_KEY.cti]: "cti",
203
+ [EAT_CLAIM_KEY.nonce]: "nonce",
204
+ [EAT_CLAIM_KEY.ueid]: "ueid",
205
+ [EAT_CLAIM_KEY.sueids]: "sueids",
206
+ [EAT_CLAIM_KEY.oemid]: "oemid",
207
+ [EAT_CLAIM_KEY.hwmodel]: "hwmodel",
208
+ [EAT_CLAIM_KEY.hwversion]: "hwversion",
209
+ [EAT_CLAIM_KEY.swname]: "swname",
210
+ [EAT_CLAIM_KEY.swversion]: "swversion",
211
+ [EAT_CLAIM_KEY.secboot]: "secboot",
212
+ [EAT_CLAIM_KEY.dbgstat]: "dbgstat"
213
+ };
214
+ function serializeClaimValue(value) {
215
+ if (value instanceof Uint8Array) {
216
+ return Array.from(value).map((b) => b.toString(16).padStart(2, "0")).join("");
217
+ }
218
+ if (typeof value === "string") return value;
219
+ if (typeof value === "number") return String(value);
220
+ if (typeof value === "boolean") return String(value);
221
+ return JSON.stringify(value);
222
+ }
223
+ async function mapEatClaims(claims, options = {}) {
224
+ const { includeRawClaims = [], type = DEFAULT_TYPE, pillars = DEFAULT_PILLARS } = options;
225
+ const rawSet = new Set(includeRawClaims);
226
+ const attestationClaims = {};
227
+ for (const [key, value] of claims) {
228
+ if (typeof key !== "number") continue;
229
+ const labelName = CLAIM_LABEL_NAMES[key] ?? `claim_${key}`;
230
+ const serialized = serializeClaimValue(value);
231
+ if (rawSet.has(key)) {
232
+ attestationClaims[labelName] = serialized;
233
+ } else {
234
+ attestationClaims[labelName] = `sha256:${await sha256Hex(serialized)}`;
235
+ }
236
+ }
237
+ const issValue = claims.get(EAT_CLAIM_KEY.iss);
238
+ const subValue = claims.get(EAT_CLAIM_KEY.sub);
239
+ return {
240
+ kind: "evidence",
241
+ type,
242
+ pillars,
243
+ attestation_claims: attestationClaims,
244
+ eat_iss: typeof issValue === "string" ? issValue : void 0,
245
+ eat_sub: typeof subValue === "string" ? subValue : void 0
246
+ };
247
+ }
248
+
249
+ export { COSE_ALG, EAT_CLAIM_KEY, EAT_SIZE_LIMIT, EatAdapterError, decodeEatPassport, mapEatClaims };
250
+ //# sourceMappingURL=index.mjs.map
251
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/passport.ts","../src/claim-mapper.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * EAT (Entity Attestation Token) and COSE types\n *\n * References:\n * - RFC 9711 (Entity Attestation Token)\n * - RFC 9052 Section 4.2 (COSE_Sign1)\n * - RFC 9053 (COSE Initial Algorithms)\n * - RFC 8949 (CBOR)\n */\n\n/**\n * COSE_Sign1 structure per RFC 9052 Section 4.2.\n *\n * COSE_Sign1 = [\n * protected : bstr, -- Serialized protected headers (CBOR-encoded map)\n * unprotected : map, -- Unprotected headers (CBOR map, may be empty)\n * payload : bstr / nil, -- Payload bytes\n * signature : bstr -- Signature bytes\n * ]\n */\nexport interface CoseSign1 {\n protected: Uint8Array;\n unprotected: Map<number, unknown>;\n payload: Uint8Array;\n signature: Uint8Array;\n}\n\n/**\n * Decoded COSE protected headers.\n *\n * COSE header parameter labels (integer keys per RFC 9052 Section 3.1):\n * 1 = alg (algorithm)\n * 4 = kid (key identifier)\n */\nexport interface CoseProtectedHeaders {\n alg: number;\n kid?: Uint8Array | string;\n}\n\n/** COSE algorithm identifiers per RFC 9053 Table 2 */\nexport const COSE_ALG = {\n /** EdDSA (Ed25519 or Ed448) */\n EdDSA: -8,\n} as const;\n\n/**\n * EAT standard claim keys (CBOR integer labels per RFC 9711 Section 4).\n *\n * Many of these inherit from CWT (RFC 8392) claim labels.\n */\nexport const EAT_CLAIM_KEY = {\n iss: 1,\n sub: 2,\n aud: 3,\n exp: 4,\n nbf: 5,\n iat: 6,\n cti: 7,\n nonce: 10,\n ueid: 256,\n sueids: 257,\n oemid: 258,\n hwmodel: 259,\n hwversion: 260,\n swname: 271,\n swversion: 272,\n oemueid: 273,\n secboot: 262,\n dbgstat: 263,\n location: 264,\n profile: 265,\n submods: 266,\n uptime: 261,\n intuse: 267,\n dloas: 268,\n manifests: 269,\n measurements: 270,\n} as const;\n\n/**\n * Decoded EAT claims (CBOR map with integer or string keys).\n *\n * The decoder preserves the raw CBOR map. The claim mapper extracts\n * specific claims by integer key.\n */\nexport type EatClaims = Map<number | string, unknown>;\n\n/** Result of decoding and verifying an EAT passport */\nexport interface EatPassportResult {\n /** Decoded protected headers */\n headers: CoseProtectedHeaders;\n /** Raw EAT claims map */\n claims: EatClaims;\n /** Whether the Ed25519 signature is valid (only present if publicKey provided) */\n signatureValid?: boolean;\n}\n\n/** Options for the claim mapper */\nexport interface ClaimMapperOptions {\n /**\n * Claim keys whose raw values should be included in the mapped output.\n * By default, all claim values are hashed (SHA-256 digest) for privacy.\n * List specific integer keys here to include their raw values.\n */\n includeRawClaims?: number[];\n /** Receipt type (reverse-DNS or URI). Defaults to 'org.peacprotocol/attestation' */\n type?: string;\n /** Pillars to include on the receipt. Defaults to ['identity'] */\n pillars?: string[];\n}\n\n/** Mapped Wire 0.2 claims from an EAT passport */\nexport interface MappedEatClaims {\n kind: 'evidence';\n type: string;\n pillars?: string[];\n /** Hashed or raw claim values, keyed by claim label */\n attestation_claims: Record<string, string>;\n /** Original issuer from EAT (if present) */\n eat_iss?: string;\n /** Original subject from EAT (if present) */\n eat_sub?: string;\n}\n\n/** Size limit for EAT tokens (64 KB, consistent with carrier transport limits) */\nexport const EAT_SIZE_LIMIT = 65_536;\n","/**\n * EAT Passport Decoder\n *\n * Decodes COSE_Sign1 structures containing EAT (Entity Attestation Token)\n * payloads per RFC 9711. Optionally verifies Ed25519 signatures per\n * RFC 9052 Section 4.4 (Sig_structure construction).\n *\n * References:\n * - RFC 9052 Section 4.2 (COSE_Sign1 structure)\n * - RFC 9052 Section 4.4 (Signing and Verification Process)\n * - RFC 9053 Table 2 (EdDSA algorithm identifier: -8)\n * - RFC 9711 (Entity Attestation Token)\n * - RFC 8949 (CBOR encoding)\n *\n * Security:\n * - 64 KB size limit enforced BEFORE CBOR decode (DoS prevention)\n * - Only Ed25519 (COSE alg -8) supported; all others rejected\n * - No network I/O\n */\n\nimport cbor from 'cbor';\n\nconst cborDecode = cbor.decode;\nconst cborEncode = cbor.encode;\nimport { ed25519Verify } from '@peac/crypto';\nimport type { CoseSign1, CoseProtectedHeaders, EatClaims, EatPassportResult } from './types.js';\nimport { COSE_ALG, EAT_SIZE_LIMIT } from './types.js';\n\n/** Error class for EAT adapter failures */\nexport class EatAdapterError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'EatAdapterError';\n }\n}\n\n/**\n * Decode a COSE_Sign1 array from raw CBOR bytes.\n *\n * Validates the COSE_Sign1 structure per RFC 9052 Section 4.2:\n * [protected, unprotected, payload, signature]\n *\n * @param data - Raw CBOR bytes\n * @returns Parsed COSE_Sign1 structure\n * @throws EatAdapterError on invalid CBOR or COSE structure\n */\nfunction decodeCoseSign1(data: Uint8Array): CoseSign1 {\n let decoded: unknown;\n try {\n decoded = cborDecode(data);\n } catch {\n throw new EatAdapterError('EAT token is not valid CBOR', 'E_EAT_INVALID_CBOR');\n }\n\n // COSE_Sign1 is a CBOR array of exactly 4 elements\n if (!Array.isArray(decoded) || decoded.length !== 4) {\n throw new EatAdapterError(\n 'EAT token is not a valid COSE_Sign1 structure (expected 4-element array)',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n const [protectedBytes, unprotectedMap, payload, signature] = decoded;\n\n if (!(protectedBytes instanceof Uint8Array)) {\n throw new EatAdapterError(\n 'COSE_Sign1 protected header must be a byte string',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (payload === null) {\n throw new EatAdapterError(\n 'Detached COSE_Sign1 payload (null) is not supported; EAT tokens require an attached payload',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (!(payload instanceof Uint8Array)) {\n throw new EatAdapterError('COSE_Sign1 payload must be a byte string', 'E_EAT_INVALID_COSE');\n }\n\n if (!(signature instanceof Uint8Array)) {\n throw new EatAdapterError('COSE_Sign1 signature must be a byte string', 'E_EAT_INVALID_COSE');\n }\n\n // Ed25519 signatures are exactly 64 bytes\n if (signature.length !== 64) {\n throw new EatAdapterError(\n `COSE_Sign1 signature has unexpected length ${signature.length} (expected 64 for Ed25519)`,\n 'E_EAT_INVALID_COSE'\n );\n }\n\n return {\n protected: protectedBytes,\n unprotected: unprotectedMap instanceof Map ? unprotectedMap : new Map<number, unknown>(),\n payload,\n signature,\n };\n}\n\n/**\n * Decode and validate COSE protected headers.\n *\n * @param protectedBytes - CBOR-encoded protected headers\n * @returns Decoded headers with algorithm and optional kid\n * @throws EatAdapterError if algorithm is not EdDSA (-8)\n */\nfunction decodeProtectedHeaders(protectedBytes: Uint8Array): CoseProtectedHeaders {\n if (protectedBytes.length === 0) {\n throw new EatAdapterError('COSE_Sign1 protected headers are empty', 'E_EAT_INVALID_COSE');\n }\n\n let headerMap: unknown;\n try {\n headerMap = cborDecode(protectedBytes);\n } catch {\n throw new EatAdapterError(\n 'COSE_Sign1 protected headers are not valid CBOR',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (!(headerMap instanceof Map)) {\n throw new EatAdapterError(\n 'COSE_Sign1 protected headers must be a CBOR map',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n // Label 1 = alg\n const alg = headerMap.get(1);\n if (typeof alg !== 'number') {\n throw new EatAdapterError(\n 'COSE_Sign1 protected headers missing algorithm (label 1)',\n 'E_EAT_INVALID_COSE'\n );\n }\n\n if (alg !== COSE_ALG.EdDSA) {\n throw new EatAdapterError(\n `Unsupported COSE algorithm ${alg}; only EdDSA (-8) is supported`,\n 'E_EAT_UNSUPPORTED_ALG'\n );\n }\n\n // Label 4 = kid (optional)\n const kid = headerMap.get(4);\n\n return {\n alg,\n kid: kid instanceof Uint8Array || typeof kid === 'string' ? kid : undefined,\n };\n}\n\n/**\n * Decode EAT claims from COSE payload bytes.\n *\n * @param payload - CBOR-encoded payload\n * @returns EAT claims as a Map\n * @throws EatAdapterError if payload is not valid CBOR\n */\nfunction decodeEatClaims(payload: Uint8Array): EatClaims {\n if (payload.length === 0) {\n return new Map();\n }\n\n let decoded: unknown;\n try {\n decoded = cborDecode(payload);\n } catch {\n throw new EatAdapterError('EAT payload is not valid CBOR', 'E_EAT_INVALID_CBOR');\n }\n\n if (decoded instanceof Map) {\n return decoded as EatClaims;\n }\n\n // Some CBOR decoders return plain objects for empty maps or when\n // configured without Map preference. Convert to Map for consistency.\n if (typeof decoded === 'object' && decoded !== null && !Array.isArray(decoded)) {\n const map = new Map<number | string, unknown>();\n for (const [k, v] of Object.entries(decoded as Record<string, unknown>)) {\n const numKey = Number(k);\n map.set(Number.isInteger(numKey) ? numKey : k, v);\n }\n return map;\n }\n\n throw new EatAdapterError('EAT payload must be a CBOR map', 'E_EAT_INVALID_CBOR');\n}\n\n/**\n * Construct the Sig_structure for COSE_Sign1 verification per RFC 9052 Section 4.4.\n *\n * Sig_structure1 = [\n * context : \"Signature1\",\n * body_protected : bstr,\n * external_aad : bstr,\n * payload : bstr\n * ]\n *\n * @param protectedBytes - Serialized protected headers\n * @param payload - Payload bytes\n * @param externalAad - External additional authenticated data (defaults to empty)\n * @returns CBOR-encoded Sig_structure bytes\n */\nfunction buildSigStructure(\n protectedBytes: Uint8Array,\n payload: Uint8Array,\n externalAad: Uint8Array = new Uint8Array(0)\n): Uint8Array {\n const sigStructure = ['Signature1', protectedBytes, externalAad, payload];\n return cborEncode(sigStructure);\n}\n\n/**\n * Decode an EAT passport from COSE_Sign1 CBOR bytes.\n *\n * Enforces a 64 KB size limit before CBOR decode (DoS prevention).\n * Validates COSE_Sign1 structure per RFC 9052 Section 4.2.\n * Optionally verifies Ed25519 signature per RFC 9052 Section 4.4.\n *\n * @param data - Raw COSE_Sign1 CBOR bytes\n * @param publicKey - Optional Ed25519 public key (32 bytes) for signature verification\n * @returns Decoded EAT passport with headers, claims, and optional signature validity\n * @throws EatAdapterError on size, CBOR, COSE, or algorithm errors\n */\nexport async function decodeEatPassport(\n data: Uint8Array,\n publicKey?: Uint8Array\n): Promise<EatPassportResult> {\n // Size limit: 64 KB enforced BEFORE any CBOR decode\n if (data.length > EAT_SIZE_LIMIT) {\n throw new EatAdapterError(\n `EAT token is ${data.length} bytes, exceeding ${EAT_SIZE_LIMIT} byte limit`,\n 'E_EAT_SIZE_EXCEEDED'\n );\n }\n\n if (data.length === 0) {\n throw new EatAdapterError('EAT token is empty', 'E_EAT_INVALID_CBOR');\n }\n\n // Step 1: Decode COSE_Sign1 structure\n const coseSign1 = decodeCoseSign1(data);\n\n // Step 2: Decode and validate protected headers\n const headers = decodeProtectedHeaders(coseSign1.protected);\n\n // Step 3: Decode EAT claims from payload\n const claims = decodeEatClaims(coseSign1.payload);\n\n // Step 4: Optionally verify Ed25519 signature\n let signatureValid: boolean | undefined;\n if (publicKey !== undefined) {\n if (publicKey.length !== 32) {\n throw new EatAdapterError(\n `Ed25519 public key must be 32 bytes, got ${publicKey.length}`,\n 'E_EAT_SIGNATURE_FAILED'\n );\n }\n\n const sigStructureBytes = buildSigStructure(coseSign1.protected, coseSign1.payload);\n\n try {\n signatureValid = await ed25519Verify(coseSign1.signature, sigStructureBytes, publicKey);\n } catch {\n throw new EatAdapterError('Ed25519 signature verification failed', 'E_EAT_SIGNATURE_FAILED');\n }\n\n if (!signatureValid) {\n throw new EatAdapterError(\n 'COSE_Sign1 Ed25519 signature is invalid',\n 'E_EAT_SIGNATURE_FAILED'\n );\n }\n }\n\n return { headers, claims, signatureValid };\n}\n","/**\n * EAT Claim Mapper: maps EAT claims to Wire 0.2 receipt claims\n *\n * Privacy-first: all claim values are SHA-256 hashed by default.\n * Callers opt in to raw value inclusion via `includeRawClaims` option.\n * This prevents accidental PII leakage from EAT attestations into PEAC receipts.\n *\n * References:\n * - RFC 9711 (Entity Attestation Token)\n * - Wire 0.2 spec: kind, type, pillars, extensions\n */\n\nimport { sha256Hex } from '@peac/crypto';\nimport { EAT_CLAIM_KEY } from './types.js';\nimport type { EatClaims, ClaimMapperOptions, MappedEatClaims } from './types.js';\n\nconst DEFAULT_TYPE = 'org.peacprotocol/attestation';\nconst DEFAULT_PILLARS = ['identity'];\n\n/** Well-known EAT claim labels (integer to string name) */\nconst CLAIM_LABEL_NAMES: Record<number, string> = {\n [EAT_CLAIM_KEY.iss]: 'iss',\n [EAT_CLAIM_KEY.sub]: 'sub',\n [EAT_CLAIM_KEY.aud]: 'aud',\n [EAT_CLAIM_KEY.exp]: 'exp',\n [EAT_CLAIM_KEY.nbf]: 'nbf',\n [EAT_CLAIM_KEY.iat]: 'iat',\n [EAT_CLAIM_KEY.cti]: 'cti',\n [EAT_CLAIM_KEY.nonce]: 'nonce',\n [EAT_CLAIM_KEY.ueid]: 'ueid',\n [EAT_CLAIM_KEY.sueids]: 'sueids',\n [EAT_CLAIM_KEY.oemid]: 'oemid',\n [EAT_CLAIM_KEY.hwmodel]: 'hwmodel',\n [EAT_CLAIM_KEY.hwversion]: 'hwversion',\n [EAT_CLAIM_KEY.swname]: 'swname',\n [EAT_CLAIM_KEY.swversion]: 'swversion',\n [EAT_CLAIM_KEY.secboot]: 'secboot',\n [EAT_CLAIM_KEY.dbgstat]: 'dbgstat',\n};\n\n/**\n * Serialize a claim value to a deterministic string for hashing.\n * Handles Uint8Array (hex), numbers, strings, and falls back to JSON.\n */\nfunction serializeClaimValue(value: unknown): string {\n if (value instanceof Uint8Array) {\n return Array.from(value)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n if (typeof value === 'string') return value;\n if (typeof value === 'number') return String(value);\n if (typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\n/**\n * Map EAT claims to Wire 0.2 receipt claims.\n *\n * Privacy-first: claim values are SHA-256 hashed unless their integer key\n * appears in `options.includeRawClaims`. This prevents accidental PII leakage.\n *\n * @param claims - Decoded EAT claims map\n * @param options - Mapper configuration\n * @returns Mapped claims suitable for Wire 0.2 receipt issuance\n */\nexport async function mapEatClaims(\n claims: EatClaims,\n options: ClaimMapperOptions = {}\n): Promise<MappedEatClaims> {\n const { includeRawClaims = [], type = DEFAULT_TYPE, pillars = DEFAULT_PILLARS } = options;\n\n const rawSet = new Set(includeRawClaims);\n const attestationClaims: Record<string, string> = {};\n\n for (const [key, value] of claims) {\n if (typeof key !== 'number') continue;\n\n const labelName = CLAIM_LABEL_NAMES[key] ?? `claim_${key}`;\n const serialized = serializeClaimValue(value);\n\n if (rawSet.has(key)) {\n attestationClaims[labelName] = serialized;\n } else {\n attestationClaims[labelName] = `sha256:${await sha256Hex(serialized)}`;\n }\n }\n\n // Extract standard identifiers (if present and opted-in to raw)\n const issValue = claims.get(EAT_CLAIM_KEY.iss);\n const subValue = claims.get(EAT_CLAIM_KEY.sub);\n\n return {\n kind: 'evidence',\n type,\n pillars,\n attestation_claims: attestationClaims,\n eat_iss: typeof issValue === 'string' ? issValue : undefined,\n eat_sub: typeof subValue === 'string' ? subValue : undefined,\n };\n}\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * EAT Passport Decoder
3
+ *
4
+ * Decodes COSE_Sign1 structures containing EAT (Entity Attestation Token)
5
+ * payloads per RFC 9711. Optionally verifies Ed25519 signatures per
6
+ * RFC 9052 Section 4.4 (Sig_structure construction).
7
+ *
8
+ * References:
9
+ * - RFC 9052 Section 4.2 (COSE_Sign1 structure)
10
+ * - RFC 9052 Section 4.4 (Signing and Verification Process)
11
+ * - RFC 9053 Table 2 (EdDSA algorithm identifier: -8)
12
+ * - RFC 9711 (Entity Attestation Token)
13
+ * - RFC 8949 (CBOR encoding)
14
+ *
15
+ * Security:
16
+ * - 64 KB size limit enforced BEFORE CBOR decode (DoS prevention)
17
+ * - Only Ed25519 (COSE alg -8) supported; all others rejected
18
+ * - No network I/O
19
+ */
20
+ import type { EatPassportResult } from './types.js';
21
+ /** Error class for EAT adapter failures */
22
+ export declare class EatAdapterError extends Error {
23
+ readonly code: string;
24
+ constructor(message: string, code: string);
25
+ }
26
+ /**
27
+ * Decode an EAT passport from COSE_Sign1 CBOR bytes.
28
+ *
29
+ * Enforces a 64 KB size limit before CBOR decode (DoS prevention).
30
+ * Validates COSE_Sign1 structure per RFC 9052 Section 4.2.
31
+ * Optionally verifies Ed25519 signature per RFC 9052 Section 4.4.
32
+ *
33
+ * @param data - Raw COSE_Sign1 CBOR bytes
34
+ * @param publicKey - Optional Ed25519 public key (32 bytes) for signature verification
35
+ * @returns Decoded EAT passport with headers, claims, and optional signature validity
36
+ * @throws EatAdapterError on size, CBOR, COSE, or algorithm errors
37
+ */
38
+ export declare function decodeEatPassport(data: Uint8Array, publicKey?: Uint8Array): Promise<EatPassportResult>;
39
+ //# sourceMappingURL=passport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passport.d.ts","sourceRoot":"","sources":["../src/passport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,KAAK,EAA8C,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGhG,2CAA2C;AAC3C,qBAAa,eAAgB,SAAQ,KAAK;aAGtB,IAAI,EAAE,MAAM;gBAD5B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM;CAK/B;AAuLD;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,EAChB,SAAS,CAAC,EAAE,UAAU,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAiD5B"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * EAT (Entity Attestation Token) and COSE types
3
+ *
4
+ * References:
5
+ * - RFC 9711 (Entity Attestation Token)
6
+ * - RFC 9052 Section 4.2 (COSE_Sign1)
7
+ * - RFC 9053 (COSE Initial Algorithms)
8
+ * - RFC 8949 (CBOR)
9
+ */
10
+ /**
11
+ * COSE_Sign1 structure per RFC 9052 Section 4.2.
12
+ *
13
+ * COSE_Sign1 = [
14
+ * protected : bstr, -- Serialized protected headers (CBOR-encoded map)
15
+ * unprotected : map, -- Unprotected headers (CBOR map, may be empty)
16
+ * payload : bstr / nil, -- Payload bytes
17
+ * signature : bstr -- Signature bytes
18
+ * ]
19
+ */
20
+ export interface CoseSign1 {
21
+ protected: Uint8Array;
22
+ unprotected: Map<number, unknown>;
23
+ payload: Uint8Array;
24
+ signature: Uint8Array;
25
+ }
26
+ /**
27
+ * Decoded COSE protected headers.
28
+ *
29
+ * COSE header parameter labels (integer keys per RFC 9052 Section 3.1):
30
+ * 1 = alg (algorithm)
31
+ * 4 = kid (key identifier)
32
+ */
33
+ export interface CoseProtectedHeaders {
34
+ alg: number;
35
+ kid?: Uint8Array | string;
36
+ }
37
+ /** COSE algorithm identifiers per RFC 9053 Table 2 */
38
+ export declare const COSE_ALG: {
39
+ /** EdDSA (Ed25519 or Ed448) */
40
+ readonly EdDSA: -8;
41
+ };
42
+ /**
43
+ * EAT standard claim keys (CBOR integer labels per RFC 9711 Section 4).
44
+ *
45
+ * Many of these inherit from CWT (RFC 8392) claim labels.
46
+ */
47
+ export declare const EAT_CLAIM_KEY: {
48
+ readonly iss: 1;
49
+ readonly sub: 2;
50
+ readonly aud: 3;
51
+ readonly exp: 4;
52
+ readonly nbf: 5;
53
+ readonly iat: 6;
54
+ readonly cti: 7;
55
+ readonly nonce: 10;
56
+ readonly ueid: 256;
57
+ readonly sueids: 257;
58
+ readonly oemid: 258;
59
+ readonly hwmodel: 259;
60
+ readonly hwversion: 260;
61
+ readonly swname: 271;
62
+ readonly swversion: 272;
63
+ readonly oemueid: 273;
64
+ readonly secboot: 262;
65
+ readonly dbgstat: 263;
66
+ readonly location: 264;
67
+ readonly profile: 265;
68
+ readonly submods: 266;
69
+ readonly uptime: 261;
70
+ readonly intuse: 267;
71
+ readonly dloas: 268;
72
+ readonly manifests: 269;
73
+ readonly measurements: 270;
74
+ };
75
+ /**
76
+ * Decoded EAT claims (CBOR map with integer or string keys).
77
+ *
78
+ * The decoder preserves the raw CBOR map. The claim mapper extracts
79
+ * specific claims by integer key.
80
+ */
81
+ export type EatClaims = Map<number | string, unknown>;
82
+ /** Result of decoding and verifying an EAT passport */
83
+ export interface EatPassportResult {
84
+ /** Decoded protected headers */
85
+ headers: CoseProtectedHeaders;
86
+ /** Raw EAT claims map */
87
+ claims: EatClaims;
88
+ /** Whether the Ed25519 signature is valid (only present if publicKey provided) */
89
+ signatureValid?: boolean;
90
+ }
91
+ /** Options for the claim mapper */
92
+ export interface ClaimMapperOptions {
93
+ /**
94
+ * Claim keys whose raw values should be included in the mapped output.
95
+ * By default, all claim values are hashed (SHA-256 digest) for privacy.
96
+ * List specific integer keys here to include their raw values.
97
+ */
98
+ includeRawClaims?: number[];
99
+ /** Receipt type (reverse-DNS or URI). Defaults to 'org.peacprotocol/attestation' */
100
+ type?: string;
101
+ /** Pillars to include on the receipt. Defaults to ['identity'] */
102
+ pillars?: string[];
103
+ }
104
+ /** Mapped Wire 0.2 claims from an EAT passport */
105
+ export interface MappedEatClaims {
106
+ kind: 'evidence';
107
+ type: string;
108
+ pillars?: string[];
109
+ /** Hashed or raw claim values, keyed by claim label */
110
+ attestation_claims: Record<string, string>;
111
+ /** Original issuer from EAT (if present) */
112
+ eat_iss?: string;
113
+ /** Original subject from EAT (if present) */
114
+ eat_sub?: string;
115
+ }
116
+ /** Size limit for EAT tokens (64 KB, consistent with carrier transport limits) */
117
+ export declare const EAT_SIZE_LIMIT = 65536;
118
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,UAAU,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAC3B;AAED,sDAAsD;AACtD,eAAO,MAAM,QAAQ;IACnB,+BAA+B;;CAEvB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BhB,CAAC;AAEX;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,uDAAuD;AACvD,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,yBAAyB;IACzB,MAAM,EAAE,SAAS,CAAC;IAClB,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,mCAAmC;AACnC,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,uDAAuD;IACvD,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,QAAS,CAAC"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@peac/adapter-eat",
3
+ "version": "0.12.6",
4
+ "description": "EAT (Entity Attestation Token, RFC 9711) passport decoder and PEAC claim mapper",
5
+ "main": "dist/index.cjs",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.cjs",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "./package.json": "./package.json"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/peacprotocol/peac.git",
19
+ "directory": "packages/adapters/eat"
20
+ },
21
+ "author": "PEAC Protocol Contributors",
22
+ "license": "Apache-2.0",
23
+ "files": [
24
+ "dist",
25
+ "README.md"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "dependencies": {
31
+ "cbor": "^9.0.0",
32
+ "@peac/kernel": "0.12.6",
33
+ "@peac/crypto": "0.12.6",
34
+ "@peac/schema": "0.12.6"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^22.19.11",
38
+ "tsup": "^8.0.0",
39
+ "typescript": "^5.3.3",
40
+ "vitest": "^4.0.0"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/peacprotocol/peac/issues"
44
+ },
45
+ "homepage": "https://github.com/peacprotocol/peac#readme",
46
+ "keywords": [
47
+ "peac",
48
+ "peacprotocol",
49
+ "interaction-records",
50
+ "signed-records",
51
+ "receipts",
52
+ "originary",
53
+ "eat",
54
+ "entity-attestation-token",
55
+ "attestation",
56
+ "cose",
57
+ "cbor",
58
+ "rfc9711"
59
+ ],
60
+ "scripts": {
61
+ "prebuild": "rm -rf dist",
62
+ "build": "pnpm run build:js && pnpm run build:types",
63
+ "test": "vitest run",
64
+ "test:watch": "vitest",
65
+ "clean": "rm -rf dist",
66
+ "build:js": "tsup",
67
+ "build:types": "rm -f dist/.tsbuildinfo && tsc && rm -f dist/.tsbuildinfo"
68
+ }
69
+ }