@ocap/mcrypto 1.29.22 → 1.29.23

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.
@@ -5,14 +5,12 @@ const require_protocols_signer = require('../protocols/signer.cjs');
5
5
  let _ocap_util = require("@ocap/util");
6
6
  let randombytes = require("randombytes");
7
7
  randombytes = require_rolldown_runtime.__toESM(randombytes);
8
- let elliptic = require("elliptic");
9
- elliptic = require_rolldown_runtime.__toESM(elliptic);
8
+ let _noble_curves_secp256k1 = require("@noble/curves/secp256k1");
9
+ let _noble_curves_abstract_utils = require("@noble/curves/abstract/utils");
10
10
 
11
11
  //#region src/signer/secp256k1.ts
12
- const EC = elliptic.default.ec;
13
- const secp256k1 = new EC("secp256k1");
14
12
  /**
15
- * Signer implementation for secp256k1, based on `elliptic`
13
+ * Signer implementation for secp256k1, based on `@noble/curves`
16
14
  *
17
15
  * @class Secp256k1Signer
18
16
  */
@@ -24,8 +22,7 @@ var Secp256k1Signer = class extends require_protocols_signer.default {
24
22
  }
25
23
  isValidSK(sk) {
26
24
  if (sk.byteLength !== 32) return false;
27
- const bn = new _ocap_util.BN(sk);
28
- return bn.cmp(secp256k1.curve.n) < 0 && !bn.isZero();
25
+ return _noble_curves_secp256k1.secp256k1.utils.isValidPrivateKey(sk);
29
26
  }
30
27
  /**
31
28
  * @public
@@ -53,7 +50,7 @@ var Secp256k1Signer = class extends require_protocols_signer.default {
53
50
  */
54
51
  getPublicKey(sk, encoding = "hex") {
55
52
  if (!this.isValidSK((0, _ocap_util.toUint8Array)(sk))) throw new Error("Invalid secret key");
56
- let pk = secp256k1.keyFromPrivate((0, _ocap_util.toBuffer)(sk)).getPublic(this.pkCompressed, "hex");
53
+ let pk = (0, _noble_curves_abstract_utils.bytesToHex)(_noble_curves_secp256k1.secp256k1.getPublicKey((0, _ocap_util.toUint8Array)(sk), this.pkCompressed));
57
54
  if (this.pkHasFormatPrefix === false) pk = pk.slice(2);
58
55
  return require_encode.encode(`0x${pk}`, encoding);
59
56
  }
