@enbox/crypto 0.0.4 → 0.0.5
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/dist/browser.mjs +1 -1
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/cose/cbor.js +35 -0
- package/dist/esm/cose/cbor.js.map +1 -0
- package/dist/esm/cose/cose-key.js +312 -0
- package/dist/esm/cose/cose-key.js.map +1 -0
- package/dist/esm/cose/cose-sign1.js +283 -0
- package/dist/esm/cose/cose-sign1.js.map +1 -0
- package/dist/esm/cose/eat.js +254 -0
- package/dist/esm/cose/eat.js.map +1 -0
- package/dist/esm/crypto-error.js +4 -0
- package/dist/esm/crypto-error.js.map +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/types/cose/cbor.d.ts +30 -0
- package/dist/types/cose/cbor.d.ts.map +1 -0
- package/dist/types/cose/cose-key.d.ts +106 -0
- package/dist/types/cose/cose-key.d.ts.map +1 -0
- package/dist/types/cose/cose-sign1.d.ts +195 -0
- package/dist/types/cose/cose-sign1.d.ts.map +1 -0
- package/dist/types/cose/eat.d.ts +203 -0
- package/dist/types/cose/eat.d.ts.map +1 -0
- package/dist/types/crypto-error.d.ts +4 -0
- package/dist/types/crypto-error.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/cose/cbor.ts +36 -0
- package/src/cose/cose-key.ts +344 -0
- package/src/cose/cose-sign1.ts +473 -0
- package/src/cose/eat.ts +368 -0
- package/src/crypto-error.ts +6 -0
- package/src/index.ts +5 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type { CoseSign1ProtectedHeader } from './cose-sign1.js';
|
|
2
|
+
import type { Jwk } from '../jose/jwk.js';
|
|
3
|
+
/**
|
|
4
|
+
* EAT (Entity Attestation Token) claim key constants.
|
|
5
|
+
*
|
|
6
|
+
* EAT reuses CWT registered claim keys and adds attestation-specific claims.
|
|
7
|
+
*
|
|
8
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9711 | RFC 9711 — Entity Attestation Token (EAT)}
|
|
9
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc8392 | RFC 8392 — CWT (CBOR Web Token)}
|
|
10
|
+
*/
|
|
11
|
+
export declare enum EatClaimKey {
|
|
12
|
+
/** Issuer (iss) — RFC 8392 */
|
|
13
|
+
Iss = 1,
|
|
14
|
+
/** Subject (sub) — RFC 8392 */
|
|
15
|
+
Sub = 2,
|
|
16
|
+
/** Audience (aud) — RFC 8392 */
|
|
17
|
+
Aud = 3,
|
|
18
|
+
/** Expiration Time (exp) — RFC 8392 */
|
|
19
|
+
Exp = 4,
|
|
20
|
+
/** Not Before (nbf) — RFC 8392 */
|
|
21
|
+
Nbf = 5,
|
|
22
|
+
/** Issued At (iat) — RFC 8392 */
|
|
23
|
+
Iat = 6,
|
|
24
|
+
/** CWT ID (cti) — RFC 8392 */
|
|
25
|
+
Cti = 7,
|
|
26
|
+
/** Nonce (eat_nonce) — RFC 9711, Section 4.1 */
|
|
27
|
+
Nonce = 10,
|
|
28
|
+
/** UEID (Universal Entity ID) — RFC 9711, Section 4.2.1 */
|
|
29
|
+
Ueid = 256,
|
|
30
|
+
/** SUEIDs (Semi-permanent UEIDs) — RFC 9711, Section 4.2.2 */
|
|
31
|
+
Sueids = 257,
|
|
32
|
+
/** OEM ID (Hardware OEM Identification) — RFC 9711, Section 4.2.3 */
|
|
33
|
+
Oemid = 258,
|
|
34
|
+
/** Hardware Model — RFC 9711, Section 4.2.4 */
|
|
35
|
+
Hwmodel = 259,
|
|
36
|
+
/** Hardware Version — RFC 9711, Section 4.2.5 */
|
|
37
|
+
Hwversion = 260,
|
|
38
|
+
/** Secure Boot — RFC 9711, Section 4.2.7 */
|
|
39
|
+
Secboot = 262,
|
|
40
|
+
/** Debug Status — RFC 9711, Section 4.2.8 */
|
|
41
|
+
Dbgstat = 263,
|
|
42
|
+
/** Location — RFC 9711, Section 4.2.9 */
|
|
43
|
+
Location = 264,
|
|
44
|
+
/** Profile — RFC 9711, Section 4.2.10 */
|
|
45
|
+
Profile = 265,
|
|
46
|
+
/** Submods (Submodules) — RFC 9711, Section 4.2.18 */
|
|
47
|
+
Submods = 266,
|
|
48
|
+
/** Measurement Results — RFC 9711, Section 4.2.15 */
|
|
49
|
+
Measres = 272,
|
|
50
|
+
/** Intended Use — RFC 9711, Section 4.2.14 */
|
|
51
|
+
Intuse = 268
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Debug status values for the `dbgstat` claim.
|
|
55
|
+
*
|
|
56
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9711#section-4.2.8 | RFC 9711, Section 4.2.8}
|
|
57
|
+
*/
|
|
58
|
+
export declare enum EatDebugStatus {
|
|
59
|
+
/** Debug is enabled */
|
|
60
|
+
Enabled = 0,
|
|
61
|
+
/** Debug is disabled */
|
|
62
|
+
Disabled = 1,
|
|
63
|
+
/** Debug is disabled since manufacture */
|
|
64
|
+
DisabledSinceBoot = 2,
|
|
65
|
+
/** Debug is disabled permanently */
|
|
66
|
+
DisabledPermanently = 3,
|
|
67
|
+
/** Debug is disabled fully and permanently */
|
|
68
|
+
DisabledFullyAndPermanently = 4
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Security level for the `seclevel` claim.
|
|
72
|
+
*
|
|
73
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9711#section-4.2.6 | RFC 9711, Section 4.2.6}
|
|
74
|
+
*/
|
|
75
|
+
export declare enum EatSecurityLevel {
|
|
76
|
+
/** Unrestricted — no security guarantees */
|
|
77
|
+
Unrestricted = 1,
|
|
78
|
+
/** Restricted — some restrictions on environment */
|
|
79
|
+
Restricted = 2,
|
|
80
|
+
/** Secure Restricted — hardware-enforced restrictions */
|
|
81
|
+
SecureRestricted = 3,
|
|
82
|
+
/** Hardware — hardware-isolated execution environment */
|
|
83
|
+
Hardware = 4
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Parsed EAT claims, providing typed access to standard and attestation-specific claims.
|
|
87
|
+
*
|
|
88
|
+
* All fields are optional because EAT does not mandate any specific claims; the
|
|
89
|
+
* required set depends on the attestation profile.
|
|
90
|
+
*
|
|
91
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9711 | RFC 9711}
|
|
92
|
+
*/
|
|
93
|
+
export interface EatClaims {
|
|
94
|
+
/** Issuer — identifies the entity that issued the token. */
|
|
95
|
+
iss?: string;
|
|
96
|
+
/** Subject — identifies the entity that is the subject of the token. */
|
|
97
|
+
sub?: string;
|
|
98
|
+
/** Audience — identifies the intended recipient(s). */
|
|
99
|
+
aud?: string;
|
|
100
|
+
/** Expiration time (seconds since epoch). */
|
|
101
|
+
exp?: number;
|
|
102
|
+
/** Not Before (seconds since epoch). */
|
|
103
|
+
nbf?: number;
|
|
104
|
+
/** Issued At (seconds since epoch). */
|
|
105
|
+
iat?: number;
|
|
106
|
+
/** CWT ID — unique token identifier (byte string). */
|
|
107
|
+
cti?: Uint8Array;
|
|
108
|
+
/** Nonce — challenge value binding the token to a request. */
|
|
109
|
+
nonce?: Uint8Array | Uint8Array[];
|
|
110
|
+
/** Universal Entity ID. */
|
|
111
|
+
ueid?: Uint8Array;
|
|
112
|
+
/** Hardware model identifier. */
|
|
113
|
+
hwmodel?: Uint8Array;
|
|
114
|
+
/** Hardware version. */
|
|
115
|
+
hwversion?: unknown;
|
|
116
|
+
/** Debug status. */
|
|
117
|
+
dbgstat?: EatDebugStatus;
|
|
118
|
+
/** Measurement results — software component measurements. */
|
|
119
|
+
measres?: unknown;
|
|
120
|
+
/** Submodules — nested EAT tokens or claims from sub-components. */
|
|
121
|
+
submods?: Map<string, unknown>;
|
|
122
|
+
/**
|
|
123
|
+
* All raw claims as a Map for access to non-standard or profile-specific claims.
|
|
124
|
+
* Integer keys correspond to {@link EatClaimKey} values.
|
|
125
|
+
*/
|
|
126
|
+
rawClaims: Map<number | string, unknown>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Parameters for decoding an EAT token.
|
|
130
|
+
*/
|
|
131
|
+
export interface EatDecodeParams {
|
|
132
|
+
/** The CBOR-encoded EAT token (COSE_Sign1 envelope). */
|
|
133
|
+
token: Uint8Array;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Parameters for verifying and decoding an EAT token.
|
|
137
|
+
*/
|
|
138
|
+
export interface EatVerifyParams {
|
|
139
|
+
/** The CBOR-encoded EAT token (COSE_Sign1 envelope). */
|
|
140
|
+
token: Uint8Array;
|
|
141
|
+
/** The public key for signature verification, in JWK format. */
|
|
142
|
+
key: Jwk;
|
|
143
|
+
/** External additional authenticated data. Defaults to empty bytes. */
|
|
144
|
+
externalAad?: Uint8Array;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Result of decoding an EAT token.
|
|
148
|
+
*/
|
|
149
|
+
export interface EatDecodeResult {
|
|
150
|
+
/** The parsed protected header from the COSE_Sign1 envelope. */
|
|
151
|
+
protectedHeader: CoseSign1ProtectedHeader;
|
|
152
|
+
/** The parsed EAT claims from the payload. */
|
|
153
|
+
claims: EatClaims;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Entity Attestation Token (EAT) implementation per RFC 9711.
|
|
157
|
+
*
|
|
158
|
+
* EATs are CBOR-based attestation tokens carried in COSE_Sign1 envelopes.
|
|
159
|
+
* They are used by TEE platforms (ARM CCA, Intel TDX, AMD SEV-SNP, Nitro Enclaves)
|
|
160
|
+
* to provide hardware-rooted attestation evidence.
|
|
161
|
+
*
|
|
162
|
+
* This implementation focuses on decoding and verification of EAT tokens — the
|
|
163
|
+
* primary use case for a DWN node that needs to verify TEE attestation from
|
|
164
|
+
* compute modules.
|
|
165
|
+
*
|
|
166
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9711 | RFC 9711 — Entity Attestation Token (EAT)}
|
|
167
|
+
*/
|
|
168
|
+
export declare class Eat {
|
|
169
|
+
/**
|
|
170
|
+
* Decodes an EAT token without verifying its signature.
|
|
171
|
+
*
|
|
172
|
+
* Use this method only when signature verification is performed separately
|
|
173
|
+
* (e.g., by a TEE attestation service) or for debugging/inspection.
|
|
174
|
+
*
|
|
175
|
+
* @param params - The parameters for decoding.
|
|
176
|
+
* @returns The decoded protected header and claims.
|
|
177
|
+
* @throws {CryptoError} If the token is not valid COSE_Sign1 or the payload is not valid CBOR.
|
|
178
|
+
*/
|
|
179
|
+
static decode({ token }: EatDecodeParams): EatDecodeResult;
|
|
180
|
+
/**
|
|
181
|
+
* Verifies the signature of an EAT token and decodes its claims.
|
|
182
|
+
*
|
|
183
|
+
* This is the primary method for processing EAT tokens from TEE attestation.
|
|
184
|
+
* It verifies the COSE_Sign1 signature using the provided public key, then
|
|
185
|
+
* parses the EAT claims from the payload.
|
|
186
|
+
*
|
|
187
|
+
* @param params - The parameters for verification and decoding.
|
|
188
|
+
* @returns The decoded protected header and claims if verification succeeds.
|
|
189
|
+
* @throws {CryptoError} If verification fails or the token is malformed.
|
|
190
|
+
*/
|
|
191
|
+
static verifyAndDecode(params: EatVerifyParams): Promise<EatDecodeResult>;
|
|
192
|
+
/**
|
|
193
|
+
* Parses CBOR-encoded EAT claims into a typed {@link EatClaims} object.
|
|
194
|
+
*
|
|
195
|
+
* Handles both integer-keyed (CBOR standard) and string-keyed claims.
|
|
196
|
+
*
|
|
197
|
+
* @param payload - The CBOR-encoded claims byte string.
|
|
198
|
+
* @returns The parsed EAT claims.
|
|
199
|
+
* @throws {CryptoError} If the payload is not valid CBOR or not a map.
|
|
200
|
+
*/
|
|
201
|
+
private static parseClaims;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=eat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eat.d.ts","sourceRoot":"","sources":["../../../src/cose/eat.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,10 @@ export declare enum CryptoErrorCode {
|
|
|
19
19
|
AlgorithmNotSupported = "algorithmNotSupported",
|
|
20
20
|
/** The encoding operation (either encoding or decoding) failed. */
|
|
21
21
|
EncodingError = "encodingError",
|
|
22
|
+
/** The COSE_Sign1 message does not conform to valid structure. */
|
|
23
|
+
InvalidCoseSign1 = "invalidCoseSign1",
|
|
24
|
+
/** The EAT (Entity Attestation Token) is malformed or failed verification. */
|
|
25
|
+
InvalidEat = "invalidEat",
|
|
22
26
|
/** The JWE supplied does not conform to valid syntax. */
|
|
23
27
|
InvalidJwe = "invalidJwe",
|
|
24
28
|
/** The JWK supplied does not conform to valid syntax. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-error.d.ts","sourceRoot":"","sources":["../../src/crypto-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IAOjB,IAAI,EAAE,eAAe;IANxC;;;;;OAKG;gBACgB,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM;CAc1D;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,gFAAgF;IAChF,qBAAqB,0BAA0B;IAE/C,mEAAmE;IACnE,aAAa,kBAAkB;IAE/B,yDAAyD;IACzD,UAAU,eAAe;IAEzB,yDAAyD;IACzD,UAAU,eAAe;IAEzB,sEAAsE;IACtE,qBAAqB,0BAA0B;CAChD"}
|
|
1
|
+
{"version":3,"file":"crypto-error.d.ts","sourceRoot":"","sources":["../../src/crypto-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IAOjB,IAAI,EAAE,eAAe;IANxC;;;;;OAKG;gBACgB,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM;CAc1D;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,gFAAgF;IAChF,qBAAqB,0BAA0B;IAE/C,mEAAmE;IACnE,aAAa,kBAAkB;IAE/B,kEAAkE;IAClE,gBAAgB,qBAAqB;IAErC,8EAA8E;IAC9E,UAAU,eAAe;IAEzB,yDAAyD;IACzD,UAAU,eAAe;IAEzB,yDAAyD;IACzD,UAAU,eAAe;IAEzB,sEAAsE;IACtE,qBAAqB,0BAA0B;CAChD"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export * from './crypto-error.js';
|
|
2
2
|
export * from './local-key-manager.js';
|
|
3
3
|
export * from './utils.js';
|
|
4
|
+
export * from './cose/cbor.js';
|
|
5
|
+
export * from './cose/cose-key.js';
|
|
6
|
+
export * from './cose/cose-sign1.js';
|
|
7
|
+
export * from './cose/eat.js';
|
|
4
8
|
export * from './algorithms/aes-ctr.js';
|
|
5
9
|
export * from './algorithms/aes-gcm.js';
|
|
6
10
|
export * from './algorithms/aes-kw.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAE3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAEhC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AAEnD,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,2BAA2B,CAAC;AAC/C,mBAAmB,0BAA0B,CAAC;AAC9C,mBAAmB,wBAAwB,CAAC;AAC5C,mBAAmB,0BAA0B,CAAC;AAC9C,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,wBAAwB,CAAC;AAC5C,mBAAmB,0BAA0B,CAAC;AAC9C,mBAAmB,4BAA4B,CAAC;AAChD,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAE3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAE9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAEhC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AAEnD,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,2BAA2B,CAAC;AAC/C,mBAAmB,0BAA0B,CAAC;AAC9C,mBAAmB,wBAAwB,CAAC;AAC5C,mBAAmB,0BAA0B,CAAC;AAC9C,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,wBAAwB,CAAC;AAC5C,mBAAmB,0BAA0B,CAAC;AAC9C,mBAAmB,4BAA4B,CAAC;AAChD,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enbox/crypto",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Web5 cryptographic library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/esm/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"test:node": "bun test .test.ts",
|
|
17
17
|
"test:node:coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage .test.ts",
|
|
18
18
|
"test:browser": "bunx --bun vitest --config vitest.browser.config.ts --run",
|
|
19
|
-
"test:browser:coverage": "bunx --bun vitest --config vitest.browser.config.ts --run --coverage --coverage.provider=istanbul
|
|
19
|
+
"test:browser:coverage": "bunx --bun vitest --config vitest.browser.config.ts --run --coverage --coverage.provider=istanbul"
|
|
20
20
|
},
|
|
21
21
|
"homepage": "https://github.com/enboxorg/enbox/tree/main/packages/crypto#readme",
|
|
22
22
|
"bugs": "https://github.com/enboxorg/enbox/issues",
|
|
@@ -68,10 +68,11 @@
|
|
|
68
68
|
"bun": ">=1.0.0"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
+
"@enbox/common": "0.0.4",
|
|
71
72
|
"@noble/ciphers": "0.5.3",
|
|
72
73
|
"@noble/curves": "1.3.0",
|
|
73
74
|
"@noble/hashes": "1.4.0",
|
|
74
|
-
"
|
|
75
|
+
"cborg": "^4.5.8"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
77
78
|
"@types/node": "20.14.8",
|
package/src/cose/cbor.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { decode as cborDecode, encode as cborEncode } from 'cborg';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CBOR (Concise Binary Object Representation) encoding and decoding utilities.
|
|
5
|
+
*
|
|
6
|
+
* Provides a thin wrapper around the `cborg` library, exposing `encode` and `decode`
|
|
7
|
+
* operations for use by COSE and EAT implementations.
|
|
8
|
+
*
|
|
9
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc8949 | RFC 8949 — CBOR}
|
|
10
|
+
*/
|
|
11
|
+
export class Cbor {
|
|
12
|
+
/**
|
|
13
|
+
* Encodes a JavaScript value to a CBOR byte string.
|
|
14
|
+
*
|
|
15
|
+
* @param value - The value to encode. Supports objects, arrays, strings, numbers,
|
|
16
|
+
* booleans, null, undefined, Uint8Array (encoded as CBOR byte string), and Map.
|
|
17
|
+
* @returns The CBOR-encoded bytes.
|
|
18
|
+
*/
|
|
19
|
+
public static encode(value: unknown): Uint8Array {
|
|
20
|
+
return cborEncode(value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Decodes a CBOR byte string to a JavaScript value.
|
|
25
|
+
*
|
|
26
|
+
* CBOR maps are decoded as JavaScript `Map` instances to support integer keys,
|
|
27
|
+
* which is required by COSE (RFC 9052) and EAT (RFC 9711).
|
|
28
|
+
*
|
|
29
|
+
* @param data - The CBOR-encoded bytes to decode.
|
|
30
|
+
* @returns The decoded JavaScript value.
|
|
31
|
+
* @throws If the input is not valid CBOR.
|
|
32
|
+
*/
|
|
33
|
+
public static decode<T = unknown>(data: Uint8Array): T {
|
|
34
|
+
return cborDecode(data, { useMaps: true }) as T;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import type { Jwk } from '../jose/jwk.js';
|
|
2
|
+
|
|
3
|
+
import { Convert } from '@enbox/common';
|
|
4
|
+
|
|
5
|
+
import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* COSE Key Type values (RFC 9052, Section 7).
|
|
9
|
+
*
|
|
10
|
+
* @see {@link https://www.iana.org/assignments/cose/cose.xhtml#key-type | IANA COSE Key Types}
|
|
11
|
+
*/
|
|
12
|
+
export enum CoseKeyType {
|
|
13
|
+
/** Octet Key Pair (e.g., Ed25519, X25519) */
|
|
14
|
+
OKP = 1,
|
|
15
|
+
/** Elliptic Curve (e.g., P-256, P-384, P-521) */
|
|
16
|
+
EC2 = 2,
|
|
17
|
+
/** Symmetric key */
|
|
18
|
+
Symmetric = 4,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* COSE Elliptic Curve identifiers (RFC 9053, Section 7.1).
|
|
23
|
+
*
|
|
24
|
+
* @see {@link https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves | IANA COSE Elliptic Curves}
|
|
25
|
+
*/
|
|
26
|
+
export enum CoseEllipticCurve {
|
|
27
|
+
/** NIST P-256 (secp256r1) */
|
|
28
|
+
P256 = 1,
|
|
29
|
+
/** NIST P-384 (secp384r1) */
|
|
30
|
+
P384 = 2,
|
|
31
|
+
/** NIST P-521 (secp521r1) */
|
|
32
|
+
P521 = 3,
|
|
33
|
+
/** X25519 for ECDH */
|
|
34
|
+
X25519 = 4,
|
|
35
|
+
/** X448 for ECDH */
|
|
36
|
+
X448 = 5,
|
|
37
|
+
/** Ed25519 for EdDSA */
|
|
38
|
+
Ed25519 = 6,
|
|
39
|
+
/** Ed448 for EdDSA */
|
|
40
|
+
Ed448 = 7,
|
|
41
|
+
/** secp256k1 */
|
|
42
|
+
Secp256k1 = 8,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* COSE Algorithm identifiers (RFC 9053).
|
|
47
|
+
*
|
|
48
|
+
* Only includes algorithms relevant to Enbox confidential compute.
|
|
49
|
+
*
|
|
50
|
+
* @see {@link https://www.iana.org/assignments/cose/cose.xhtml#algorithms | IANA COSE Algorithms}
|
|
51
|
+
*/
|
|
52
|
+
export enum CoseAlgorithm {
|
|
53
|
+
/** EdDSA (Ed25519 or Ed448) */
|
|
54
|
+
EdDSA = -8,
|
|
55
|
+
/** ECDSA with SHA-256 (P-256) */
|
|
56
|
+
ES256 = -7,
|
|
57
|
+
/** ECDSA with SHA-384 (P-384) */
|
|
58
|
+
ES384 = -35,
|
|
59
|
+
/** ECDSA with SHA-512 (P-521) */
|
|
60
|
+
ES512 = -36,
|
|
61
|
+
/** ECDSA with SHA-256 (secp256k1) */
|
|
62
|
+
ES256K = -47,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* COSE Key common parameter labels (RFC 9052, Section 7.1).
|
|
67
|
+
*/
|
|
68
|
+
enum CoseKeyLabel {
|
|
69
|
+
/** Key Type (kty) */
|
|
70
|
+
Kty = 1,
|
|
71
|
+
/** Key ID (kid) */
|
|
72
|
+
Kid = 2,
|
|
73
|
+
/** Algorithm */
|
|
74
|
+
Alg = 3,
|
|
75
|
+
/** Key Operations */
|
|
76
|
+
KeyOps = 4,
|
|
77
|
+
/** Base IV */
|
|
78
|
+
BaseIv = 5,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* COSE Key type-specific parameter labels.
|
|
83
|
+
*
|
|
84
|
+
* For OKP and EC2 keys, the curve and coordinate labels share the same
|
|
85
|
+
* negative-integer label space (RFC 9053, Section 7.1-7.2).
|
|
86
|
+
*/
|
|
87
|
+
enum CoseKeyParamLabel {
|
|
88
|
+
/** Curve identifier (OKP and EC2) */
|
|
89
|
+
Crv = -1,
|
|
90
|
+
/** X coordinate (OKP public key or EC2 x-coordinate) */
|
|
91
|
+
X = -2,
|
|
92
|
+
/** Y coordinate (EC2 only) */
|
|
93
|
+
Y = -3,
|
|
94
|
+
/** Private key (OKP d value or EC2 d value) */
|
|
95
|
+
D = -4,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Maps JWK curve names to COSE elliptic curve identifiers.
|
|
100
|
+
*/
|
|
101
|
+
const jwkCrvToCose: Record<string, CoseEllipticCurve> = {
|
|
102
|
+
'P-256' : CoseEllipticCurve.P256,
|
|
103
|
+
'P-384' : CoseEllipticCurve.P384,
|
|
104
|
+
'P-521' : CoseEllipticCurve.P521,
|
|
105
|
+
'X25519' : CoseEllipticCurve.X25519,
|
|
106
|
+
'Ed25519' : CoseEllipticCurve.Ed25519,
|
|
107
|
+
'Ed448' : CoseEllipticCurve.Ed448,
|
|
108
|
+
'secp256k1' : CoseEllipticCurve.Secp256k1,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Maps COSE elliptic curve identifiers to JWK curve names.
|
|
113
|
+
*/
|
|
114
|
+
const coseCrvToJwk: Record<number, string> = {
|
|
115
|
+
[CoseEllipticCurve.P256] : 'P-256',
|
|
116
|
+
[CoseEllipticCurve.P384] : 'P-384',
|
|
117
|
+
[CoseEllipticCurve.P521] : 'P-521',
|
|
118
|
+
[CoseEllipticCurve.X25519] : 'X25519',
|
|
119
|
+
[CoseEllipticCurve.Ed25519] : 'Ed25519',
|
|
120
|
+
[CoseEllipticCurve.Ed448] : 'Ed448',
|
|
121
|
+
[CoseEllipticCurve.Secp256k1] : 'secp256k1',
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Maps JWK algorithm names to COSE algorithm identifiers.
|
|
126
|
+
*/
|
|
127
|
+
const jwkAlgToCose: Record<string, CoseAlgorithm> = {
|
|
128
|
+
'EdDSA' : CoseAlgorithm.EdDSA,
|
|
129
|
+
'ES256' : CoseAlgorithm.ES256,
|
|
130
|
+
'ES384' : CoseAlgorithm.ES384,
|
|
131
|
+
'ES512' : CoseAlgorithm.ES512,
|
|
132
|
+
'ES256K' : CoseAlgorithm.ES256K,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Maps COSE algorithm identifiers to JWK algorithm names.
|
|
137
|
+
*/
|
|
138
|
+
const coseAlgToJwk: Record<number, string> = {
|
|
139
|
+
[CoseAlgorithm.EdDSA] : 'EdDSA',
|
|
140
|
+
[CoseAlgorithm.ES256] : 'ES256',
|
|
141
|
+
[CoseAlgorithm.ES384] : 'ES384',
|
|
142
|
+
[CoseAlgorithm.ES512] : 'ES512',
|
|
143
|
+
[CoseAlgorithm.ES256K] : 'ES256K',
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Utilities for converting between JWK and COSE key representations.
|
|
148
|
+
*
|
|
149
|
+
* COSE keys use integer labels and CBOR encoding, while JWK uses string
|
|
150
|
+
* property names and JSON. This class provides bidirectional conversion.
|
|
151
|
+
*
|
|
152
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9052#section-7 | RFC 9052, Section 7}
|
|
153
|
+
*/
|
|
154
|
+
export class CoseKey {
|
|
155
|
+
/**
|
|
156
|
+
* Converts a JWK to a COSE key represented as a Map.
|
|
157
|
+
*
|
|
158
|
+
* @param jwk - The JWK to convert.
|
|
159
|
+
* @returns A Map with integer labels as keys, suitable for CBOR encoding.
|
|
160
|
+
* @throws {CryptoError} If the JWK key type or curve is not supported.
|
|
161
|
+
*/
|
|
162
|
+
public static fromJwk(jwk: Jwk): Map<number, unknown> {
|
|
163
|
+
const coseKey = new Map<number, unknown>();
|
|
164
|
+
|
|
165
|
+
if (jwk.kty === 'OKP') {
|
|
166
|
+
coseKey.set(CoseKeyLabel.Kty, CoseKeyType.OKP);
|
|
167
|
+
|
|
168
|
+
const crv = jwk.crv;
|
|
169
|
+
if (crv === undefined || !(crv in jwkCrvToCose)) {
|
|
170
|
+
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `CoseKey: unsupported OKP curve '${crv}'`);
|
|
171
|
+
}
|
|
172
|
+
coseKey.set(CoseKeyParamLabel.Crv, jwkCrvToCose[crv]);
|
|
173
|
+
|
|
174
|
+
if (jwk.x !== undefined) {
|
|
175
|
+
coseKey.set(CoseKeyParamLabel.X, Convert.base64Url(jwk.x as string).toUint8Array());
|
|
176
|
+
}
|
|
177
|
+
if (jwk.d !== undefined) {
|
|
178
|
+
coseKey.set(CoseKeyParamLabel.D, Convert.base64Url(jwk.d as string).toUint8Array());
|
|
179
|
+
}
|
|
180
|
+
} else if (jwk.kty === 'EC') {
|
|
181
|
+
coseKey.set(CoseKeyLabel.Kty, CoseKeyType.EC2);
|
|
182
|
+
|
|
183
|
+
const crv = jwk.crv;
|
|
184
|
+
if (crv === undefined || !(crv in jwkCrvToCose)) {
|
|
185
|
+
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `CoseKey: unsupported EC curve '${crv}'`);
|
|
186
|
+
}
|
|
187
|
+
coseKey.set(CoseKeyParamLabel.Crv, jwkCrvToCose[crv]);
|
|
188
|
+
|
|
189
|
+
if (jwk.x !== undefined) {
|
|
190
|
+
coseKey.set(CoseKeyParamLabel.X, Convert.base64Url(jwk.x as string).toUint8Array());
|
|
191
|
+
}
|
|
192
|
+
if (jwk.y !== undefined) {
|
|
193
|
+
coseKey.set(CoseKeyParamLabel.Y, Convert.base64Url(jwk.y as string).toUint8Array());
|
|
194
|
+
}
|
|
195
|
+
if (jwk.d !== undefined) {
|
|
196
|
+
coseKey.set(CoseKeyParamLabel.D, Convert.base64Url(jwk.d as string).toUint8Array());
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `CoseKey: unsupported key type '${jwk.kty}'`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (jwk.kid !== undefined) {
|
|
203
|
+
coseKey.set(CoseKeyLabel.Kid, Convert.string(jwk.kid).toUint8Array());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (jwk.alg !== undefined && jwk.alg in jwkAlgToCose) {
|
|
207
|
+
coseKey.set(CoseKeyLabel.Alg, jwkAlgToCose[jwk.alg]);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return coseKey;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Converts a COSE key Map to a JWK.
|
|
215
|
+
*
|
|
216
|
+
* @param coseKey - A Map with integer labels as keys (from CBOR decoding).
|
|
217
|
+
* @returns The equivalent JWK.
|
|
218
|
+
* @throws {CryptoError} If the COSE key type or curve is not supported.
|
|
219
|
+
*/
|
|
220
|
+
public static toJwk(coseKey: Map<number, unknown>): Jwk {
|
|
221
|
+
const kty = coseKey.get(CoseKeyLabel.Kty) as number;
|
|
222
|
+
|
|
223
|
+
if (kty === CoseKeyType.OKP) {
|
|
224
|
+
const crv = coseKey.get(CoseKeyParamLabel.Crv) as number;
|
|
225
|
+
if (!(crv in coseCrvToJwk)) {
|
|
226
|
+
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `CoseKey: unsupported COSE OKP curve ${crv}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const jwk: Jwk = {
|
|
230
|
+
kty : 'OKP',
|
|
231
|
+
crv : coseCrvToJwk[crv],
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const x = coseKey.get(CoseKeyParamLabel.X) as Uint8Array | undefined;
|
|
235
|
+
if (x !== undefined) {
|
|
236
|
+
jwk.x = Convert.uint8Array(x).toBase64Url();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const d = coseKey.get(CoseKeyParamLabel.D) as Uint8Array | undefined;
|
|
240
|
+
if (d !== undefined) {
|
|
241
|
+
jwk.d = Convert.uint8Array(d).toBase64Url();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
CoseKey.applyCommonFields(coseKey, jwk);
|
|
245
|
+
return jwk;
|
|
246
|
+
|
|
247
|
+
} else if (kty === CoseKeyType.EC2) {
|
|
248
|
+
const crv = coseKey.get(CoseKeyParamLabel.Crv) as number;
|
|
249
|
+
if (!(crv in coseCrvToJwk)) {
|
|
250
|
+
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `CoseKey: unsupported COSE EC2 curve ${crv}`);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const jwk: Jwk = {
|
|
254
|
+
kty : 'EC',
|
|
255
|
+
crv : coseCrvToJwk[crv],
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const x = coseKey.get(CoseKeyParamLabel.X) as Uint8Array | undefined;
|
|
259
|
+
if (x !== undefined) {
|
|
260
|
+
jwk.x = Convert.uint8Array(x).toBase64Url();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const y = coseKey.get(CoseKeyParamLabel.Y) as Uint8Array | undefined;
|
|
264
|
+
if (y !== undefined) {
|
|
265
|
+
jwk.y = Convert.uint8Array(y).toBase64Url();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const d = coseKey.get(CoseKeyParamLabel.D) as Uint8Array | undefined;
|
|
269
|
+
if (d !== undefined) {
|
|
270
|
+
jwk.d = Convert.uint8Array(d).toBase64Url();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
CoseKey.applyCommonFields(coseKey, jwk);
|
|
274
|
+
return jwk;
|
|
275
|
+
|
|
276
|
+
} else {
|
|
277
|
+
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `CoseKey: unsupported COSE key type ${kty}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Infers the COSE algorithm identifier from a JWK.
|
|
283
|
+
*
|
|
284
|
+
* If the JWK has an `alg` field, it is used directly. Otherwise, the algorithm
|
|
285
|
+
* is inferred from the key type and curve.
|
|
286
|
+
*
|
|
287
|
+
* @param jwk - The JWK to infer the algorithm from.
|
|
288
|
+
* @returns The COSE algorithm identifier.
|
|
289
|
+
* @throws {CryptoError} If the algorithm cannot be determined.
|
|
290
|
+
*/
|
|
291
|
+
public static algorithmFromJwk(jwk: Jwk): CoseAlgorithm {
|
|
292
|
+
if (jwk.alg !== undefined && jwk.alg in jwkAlgToCose) {
|
|
293
|
+
return jwkAlgToCose[jwk.alg];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Infer from key type and curve.
|
|
297
|
+
if (jwk.kty === 'OKP') {
|
|
298
|
+
if (jwk.crv === 'Ed25519' || jwk.crv === 'Ed448') {
|
|
299
|
+
return CoseAlgorithm.EdDSA;
|
|
300
|
+
}
|
|
301
|
+
} else if (jwk.kty === 'EC') {
|
|
302
|
+
switch (jwk.crv) {
|
|
303
|
+
case 'P-256': return CoseAlgorithm.ES256;
|
|
304
|
+
case 'P-384': return CoseAlgorithm.ES384;
|
|
305
|
+
case 'P-521': return CoseAlgorithm.ES512;
|
|
306
|
+
case 'secp256k1': return CoseAlgorithm.ES256K;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
throw new CryptoError(
|
|
311
|
+
CryptoErrorCode.AlgorithmNotSupported,
|
|
312
|
+
`CoseKey: cannot determine COSE algorithm for key type '${jwk.kty}' curve '${jwk.crv}'`
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Maps a COSE algorithm identifier to a JWK algorithm name.
|
|
318
|
+
*
|
|
319
|
+
* @param alg - The COSE algorithm identifier.
|
|
320
|
+
* @returns The JWK algorithm name.
|
|
321
|
+
* @throws {CryptoError} If the algorithm is not supported.
|
|
322
|
+
*/
|
|
323
|
+
public static algorithmToJwk(alg: CoseAlgorithm): string {
|
|
324
|
+
if (alg in coseAlgToJwk) {
|
|
325
|
+
return coseAlgToJwk[alg];
|
|
326
|
+
}
|
|
327
|
+
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `CoseKey: unsupported COSE algorithm ${alg}`);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Applies common COSE key fields (kid, alg) to a JWK.
|
|
332
|
+
*/
|
|
333
|
+
private static applyCommonFields(coseKey: Map<number, unknown>, jwk: Jwk): void {
|
|
334
|
+
const kid = coseKey.get(CoseKeyLabel.Kid) as Uint8Array | undefined;
|
|
335
|
+
if (kid !== undefined) {
|
|
336
|
+
jwk.kid = Convert.uint8Array(kid).toString();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const alg = coseKey.get(CoseKeyLabel.Alg) as number | undefined;
|
|
340
|
+
if (alg !== undefined && alg in coseAlgToJwk) {
|
|
341
|
+
jwk.alg = coseAlgToJwk[alg];
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|