iso-ucan 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/delegation.d.ts +1 -1
- package/dist/src/envelope.d.ts +2 -1
- package/dist/src/envelope.d.ts.map +1 -1
- package/dist/src/invocation.d.ts +1 -12
- package/dist/src/invocation.d.ts.map +1 -1
- package/dist/src/types/varsig.d.ts +11 -1
- package/dist/src/types/varsig.d.ts.map +1 -1
- package/dist/src/types.d.ts +1 -8
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils.d.ts +2 -41
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/varsig.d.ts +2 -2
- package/dist/src/varsig.d.ts.map +1 -1
- package/package.json +3 -3
- package/readme.md +57 -9
- package/src/delegation.js +4 -4
- package/src/envelope.js +4 -0
- package/src/invocation.js +12 -32
- package/src/types/varsig.ts +12 -1
- package/src/types.ts +1 -8
- package/src/utils.js +7 -154
- package/src/varsig.js +4 -12
package/dist/src/delegation.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export class Delegation {
|
|
|
82
82
|
meta: Record<string, unknown> | undefined;
|
|
83
83
|
};
|
|
84
84
|
signature: string;
|
|
85
|
-
alg: import("
|
|
85
|
+
alg: import("./types.js").VarsigAlgorithm;
|
|
86
86
|
enc: import("./types.js").VarsigEncoding;
|
|
87
87
|
spec: "dlg";
|
|
88
88
|
version: string;
|
package/dist/src/envelope.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export function getSignaturePayload(options: {
|
|
|
29
29
|
* @param {Uint8Array} bytes
|
|
30
30
|
*/
|
|
31
31
|
export function decodeSignaturePayload(bytes: Uint8Array): {
|
|
32
|
-
alg: import("
|
|
32
|
+
alg: import("./types.js").VarsigAlgorithm;
|
|
33
33
|
enc: "DAG-CBOR";
|
|
34
34
|
spec: PayloadSpec;
|
|
35
35
|
version: string;
|
|
@@ -54,6 +54,7 @@ export function isDelegationPayload(payload: Payload): payload is DelegationPayl
|
|
|
54
54
|
* @param {EnvelopeSignOptions} options
|
|
55
55
|
*/
|
|
56
56
|
export function sign(options: EnvelopeSignOptions): Promise<{
|
|
57
|
+
alg: import("./types.js").VarsigAlgorithm;
|
|
57
58
|
signature: Uint8Array<ArrayBufferLike>;
|
|
58
59
|
signaturePayload: SignaturePayload;
|
|
59
60
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/envelope.js"],"names":[],"mappings":"AAmCA;;;;GAIG;AACH,qCAFW,MAAM;SAsBU,UAAU;;;EACpC;AAED;;;;;;;;GAQG;AACH,6CALG;IAA6B,IAAI,EAAzB,WAAW;IACM,OAAO,EAAxB,OAAO;IACU,OAAO;IAC8B,aAAa,EAAnE,OAAO,sBAAsB,EAAE,aAAa;CACtD,oBAgBA;AA0DD;;;;GAIG;AACH,8CAFW,UAAU;;;;;aAPG,OAAO;EAW9B;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;GAGG;AACH,8BAFW,mBAAmB;;;
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/envelope.js"],"names":[],"mappings":"AAmCA;;;;GAIG;AACH,qCAFW,MAAM;SAsBU,UAAU;;;EACpC;AAED;;;;;;;;GAQG;AACH,6CALG;IAA6B,IAAI,EAAzB,WAAW;IACM,OAAO,EAAxB,OAAO;IACU,OAAO;IAC8B,aAAa,EAAnE,OAAO,sBAAsB,EAAE,aAAa;CACtD,oBAgBA;AA0DD;;;;GAIG;AACH,8CAFW,UAAU;;;;;aAPG,OAAO;EAW9B;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;GAGG;AACH,8BAFW,mBAAmB;SAcV,OAAO,YAAY,EAAE,eAAe;;;GAMvD;AAED;;;;;;GAMG;AACH,gCAHW,qBAAqB,iHAS/B;AAED;;;;;;;GAOG;AACH,uBAL2B,IAAI,SAAlB,WAAa,WAEf,qBAAqB,GACnB,gBAAgB,IAAI,CAAC,CAgCjC;AAvPD;;GAEG;AAEH;;;;;GAKG;AACH,sBAAuB,OAAO,CAAA;AAE9B;;;;;;;GAOG;AACH,iCAFU,SAAS,MAAM,EAAE,CAE6C;AAExE;;;;GAIG;AACH,oBAFU,SAAS,WAAW,EAAE,CAEyC;gCA1BuH,YAAY;iCAAZ,YAAY;6BAAZ,YAAY;sCAAZ,YAAY;uCAAZ,YAAY;uCAAZ,YAAY;yCAAZ,YAAY;2CAAZ,YAAY;2CAAZ,YAAY;qCAAZ,YAAY"}
|
package/dist/src/invocation.d.ts
CHANGED
|
@@ -26,9 +26,8 @@ export class Invocation {
|
|
|
26
26
|
* @param {Uint8Array} bytes
|
|
27
27
|
* @param {CID} cid
|
|
28
28
|
* @param {Delegation[]} delegations
|
|
29
|
-
* @param {string} replayKey
|
|
30
29
|
*/
|
|
31
|
-
constructor(envelope: import("./types.js").DecodedEnvelope<"inv">, bytes: Uint8Array, cid: CID, delegations: Delegation[]
|
|
30
|
+
constructor(envelope: import("./types.js").DecodedEnvelope<"inv">, bytes: Uint8Array, cid: CID, delegations: Delegation[]);
|
|
32
31
|
/**
|
|
33
32
|
* @type {Delegation[]}
|
|
34
33
|
*/
|
|
@@ -37,16 +36,6 @@ export class Invocation {
|
|
|
37
36
|
* @type {CID}
|
|
38
37
|
*/
|
|
39
38
|
cid: CID;
|
|
40
|
-
/**
|
|
41
|
-
* Key to deduplicate this invocation on: the CID of its signature payload.
|
|
42
|
-
*
|
|
43
|
-
* Use this instead of {@link Invocation.cid} to detect replays. The CID
|
|
44
|
-
* covers the signature bytes, and some signature algorithms (e.g. ECDSA)
|
|
45
|
-
* accept more than one valid signature for the same payload.
|
|
46
|
-
*
|
|
47
|
-
* @type {string}
|
|
48
|
-
*/
|
|
49
|
-
replayKey: string;
|
|
50
39
|
envelope: import("./types.js").DecodedEnvelope<"inv">;
|
|
51
40
|
payload: import("./types.js").InvocationPayload;
|
|
52
41
|
bytes: Uint8Array<ArrayBufferLike>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invocation.d.ts","sourceRoot":"","sources":["../../src/invocation.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"invocation.d.ts","sourceRoot":"","sources":["../../src/invocation.js"],"names":[],"mappings":"AA4PA;;;;GAIG;AACH,sCAHW,OAAO,YAAY,EAAE,iBAAiB,UACtC,UAAU,EAAE,WA6DtB;AAxSD;;GAEG;AAEH;;GAEG;AACH;IA0BE;;;OAGG;IACH,qBAFW,OAAO,YAAY,EAAE,qBAAqB,uBAoEpD;IAED;;OAEG;IACH,uBAFW,OAAO,YAAY,EAAE,iBAAiB,uBA2DhD;IAnJD;;;;;;OAMG;IACH,sBALW,OAAO,YAAY,EAAE,eAAe,CAAC,KAAK,CAAC,SAC3C,UAAU,OACV,GAAG,eACH,UAAU,EAAE,EAQtB;IAvBD;;OAEG;IACH,aAFU,UAAU,EAAE,CAEX;IAEX;;OAEG;IACH,KAFU,GAAG,CAEV;IAUD,sDAAwB;IACxB,gDAA+B;IAC/B,mCAAkB;CA0IrB;gCArK4B,iBAAiB;oBAnB1B,kBAAkB"}
|
|
@@ -8,11 +8,21 @@ import type { SignatureType } from 'iso-signatures/types';
|
|
|
8
8
|
export type VarsigEncoding = 'RAW' | 'DAG-CBOR';
|
|
9
9
|
/**
|
|
10
10
|
* Supported signature types
|
|
11
|
+
*
|
|
12
|
+
* RSA (`RS256`) is not supported.
|
|
11
13
|
*/
|
|
12
|
-
export type VarsigAlgorithm = SignatureType
|
|
14
|
+
export type VarsigAlgorithm = Exclude<SignatureType, 'RS256'>;
|
|
13
15
|
export interface VarsigOptions {
|
|
14
16
|
enc: VarsigEncoding;
|
|
15
17
|
alg: VarsigAlgorithm;
|
|
16
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Options for varsig `encode`. Accepts any signer type so unsupported
|
|
21
|
+
* algorithms (e.g. `RS256`) fail at runtime with a clear error.
|
|
22
|
+
*/
|
|
23
|
+
export interface VarsigEncodeOptions {
|
|
24
|
+
enc: VarsigEncoding;
|
|
25
|
+
alg: SignatureType;
|
|
26
|
+
}
|
|
17
27
|
export type DecodeOutput = VarsigOptions;
|
|
18
28
|
//# sourceMappingURL=varsig.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"varsig.d.ts","sourceRoot":"","sources":["../../../src/types/varsig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,UAAU,CAAA;AAE/C
|
|
1
|
+
{"version":3,"file":"varsig.d.ts","sourceRoot":"","sources":["../../../src/types/varsig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,UAAU,CAAA;AAE/C;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;AAE7D,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,cAAc,CAAA;IACnB,GAAG,EAAE,eAAe,CAAA;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,cAAc,CAAA;IACnB,GAAG,EAAE,aAAa,CAAA;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,aAAa,CAAA"}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -17,13 +17,6 @@ export * from './types/envelope';
|
|
|
17
17
|
export * from './types/policy';
|
|
18
18
|
export * from './types/varsig';
|
|
19
19
|
export type ResolveProof = (proof: CID) => Promise<Delegation>;
|
|
20
|
-
/**
|
|
21
|
-
* Check whether a delegation CID is revoked.
|
|
22
|
-
*
|
|
23
|
-
* Called once for each CID the delegation could have been issued under
|
|
24
|
-
* (up to 2 for ECDSA and 4 for EIP-191 signatures), since those signatures
|
|
25
|
-
* can be re-encoded into another valid signature with a different CID.
|
|
26
|
-
*/
|
|
27
20
|
export type IsRevoked = (cid: CID) => Promise<boolean>;
|
|
28
21
|
export type VerifierResolver = Resolver;
|
|
29
22
|
export type DidResolver = _DidResolver;
|
|
@@ -147,7 +140,7 @@ export interface ReplayStore {
|
|
|
147
140
|
* Atomically record `key` and resolve `true`, or resolve `false` if `key`
|
|
148
141
|
* was already recorded and has not expired.
|
|
149
142
|
*
|
|
150
|
-
* @param key -
|
|
143
|
+
* @param key - CID of the invocation, see {@link Invocation.cid}
|
|
151
144
|
* @param expiration - Unix time in seconds after which the key can be forgotten, or `null` to keep it forever
|
|
152
145
|
*/
|
|
153
146
|
checkAndSet(key: string, expiration: number | null): Promise<boolean>;
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,KAAK,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAA;AACpE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAE5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC9D,YAAY,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACnD,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAE9B,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;AAC9D
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/src/utils.d.ts
CHANGED
|
@@ -28,17 +28,6 @@ export function cid(envelope: import("./types.js").DecodedEnvelope<PayloadSpec>)
|
|
|
28
28
|
* @param {Uint8Array} bytes
|
|
29
29
|
*/
|
|
30
30
|
export function assertCanonical(envelope: import("./types.js").DecodedEnvelope<PayloadSpec>, bytes: Uint8Array): void;
|
|
31
|
-
/**
|
|
32
|
-
* Replay key of a UCAN: the CID of its signature payload, the exact bytes the
|
|
33
|
-
* signature covers.
|
|
34
|
-
*
|
|
35
|
-
* Unlike {@link cid}, it does not depend on the signature bytes, so a second
|
|
36
|
-
* valid signature over the same payload (for example a malleated ECDSA
|
|
37
|
-
* signature) gets the same key.
|
|
38
|
-
*
|
|
39
|
-
* @param {import('./types.js').DecodedEnvelope<PayloadSpec>} envelope
|
|
40
|
-
*/
|
|
41
|
-
export function replayKey(envelope: import("./types.js").DecodedEnvelope<PayloadSpec>): Promise<string>;
|
|
42
31
|
/**
|
|
43
32
|
* Check if a DID and signature type are compatible
|
|
44
33
|
*
|
|
@@ -142,41 +131,13 @@ export function assertArgs(args: unknown): void;
|
|
|
142
131
|
* @returns {void}
|
|
143
132
|
*/
|
|
144
133
|
export function assertMeta(meta: unknown): void;
|
|
145
|
-
/**
|
|
146
|
-
* Signatures a signer could have issued that verify the same as `signature`.
|
|
147
|
-
*
|
|
148
|
-
* ECDSA signatures are malleable: `(r, s)` and `(r, n - s)` are both valid.
|
|
149
|
-
* EIP-191 signatures additionally carry a recovery byte `v` that wallets
|
|
150
|
-
* return as 27/28 or 0/1. Verifiers also accept EIP-155 style `v >= 35`,
|
|
151
|
-
* but no signer issues those for `personal_sign`, so they are not listed.
|
|
152
|
-
*
|
|
153
|
-
* The result always includes `signature` itself. Other algorithms (Ed25519,
|
|
154
|
-
* RSA) have a single valid signature.
|
|
155
|
-
*
|
|
156
|
-
* @param {import('iso-signatures/types').SignatureType} alg
|
|
157
|
-
* @param {Uint8Array} signature
|
|
158
|
-
* @returns {Uint8Array[]}
|
|
159
|
-
*/
|
|
160
|
-
export function equivalentSignatures(alg: import("iso-signatures/types").SignatureType, signature: Uint8Array): Uint8Array[];
|
|
161
|
-
/**
|
|
162
|
-
* CIDs of every envelope that verifies the same as `envelope`: one per
|
|
163
|
-
* signature in {@link equivalentSignatures}, starting with the CID of
|
|
164
|
-
* `envelope` itself.
|
|
165
|
-
*
|
|
166
|
-
* @param {import('./types.js').DecodedEnvelope<PayloadSpec>} envelope
|
|
167
|
-
*/
|
|
168
|
-
export function equivalentCids(envelope: import("./types.js").DecodedEnvelope<PayloadSpec>): Promise<CID<any, 113, 18, 1>[]>;
|
|
169
134
|
/**
|
|
170
135
|
* Assert that the input is not revoked.
|
|
171
136
|
*
|
|
172
|
-
*
|
|
173
|
-
* so re-encoding a revoked UCAN with another valid signature does not get it
|
|
174
|
-
* past a CID-based revocation list.
|
|
175
|
-
*
|
|
176
|
-
* @param {import('./types.js').DecodedEnvelope<PayloadSpec>} envelope
|
|
137
|
+
* @param {CID} cid
|
|
177
138
|
* @param {(cid: CID) => Promise<boolean>} [isRevokedFn]
|
|
178
139
|
*/
|
|
179
|
-
export function assertNotRevoked(
|
|
140
|
+
export function assertNotRevoked(cid: CID, isRevokedFn?: (cid: CID) => Promise<boolean>): Promise<void>;
|
|
180
141
|
/**
|
|
181
142
|
* Expiration or TTL (default 300 seconds)
|
|
182
143
|
*
|
package/dist/src/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.js"],"names":[],"mappings":"AAWA;;GAEG;AAEH;;;;;GAKG;AACH,2CAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC;;;EAe3D;AAED,uCAEC;AAED;;;GAGG;AACH,8BAFW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,iCAW3D;AAED;;;;;;;;;GASG;AACH,0CAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,SACjD,UAAU,QAapB;AAED
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.js"],"names":[],"mappings":"AAWA;;GAEG;AAEH;;;;;GAKG;AACH,2CAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC;;;EAe3D;AAED,uCAEC;AAED;;;GAGG;AACH,8BAFW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,iCAW3D;AAED;;;;;;;;;GASG;AACH,0CAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,SACjD,UAAU,QAapB;AAED;;;;;GAKG;AACH,2CAHW,OAAO,eAAe,EAAE,aAAa,WACrC,OAAO,sBAAsB,EAAE,aAAa,WA4BtD;AAED;;;;;GAKG;AACH,sCAHW,MAAM,GAAG,IAAI,QACb,MAAM,QAchB;AAED;;;;;;GAMG;AACH,uCAHW,OAAO,QACP,MAAM,QAQhB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,QACN,MAAM,QAMhB;AAED;;;;;GAKG;AACH,qDAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,gBACjD,OAAO,SAAS,EAAE,QAAQ,gBAYpC;AAED;;;;;;GAMG;AACH,0CAJW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,6BACjD,OAAO,sCAAsC,EAAE,QAAQ,gBACvD,OAAO,SAAS,EAAE,QAAQ,oBA2BpC;AAED;;;;;;;;;;;;;GAaG;AACH,sCAJW,MAAM,SACN,MAAM,GACJ,OAAO,CAKnB;AAED;;;;;;;;;;;;;GAaG;AACH,8CAJW,MAAM,GAEJ,IAAI,CAuChB;AAED;;;;;;;;;;;;;GAaG;AACH,mCAXW,OAAO,GAEL,IAAI,CAehB;AACD;;;;GAIG;AACH,iCAFW,OAAO,QASjB;AAED;;;;;;GAMG;AACH,iCAJW,OAAO,GAEL,IAAI,CAWhB;AAED;;;;;GAKG;AACH,sCAHW,GAAG,gBACH,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,iBAMxC;AAED;;;;;;GAMG;AACH,uCAHG;IAAgC,GAAG;IACV,GAAG;CAAC,iBAU/B;AA+ED;;GAEG;AACH,qCAFW,OAAO,QASjB;AAED;;;;;;GAMG;AACH,gCAJW,OAAO,GACL,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAKjD;AAlGD,iJAeI;AACJ,4KAAyD;AAEzD;;;;GAIG;AACH,mCASE;AAEF;;GAEG;AAEH;;;;;;GAMG;AACH,mKA4BI;AAEJ,kLAA8C;uBAxCjC,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC;iCAnYP,YAAY;oBATtB,kBAAkB;oBADlB,SAAS;kBAGX,QAAQ"}
|
package/dist/src/varsig.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @param {import('./types.js').
|
|
2
|
+
* @param {import('./types.js').VarsigEncodeOptions} options
|
|
3
3
|
*/
|
|
4
|
-
export function encode(options: import("./types.js").
|
|
4
|
+
export function encode(options: import("./types.js").VarsigEncodeOptions): Uint8Array<ArrayBuffer>;
|
|
5
5
|
/**
|
|
6
6
|
* Decode varsig header
|
|
7
7
|
*
|
package/dist/src/varsig.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"varsig.d.ts","sourceRoot":"","sources":["../../src/varsig.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"varsig.d.ts","sourceRoot":"","sources":["../../src/varsig.js"],"names":[],"mappings":"AAoDA;;GAEG;AACH,gCAFW,OAAO,YAAY,EAAE,mBAAmB,2BAgBlD;AA2BD;;;;;GAKG;AACH,4BAHW,UAAU,GACR,OAAO,YAAY,EAAE,YAAY,CA2D7C;AA1JD,qBAAsB,EAAI,CAAA;AAC1B,sBAAuB,CAAI,CAAA;AAC3B,8BAA+B,KAAM,CAAA;AAErC;;GAEG;AACH,4BAFU,MAAM,CAAC,MAAM,EAAE,OAAO,YAAY,EAAE,cAAc,CAAC,CAK5D;AAED;;GAEG;AACH,yBAFU,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK9B"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iso-ucan",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"description": "Isomorphic UCAN",
|
|
6
6
|
"author": "Hugo Dias <hugomrdias@gmail.com> (hugodias.me)",
|
|
7
7
|
"license": "MIT",
|
|
@@ -108,8 +108,8 @@
|
|
|
108
108
|
"iobuffer": "^6.0.1",
|
|
109
109
|
"iso-base": "^4.4.0",
|
|
110
110
|
"iso-did": "^3.0.0",
|
|
111
|
-
"iso-kv": "^
|
|
112
|
-
"iso-signatures": "^0.
|
|
111
|
+
"iso-kv": "^4.0.0",
|
|
112
|
+
"iso-signatures": "^0.7.0",
|
|
113
113
|
"iso-web": "^4.0.0",
|
|
114
114
|
"it-merge": "^3.0.15",
|
|
115
115
|
"multiformats": "^14.0.5",
|
package/readme.md
CHANGED
|
@@ -115,10 +115,11 @@ const invocation = await Invocation.from({
|
|
|
115
115
|
})
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
The store is keyed on `invocation.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for
|
|
118
|
+
The store is keyed on `invocation.cid`. `iso-ucan` verifies signatures in
|
|
119
|
+
strict mode, which accepts only the
|
|
120
|
+
[canonical Varsig encoding](https://github.com/ChainAgnostic/varsig#canonical-signatures),
|
|
121
|
+
for example low-S for ECDSA. An attacker can't re-encode an intercepted
|
|
122
|
+
invocation under a different CID.
|
|
122
123
|
|
|
123
124
|
`KVReplayStore` is atomic within one process only. When several processes or
|
|
124
125
|
instances execute invocations, implement the `ReplayStore` interface on a
|
|
@@ -128,11 +129,58 @@ shared store with an atomic set-if-absent, such as Redis `SET NX` or SQL
|
|
|
128
129
|
## Revocation
|
|
129
130
|
|
|
130
131
|
Pass `isRevoked` to `Delegation.from`, `Delegation#validate` or
|
|
131
|
-
`Invocation.from` to reject revoked delegations by CID.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
`Invocation.from` to reject revoked delegations by CID. Strict verification
|
|
133
|
+
rejects non-canonical signatures, so a revoked delegation can't come back under
|
|
134
|
+
a different CID.
|
|
135
|
+
|
|
136
|
+
### Migrate revocation lists from earlier versions
|
|
137
|
+
|
|
138
|
+
Earlier versions accepted ECDSA (ES256, ES384, ES512) signatures with high S,
|
|
139
|
+
and EIP-191 signatures with `v` of 0 or 1. If your revocation list holds the
|
|
140
|
+
CID of such a delegation, anyone holding the delegation can convert it to the
|
|
141
|
+
canonical encoding. The canonical CID is not in your list, so the revoked
|
|
142
|
+
delegation passes `isRevoked`.
|
|
143
|
+
|
|
144
|
+
To keep those revocations, add the canonical CID of each revoked delegation to
|
|
145
|
+
your list. Compute it from the stored delegation bytes:
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
import { Delegation } from 'iso-ucan/delegation'
|
|
149
|
+
import * as Envelope from 'iso-ucan/envelope'
|
|
150
|
+
import { normalizeS } from 'iso-signatures/signers/ecdsa.js'
|
|
151
|
+
import { normalizeSignature } from 'iso-signatures/signers/eip191.js'
|
|
152
|
+
|
|
153
|
+
const CURVES = { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' }
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {Uint8Array} bytes - Revoked delegation, as stored
|
|
157
|
+
* @param {import('iso-ucan/types').VerifierResolver} verifierResolver
|
|
158
|
+
*/
|
|
159
|
+
async function canonicalCid(bytes, verifierResolver) {
|
|
160
|
+
const envelope = Envelope.decode({ envelope: bytes })
|
|
161
|
+
let signature = envelope.signature
|
|
162
|
+
if (envelope.alg === 'EIP191') {
|
|
163
|
+
signature = normalizeSignature(signature)
|
|
164
|
+
} else if (envelope.alg in CURVES) {
|
|
165
|
+
signature = normalizeS(CURVES[envelope.alg], signature)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const canonical = Envelope.encode({
|
|
169
|
+
signature,
|
|
170
|
+
signaturePayload: Envelope.getSignaturePayload({
|
|
171
|
+
spec: envelope.spec,
|
|
172
|
+
version: envelope.version,
|
|
173
|
+
signatureType: envelope.alg,
|
|
174
|
+
payload: envelope.payload,
|
|
175
|
+
}),
|
|
176
|
+
})
|
|
177
|
+
const delegation = await Delegation.from({ bytes: canonical, verifierResolver })
|
|
178
|
+
return delegation.cid
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Ed25519 and ES256K signatures were already canonical, so their CIDs don't
|
|
183
|
+
change.
|
|
136
184
|
|
|
137
185
|
## EIP-191 wallet signing
|
|
138
186
|
|
package/src/delegation.js
CHANGED
|
@@ -93,7 +93,7 @@ export class Delegation {
|
|
|
93
93
|
await verifySignature(envelope, verifierResolver, didResolveOptions)
|
|
94
94
|
|
|
95
95
|
const _cid = await cid(envelope)
|
|
96
|
-
await assertNotRevoked(
|
|
96
|
+
await assertNotRevoked(_cid, options.isRevoked)
|
|
97
97
|
|
|
98
98
|
return new Delegation(envelope, bytes, _cid)
|
|
99
99
|
}
|
|
@@ -151,7 +151,7 @@ export class Delegation {
|
|
|
151
151
|
|
|
152
152
|
assertStructure(payload, options.now)
|
|
153
153
|
|
|
154
|
-
const { signature, signaturePayload } = await Envelope.sign({
|
|
154
|
+
const { alg, signature, signaturePayload } = await Envelope.sign({
|
|
155
155
|
spec: 'dlg',
|
|
156
156
|
signer: options.iss,
|
|
157
157
|
payload,
|
|
@@ -161,7 +161,7 @@ export class Delegation {
|
|
|
161
161
|
|
|
162
162
|
/** @type {import("./types.js").DecodedEnvelope<'dlg'>} */
|
|
163
163
|
const envelope = {
|
|
164
|
-
alg
|
|
164
|
+
alg,
|
|
165
165
|
enc: 'DAG-CBOR',
|
|
166
166
|
signature,
|
|
167
167
|
payload,
|
|
@@ -187,7 +187,7 @@ export class Delegation {
|
|
|
187
187
|
options.verifierResolver,
|
|
188
188
|
options.didResolver
|
|
189
189
|
)
|
|
190
|
-
await assertNotRevoked(this.
|
|
190
|
+
await assertNotRevoked(this.cid, options.isRevoked)
|
|
191
191
|
|
|
192
192
|
return true
|
|
193
193
|
}
|
package/src/envelope.js
CHANGED
|
@@ -187,6 +187,10 @@ export async function sign(options) {
|
|
|
187
187
|
})
|
|
188
188
|
const signature = await signer.sign(cbor.encode(signaturePayload))
|
|
189
189
|
return {
|
|
190
|
+
// getSignaturePayload throws for algorithms varsig does not support
|
|
191
|
+
alg: /** @type {import('./types.js').VarsigAlgorithm} */ (
|
|
192
|
+
signer.signatureType
|
|
193
|
+
),
|
|
190
194
|
signature,
|
|
191
195
|
signaturePayload,
|
|
192
196
|
}
|
package/src/invocation.js
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
expOrTtl,
|
|
16
16
|
isObject,
|
|
17
17
|
nowInSeconds,
|
|
18
|
-
replayKey,
|
|
19
18
|
verifySignature,
|
|
20
19
|
} from './utils.js'
|
|
21
20
|
|
|
@@ -37,32 +36,19 @@ export class Invocation {
|
|
|
37
36
|
*/
|
|
38
37
|
cid
|
|
39
38
|
|
|
40
|
-
/**
|
|
41
|
-
* Key to deduplicate this invocation on: the CID of its signature payload.
|
|
42
|
-
*
|
|
43
|
-
* Use this instead of {@link Invocation.cid} to detect replays. The CID
|
|
44
|
-
* covers the signature bytes, and some signature algorithms (e.g. ECDSA)
|
|
45
|
-
* accept more than one valid signature for the same payload.
|
|
46
|
-
*
|
|
47
|
-
* @type {string}
|
|
48
|
-
*/
|
|
49
|
-
replayKey
|
|
50
|
-
|
|
51
39
|
/**
|
|
52
40
|
*
|
|
53
41
|
* @param {import("./types.js").DecodedEnvelope<'inv'>} envelope
|
|
54
42
|
* @param {Uint8Array} bytes
|
|
55
43
|
* @param {CID} cid
|
|
56
44
|
* @param {Delegation[]} delegations
|
|
57
|
-
* @param {string} replayKey
|
|
58
45
|
*/
|
|
59
|
-
constructor(envelope, bytes, cid, delegations
|
|
46
|
+
constructor(envelope, bytes, cid, delegations) {
|
|
60
47
|
this.envelope = envelope
|
|
61
48
|
this.payload = envelope.payload
|
|
62
49
|
this.bytes = bytes
|
|
63
50
|
this.cid = cid
|
|
64
51
|
this.delegations = delegations
|
|
65
|
-
this.replayKey = replayKey
|
|
66
52
|
}
|
|
67
53
|
|
|
68
54
|
/**
|
|
@@ -104,7 +90,7 @@ export class Invocation {
|
|
|
104
90
|
for (const proof of envelope.payload.prf) {
|
|
105
91
|
const delegation = await options.resolveProof(proof)
|
|
106
92
|
// The signature covers the proof CIDs, so the resolved delegation
|
|
107
|
-
// must be exactly that one
|
|
93
|
+
// must be exactly that one
|
|
108
94
|
if (!delegation.cid.equals(proof)) {
|
|
109
95
|
throw new Error(
|
|
110
96
|
`UCAN Invocation proof CID mismatch, expected ${proof} but resolver returned ${delegation.cid}`
|
|
@@ -121,20 +107,20 @@ export class Invocation {
|
|
|
121
107
|
assertMaxTtl(envelope.payload.exp, options.maxTtl, options.now)
|
|
122
108
|
}
|
|
123
109
|
|
|
124
|
-
const
|
|
110
|
+
const _cid = await cid(envelope)
|
|
125
111
|
|
|
126
112
|
// Must run last, so only fully validated invocations are recorded
|
|
127
113
|
if (
|
|
128
114
|
options.replayStore &&
|
|
129
|
-
!(await options.replayStore.checkAndSet(
|
|
115
|
+
!(await options.replayStore.checkAndSet(
|
|
116
|
+
_cid.toString(),
|
|
117
|
+
envelope.payload.exp
|
|
118
|
+
))
|
|
130
119
|
) {
|
|
131
|
-
throw new Error(
|
|
132
|
-
`UCAN Invocation replay detected, already seen ${_replayKey}`
|
|
133
|
-
)
|
|
120
|
+
throw new Error(`UCAN Invocation replay detected, already seen ${_cid}`)
|
|
134
121
|
}
|
|
135
122
|
|
|
136
|
-
|
|
137
|
-
return new Invocation(envelope, bytes, _cid, proofs, _replayKey)
|
|
123
|
+
return new Invocation(envelope, bytes, _cid, proofs)
|
|
138
124
|
}
|
|
139
125
|
|
|
140
126
|
/**
|
|
@@ -178,7 +164,7 @@ export class Invocation {
|
|
|
178
164
|
assertProofs(payload, options.prf)
|
|
179
165
|
}
|
|
180
166
|
|
|
181
|
-
const { signature, signaturePayload } = await Envelope.sign({
|
|
167
|
+
const { alg, signature, signaturePayload } = await Envelope.sign({
|
|
182
168
|
spec: 'inv',
|
|
183
169
|
signer: options.iss,
|
|
184
170
|
payload,
|
|
@@ -188,7 +174,7 @@ export class Invocation {
|
|
|
188
174
|
|
|
189
175
|
/** @type {import("./types.js").DecodedEnvelope<'inv'>} */
|
|
190
176
|
const envelope = {
|
|
191
|
-
alg
|
|
177
|
+
alg,
|
|
192
178
|
enc: 'DAG-CBOR',
|
|
193
179
|
signature,
|
|
194
180
|
payload,
|
|
@@ -196,13 +182,7 @@ export class Invocation {
|
|
|
196
182
|
version: Envelope.VERSION,
|
|
197
183
|
}
|
|
198
184
|
|
|
199
|
-
return new Invocation(
|
|
200
|
-
envelope,
|
|
201
|
-
bytes,
|
|
202
|
-
await cid(envelope),
|
|
203
|
-
options.prf,
|
|
204
|
-
await replayKey(envelope)
|
|
205
|
-
)
|
|
185
|
+
return new Invocation(envelope, bytes, await cid(envelope), options.prf)
|
|
206
186
|
}
|
|
207
187
|
}
|
|
208
188
|
|
package/src/types/varsig.ts
CHANGED
|
@@ -11,12 +11,23 @@ export type VarsigEncoding = 'RAW' | 'DAG-CBOR'
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Supported signature types
|
|
14
|
+
*
|
|
15
|
+
* RSA (`RS256`) is not supported.
|
|
14
16
|
*/
|
|
15
|
-
export type VarsigAlgorithm = SignatureType
|
|
17
|
+
export type VarsigAlgorithm = Exclude<SignatureType, 'RS256'>
|
|
16
18
|
|
|
17
19
|
export interface VarsigOptions {
|
|
18
20
|
enc: VarsigEncoding
|
|
19
21
|
alg: VarsigAlgorithm
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Options for varsig `encode`. Accepts any signer type so unsupported
|
|
26
|
+
* algorithms (e.g. `RS256`) fail at runtime with a clear error.
|
|
27
|
+
*/
|
|
28
|
+
export interface VarsigEncodeOptions {
|
|
29
|
+
enc: VarsigEncoding
|
|
30
|
+
alg: SignatureType
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
export type DecodeOutput = VarsigOptions
|
package/src/types.ts
CHANGED
|
@@ -19,13 +19,6 @@ export * from './types/policy'
|
|
|
19
19
|
export * from './types/varsig'
|
|
20
20
|
|
|
21
21
|
export type ResolveProof = (proof: CID) => Promise<Delegation>
|
|
22
|
-
/**
|
|
23
|
-
* Check whether a delegation CID is revoked.
|
|
24
|
-
*
|
|
25
|
-
* Called once for each CID the delegation could have been issued under
|
|
26
|
-
* (up to 2 for ECDSA and 4 for EIP-191 signatures), since those signatures
|
|
27
|
-
* can be re-encoded into another valid signature with a different CID.
|
|
28
|
-
*/
|
|
29
22
|
export type IsRevoked = (cid: CID) => Promise<boolean>
|
|
30
23
|
export type VerifierResolver = Resolver
|
|
31
24
|
export type DidResolver = _DidResolver
|
|
@@ -164,7 +157,7 @@ export interface ReplayStore {
|
|
|
164
157
|
* Atomically record `key` and resolve `true`, or resolve `false` if `key`
|
|
165
158
|
* was already recorded and has not expired.
|
|
166
159
|
*
|
|
167
|
-
* @param key -
|
|
160
|
+
* @param key - CID of the invocation, see {@link Invocation.cid}
|
|
168
161
|
* @param expiration - Unix time in seconds after which the key can be forgotten, or `null` to keep it forever
|
|
169
162
|
*/
|
|
170
163
|
checkAndSet(key: string, expiration: number | null): Promise<boolean>
|
package/src/utils.js
CHANGED
|
@@ -75,22 +75,6 @@ export function assertCanonical(envelope, bytes) {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
/**
|
|
79
|
-
* Replay key of a UCAN: the CID of its signature payload, the exact bytes the
|
|
80
|
-
* signature covers.
|
|
81
|
-
*
|
|
82
|
-
* Unlike {@link cid}, it does not depend on the signature bytes, so a second
|
|
83
|
-
* valid signature over the same payload (for example a malleated ECDSA
|
|
84
|
-
* signature) gets the same key.
|
|
85
|
-
*
|
|
86
|
-
* @param {import('./types.js').DecodedEnvelope<PayloadSpec>} envelope
|
|
87
|
-
*/
|
|
88
|
-
export async function replayKey(envelope) {
|
|
89
|
-
const hash = await sha256.digest(dagCbor.encode(signaturePayload(envelope)))
|
|
90
|
-
|
|
91
|
-
return CID.create(1, dagCbor.code, hash).toString()
|
|
92
|
-
}
|
|
93
|
-
|
|
94
78
|
/**
|
|
95
79
|
* Check if a DID and signature type are compatible
|
|
96
80
|
*
|
|
@@ -118,9 +102,6 @@ export function isSigAndDidCompatible(did, sigType) {
|
|
|
118
102
|
return true
|
|
119
103
|
}
|
|
120
104
|
|
|
121
|
-
if (did.verifiableDid.type === 'RSA' && sigType === 'RS256') {
|
|
122
|
-
return true
|
|
123
|
-
}
|
|
124
105
|
if (did.verifiableDid.type === 'secp256k1' && sigType === 'EIP191') {
|
|
125
106
|
return true
|
|
126
107
|
}
|
|
@@ -212,6 +193,9 @@ export async function verifySignature(
|
|
|
212
193
|
message: dagCbor.encode(signaturePayload(envelope)),
|
|
213
194
|
did: issuer,
|
|
214
195
|
type: envelope.alg,
|
|
196
|
+
// Accept only canonical signatures, such as low-S ECDSA, so each UCAN
|
|
197
|
+
// has one CID for replay and revocation checks
|
|
198
|
+
strict: true,
|
|
215
199
|
})
|
|
216
200
|
|
|
217
201
|
if (!isVerified) {
|
|
@@ -349,146 +333,15 @@ export function assertMeta(meta) {
|
|
|
349
333
|
}
|
|
350
334
|
}
|
|
351
335
|
|
|
352
|
-
/**
|
|
353
|
-
* ECDSA curve orders by signature algorithm, with the byte length of each
|
|
354
|
-
* signature component.
|
|
355
|
-
*
|
|
356
|
-
* @type {Record<string, {n: bigint, size: number}>}
|
|
357
|
-
*/
|
|
358
|
-
const ECDSA_CURVES = {
|
|
359
|
-
ES256: {
|
|
360
|
-
n: 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n,
|
|
361
|
-
size: 32,
|
|
362
|
-
},
|
|
363
|
-
ES384: {
|
|
364
|
-
n: 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973n,
|
|
365
|
-
size: 48,
|
|
366
|
-
},
|
|
367
|
-
ES512: {
|
|
368
|
-
n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n,
|
|
369
|
-
size: 66,
|
|
370
|
-
},
|
|
371
|
-
ES256K: {
|
|
372
|
-
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
|
|
373
|
-
size: 32,
|
|
374
|
-
},
|
|
375
|
-
EIP191: {
|
|
376
|
-
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
|
|
377
|
-
size: 32,
|
|
378
|
-
},
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* @param {Uint8Array} bytes
|
|
383
|
-
*/
|
|
384
|
-
function bytesToBigInt(bytes) {
|
|
385
|
-
let n = 0n
|
|
386
|
-
for (const b of bytes) n = (n << 8n) | BigInt(b)
|
|
387
|
-
return n
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* @param {bigint} n
|
|
392
|
-
* @param {number} size
|
|
393
|
-
*/
|
|
394
|
-
function bigIntToBytes(n, size) {
|
|
395
|
-
const out = new Uint8Array(size)
|
|
396
|
-
for (let i = size - 1; i >= 0; i--) {
|
|
397
|
-
out[i] = Number(n & 0xffn)
|
|
398
|
-
n >>= 8n
|
|
399
|
-
}
|
|
400
|
-
return out
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Signatures a signer could have issued that verify the same as `signature`.
|
|
405
|
-
*
|
|
406
|
-
* ECDSA signatures are malleable: `(r, s)` and `(r, n - s)` are both valid.
|
|
407
|
-
* EIP-191 signatures additionally carry a recovery byte `v` that wallets
|
|
408
|
-
* return as 27/28 or 0/1. Verifiers also accept EIP-155 style `v >= 35`,
|
|
409
|
-
* but no signer issues those for `personal_sign`, so they are not listed.
|
|
410
|
-
*
|
|
411
|
-
* The result always includes `signature` itself. Other algorithms (Ed25519,
|
|
412
|
-
* RSA) have a single valid signature.
|
|
413
|
-
*
|
|
414
|
-
* @param {import('iso-signatures/types').SignatureType} alg
|
|
415
|
-
* @param {Uint8Array} signature
|
|
416
|
-
* @returns {Uint8Array[]}
|
|
417
|
-
*/
|
|
418
|
-
export function equivalentSignatures(alg, signature) {
|
|
419
|
-
const curve = ECDSA_CURVES[alg]
|
|
420
|
-
if (!curve) {
|
|
421
|
-
return [signature]
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
const { n, size } = curve
|
|
425
|
-
const isEip191 = alg === 'EIP191'
|
|
426
|
-
if (signature.length !== size * 2 + (isEip191 ? 1 : 0)) {
|
|
427
|
-
return [signature]
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const r = signature.subarray(0, size)
|
|
431
|
-
const s = bytesToBigInt(signature.subarray(size, size * 2))
|
|
432
|
-
if (s === 0n || s >= n) {
|
|
433
|
-
return [signature]
|
|
434
|
-
}
|
|
435
|
-
const sFlipped = bigIntToBytes(n - s, size)
|
|
436
|
-
|
|
437
|
-
if (!isEip191) {
|
|
438
|
-
return [signature, new Uint8Array([...r, ...sFlipped])]
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const v = signature[size * 2]
|
|
442
|
-
/** @type {number} */
|
|
443
|
-
let parity
|
|
444
|
-
if (v === 0 || v === 27) parity = 0
|
|
445
|
-
else if (v === 1 || v === 28) parity = 1
|
|
446
|
-
else if (v >= 35) parity = v % 2 === 0 ? 1 : 0
|
|
447
|
-
else return [signature]
|
|
448
|
-
|
|
449
|
-
const sBytes = signature.subarray(size, size * 2)
|
|
450
|
-
const candidates = [
|
|
451
|
-
new Uint8Array([...r, ...sBytes, parity]),
|
|
452
|
-
new Uint8Array([...r, ...sBytes, parity + 27]),
|
|
453
|
-
new Uint8Array([...r, ...sFlipped, 1 - parity]),
|
|
454
|
-
new Uint8Array([...r, ...sFlipped, 28 - parity]),
|
|
455
|
-
]
|
|
456
|
-
return [signature, ...candidates.filter((c) => !equals(c, signature))]
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* CIDs of every envelope that verifies the same as `envelope`: one per
|
|
461
|
-
* signature in {@link equivalentSignatures}, starting with the CID of
|
|
462
|
-
* `envelope` itself.
|
|
463
|
-
*
|
|
464
|
-
* @param {import('./types.js').DecodedEnvelope<PayloadSpec>} envelope
|
|
465
|
-
*/
|
|
466
|
-
export async function equivalentCids(envelope) {
|
|
467
|
-
return await Promise.all(
|
|
468
|
-
equivalentSignatures(envelope.alg, envelope.signature).map((signature) =>
|
|
469
|
-
cid({ ...envelope, signature })
|
|
470
|
-
)
|
|
471
|
-
)
|
|
472
|
-
}
|
|
473
|
-
|
|
474
336
|
/**
|
|
475
337
|
* Assert that the input is not revoked.
|
|
476
338
|
*
|
|
477
|
-
*
|
|
478
|
-
* so re-encoding a revoked UCAN with another valid signature does not get it
|
|
479
|
-
* past a CID-based revocation list.
|
|
480
|
-
*
|
|
481
|
-
* @param {import('./types.js').DecodedEnvelope<PayloadSpec>} envelope
|
|
339
|
+
* @param {CID} cid
|
|
482
340
|
* @param {(cid: CID) => Promise<boolean>} [isRevokedFn]
|
|
483
341
|
*/
|
|
484
|
-
export async function assertNotRevoked(
|
|
485
|
-
if (
|
|
486
|
-
|
|
487
|
-
}
|
|
488
|
-
for (const c of await equivalentCids(envelope)) {
|
|
489
|
-
if (await isRevokedFn(c)) {
|
|
490
|
-
throw new Error('UCAN revoked')
|
|
491
|
-
}
|
|
342
|
+
export async function assertNotRevoked(cid, isRevokedFn) {
|
|
343
|
+
if (isRevokedFn && (await isRevokedFn(cid))) {
|
|
344
|
+
throw new Error('UCAN revoked')
|
|
492
345
|
}
|
|
493
346
|
}
|
|
494
347
|
|
package/src/varsig.js
CHANGED
|
@@ -19,7 +19,6 @@ export const CODE_ENCODING = /** @types {const} */ {
|
|
|
19
19
|
* @type {Record<number, string>}
|
|
20
20
|
*/
|
|
21
21
|
export const SIG_PREFIX = /** @type {const} */ ({
|
|
22
|
-
0x12_05: 'RSA',
|
|
23
22
|
0xed: 'EdDSA',
|
|
24
23
|
0xec: 'ECDSA',
|
|
25
24
|
})
|
|
@@ -37,8 +36,6 @@ const VARINT = {
|
|
|
37
36
|
'DAG-CBOR': [113],
|
|
38
37
|
|
|
39
38
|
/** Presets */
|
|
40
|
-
// rsa(2b)+SHA2-256(1b)+256(1b)
|
|
41
|
-
RS256: [133, 36, 18, 128, 2],
|
|
42
39
|
// eddsa(2b)+edwards25519(2b)+SHA2-512(1b)
|
|
43
40
|
Ed25519: [237, 1, 237, 1, 19],
|
|
44
41
|
// ECDSA(2b) + p256(2b) + SHA2-256(1b)
|
|
@@ -54,7 +51,7 @@ const VARINT = {
|
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
/**
|
|
57
|
-
* @param {import('./types.js').
|
|
54
|
+
* @param {import('./types.js').VarsigEncodeOptions} options
|
|
58
55
|
*/
|
|
59
56
|
export function encode(options) {
|
|
60
57
|
const enc = VARINT[options.enc]
|
|
@@ -62,7 +59,9 @@ export function encode(options) {
|
|
|
62
59
|
throw new TypeError(`Unsupported encoding ${options.enc}`)
|
|
63
60
|
}
|
|
64
61
|
|
|
65
|
-
const alg = VARINT[
|
|
62
|
+
const alg = /** @type {Partial<Record<string, number[]>>} */ (VARINT)[
|
|
63
|
+
options.alg
|
|
64
|
+
]
|
|
66
65
|
if (!alg) {
|
|
67
66
|
throw new TypeError(`Unsupported algorithm ${options.alg}`)
|
|
68
67
|
}
|
|
@@ -121,13 +120,6 @@ export function decode(buf) {
|
|
|
121
120
|
/** @type {import('./types.js').DecodeOutput} */
|
|
122
121
|
let output
|
|
123
122
|
switch (SIG_PREFIX[code]) {
|
|
124
|
-
case 'RSA': {
|
|
125
|
-
output = {
|
|
126
|
-
alg: getPreset(bytes.readBytes(5), ['RS256']),
|
|
127
|
-
enc: getEncoding(bytes.readBytes(1)),
|
|
128
|
-
}
|
|
129
|
-
break
|
|
130
|
-
}
|
|
131
123
|
case 'EdDSA': {
|
|
132
124
|
output = {
|
|
133
125
|
alg: getPreset(bytes.readBytes(5), ['Ed25519']),
|