@@ -62,30 +59,28 @@ var Secp256k1Signer = class extends require_protocols_signer.default {
62
59
  */
63
60
  sign(message, sk, encoding = "hex") {
64
61
  const msg = (0, _ocap_util.toUint8Array)(message);
65
- return require_encode.encode(`0x${secp256k1.keyFromPrivate((0, _ocap_util.toBuffer)(sk)).sign((0, _ocap_util.stripHexPrefix)(msg), { canonical: true }).toDER("hex")}`, encoding);
62
+ return require_encode.encode(`0x${_noble_curves_secp256k1.secp256k1.sign(msg, (0, _ocap_util.toUint8Array)(sk)).toDERHex()}`, encoding);
66
63
  }
67
64
  /**
68
65
  * Verify if a signature is valid
69
66
  */
70
67
  verify(message, signature, pk) {
71
68
  const msg = (0, _ocap_util.toUint8Array)(message);
72
- const sigHex = (0, _ocap_util.stripHexPrefix)((0, _ocap_util.toHex)(signature));
73
- const sigBuf = Buffer.from(sigHex, "hex");
74
- if (sigBuf.length > 6 && sigBuf[0] === 48) {
75
- const sLenIndex = 4 + sigBuf[3] + 1;
76
- if (sLenIndex < sigBuf.length) {
77
- const sLen = sigBuf[sLenIndex];
78
- const sStart = sLenIndex + 1;
79
- if (sStart + sLen <= sigBuf.length) {
80
- const sValue = new _ocap_util.BN(sigBuf.slice(sStart, sStart + sLen));
81
- const halfOrder = secp256k1.curve.n.shrn(1);
82
- if (sValue.cmp(halfOrder) > 0) return false;
83
- }
84
- }
69
+ const sigHex = (0, _ocap_util.toHex)(signature).replace(/^0x/i, "");
70
+ let pkBytes = (0, _ocap_util.toUint8Array)(pk);
71
+ if (this.pkHasFormatPrefix === false && pkBytes[0] !== 4 && pkBytes.byteLength === 64) {
72
+ const prefixed = new Uint8Array(65);
73
+ prefixed[0] = 4;
74
+ prefixed.set(pkBytes, 1);
75
+ pkBytes = prefixed;
76
+ }
77
+ try {
78
+ const sig = _noble_curves_secp256k1.secp256k1.Signature.fromDER(sigHex);
79
+ if (sig.hasHighS()) return false;
80
+ return _noble_curves_secp256k1.secp256k1.verify(sig, msg, pkBytes);
81
+ } catch {
82
+ return false;
85
83
  }
86
- let pkBuffer = (0, _ocap_util.toBuffer)(pk);
87
- if (this.pkHasFormatPrefix === false && pkBuffer[0] !== 4 && pkBuffer.byteLength === 64) pkBuffer = Buffer.concat([Uint8Array.from([4]), Uint8Array.from(pkBuffer)]);
88
- return secp256k1.keyFromPublic(pkBuffer).verify((0, _ocap_util.stripHexPrefix)(msg), sigHex);
89
84
  }
90
85
  };
91
86
  var secp256k1_default = new Secp256k1Signer();
@@ -4,7 +4,7 @@ import { BytesType, EncodingType, KeyPairType } from "@ocap/util";
4
4
  //#region src/signer/secp256k1.d.ts
5
5
 
6
6
  /**
7
- * Signer implementation for secp256k1, based on `elliptic`
7
+ * Signer implementation for secp256k1, based on `@noble/curves`
8
8
  *
9
9
  * @class Secp256k1Signer
10
10
  */
@@ -0,0 +1,533 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ let _noble_hashes_sha2_js = require("@noble/hashes/sha2.js");
3
+ let _noble_curves_secp256k1 = require("@noble/curves/secp256k1");
4
+ let _noble_curves_p256 = require("@noble/curves/p256");
5
+ let _noble_curves_p384 = require("@noble/curves/p384");
6
+ let _noble_curves_p521 = require("@noble/curves/p521");
7
+
8
+ //#region src/webauthn.ts
9
+ /**
10
+ * Lightweight WebAuthn/passkey utilities — replaces @simplewebauthn/server/helpers.
11
+ *
12
+ * Provides COSE constants, CBOR-based credential public key decoding, base64url helpers,
13
+ * authenticator data parsing, and ECDSA signature verification using @noble/curves.
14
+ *
15
+ * Designed for environments sensitive to bundle size (e.g. Cloudflare Workers).
16
+ */
17
+ var webauthn_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
18
+ COSEALG: () => COSEALG,
19
+ COSECRV: () => COSECRV,
20
+ COSEKEYS: () => COSEKEYS,
21
+ COSEKTY: () => COSEKTY,
22
+ cose: () => cose,
23
+ decodeClientDataJSON: () => decodeClientDataJSON,
24
+ generateAuthenticationOptions: () => generateAuthenticationOptions,
25
+ generateChallenge: () => generateChallenge,
26
+ generateRegistrationOptions: () => generateRegistrationOptions,
27
+ isoBase64URL: () => isoBase64URL,
28
+ isoCBOR: () => isoCBOR,
29
+ isoUint8Array: () => isoUint8Array,
30
+ parseAuthenticatorData: () => parseAuthenticatorData,
31
+ toHash: () => toHash,
32
+ verifyRegistrationResponse: () => verifyRegistrationResponse,
33
+ verifySignature: () => verifySignature
34
+ });
35
+ const COSEKEYS = {
36
+ kty: 1,
37
+ alg: 3,
38
+ crv: -1,
39
+ x: -2,
40
+ y: -3,
41
+ n: -1,
42
+ e: -2
43
+ };
44
+ const COSEKTY = {
45
+ OKP: 1,
46
+ EC2: 2,
47
+ RSA: 3
48
+ };
49
+ const COSEALG = {
50
+ ES256: -7,
51
+ EdDSA: -8,
52
+ ES384: -35,
53
+ ES512: -36,
54
+ PS256: -37,
55
+ PS384: -38,
56
+ PS512: -39,
57
+ ES256K: -47,
58
+ RS256: -257,
59
+ RS384: -258,
60
+ RS512: -259,
61
+ RS1: -65535
62
+ };
63
+ const COSECRV = {
64
+ P256: 1,
65
+ P384: 2,
66
+ P521: 3,
67
+ ED25519: 6,
68
+ SECP256K1: 8
69
+ };
70
+ const cose = {
71
+ COSEKEYS,
72
+ COSEKTY,
73
+ COSEALG,
74
+ COSECRV
75
+ };
76
+ const isoBase64URL = {
77
+ toBuffer(base64url) {
78
+ const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
79
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
80
+ const binary = atob(padded);
81
+ const bytes = new Uint8Array(binary.length);
82
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
83
+ return bytes;
84
+ },
85
+ fromBuffer(buffer, to = "base64url") {
86
+ const normalized = new Uint8Array(buffer);
87
+ let binary = "";
88
+ for (let i = 0; i < normalized.length; i++) binary += String.fromCharCode(normalized[i]);
89
+ const base64 = btoa(binary);
90
+ if (to === "base64") return base64;
91
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
92
+ },
93
+ toUTF8String(base64url) {
94
+ const bytes = isoBase64URL.toBuffer(base64url);
95
+ return new TextDecoder().decode(bytes);
96
+ },
97
+ fromUTF8String(utf8String) {
98
+ const bytes = new TextEncoder().encode(utf8String);
99
+ return isoBase64URL.fromBuffer(bytes);
100
+ }
101
+ };
102
+ const isoUint8Array = {
103
+ concat(arrays) {
104
+ const totalLength = arrays.reduce((sum, a) => sum + a.length, 0);
105
+ const result = new Uint8Array(totalLength);
106
+ let offset = 0;
107
+ for (const arr of arrays) {
108
+ result.set(arr, offset);
109
+ offset += arr.length;
110
+ }
111
+ return result;
112
+ },
113
+ areEqual(a, b) {
114
+ if (a.length !== b.length) return false;
115
+ return a.every((v, i) => v === b[i]);
116
+ },
117
+ toDataView(array) {
118
+ return new DataView(array.buffer, array.byteOffset, array.length);
119
+ },
120
+ fromHex(hex) {
121
+ const bytes = new Uint8Array(hex.length / 2);
122
+ for (let i = 0; i < hex.length; i += 2) bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);
123
+ return bytes;
124
+ }
125
+ };
126
+ function decodeCBORInternal(data, offset) {
127
+ const major = data[offset] >> 5;
128
+ const additional = data[offset] & 31;
129
+ offset++;
130
+ let length;
131
+ if (additional < 24) length = additional;
132
+ else if (additional === 24) length = data[offset++];
133
+ else if (additional === 25) {
134
+ length = data[offset] << 8 | data[offset + 1];
135
+ offset += 2;
136
+ } else if (additional === 26) {
137
+ length = data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
138
+ offset += 4;
139
+ } else throw new Error(`CBOR: unsupported additional info ${additional}`);
140
+ switch (major) {
141
+ case 0: return [length, offset];
142
+ case 1: return [-1 - length, offset];
143
+ case 2: return [data.slice(offset, offset + length), offset + length];
144
+ case 3: return [new TextDecoder().decode(data.slice(offset, offset + length)), offset + length];
145
+ case 4: {
146
+ const arr = [];
147
+ for (let i = 0; i < length; i++) {
148
+ const [value, newOffset] = decodeCBORInternal(data, offset);
149
+ arr.push(value);
150
+ offset = newOffset;
151
+ }
152
+ return [arr, offset];
153
+ }
154
+ case 5: {
155
+ const map = /* @__PURE__ */ new Map();
156
+ for (let i = 0; i < length; i++) {
157
+ const [key, keyOffset] = decodeCBORInternal(data, offset);
158
+ const [value, valueOffset] = decodeCBORInternal(data, keyOffset);
159
+ map.set(key, value);
160
+ offset = valueOffset;
161
+ }
162
+ return [map, offset];
163
+ }
164
+ default: throw new Error(`CBOR: unsupported major type ${major}`);
165
+ }
166
+ }
167
+ function encodeCBORValue(value) {
168
+ if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
169
+ const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
170
+ return [...encodeCBORHead(2, bytes.length), ...bytes];
171
+ }
172
+ if (typeof value === "number") {
173
+ if (value >= 0) return encodeCBORHead(0, value);
174
+ return encodeCBORHead(1, -1 - value);
175
+ }
176
+ if (typeof value === "string") {
177
+ const encoded = new TextEncoder().encode(value);
178
+ return [...encodeCBORHead(3, encoded.length), ...encoded];
179
+ }
180
+ if (Array.isArray(value)) {
181
+ const items = value.flatMap((v) => encodeCBORValue(v));
182
+ return [...encodeCBORHead(4, value.length), ...items];
183
+ }
184
+ if (value instanceof Map) {
185
+ const items = [];
186
+ for (const [k, v] of value) items.push(...encodeCBORValue(k), ...encodeCBORValue(v));
187
+ return [...encodeCBORHead(5, value.size), ...items];
188
+ }
189
+ throw new Error(`CBOR encode: unsupported type ${typeof value}`);
190
+ }
191
+ function encodeCBORHead(major, length) {
192
+ const prefix = major << 5;
193
+ if (length < 24) return [prefix | length];
194
+ if (length < 256) return [prefix | 24, length];
195
+ if (length < 65536) return [
196
+ prefix | 25,
197
+ length >> 8 & 255,
198
+ length & 255
199
+ ];
200
+ return [
201
+ prefix | 26,
202
+ length >> 24 & 255,
203
+ length >> 16 & 255,
204
+ length >> 8 & 255,
205
+ length & 255
206
+ ];
207
+ }
208
+ const isoCBOR = {
209
+ decodeFirst(input) {
210
+ const [value] = decodeCBORInternal(new Uint8Array(input), 0);
211
+ return value;
212
+ },
213
+ encode(input) {
214
+ return new Uint8Array(encodeCBORValue(input));
215
+ }
216
+ };
217
+ async function toHash(data, algorithm = COSEALG.ES256) {
218
+ const input = typeof data === "string" ? new TextEncoder().encode(data) : data;
219
+ if ([
220
+ COSEALG.ES256,
221
+ COSEALG.PS256,
222
+ COSEALG.RS256,
223
+ COSEALG.ES256K
224
+ ].includes(algorithm)) return (0, _noble_hashes_sha2_js.sha256)(input);
225
+ if ([
226
+ COSEALG.ES384,
227
+ COSEALG.PS384,
228
+ COSEALG.RS384
229
+ ].includes(algorithm)) return (0, _noble_hashes_sha2_js.sha384)(input);
230
+ if ([
231
+ COSEALG.ES512,
232
+ COSEALG.PS512,
233
+ COSEALG.RS512,
234
+ COSEALG.EdDSA
235
+ ].includes(algorithm)) return (0, _noble_hashes_sha2_js.sha512)(input);
236
+ return (0, _noble_hashes_sha2_js.sha256)(input);
237
+ }
238
+ function decodeClientDataJSON(data) {
239
+ return JSON.parse(isoBase64URL.toUTF8String(data));
240
+ }
241
+ function parseAuthenticatorData(authData) {
242
+ if (authData.byteLength < 37) throw new Error(`Authenticator data was ${authData.byteLength} bytes, expected at least 37 bytes`);
243
+ let pointer = 0;
244
+ const dataView = isoUint8Array.toDataView(authData);
245
+ const rpIdHash = authData.slice(pointer, pointer += 32);
246
+ const flagsBuf = authData.slice(pointer, pointer += 1);
247
+ const flagsInt = flagsBuf[0];
248
+ const flags = {
249
+ up: !!(flagsInt & 1),
250
+ uv: !!(flagsInt & 4),
251
+ be: !!(flagsInt & 8),
252
+ bs: !!(flagsInt & 16),
253
+ at: !!(flagsInt & 64),
254
+ ed: !!(flagsInt & 128),
255
+ flagsInt
256
+ };
257
+ const counterBuf = authData.slice(pointer, pointer + 4);
258
+ const counter = dataView.getUint32(pointer, false);
259
+ pointer += 4;
260
+ let aaguid;
261
+ let credentialID;
262
+ let credentialPublicKey;
263
+ if (flags.at) {
264
+ aaguid = authData.slice(pointer, pointer += 16);
265
+ const credIDLen = dataView.getUint16(pointer);
266
+ pointer += 2;
267
+ credentialID = authData.slice(pointer, pointer += credIDLen);
268
+ const firstDecoded = isoCBOR.decodeFirst(authData.slice(pointer));
269
+ const firstEncoded = isoCBOR.encode(firstDecoded);
270
+ credentialPublicKey = firstEncoded;
271
+ pointer += firstEncoded.byteLength;
272
+ }
273
+ let extensionsData;
274
+ let extensionsDataBuffer;
275
+ if (flags.ed) {
276
+ const firstDecoded = isoCBOR.decodeFirst(authData.slice(pointer));
277
+ extensionsDataBuffer = isoCBOR.encode(firstDecoded);
278
+ extensionsData = firstDecoded;
279
+ pointer += extensionsDataBuffer.byteLength;
280
+ }
281
+ return {
282
+ rpIdHash,
283
+ flagsBuf,
284
+ flags,
285
+ counter,
286
+ counterBuf,
287
+ aaguid,
288
+ credentialID,
289
+ credentialPublicKey,
290
+ extensionsData,
291
+ extensionsDataBuffer
292
+ };
293
+ }
294
+ function getCurveForCrv(crv) {
295
+ switch (crv) {
296
+ case COSECRV.P256: return {
297
+ curve: _noble_curves_p256.p256,
298
+ hash: _noble_hashes_sha2_js.sha256,
299
+ componentLen: 32
300
+ };
301
+ case COSECRV.P384: return {
302
+ curve: _noble_curves_p384.p384,
303
+ hash: _noble_hashes_sha2_js.sha384,
304
+ componentLen: 48
305
+ };
306
+ case COSECRV.P521: return {
307
+ curve: _noble_curves_p521.p521,
308
+ hash: _noble_hashes_sha2_js.sha512,
309
+ componentLen: 66
310
+ };
311
+ case COSECRV.SECP256K1: return {
312
+ curve: _noble_curves_secp256k1.secp256k1,
313
+ hash: _noble_hashes_sha2_js.sha256,
314
+ componentLen: 32
315
+ };
316
+ default: throw new Error(`Unsupported COSE curve: ${crv}`);
317
+ }
318
+ }
319
+ async function verifySignature(opts) {
320
+ const { signature, data, credentialPublicKey } = opts;
321
+ const coseKey = isoCBOR.decodeFirst(credentialPublicKey);
322
+ const kty = coseKey.get(COSEKEYS.kty);
323
+ if (kty !== COSEKTY.EC2) throw new Error(`Unsupported COSE key type: ${kty} (only EC2 is supported)`);
324
+ const crv = coseKey.get(COSEKEYS.crv);
325
+ const x = coseKey.get(COSEKEYS.x);
326
+ const y = coseKey.get(COSEKEYS.y);
327
+ if (!x || !y) throw new Error("COSE public key missing x or y coordinate");
328
+ const { curve, hash, componentLen } = getCurveForCrv(crv);
329
+ const pubKeyBytes = new Uint8Array(1 + componentLen * 2);
330
+ pubKeyBytes[0] = 4;
331
+ pubKeyBytes.set(x.length <= componentLen ? x : x.slice(x.length - componentLen), 1 + (componentLen - x.length));
332
+ pubKeyBytes.set(y.length <= componentLen ? y : y.slice(y.length - componentLen), 1 + componentLen + (componentLen - y.length));
333
+ const msgHash = hash(data);
334
+ try {
335
+ const sig = curve.Signature.fromDER(signature);
336
+ return curve.verify(sig, msgHash, pubKeyBytes);
337
+ } catch {
338
+ return false;
339
+ }
340
+ }
341
+ function generateChallenge() {
342
+ return crypto.getRandomValues(new Uint8Array(32));
343
+ }
344
+ function convertAAGUIDToString(aaguid) {
345
+ const hex = Array.from(aaguid, (b) => b.toString(16).padStart(2, "0")).join("");
346
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
347
+ }
348
+ async function matchExpectedRPID(rpIdHash, expectedRPIDs) {
349
+ for (const rpID of expectedRPIDs) {
350
+ const expectedHash = (0, _noble_hashes_sha2_js.sha256)(new TextEncoder().encode(rpID));
351
+ if (isoUint8Array.areEqual(rpIdHash, expectedHash)) return rpID;
352
+ }
353
+ throw new Error(`Unexpected RP ID hash, expected one of: ${expectedRPIDs.join(", ")}`);
354
+ }
355
+ function parseBackupFlags(flags) {
356
+ const credentialDeviceType = flags.be ? "multiDevice" : "singleDevice";
357
+ const credentialBackedUp = flags.bs;
358
+ if (!flags.be && flags.bs) throw new Error("Credential indicates backup state but not backup eligibility");
359
+ return {
360
+ credentialDeviceType,
361
+ credentialBackedUp
362
+ };
363
+ }
364
+ async function generateRegistrationOptions(options) {
365
+ const { rpName, rpID, userName, userID, challenge = generateChallenge(), userDisplayName = "", timeout = 6e4, attestationType = "none", excludeCredentials = [], authenticatorSelection = {
366
+ residentKey: "preferred",
367
+ userVerification: "preferred"
368
+ }, extensions, supportedAlgorithmIDs = [
369
+ -8,
370
+ -7,
371
+ -257
372
+ ] } = options;
373
+ const pubKeyCredParams = supportedAlgorithmIDs.map((id) => ({
374
+ alg: id,
375
+ type: "public-key"
376
+ }));
377
+ if (authenticatorSelection.residentKey === void 0) {
378
+ if (authenticatorSelection.requireResidentKey) authenticatorSelection.residentKey = "required";
379
+ } else authenticatorSelection.requireResidentKey = authenticatorSelection.residentKey === "required";
380
+ let _challenge = challenge;
381
+ if (typeof _challenge === "string") _challenge = new TextEncoder().encode(_challenge);
382
+ let _userID = userID;
383
+ if (!_userID) _userID = crypto.getRandomValues(new Uint8Array(32));
384
+ return {
385
+ challenge: isoBase64URL.fromBuffer(_challenge),
386
+ rp: {
387
+ name: rpName,
388
+ id: rpID
389
+ },
390
+ user: {
391
+ id: isoBase64URL.fromBuffer(_userID),
392
+ name: userName,
393
+ displayName: userDisplayName
394
+ },
395
+ pubKeyCredParams,
396
+ timeout,
397
+ attestation: attestationType,
398
+ excludeCredentials: excludeCredentials.map((cred) => ({
399
+ ...cred,
400
+ id: cred.id.replace(/=+$/, ""),
401
+ type: "public-key"
402
+ })),
403
+ authenticatorSelection,
404
+ extensions: {
405
+ ...extensions,
406
+ credProps: true
407
+ }
408
+ };
409
+ }
410
+ async function generateAuthenticationOptions(options) {
411
+ const { rpID, allowCredentials, challenge = generateChallenge(), timeout = 6e4, userVerification = "preferred", extensions } = options;
412
+ let _challenge = challenge;
413
+ if (typeof _challenge === "string") _challenge = new TextEncoder().encode(_challenge);
414
+ return {
415
+ rpId: rpID,
416
+ challenge: isoBase64URL.fromBuffer(_challenge),
417
+ allowCredentials: allowCredentials?.map((cred) => ({
418
+ ...cred,
419
+ id: cred.id.replace(/=+$/, ""),
420
+ type: "public-key"
421
+ })),
422
+ timeout,
423
+ userVerification,
424
+ extensions
425
+ };
426
+ }
427
+ async function verifyRegistrationResponse(options) {
428
+ const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, requireUserPresence = true, requireUserVerification = true, supportedAlgorithmIDs = [
429
+ -8,
430
+ -7,
431
+ -36,
432
+ -37,
433
+ -38,
434
+ -39,
435
+ -257,
436
+ -258,
437
+ -259,
438
+ -65535
439
+ ] } = options;
440
+ const { id, rawId, type: credentialType, response: attestationResponse } = response;
441
+ if (!id) throw new Error("Missing credential ID");
442
+ if (id !== rawId) throw new Error("Credential ID was not base64url-encoded");
443
+ if (credentialType !== "public-key") throw new Error(`Unexpected credential type ${credentialType}, expected "public-key"`);
444
+ const clientDataJSON = decodeClientDataJSON(attestationResponse.clientDataJSON);
445
+ const { type, origin, challenge } = clientDataJSON;
446
+ if (Array.isArray(expectedType)) {
447
+ if (!expectedType.includes(type)) throw new Error(`Unexpected registration response type "${type}", expected one of: ${expectedType.join(", ")}`);
448
+ } else if (expectedType) {
449
+ if (type !== expectedType) throw new Error(`Unexpected registration response type "${type}", expected "${expectedType}"`);
450
+ } else if (type !== "webauthn.create") throw new Error(`Unexpected registration response type: ${type}`);
451
+ if (typeof expectedChallenge === "function") {
452
+ if (!await expectedChallenge(challenge)) throw new Error(`Custom challenge verifier returned false for registration response challenge "${challenge}"`);
453
+ } else if (challenge !== expectedChallenge) throw new Error(`Unexpected registration response challenge "${challenge}", expected "${expectedChallenge}"`);
454
+ if (Array.isArray(expectedOrigin)) {
455
+ if (!expectedOrigin.includes(origin)) throw new Error(`Unexpected registration response origin "${origin}", expected one of: ${expectedOrigin.join(", ")}`);
456
+ } else if (origin !== expectedOrigin) throw new Error(`Unexpected registration response origin "${origin}", expected "${expectedOrigin}"`);
457
+ const attestationObject = isoBase64URL.toBuffer(attestationResponse.attestationObject);
458
+ const decodedAttestationObject = isoCBOR.decodeFirst(attestationObject);
459
+ const fmt = decodedAttestationObject.get("fmt");
460
+ const authData = decodedAttestationObject.get("authData");
461
+ const attStmt = decodedAttestationObject.get("attStmt");
462
+ const { aaguid, rpIdHash, flags, credentialID, counter, credentialPublicKey, extensionsData } = parseAuthenticatorData(authData);
463
+ let matchedRPID;
464
+ if (expectedRPID) matchedRPID = await matchExpectedRPID(rpIdHash, Array.isArray(expectedRPID) ? expectedRPID : [expectedRPID]);
465
+ if (requireUserPresence && !flags.up) throw new Error("User presence was required, but user was not present");
466
+ if (requireUserVerification && !flags.uv) throw new Error("User verification was required, but user could not be verified");
467
+ if (!credentialID) throw new Error("No credential ID was provided by authenticator");
468
+ if (!credentialPublicKey) throw new Error("No public key was provided by authenticator");
469
+ if (!aaguid) throw new Error("No AAGUID was present during registration");
470
+ const alg = isoCBOR.decodeFirst(credentialPublicKey).get(COSEKEYS.alg);
471
+ if (typeof alg !== "number") throw new Error("Credential public key was missing numeric alg");
472
+ if (!supportedAlgorithmIDs.includes(alg)) throw new Error(`Unexpected public key alg "${alg}", expected one of "${supportedAlgorithmIDs.join(", ")}"`);
473
+ let verified = false;
474
+ if (fmt === "none") {
475
+ if (attStmt.size > 0) throw new Error("None attestation had unexpected attestation statement");
476
+ verified = true;
477
+ } else if (fmt === "packed" && attStmt.size === 2 && attStmt.has("alg") && attStmt.has("sig")) {
478
+ const clientDataHash = await toHash(isoBase64URL.toBuffer(attestationResponse.clientDataJSON));
479
+ const signedData = isoUint8Array.concat([authData, clientDataHash]);
480
+ verified = await verifySignature({
481
+ signature: attStmt.get("sig"),
482
+ data: signedData,
483
+ credentialPublicKey
484
+ });
485
+ } else throw new Error(`Unsupported attestation format: "${fmt}". Only "none" and "packed" (self-attestation) are supported.`);
486
+ if (!verified) return { verified: false };
487
+ const { credentialDeviceType, credentialBackedUp } = parseBackupFlags(flags);
488
+ return {
489
+ verified: true,
490
+ registrationInfo: {
491
+ fmt,
492
+ aaguid: convertAAGUIDToString(aaguid),
493
+ credential: {
494
+ id: isoBase64URL.fromBuffer(credentialID),
495
+ publicKey: credentialPublicKey,
496
+ counter,
497
+ transports: response.response.transports
498
+ },
499
+ credentialType: "public-key",
500
+ attestationObject,
501
+ userVerified: flags.uv,
502
+ credentialDeviceType,
503
+ credentialBackedUp,
504
+ origin: clientDataJSON.origin,
505
+ rpID: matchedRPID,
506
+ authenticatorExtensionResults: extensionsData
507
+ }
508
+ };
509
+ }
510
+
511
+ //#endregion
512
+ exports.COSEALG = COSEALG;
513
+ exports.COSECRV = COSECRV;
514
+ exports.COSEKEYS = COSEKEYS;
515
+ exports.COSEKTY = COSEKTY;
516
+ exports.cose = cose;
517
+ exports.decodeClientDataJSON = decodeClientDataJSON;
518
+ exports.generateAuthenticationOptions = generateAuthenticationOptions;
519
+ exports.generateChallenge = generateChallenge;
520
+ exports.generateRegistrationOptions = generateRegistrationOptions;
521
+ exports.isoBase64URL = isoBase64URL;
522
+ exports.isoCBOR = isoCBOR;
523
+ exports.isoUint8Array = isoUint8Array;
524
+ exports.parseAuthenticatorData = parseAuthenticatorData;
525
+ exports.toHash = toHash;
526
+ exports.verifyRegistrationResponse = verifyRegistrationResponse;
527
+ exports.verifySignature = verifySignature;
528
+ Object.defineProperty(exports, 'webauthn_exports', {
529
+ enumerable: true,
530
+ get: function () {
531
+ return webauthn_exports;
532
+ }
533
+ });