@onekeyfe/hwk-trezor-adapter 1.2.1 → 1.2.2-alpha.1
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/index.d.mts +89 -2
- package/dist/index.d.ts +89 -2
- package/dist/index.js +811 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +786 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -12,6 +12,713 @@
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
var _hwkadaptercore = require('@onekeyfe/hwk-adapter-core');
|
|
15
|
+
var _utils = require('@noble/hashes/utils');
|
|
16
|
+
|
|
17
|
+
// src/deviceAuthenticity/index.ts
|
|
18
|
+
var _sha3 = require('@noble/hashes/sha3');
|
|
19
|
+
|
|
20
|
+
// src/deviceAuthenticity/config.ts
|
|
21
|
+
var deviceAuthenticityConfig = {
|
|
22
|
+
version: 2,
|
|
23
|
+
T2B1: {
|
|
24
|
+
rootPubKeysOptiga: [
|
|
25
|
+
// upstream: DEV_AUTH_ROOT_PROD_P256
|
|
26
|
+
"04ca97480ac0d7b1e6efafe518cd433cec2bf8ab9822d76eafd34363b55d63e60380bff20acc75cde03cffcb50ab6f8ce70c878e37ebc58ff7cca0a83b16b15fa5"
|
|
27
|
+
],
|
|
28
|
+
debug: {
|
|
29
|
+
rootPubKeysOptiga: [
|
|
30
|
+
// upstream: DEV_AUTH_ROOT_DEBUG_P256 shared with T3B1
|
|
31
|
+
"047f77368dea2d4d61e989f474a56723c3212dacf8a808d8795595ef38441427c4389bc454f02089d7f08b873005e4c28d432468997871c0bf286fd3861e21e96a"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
T3B1: {
|
|
36
|
+
rootPubKeysOptiga: [
|
|
37
|
+
// upstream: DEV_AUTH_ROOT_PROD_P256
|
|
38
|
+
"045b5c3fdd01f3602092834209b86df0ca86a9faf25cac35c73bf6237d66eb21eafcec3706f1ccd5eb4cc7f2fa1751213eccb1c78389afba89a5788ff31ee46a5d"
|
|
39
|
+
],
|
|
40
|
+
debug: {
|
|
41
|
+
rootPubKeysOptiga: [
|
|
42
|
+
// upstream: DEV_AUTH_ROOT_DEBUG_P256 shared with T2B1
|
|
43
|
+
"047f77368dea2d4d61e989f474a56723c3212dacf8a808d8795595ef38441427c4389bc454f02089d7f08b873005e4c28d432468997871c0bf286fd3861e21e96a"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
T3T1: {
|
|
48
|
+
rootPubKeysOptiga: [
|
|
49
|
+
// upstream: DEV_AUTH_ROOT_PROD_P256
|
|
50
|
+
"041854b27fb1d9f65abb66828e78c9dc0ca301e66081ab0c6a4d104f9df1cd0ad5a7c75f77a8c092f55cf825d2abaf734f934c9394d5e75f75a5a06a5ee9be93ae"
|
|
51
|
+
],
|
|
52
|
+
debug: {
|
|
53
|
+
rootPubKeysOptiga: [
|
|
54
|
+
// upstream: DEV_AUTH_ROOT_DEBUG_P256
|
|
55
|
+
"04e48b69cd7962068d3cca3bcc6b1747ef496c1e28b5529e34ad7295215ea161dbe8fb08ae0479568f9d2cb07630cb3e52f4af0692102da5873559e45e9fa72959"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
T3W1: {
|
|
60
|
+
rootPubKeysOptiga: [
|
|
61
|
+
// upstream: DEV_AUTH_ROOT_PROD_P256
|
|
62
|
+
"040dde0d3e0d4da593fac6fd02a461d0e7eef238aca55c7c50b4e9ec37f3873303b6429ef1c9b78b4411a7dcbbc5dde5225979c1c2da3b073e82b1ed3f5f9825bb",
|
|
63
|
+
// upstream: DEV_AUTH_ROOT_PROD_BACKUP_P256
|
|
64
|
+
"04c6a673af4ec44b10441b1d78676e15173ad0e36df9f7f2fa1cd819955f20fe32917b60da5fed3b3aa54a9ab8b3ed27d198b3768cad26eef5935cd87af0af065e"
|
|
65
|
+
],
|
|
66
|
+
rootPubKeysTropic: [
|
|
67
|
+
// upstream: DEV_AUTH_ROOT_PROD_ED25519
|
|
68
|
+
"59237acd17134061d655b3f8d624573ca06ce8d862f38ba4e05140ce1d3d609d",
|
|
69
|
+
// upstream: DEV_AUTH_ROOT_PROD_BACKUP_ED25519
|
|
70
|
+
"5612606584ee7e0bc313b13f7ac94156bb4cb75bd77585ddbe579301306e85f1"
|
|
71
|
+
],
|
|
72
|
+
debug: {
|
|
73
|
+
rootPubKeysOptiga: [
|
|
74
|
+
// upstream: DEV_AUTH_ROOT_DEBUG_P256
|
|
75
|
+
"04521192e173a9da4e3023f747d836563725372681eba3079c56ff11b2fc137ab189eb4155f371127651b5594f8c332fc1e9c0f3b80d4212822668b63189706578",
|
|
76
|
+
// upstream: DEV_AUTH_ROOT_STAGING_P256
|
|
77
|
+
"0465e88f9b2cea67e8364f0cfcfacd500af24e9040b357beee629ccc4fce1704d1a7ef7284f387708f92ef14600e2caad6894016fee819d623b95d66210c3e7519"
|
|
78
|
+
],
|
|
79
|
+
rootPubKeysTropic: [
|
|
80
|
+
// upstream: DEV_AUTH_ROOT_STAGING_ED25519
|
|
81
|
+
"cd318dc8405ae4f4144e3284dcb7b0cb0f0c2195c2ca14a0f6fccd9104e32a4b"
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// src/deviceAuthenticity/findSubjectContentByOid.ts
|
|
88
|
+
var findSubjectContentByOid = (deviceCert, oid) => {
|
|
89
|
+
const subjectItems = deviceCert.tbsCertificate.subject;
|
|
90
|
+
const matchedItem = subjectItems.find(({ algorithmOid }) => algorithmOid === oid);
|
|
91
|
+
if (!matchedItem || !matchedItem.parameters) return null;
|
|
92
|
+
return matchedItem.parameters.asn1.contents;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/deviceAuthenticity/validateCaCertExtensions.ts
|
|
96
|
+
var validateCaCertExtensions = (cert, pathLen) => {
|
|
97
|
+
let hasKeyUsage = false;
|
|
98
|
+
let hasBasicConstraints = false;
|
|
99
|
+
cert.tbsCertificate.extensions.forEach((ext) => {
|
|
100
|
+
if (ext.key === "keyUsage") {
|
|
101
|
+
if (ext.keyCertSign !== "1") {
|
|
102
|
+
throw new Error(`CA keyCertSign not set`);
|
|
103
|
+
}
|
|
104
|
+
hasKeyUsage = true;
|
|
105
|
+
} else if (ext.key === "basicConstraints") {
|
|
106
|
+
if (!ext.cA) {
|
|
107
|
+
throw new Error(`CA basicConstraints.cA not set`);
|
|
108
|
+
}
|
|
109
|
+
if (typeof ext.pathLenConstraint !== "number") {
|
|
110
|
+
throw new Error("CA basicConstraints.pathLenConstraint not set");
|
|
111
|
+
}
|
|
112
|
+
if (ext.pathLenConstraint < pathLen) {
|
|
113
|
+
throw new Error("Issuer was not permitted to issue certificate");
|
|
114
|
+
}
|
|
115
|
+
hasBasicConstraints = true;
|
|
116
|
+
} else if (ext.critical) {
|
|
117
|
+
throw new Error(`Unknown critical extension ${ext.key} in CA certificate`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
if (!hasKeyUsage || !hasBasicConstraints) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`CA missing extensions keyUsage: ${hasKeyUsage}, basicConstraints: ${hasBasicConstraints}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/deviceAuthenticity/verifySignatures.ts
|
|
128
|
+
var _ed25519 = require('@noble/curves/ed25519');
|
|
129
|
+
var _p256 = require('@noble/curves/p256');
|
|
130
|
+
var _sha256 = require('@noble/hashes/sha256');
|
|
131
|
+
|
|
132
|
+
// src/deviceAuthenticity/x509certificate.ts
|
|
133
|
+
var parseOidToAlgorithmName = (oid) => {
|
|
134
|
+
if (oid === "1.2.840.10045.4.3.2") return "P-256";
|
|
135
|
+
if (oid === "1.3.101.112") return "Ed25519";
|
|
136
|
+
if (oid === "2.16.840.1.101.3.4.3.17") return "MLDSA44";
|
|
137
|
+
return "unknown";
|
|
138
|
+
};
|
|
139
|
+
var derToAsn1 = (byteArray) => {
|
|
140
|
+
let position = 0;
|
|
141
|
+
function getTag() {
|
|
142
|
+
let tag2 = byteArray[0] & 31;
|
|
143
|
+
position += 1;
|
|
144
|
+
if (tag2 === 31) {
|
|
145
|
+
tag2 = 0;
|
|
146
|
+
while (byteArray[position] >= 128) {
|
|
147
|
+
tag2 = tag2 * 128 + byteArray[position] - 128;
|
|
148
|
+
position += 1;
|
|
149
|
+
}
|
|
150
|
+
tag2 = tag2 * 128 + byteArray[position] - 128;
|
|
151
|
+
position += 1;
|
|
152
|
+
}
|
|
153
|
+
return tag2;
|
|
154
|
+
}
|
|
155
|
+
function getLength() {
|
|
156
|
+
let length2 = 0;
|
|
157
|
+
if (byteArray[position] < 128) {
|
|
158
|
+
length2 = byteArray[position];
|
|
159
|
+
position += 1;
|
|
160
|
+
} else {
|
|
161
|
+
const numberOfDigits = byteArray[position] & 127;
|
|
162
|
+
position += 1;
|
|
163
|
+
length2 = 0;
|
|
164
|
+
for (let i = 0; i < numberOfDigits; i++) {
|
|
165
|
+
length2 = length2 * 256 + byteArray[position];
|
|
166
|
+
position += 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return length2;
|
|
170
|
+
}
|
|
171
|
+
const cls = (byteArray[0] & 192) / 64;
|
|
172
|
+
const structured = (byteArray[0] & 32) === 32;
|
|
173
|
+
const tag = getTag();
|
|
174
|
+
if (byteArray[position] === 128) {
|
|
175
|
+
throw new Error("Unsupported length encoding");
|
|
176
|
+
}
|
|
177
|
+
const length = getLength();
|
|
178
|
+
const byteLength = position + length;
|
|
179
|
+
const contents = byteArray.subarray(position, byteLength);
|
|
180
|
+
const raw = byteArray.subarray(0, byteLength);
|
|
181
|
+
return {
|
|
182
|
+
cls,
|
|
183
|
+
tag,
|
|
184
|
+
structured,
|
|
185
|
+
byteLength,
|
|
186
|
+
contents,
|
|
187
|
+
raw
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
var derToAsn1List = (byteArray) => {
|
|
191
|
+
const result = [];
|
|
192
|
+
let nextPosition = 0;
|
|
193
|
+
while (nextPosition < byteArray.length) {
|
|
194
|
+
const nextPiece = derToAsn1(byteArray.subarray(nextPosition));
|
|
195
|
+
result.push(nextPiece);
|
|
196
|
+
nextPosition += nextPiece.byteLength;
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
};
|
|
200
|
+
var derBitStringValue = (byteArray) => ({
|
|
201
|
+
unusedBits: byteArray[0],
|
|
202
|
+
bytes: byteArray.subarray(1)
|
|
203
|
+
});
|
|
204
|
+
var parseSignatureValue = (asn1) => {
|
|
205
|
+
if (asn1.cls !== 0 || asn1.tag !== 3 || asn1.structured) {
|
|
206
|
+
throw new Error("Bad signature value. Not a BIT STRING.");
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
asn1,
|
|
210
|
+
bits: derBitStringValue(asn1.contents)
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
var fixSignature = (byteArray) => {
|
|
214
|
+
const asn1 = derToAsn1(byteArray);
|
|
215
|
+
if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
|
|
216
|
+
throw new Error("Bad signature. Not a SEQUENCE.");
|
|
217
|
+
}
|
|
218
|
+
const items = derToAsn1List(asn1.contents);
|
|
219
|
+
let newLength = 0;
|
|
220
|
+
const fixedItems = items.map((chunk) => {
|
|
221
|
+
const index = chunk.contents.findIndex((value) => value > 0);
|
|
222
|
+
const data = chunk.contents.subarray(index);
|
|
223
|
+
const offset = data[0] >= 128 ? 1 : 0;
|
|
224
|
+
const chunkLength = data.length + offset;
|
|
225
|
+
const newChunk = new Uint8Array(chunkLength + 2);
|
|
226
|
+
newChunk.set([chunk.raw[0], chunkLength]);
|
|
227
|
+
if (offset > 0) {
|
|
228
|
+
newChunk.set([0], 2);
|
|
229
|
+
}
|
|
230
|
+
newChunk.set(data, 2 + offset);
|
|
231
|
+
newLength += newChunk.length;
|
|
232
|
+
return newChunk;
|
|
233
|
+
});
|
|
234
|
+
const signature = new Uint8Array(newLength + 2);
|
|
235
|
+
signature.set([byteArray[0], newLength]);
|
|
236
|
+
let signatureOffset = 2;
|
|
237
|
+
fixedItems.forEach((item) => {
|
|
238
|
+
signature.set(item, signatureOffset);
|
|
239
|
+
signatureOffset += item.length;
|
|
240
|
+
});
|
|
241
|
+
return signature;
|
|
242
|
+
};
|
|
243
|
+
var derObjectIdentifierValue = (byteArray) => {
|
|
244
|
+
let oid = `${Math.floor(byteArray[0] / 40)}.${byteArray[0] % 40}`;
|
|
245
|
+
let position = 1;
|
|
246
|
+
while (position < byteArray.length) {
|
|
247
|
+
let nextInteger = 0;
|
|
248
|
+
while (byteArray[position] >= 128) {
|
|
249
|
+
nextInteger = nextInteger * 128 + (byteArray[position] & 127);
|
|
250
|
+
position += 1;
|
|
251
|
+
}
|
|
252
|
+
nextInteger = nextInteger * 128 + byteArray[position];
|
|
253
|
+
position += 1;
|
|
254
|
+
oid += `.${nextInteger}`;
|
|
255
|
+
}
|
|
256
|
+
return oid;
|
|
257
|
+
};
|
|
258
|
+
var parseAlgorithmIdentifier = (asn1) => {
|
|
259
|
+
if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
|
|
260
|
+
throw new Error("Bad algorithm identifier. Not a SEQUENCE.");
|
|
261
|
+
}
|
|
262
|
+
const pieces = derToAsn1List(asn1.contents);
|
|
263
|
+
if (pieces.length > 2) {
|
|
264
|
+
throw new Error("Bad algorithm identifier. Contains too many child objects.");
|
|
265
|
+
}
|
|
266
|
+
const encodedAlgorithm = pieces[0];
|
|
267
|
+
if (encodedAlgorithm.cls !== 0 || encodedAlgorithm.tag !== 6 || encodedAlgorithm.structured) {
|
|
268
|
+
throw new Error("Bad algorithm identifier. Does not begin with an OBJECT IDENTIFIER.");
|
|
269
|
+
}
|
|
270
|
+
const algorithmOid = derObjectIdentifierValue(encodedAlgorithm.contents);
|
|
271
|
+
const algorithmName = parseOidToAlgorithmName(algorithmOid);
|
|
272
|
+
return {
|
|
273
|
+
asn1,
|
|
274
|
+
algorithmOid,
|
|
275
|
+
algorithmName,
|
|
276
|
+
parameters: pieces.length === 2 ? { asn1: pieces[1] } : null
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
var parseName = (asn1) => (
|
|
280
|
+
// SEQUENCE > SET > SEQUENCE
|
|
281
|
+
derToAsn1List(asn1.contents).map((item) => {
|
|
282
|
+
const attrSet = derToAsn1(item.contents);
|
|
283
|
+
return parseAlgorithmIdentifier(attrSet);
|
|
284
|
+
})
|
|
285
|
+
);
|
|
286
|
+
var parseSubjectPublicKeyInfo = (asn1) => {
|
|
287
|
+
if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
|
|
288
|
+
throw new Error("Bad SPKI. Not a SEQUENCE.");
|
|
289
|
+
}
|
|
290
|
+
const pieces = derToAsn1List(asn1.contents);
|
|
291
|
+
if (pieces.length !== 2) {
|
|
292
|
+
throw new Error("Bad SubjectPublicKeyInfo. Wrong number of child objects.");
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
asn1,
|
|
296
|
+
algorithm: parseAlgorithmIdentifier(pieces[0]),
|
|
297
|
+
bits: derBitStringValue(pieces[1].contents)
|
|
298
|
+
};
|
|
299
|
+
};
|
|
300
|
+
var parseUtcTime = (time) => {
|
|
301
|
+
let offset = 4;
|
|
302
|
+
let yearOffset = 0;
|
|
303
|
+
if (time.tag === 23) {
|
|
304
|
+
offset = 2;
|
|
305
|
+
yearOffset = 2e3;
|
|
306
|
+
}
|
|
307
|
+
const utc = Buffer.from(time.contents).toString();
|
|
308
|
+
const year = yearOffset + Number(utc.substring(0, offset));
|
|
309
|
+
const month = Number(utc.substring(offset, offset + 2)) - 1;
|
|
310
|
+
const day = Number(utc.substring(offset + 2, offset + 4));
|
|
311
|
+
const hour = Number(utc.substring(offset + 4, offset + 6));
|
|
312
|
+
const minute = Number(utc.substring(offset + 6, offset + 8));
|
|
313
|
+
const date = /* @__PURE__ */ new Date();
|
|
314
|
+
date.setUTCFullYear(year, month, day);
|
|
315
|
+
date.setUTCHours(hour, minute, 0);
|
|
316
|
+
return date;
|
|
317
|
+
};
|
|
318
|
+
var parseValidity = (asn1) => {
|
|
319
|
+
const [from, to] = derToAsn1List(asn1.contents);
|
|
320
|
+
return {
|
|
321
|
+
from: parseUtcTime(from),
|
|
322
|
+
to: parseUtcTime(to)
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
var parseExtensions = (data) => {
|
|
326
|
+
const asn1 = derToAsn1(data.contents);
|
|
327
|
+
if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
|
|
328
|
+
throw new Error("This can't be a Extension. Wrong data type.");
|
|
329
|
+
}
|
|
330
|
+
const readBoolean = (value) => {
|
|
331
|
+
if (!value) return false;
|
|
332
|
+
if (value.cls !== 0 || value.tag !== 1 || value.contents.length !== 1 || value.structured) {
|
|
333
|
+
throw new Error("This can't be a boolean. Wrong data type.");
|
|
334
|
+
}
|
|
335
|
+
if (![0, 255].includes(value.contents[0])) {
|
|
336
|
+
throw new Error("Invalid boolean value.");
|
|
337
|
+
}
|
|
338
|
+
return value.contents[0] === 255;
|
|
339
|
+
};
|
|
340
|
+
const readBitString = (uint8Array) => {
|
|
341
|
+
const buffer = Buffer.from(uint8Array);
|
|
342
|
+
const tag = buffer.readUInt8(0);
|
|
343
|
+
if (tag !== 3) {
|
|
344
|
+
throw new Error("This can't be a bit string. Wrong data type.");
|
|
345
|
+
}
|
|
346
|
+
const length = buffer.readUInt8(1);
|
|
347
|
+
const unusedBits = buffer.readUInt8(2);
|
|
348
|
+
const bitStringBytes = buffer.subarray(3, 3 + length - 1);
|
|
349
|
+
const bitString = bitStringBytes.reduce(
|
|
350
|
+
(str, byte) => str + byte.toString(2).padStart(8, "0"),
|
|
351
|
+
""
|
|
352
|
+
);
|
|
353
|
+
return bitString.slice(0, bitString.length - unusedBits);
|
|
354
|
+
};
|
|
355
|
+
const readInteger = (value) => {
|
|
356
|
+
if (!value) return void 0;
|
|
357
|
+
if (value.cls !== 0 || value.tag !== 2 || value.contents.length !== 1 || value.structured) {
|
|
358
|
+
throw new Error("This can't be a integer. Wrong data type.");
|
|
359
|
+
}
|
|
360
|
+
return Buffer.from(value.contents).readInt8();
|
|
361
|
+
};
|
|
362
|
+
const extensions = [];
|
|
363
|
+
derToAsn1List(asn1.contents).forEach((item) => {
|
|
364
|
+
const [id, ...pieces] = derToAsn1List(item.contents);
|
|
365
|
+
if (id.cls !== 0 || id.tag !== 6 || id.structured) {
|
|
366
|
+
throw new Error("Bad extension. Does not begin with an OBJECT IDENTIFIER.");
|
|
367
|
+
}
|
|
368
|
+
const algorithm = derObjectIdentifierValue(id.contents);
|
|
369
|
+
const critical = pieces.length > 1 ? readBoolean(pieces[0]) : false;
|
|
370
|
+
const extnValue = pieces.length > 1 ? pieces[1] : pieces[0];
|
|
371
|
+
if (extnValue.cls !== 0 || extnValue.tag !== 4 || extnValue.structured) {
|
|
372
|
+
throw new Error("This can't be a octet string. Wrong data type.");
|
|
373
|
+
}
|
|
374
|
+
if (algorithm === "2.5.29.15") {
|
|
375
|
+
extensions.push({
|
|
376
|
+
key: "keyUsage",
|
|
377
|
+
critical,
|
|
378
|
+
keyCertSign: readBitString(extnValue.contents)[5]
|
|
379
|
+
});
|
|
380
|
+
} else if (algorithm === "2.5.29.19") {
|
|
381
|
+
const fields = derToAsn1List(derToAsn1(extnValue.contents).contents);
|
|
382
|
+
const ca = fields.length > 0 && fields[0].tag === 1 ? fields[0] : void 0;
|
|
383
|
+
const len = fields.length > 0 && fields[0].tag === 2 ? fields[0] : fields[1];
|
|
384
|
+
extensions.push({
|
|
385
|
+
key: "basicConstraints",
|
|
386
|
+
critical,
|
|
387
|
+
cA: readBoolean(ca),
|
|
388
|
+
pathLenConstraint: readInteger(len)
|
|
389
|
+
});
|
|
390
|
+
} else {
|
|
391
|
+
extensions.push({
|
|
392
|
+
key: algorithm,
|
|
393
|
+
critical,
|
|
394
|
+
...item
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
return extensions;
|
|
399
|
+
};
|
|
400
|
+
var parseTBSCertificate = (asn1) => {
|
|
401
|
+
if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
|
|
402
|
+
throw new Error("This can't be a TBSCertificate. Wrong data type.");
|
|
403
|
+
}
|
|
404
|
+
const pieces = derToAsn1List(asn1.contents);
|
|
405
|
+
if (pieces.length < 7) {
|
|
406
|
+
throw new Error("Bad TBS Certificate. There are fewer than the seven required children.");
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
asn1,
|
|
410
|
+
version: pieces[0],
|
|
411
|
+
serialNumber: pieces[1],
|
|
412
|
+
signature: parseAlgorithmIdentifier(pieces[2]),
|
|
413
|
+
issuer: pieces[3],
|
|
414
|
+
validity: parseValidity(pieces[4]),
|
|
415
|
+
subject: parseName(pieces[5]),
|
|
416
|
+
subjectPublicKeyInfo: parseSubjectPublicKeyInfo(pieces[6]),
|
|
417
|
+
extensions: parseExtensions(pieces[7])
|
|
418
|
+
};
|
|
419
|
+
};
|
|
420
|
+
var parseCertificate = (byteArray) => {
|
|
421
|
+
const asn1 = derToAsn1(byteArray);
|
|
422
|
+
if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
|
|
423
|
+
throw new Error("This can't be an X.509 certificate. Wrong data type.");
|
|
424
|
+
}
|
|
425
|
+
const pieces = derToAsn1List(asn1.contents);
|
|
426
|
+
if (pieces.length !== 3) {
|
|
427
|
+
throw new Error("Certificate contains more than the three specified children.");
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
asn1,
|
|
431
|
+
tbsCertificate: parseTBSCertificate(pieces[0]),
|
|
432
|
+
signatureAlgorithm: parseAlgorithmIdentifier(pieces[1]),
|
|
433
|
+
signatureValue: parseSignatureValue(pieces[2])
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// src/deviceAuthenticity/verifySignatures.ts
|
|
438
|
+
var verifySignatureP256 = (rawKey, data, signature) => {
|
|
439
|
+
try {
|
|
440
|
+
const sig = _p256.p256.Signature.fromDER(Buffer.from(fixSignature(signature)).toString("hex"));
|
|
441
|
+
return _p256.p256.verify(sig.toBytes("compact"), _sha256.sha256.call(void 0, data), rawKey, { lowS: false });
|
|
442
|
+
} catch (e) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
var verifySignatureEd25519 = (rawKey, data, signature) => {
|
|
447
|
+
try {
|
|
448
|
+
return _ed25519.ed25519.verify(signature, data, rawKey);
|
|
449
|
+
} catch (e2) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
var getVerifyFn = (algorithmName) => {
|
|
454
|
+
if (algorithmName === "P-256") return verifySignatureP256;
|
|
455
|
+
if (algorithmName === "Ed25519") return verifySignatureEd25519;
|
|
456
|
+
throw new Error(`Unsupported signature algorithm: ${algorithmName}`);
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// src/deviceAuthenticity/verifyAuthenticityProof.ts
|
|
460
|
+
var getChunkSize = (byteLength) => {
|
|
461
|
+
if (byteLength < 253) return Uint8Array.from([byteLength]);
|
|
462
|
+
if (byteLength <= 65535) {
|
|
463
|
+
const b2 = Buffer.alloc(3);
|
|
464
|
+
b2[0] = 253;
|
|
465
|
+
b2.writeUInt16LE(byteLength, 1);
|
|
466
|
+
return Uint8Array.from(b2);
|
|
467
|
+
}
|
|
468
|
+
const b = Buffer.alloc(5);
|
|
469
|
+
b[0] = 254;
|
|
470
|
+
b.writeUInt32LE(byteLength, 1);
|
|
471
|
+
return Uint8Array.from(b);
|
|
472
|
+
};
|
|
473
|
+
var prepareDeviceAuthenticityData = ({
|
|
474
|
+
payload,
|
|
475
|
+
prefix = "AuthenticateDevice:"
|
|
476
|
+
}) => {
|
|
477
|
+
const chunks = [
|
|
478
|
+
Uint8Array.from(Buffer.from(prefix)),
|
|
479
|
+
...(Array.isArray(payload) ? payload : [payload]).map((chunk) => Uint8Array.from(chunk))
|
|
480
|
+
];
|
|
481
|
+
const framed = chunks.flatMap((chunk) => [getChunkSize(chunk.byteLength), chunk]);
|
|
482
|
+
const result = new Uint8Array(framed.reduce((total, chunk) => total + chunk.byteLength, 0));
|
|
483
|
+
let offset = 0;
|
|
484
|
+
for (const chunk of framed) {
|
|
485
|
+
result.set(chunk, offset);
|
|
486
|
+
offset += chunk.byteLength;
|
|
487
|
+
}
|
|
488
|
+
return result;
|
|
489
|
+
};
|
|
490
|
+
var getRootPubKeys = ({
|
|
491
|
+
config,
|
|
492
|
+
deviceModel,
|
|
493
|
+
proofType,
|
|
494
|
+
allowDebugKeys
|
|
495
|
+
}) => {
|
|
496
|
+
const modelConfig = config[deviceModel];
|
|
497
|
+
if (!modelConfig || typeof modelConfig === "number") {
|
|
498
|
+
throw new Error(`Pubkeys for ${deviceModel} not found in config`);
|
|
499
|
+
}
|
|
500
|
+
const prod = proofType === "optiga" ? _nullishCoalesce(modelConfig.rootPubKeysOptiga, () => ( [])) : _nullishCoalesce(modelConfig.rootPubKeysTropic, () => ( []));
|
|
501
|
+
if (!allowDebugKeys) return prod;
|
|
502
|
+
return [
|
|
503
|
+
...prod,
|
|
504
|
+
...proofType === "optiga" ? _nullishCoalesce(_optionalChain([modelConfig, 'access', _2 => _2.debug, 'optionalAccess', _3 => _3.rootPubKeysOptiga]), () => ( [])) : _nullishCoalesce(_optionalChain([modelConfig, 'access', _4 => _4.debug, 'optionalAccess', _5 => _5.rootPubKeysTropic]), () => ( []))
|
|
505
|
+
];
|
|
506
|
+
};
|
|
507
|
+
var matchRootPubKeyToCertificate = ({
|
|
508
|
+
cert,
|
|
509
|
+
allRootPubKeys
|
|
510
|
+
}) => {
|
|
511
|
+
const verifySignatureFn = getVerifyFn(cert.signatureAlgorithm.algorithmName);
|
|
512
|
+
return allRootPubKeys.find(
|
|
513
|
+
(rootPubKey) => verifySignatureFn(
|
|
514
|
+
Uint8Array.from(Buffer.from(rootPubKey, "hex")),
|
|
515
|
+
cert.tbsCertificate.asn1.raw,
|
|
516
|
+
cert.signatureValue.bits.bytes
|
|
517
|
+
)
|
|
518
|
+
);
|
|
519
|
+
};
|
|
520
|
+
var parseModelFromDeviceCertSubject = (deviceCert) => {
|
|
521
|
+
const modelDescriptionBytes = findSubjectContentByOid(deviceCert, "2.5.4.3");
|
|
522
|
+
if (modelDescriptionBytes === null) return null;
|
|
523
|
+
return Buffer.from(modelDescriptionBytes.subarray(0, 4)).toString();
|
|
524
|
+
};
|
|
525
|
+
var parseSerialNumberFromDeviceCert = (deviceCert) => {
|
|
526
|
+
const serialNumber = findSubjectContentByOid(deviceCert, "2.5.4.5");
|
|
527
|
+
if (serialNumber === null) return void 0;
|
|
528
|
+
return Buffer.from(serialNumber).toString("hex");
|
|
529
|
+
};
|
|
530
|
+
var verifyAuthenticityProof = ({
|
|
531
|
+
proofType,
|
|
532
|
+
certificates,
|
|
533
|
+
signature,
|
|
534
|
+
signedData,
|
|
535
|
+
deviceModel,
|
|
536
|
+
config,
|
|
537
|
+
allowDebugKeys,
|
|
538
|
+
caPubKeyBlacklist: caPubKeyBlacklist2 = []
|
|
539
|
+
}) => {
|
|
540
|
+
const allRootPubKeys = getRootPubKeys({
|
|
541
|
+
config,
|
|
542
|
+
deviceModel,
|
|
543
|
+
proofType,
|
|
544
|
+
allowDebugKeys
|
|
545
|
+
});
|
|
546
|
+
const parsedCertificates = certificates.map(
|
|
547
|
+
(c) => parseCertificate(new Uint8Array(Buffer.from(c, "hex")))
|
|
548
|
+
);
|
|
549
|
+
const firstCertAlgName = _optionalChain([parsedCertificates, 'access', _6 => _6[0], 'optionalAccess', _7 => _7.signatureAlgorithm, 'access', _8 => _8.algorithmName]);
|
|
550
|
+
const expectedAlgorithmName = proofType === "optiga" ? "P-256" : "Ed25519";
|
|
551
|
+
if (firstCertAlgName !== expectedAlgorithmName) {
|
|
552
|
+
return { valid: false, error: "RESPONSE_MALFORMED" };
|
|
553
|
+
}
|
|
554
|
+
if (parsedCertificates.length !== 2) {
|
|
555
|
+
return { valid: false, error: "RESPONSE_MALFORMED" };
|
|
556
|
+
}
|
|
557
|
+
const [deviceCert, caCert] = parsedCertificates;
|
|
558
|
+
const deviceCertPubKey = Buffer.from(
|
|
559
|
+
deviceCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes
|
|
560
|
+
).toString("hex");
|
|
561
|
+
const deviceCertAlgName = deviceCert.signatureAlgorithm.algorithmName;
|
|
562
|
+
const caCertAlgName = caCert.signatureAlgorithm.algorithmName;
|
|
563
|
+
if (deviceCertAlgName !== caCertAlgName) {
|
|
564
|
+
return { valid: false, deviceCertPubKey, error: "RESPONSE_MALFORMED" };
|
|
565
|
+
}
|
|
566
|
+
validateCaCertExtensions(caCert, 0);
|
|
567
|
+
const verifySignatureFn = getVerifyFn(deviceCertAlgName);
|
|
568
|
+
const caPubKeyBytes = caCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes;
|
|
569
|
+
const caPubKey = Buffer.from(caPubKeyBytes).toString("hex");
|
|
570
|
+
const rootPubKeyMatch = matchRootPubKeyToCertificate({ allRootPubKeys, cert: caCert });
|
|
571
|
+
if (rootPubKeyMatch === void 0) {
|
|
572
|
+
return { valid: false, caPubKey, deviceCertPubKey, error: "ROOT_PUBKEY_NOT_FOUND" };
|
|
573
|
+
}
|
|
574
|
+
if (caPubKeyBlacklist2.includes(caPubKey)) {
|
|
575
|
+
return {
|
|
576
|
+
valid: false,
|
|
577
|
+
caPubKey,
|
|
578
|
+
rootPubKey: rootPubKeyMatch,
|
|
579
|
+
deviceCertPubKey,
|
|
580
|
+
error: "CA_PUBKEY_BLACKLISTED"
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const now = Date.now();
|
|
584
|
+
const isWithinValidity = (validity) => validity.from.getTime() <= now && now <= validity.to.getTime();
|
|
585
|
+
if (!isWithinValidity(caCert.tbsCertificate.validity) || !isWithinValidity(deviceCert.tbsCertificate.validity)) {
|
|
586
|
+
return {
|
|
587
|
+
valid: false,
|
|
588
|
+
caPubKey,
|
|
589
|
+
rootPubKey: rootPubKeyMatch,
|
|
590
|
+
deviceCertPubKey,
|
|
591
|
+
error: "CERTIFICATE_EXPIRED"
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
const modelFromSubject = parseModelFromDeviceCertSubject(deviceCert);
|
|
595
|
+
if (modelFromSubject !== deviceModel) {
|
|
596
|
+
return {
|
|
597
|
+
valid: false,
|
|
598
|
+
caPubKey,
|
|
599
|
+
rootPubKey: rootPubKeyMatch,
|
|
600
|
+
deviceCertPubKey,
|
|
601
|
+
error: "INVALID_DEVICE_MODEL"
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
const isDeviceCertValid = verifySignatureFn(
|
|
605
|
+
Uint8Array.from(caPubKeyBytes),
|
|
606
|
+
deviceCert.tbsCertificate.asn1.raw,
|
|
607
|
+
deviceCert.signatureValue.bits.bytes
|
|
608
|
+
);
|
|
609
|
+
if (!isDeviceCertValid) {
|
|
610
|
+
return {
|
|
611
|
+
valid: false,
|
|
612
|
+
caPubKey,
|
|
613
|
+
rootPubKey: rootPubKeyMatch,
|
|
614
|
+
deviceCertPubKey,
|
|
615
|
+
error: "INVALID_DEVICE_CERTIFICATE"
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
const isSignatureValid = verifySignatureFn(
|
|
619
|
+
Uint8Array.from(deviceCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes),
|
|
620
|
+
signedData,
|
|
621
|
+
Uint8Array.from(Buffer.from(signature, "hex"))
|
|
622
|
+
);
|
|
623
|
+
if (!isSignatureValid) {
|
|
624
|
+
return {
|
|
625
|
+
valid: false,
|
|
626
|
+
caPubKey,
|
|
627
|
+
rootPubKey: rootPubKeyMatch,
|
|
628
|
+
deviceCertPubKey,
|
|
629
|
+
error: "INVALID_DEVICE_SIGNATURE"
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
return {
|
|
633
|
+
valid: true,
|
|
634
|
+
caPubKey,
|
|
635
|
+
rootPubKey: rootPubKeyMatch,
|
|
636
|
+
deviceCertPubKey,
|
|
637
|
+
serialNumber: parseSerialNumberFromDeviceCert(deviceCert)
|
|
638
|
+
};
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
// src/deviceAuthenticity/index.ts
|
|
642
|
+
var caPubKeyBlacklist = [];
|
|
643
|
+
var modelConfigOf = (config, deviceModel) => {
|
|
644
|
+
const modelConfig = config[deviceModel];
|
|
645
|
+
return modelConfig && typeof modelConfig !== "number" ? modelConfig : void 0;
|
|
646
|
+
};
|
|
647
|
+
var getRequiredDeviceAuthenticityLayers = (deviceModel) => deviceModel === "T3W1" ? ["optiga", "tropic"] : ["optiga"];
|
|
648
|
+
var isTropicExpected = (deviceModel) => getRequiredDeviceAuthenticityLayers(deviceModel).includes("tropic");
|
|
649
|
+
var matchedDebugKey = (config, deviceModel, rootPubKey) => {
|
|
650
|
+
if (!rootPubKey) return false;
|
|
651
|
+
const m = modelConfigOf(config, deviceModel);
|
|
652
|
+
if (!_optionalChain([m, 'optionalAccess', _9 => _9.debug])) return false;
|
|
653
|
+
return [..._nullishCoalesce(m.debug.rootPubKeysOptiga, () => ( [])), ..._nullishCoalesce(m.debug.rootPubKeysTropic, () => ( []))].includes(
|
|
654
|
+
rootPubKey
|
|
655
|
+
);
|
|
656
|
+
};
|
|
657
|
+
var authenticateDeviceFromProof = ({
|
|
658
|
+
proof,
|
|
659
|
+
challenge,
|
|
660
|
+
deviceModel,
|
|
661
|
+
config = deviceAuthenticityConfig,
|
|
662
|
+
allowDebugKeys
|
|
663
|
+
}) => {
|
|
664
|
+
try {
|
|
665
|
+
const signedData = prepareDeviceAuthenticityData({ payload: challenge });
|
|
666
|
+
const common = { signedData, deviceModel, config, allowDebugKeys, caPubKeyBlacklist };
|
|
667
|
+
const { optiga_certificates: optigaCertificates, optiga_signature: optigaSignature } = proof;
|
|
668
|
+
if (!optigaSignature || !_optionalChain([optigaCertificates, 'optionalAccess', _10 => _10.length])) {
|
|
669
|
+
return { verified: false, error: "RESPONSE_PAYLOAD_MISSING" };
|
|
670
|
+
}
|
|
671
|
+
const optiga = verifyAuthenticityProof({
|
|
672
|
+
...common,
|
|
673
|
+
proofType: "optiga",
|
|
674
|
+
certificates: optigaCertificates,
|
|
675
|
+
signature: optigaSignature
|
|
676
|
+
});
|
|
677
|
+
if (!optiga.valid) {
|
|
678
|
+
return {
|
|
679
|
+
verified: false,
|
|
680
|
+
deviceCertPubKey: optiga.deviceCertPubKey,
|
|
681
|
+
caPubKey: optiga.caPubKey,
|
|
682
|
+
rootPubKey: optiga.rootPubKey,
|
|
683
|
+
error: optiga.error
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
let usedDebugKey = matchedDebugKey(config, deviceModel, optiga.rootPubKey);
|
|
687
|
+
if (isTropicExpected(deviceModel)) {
|
|
688
|
+
const { tropic_certificates: tropicCertificates, tropic_signature: tropicSignature } = proof;
|
|
689
|
+
if (!tropicSignature || !_optionalChain([tropicCertificates, 'optionalAccess', _11 => _11.length])) {
|
|
690
|
+
return { verified: false, error: "RESPONSE_PAYLOAD_MISSING" };
|
|
691
|
+
}
|
|
692
|
+
const tropic = verifyAuthenticityProof({
|
|
693
|
+
...common,
|
|
694
|
+
proofType: "tropic",
|
|
695
|
+
certificates: tropicCertificates,
|
|
696
|
+
signature: tropicSignature
|
|
697
|
+
});
|
|
698
|
+
if (!tropic.valid) {
|
|
699
|
+
return { verified: false, error: tropic.error };
|
|
700
|
+
}
|
|
701
|
+
usedDebugKey = usedDebugKey || matchedDebugKey(config, deviceModel, tropic.rootPubKey);
|
|
702
|
+
}
|
|
703
|
+
const deviceId = Buffer.from(
|
|
704
|
+
_sha3.sha3_256.call(void 0, Uint8Array.from(Buffer.from(optiga.deviceCertPubKey, "hex")))
|
|
705
|
+
).toString("hex");
|
|
706
|
+
return {
|
|
707
|
+
verified: true,
|
|
708
|
+
deviceId,
|
|
709
|
+
deviceCertPubKey: optiga.deviceCertPubKey,
|
|
710
|
+
serialNumber: optiga.serialNumber,
|
|
711
|
+
rootPubKey: optiga.rootPubKey,
|
|
712
|
+
caPubKey: optiga.caPubKey,
|
|
713
|
+
usedDebugKey
|
|
714
|
+
};
|
|
715
|
+
} catch (error) {
|
|
716
|
+
return {
|
|
717
|
+
verified: false,
|
|
718
|
+
error: `RESPONSE_MALFORMED: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _12 => _12.message]), () => ( "parse error"))}`
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
};
|
|
15
722
|
|
|
16
723
|
// src/utils/sdkEventBus.ts
|
|
17
724
|
var listeners = /* @__PURE__ */ new Set();
|
|
@@ -29,7 +736,7 @@ function emitSdkEvent(event) {
|
|
|
29
736
|
for (const listener of listeners) {
|
|
30
737
|
try {
|
|
31
738
|
listener(event);
|
|
32
|
-
} catch (
|
|
739
|
+
} catch (e3) {
|
|
33
740
|
}
|
|
34
741
|
}
|
|
35
742
|
}
|
|
@@ -45,7 +752,7 @@ ${value.stack}` : value.message;
|
|
|
45
752
|
}
|
|
46
753
|
try {
|
|
47
754
|
return JSON.stringify(value);
|
|
48
|
-
} catch (
|
|
755
|
+
} catch (e4) {
|
|
49
756
|
return String(value);
|
|
50
757
|
}
|
|
51
758
|
}
|
|
@@ -122,8 +829,8 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
122
829
|
...data,
|
|
123
830
|
payload: {
|
|
124
831
|
...payload,
|
|
125
|
-
..._optionalChain([context, 'optionalAccess',
|
|
126
|
-
..._optionalChain([context, 'optionalAccess',
|
|
832
|
+
..._optionalChain([context, 'optionalAccess', _13 => _13.passphraseState]) !== void 0 ? { passphraseState: context.passphraseState } : {},
|
|
833
|
+
..._optionalChain([context, 'optionalAccess', _14 => _14.useEmptyPassphrase]) !== void 0 ? { useEmptyPassphrase: context.useEmptyPassphrase } : {}
|
|
127
834
|
}
|
|
128
835
|
}
|
|
129
836
|
);
|
|
@@ -177,9 +884,9 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
177
884
|
return { rest: _nullishCoalesce(params, () => ( {})) };
|
|
178
885
|
}
|
|
179
886
|
static _withAllNetworkRequestCommonParams(item, commonParams) {
|
|
180
|
-
const autoInstallApp = _optionalChain([commonParams, 'optionalAccess',
|
|
181
|
-
const passphraseState = _optionalChain([commonParams, 'optionalAccess',
|
|
182
|
-
const useEmptyPassphrase = _optionalChain([commonParams, 'optionalAccess',
|
|
887
|
+
const autoInstallApp = _optionalChain([commonParams, 'optionalAccess', _15 => _15.autoInstallApp]);
|
|
888
|
+
const passphraseState = _optionalChain([commonParams, 'optionalAccess', _16 => _16.passphraseState]);
|
|
889
|
+
const useEmptyPassphrase = _optionalChain([commonParams, 'optionalAccess', _17 => _17.useEmptyPassphrase]);
|
|
183
890
|
if (autoInstallApp === void 0 && passphraseState === void 0 && useEmptyPassphrase === void 0) {
|
|
184
891
|
return item;
|
|
185
892
|
}
|
|
@@ -243,8 +950,8 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
243
950
|
};
|
|
244
951
|
}
|
|
245
952
|
static _trezorFailureMessage(error) {
|
|
246
|
-
const response = _optionalChain([error, 'optionalAccess',
|
|
247
|
-
const message = _optionalChain([response, 'optionalAccess',
|
|
953
|
+
const response = _optionalChain([error, 'optionalAccess', _18 => _18.response]);
|
|
954
|
+
const message = _optionalChain([response, 'optionalAccess', _19 => _19.message]);
|
|
248
955
|
if (!message || typeof message !== "object") return {};
|
|
249
956
|
const failureMessage = message;
|
|
250
957
|
return {
|
|
@@ -253,7 +960,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
253
960
|
};
|
|
254
961
|
}
|
|
255
962
|
static _mapTrezorFailureCode(error) {
|
|
256
|
-
const directCode = _optionalChain([error, 'optionalAccess',
|
|
963
|
+
const directCode = _optionalChain([error, 'optionalAccess', _20 => _20.code]);
|
|
257
964
|
if (directCode === "Device_InitializeFailed") {
|
|
258
965
|
return _hwkadaptercore.HardwareErrorCode.PinCancelled;
|
|
259
966
|
}
|
|
@@ -266,7 +973,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
266
973
|
if (directCode === "Failure_UnexpectedMessage") {
|
|
267
974
|
return _hwkadaptercore.HardwareErrorCode.MethodNotSupported;
|
|
268
975
|
}
|
|
269
|
-
const message = _optionalChain([error, 'optionalAccess',
|
|
976
|
+
const message = _optionalChain([error, 'optionalAccess', _21 => _21.message]);
|
|
270
977
|
if (typeof message === "string" && message.includes("Failed to execute 'transfer") && message.includes("on 'USBDevice'")) {
|
|
271
978
|
return _hwkadaptercore.HardwareErrorCode.TransportError;
|
|
272
979
|
}
|
|
@@ -323,6 +1030,10 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
323
1030
|
const { code } = error;
|
|
324
1031
|
return code === _hwkadaptercore.HardwareErrorCode.DeviceNotFound || code === _hwkadaptercore.HardwareErrorCode.DeviceDisconnected;
|
|
325
1032
|
}
|
|
1033
|
+
static _isRecoverableProtocolResidueError(error) {
|
|
1034
|
+
const protocolError = error;
|
|
1035
|
+
return protocolError.name === "TrezorProtocolError" && protocolError.code === "Malformed protocol format" && protocolError.message === "Malformed protocol format";
|
|
1036
|
+
}
|
|
326
1037
|
/**
|
|
327
1038
|
* Race a promise against an abort signal. Copied from LedgerAdapter:
|
|
328
1039
|
* IConnector.call() can't actually be cancelled at the protocol level, but
|
|
@@ -353,8 +1064,8 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
353
1064
|
});
|
|
354
1065
|
}
|
|
355
1066
|
async _connectSession(connectId, signal) {
|
|
356
|
-
const
|
|
357
|
-
|
|
1067
|
+
const connectOnce = async () => {
|
|
1068
|
+
const connectPromise = this._connector.connect(connectId);
|
|
358
1069
|
if (!signal) return connectPromise;
|
|
359
1070
|
try {
|
|
360
1071
|
return await _TrezorAdapter._abortable(signal, connectPromise);
|
|
@@ -365,7 +1076,19 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
365
1076
|
);
|
|
366
1077
|
throw error;
|
|
367
1078
|
}
|
|
368
|
-
}
|
|
1079
|
+
};
|
|
1080
|
+
let session;
|
|
1081
|
+
try {
|
|
1082
|
+
session = await connectOnce();
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
if (_optionalChain([signal, 'optionalAccess', _22 => _22.aborted]) || !_TrezorAdapter._isRecoverableProtocolResidueError(error)) {
|
|
1085
|
+
throw error;
|
|
1086
|
+
}
|
|
1087
|
+
debugLog("[TrezorAdapter] retrying connect after draining a stale THP frame", {
|
|
1088
|
+
connectId
|
|
1089
|
+
});
|
|
1090
|
+
session = await connectOnce();
|
|
1091
|
+
}
|
|
369
1092
|
if (this._disconnectRequested.delete(connectId)) {
|
|
370
1093
|
await this._connector.disconnect(session.sessionId).catch(() => void 0);
|
|
371
1094
|
throw Object.assign(new Error("Trezor connection aborted"), {
|
|
@@ -414,7 +1137,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
414
1137
|
async searchDevices(options) {
|
|
415
1138
|
await this._ensureDevicePermission();
|
|
416
1139
|
const scanned = await this._connector.searchDevices(
|
|
417
|
-
_optionalChain([options, 'optionalAccess',
|
|
1140
|
+
_optionalChain([options, 'optionalAccess', _23 => _23.waitForAllTransports]) ? { waitForAll: true } : void 0
|
|
418
1141
|
);
|
|
419
1142
|
const scannedIds = new Set(scanned.map((d) => d.connectId));
|
|
420
1143
|
for (const connectId of [...this._devices.keys()]) {
|
|
@@ -461,7 +1184,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
461
1184
|
let liveDeviceId = "";
|
|
462
1185
|
const topLevelFailureIndexes = /* @__PURE__ */ new Set();
|
|
463
1186
|
const isSingleNetworkBundle = params.bundle.every(
|
|
464
|
-
(item) => item.network === _optionalChain([params, 'access',
|
|
1187
|
+
(item) => item.network === _optionalChain([params, 'access', _24 => _24.bundle, 'access', _25 => _25[0], 'optionalAccess', _26 => _26.network])
|
|
465
1188
|
);
|
|
466
1189
|
const getLiveDeviceId = async () => {
|
|
467
1190
|
if (liveDeviceId) return _hwkadaptercore.success.call(void 0, liveDeviceId);
|
|
@@ -521,7 +1244,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
521
1244
|
// One named boolean per abort reason.
|
|
522
1245
|
shouldAbortBundle: (response, { index }) => {
|
|
523
1246
|
const isSessionLevelFailure = topLevelFailureIndexes.has(index);
|
|
524
|
-
const isWholeChainForbidden = isSingleNetworkBundle && _optionalChain([response, 'access',
|
|
1247
|
+
const isWholeChainForbidden = isSingleNetworkBundle && _optionalChain([response, 'access', _27 => _27.payload, 'optionalAccess', _28 => _28.code]) === _hwkadaptercore.HardwareErrorCode.DevicePathForbidden;
|
|
525
1248
|
return isSessionLevelFailure || isWholeChainForbidden;
|
|
526
1249
|
}
|
|
527
1250
|
});
|
|
@@ -529,6 +1252,64 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
529
1252
|
getFeatures(connectId) {
|
|
530
1253
|
return this._callDeviceManagerMethod("getFeatures", connectId, {});
|
|
531
1254
|
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Device authenticity attestation. Sends a host-generated challenge, has the
|
|
1257
|
+
* device sign it with its secure-element key, then verifies the returned
|
|
1258
|
+
* certificate chain up to a trusted Trezor root CA. On success returns a
|
|
1259
|
+
* `deviceId` that uniquely identifies the physical device, survives wipe, and
|
|
1260
|
+
* cannot be forged from a seed. Only trust the result when `verified` is true
|
|
1261
|
+
* (and `usedDebugKey` is false in production).
|
|
1262
|
+
*
|
|
1263
|
+
* Requires a secure-element model (Safe 3 = T2B1/T3B1, Safe 5 = T3T1, T3W1)
|
|
1264
|
+
* and an on-device confirmation. Older models (T1B1, T2T1) will fail.
|
|
1265
|
+
*
|
|
1266
|
+
* `dangerouslyAllowDebugKeys` accepts simulator / development root keys — NEVER
|
|
1267
|
+
* enable it in a production accounting flow, it lets an emulator mint any id.
|
|
1268
|
+
*/
|
|
1269
|
+
async verifyDeviceAuthenticity(connectId, params = {}) {
|
|
1270
|
+
if (params.challenge && params.dangerouslyAllowDebugKeys) {
|
|
1271
|
+
return _hwkadaptercore.failure.call(void 0,
|
|
1272
|
+
_hwkadaptercore.HardwareErrorCode.InvalidParams,
|
|
1273
|
+
"Debug attestation roots cannot be used with a server challenge"
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
if (params.challenge && !/^[0-9a-fA-F]{64}$/.test(params.challenge)) {
|
|
1277
|
+
return _hwkadaptercore.failure.call(void 0,
|
|
1278
|
+
_hwkadaptercore.HardwareErrorCode.InvalidParams,
|
|
1279
|
+
"Device authenticity challenge must be exactly 32 bytes encoded as hex"
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
const featuresRes = await this.getFeatures(connectId);
|
|
1283
|
+
if (!featuresRes.success) return featuresRes;
|
|
1284
|
+
const internalModel = featuresRes.payload.internal_model;
|
|
1285
|
+
if (!internalModel) {
|
|
1286
|
+
return _hwkadaptercore.failure.call(void 0, _hwkadaptercore.HardwareErrorCode.UnknownError, "Device internal_model unavailable");
|
|
1287
|
+
}
|
|
1288
|
+
const challengeHex = _nullishCoalesce(_optionalChain([params, 'access', _29 => _29.challenge, 'optionalAccess', _30 => _30.toLowerCase, 'call', _31 => _31()]), () => ( Buffer.from(_utils.randomBytes.call(void 0, 32)).toString("hex")));
|
|
1289
|
+
const challenge = Buffer.from(challengeHex, "hex");
|
|
1290
|
+
const proofRes = await this._callDeviceManagerMethod(
|
|
1291
|
+
"authenticateDevice",
|
|
1292
|
+
connectId,
|
|
1293
|
+
{ challenge: challengeHex }
|
|
1294
|
+
);
|
|
1295
|
+
if (!proofRes.success) return proofRes;
|
|
1296
|
+
const proof = proofRes.payload;
|
|
1297
|
+
const verification = authenticateDeviceFromProof({
|
|
1298
|
+
proof,
|
|
1299
|
+
challenge,
|
|
1300
|
+
deviceModel: internalModel,
|
|
1301
|
+
allowDebugKeys: params.dangerouslyAllowDebugKeys
|
|
1302
|
+
});
|
|
1303
|
+
return _hwkadaptercore.success.call(void 0, {
|
|
1304
|
+
...verification,
|
|
1305
|
+
vendor: "trezor",
|
|
1306
|
+
trezorProof: {
|
|
1307
|
+
challenge: challengeHex,
|
|
1308
|
+
deviceModel: internalModel,
|
|
1309
|
+
proof
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
532
1313
|
deviceSettings(connectId, params) {
|
|
533
1314
|
return this._callDeviceManagerMethod(
|
|
534
1315
|
"deviceSettings",
|
|
@@ -858,7 +1639,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
858
1639
|
if (pending) return pending;
|
|
859
1640
|
const promise = (async () => {
|
|
860
1641
|
try {
|
|
861
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
1642
|
+
if (_optionalChain([signal, 'optionalAccess', _32 => _32.aborted])) {
|
|
862
1643
|
throw Object.assign(new Error("Trezor connection aborted"), {
|
|
863
1644
|
code: _hwkadaptercore.HardwareErrorCode.UserAborted
|
|
864
1645
|
});
|
|
@@ -904,8 +1685,8 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
904
1685
|
passphraseMode: "prompt"
|
|
905
1686
|
})
|
|
906
1687
|
);
|
|
907
|
-
if (_optionalChain([created, 'optionalAccess',
|
|
908
|
-
if (_optionalChain([created, 'optionalAccess',
|
|
1688
|
+
if (_optionalChain([created, 'optionalAccess', _33 => _33.protocol]) === "thp" && !created.thpSessionId) return;
|
|
1689
|
+
if (_optionalChain([created, 'optionalAccess', _34 => _34.protocol]) !== "thp" && _optionalChain([created, 'optionalAccess', _35 => _35.protocol]) !== "v1") return;
|
|
909
1690
|
const state = await this._deriveState(sessionId, signal);
|
|
910
1691
|
if (state !== passphraseState) {
|
|
911
1692
|
throw Object.assign(
|
|
@@ -919,13 +1700,13 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
919
1700
|
}
|
|
920
1701
|
_rememberVerifiedPassphraseSession(connectId, passphraseState, sessionId, created) {
|
|
921
1702
|
let session;
|
|
922
|
-
if (_optionalChain([created, 'optionalAccess',
|
|
1703
|
+
if (_optionalChain([created, 'optionalAccess', _36 => _36.protocol]) === "thp" && typeof created.thpSessionId === "string") {
|
|
923
1704
|
session = {
|
|
924
1705
|
sessionId,
|
|
925
1706
|
protocol: "thp",
|
|
926
1707
|
thpSessionId: created.thpSessionId
|
|
927
1708
|
};
|
|
928
|
-
} else if (_optionalChain([created, 'optionalAccess',
|
|
1709
|
+
} else if (_optionalChain([created, 'optionalAccess', _37 => _37.protocol]) === "v1") {
|
|
929
1710
|
session = {
|
|
930
1711
|
sessionId,
|
|
931
1712
|
protocol: "v1"
|
|
@@ -945,7 +1726,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
945
1726
|
}
|
|
946
1727
|
}
|
|
947
1728
|
async _reuseVerifiedPassphraseSession(connectId, sessionId, passphraseState, signal) {
|
|
948
|
-
const cached = _optionalChain([this, 'access',
|
|
1729
|
+
const cached = _optionalChain([this, 'access', _38 => _38._verifiedPassphraseSessionsByConnectId, 'access', _39 => _39.get, 'call', _40 => _40(connectId), 'optionalAccess', _41 => _41.get, 'call', _42 => _42(passphraseState)]);
|
|
949
1730
|
if (!cached || cached.sessionId !== sessionId) {
|
|
950
1731
|
this._forgetVerifiedPassphraseSession(connectId, passphraseState);
|
|
951
1732
|
return false;
|
|
@@ -997,7 +1778,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
997
1778
|
showOnDevice: false
|
|
998
1779
|
})
|
|
999
1780
|
);
|
|
1000
|
-
const state = _optionalChain([derived, 'optionalAccess',
|
|
1781
|
+
const state = _optionalChain([derived, 'optionalAccess', _43 => _43.publicKey]);
|
|
1001
1782
|
if (!state) {
|
|
1002
1783
|
throw Object.assign(new Error("Failed to derive passphrase state (wallet public key)"), {
|
|
1003
1784
|
code: _hwkadaptercore.HardwareErrorCode.UnknownError
|
|
@@ -1023,7 +1804,7 @@ var _TrezorAdapter = class _TrezorAdapter {
|
|
|
1023
1804
|
signal,
|
|
1024
1805
|
_TrezorAdapter._callConnector(this._connector, sessionId, "getFeatures", { refresh: true })
|
|
1025
1806
|
);
|
|
1026
|
-
if (_optionalChain([features, 'optionalAccess',
|
|
1807
|
+
if (_optionalChain([features, 'optionalAccess', _44 => _44.passphrase_protection]) !== true) {
|
|
1027
1808
|
return _hwkadaptercore.success.call(void 0, null);
|
|
1028
1809
|
}
|
|
1029
1810
|
this._rememberVerifiedPassphraseSession(connectId, state, sessionId, created);
|
|
@@ -1227,7 +2008,7 @@ async function fetchDefinitionHex(url, fetchImpl) {
|
|
|
1227
2008
|
}
|
|
1228
2009
|
return arrayBufferToHex(await response.arrayBuffer());
|
|
1229
2010
|
});
|
|
1230
|
-
} catch (
|
|
2011
|
+
} catch (e5) {
|
|
1231
2012
|
return void 0;
|
|
1232
2013
|
}
|
|
1233
2014
|
}
|
|
@@ -1256,7 +2037,7 @@ async function fetchSolanaTokenDefinition({
|
|
|
1256
2037
|
}
|
|
1257
2038
|
return Buffer.from(await response.arrayBuffer()).toString("hex");
|
|
1258
2039
|
});
|
|
1259
|
-
} catch (
|
|
2040
|
+
} catch (e6) {
|
|
1260
2041
|
return void 0;
|
|
1261
2042
|
}
|
|
1262
2043
|
}
|
|
@@ -1327,5 +2108,7 @@ function resolveTrezorBleConnectId(descriptor) {
|
|
|
1327
2108
|
|
|
1328
2109
|
|
|
1329
2110
|
|
|
1330
|
-
|
|
2111
|
+
|
|
2112
|
+
|
|
2113
|
+
exports.DEFAULT_ETHEREUM_DEFINITIONS_BASE_URL = DEFAULT_ETHEREUM_DEFINITIONS_BASE_URL; exports.DEFAULT_SOLANA_TOKEN_DEFINITION_BASE_URL = DEFAULT_SOLANA_TOKEN_DEFINITION_BASE_URL; exports.TREZOR_BLE_PACKET_SIZE = TREZOR_BLE_PACKET_SIZE; exports.TREZOR_BLE_SUPPORTED_MODELS = TREZOR_BLE_SUPPORTED_MODELS; exports.TREZOR_BLE_UUIDS = TREZOR_BLE_UUIDS; exports.TREZOR_SAFE_7_MODEL = TREZOR_SAFE_7_MODEL; exports.TrezorAdapter = TrezorAdapter; exports.authenticateDeviceFromProof = authenticateDeviceFromProof; exports.buildEthereumDefinitionsForPath = buildEthereumDefinitionsForPath; exports.buildEthereumDefinitionsForSignTx = buildEthereumDefinitionsForSignTx; exports.fetchEthereumDefinitions = fetchEthereumDefinitions; exports.fetchSolanaTokenDefinition = fetchSolanaTokenDefinition; exports.getRequiredDeviceAuthenticityLayers = getRequiredDeviceAuthenticityLayers; exports.getSlip44FromPath = getSlip44FromPath; exports.isTrezorBleDescriptor = isTrezorBleDescriptor; exports.isTrezorBleServiceUuid = isTrezorBleServiceUuid; exports.isTrezorBleSupportedModel = isTrezorBleSupportedModel; exports.isTrezorSafe7BleDescriptor = isTrezorSafe7BleDescriptor; exports.isTrezorSafe7BleName = isTrezorSafe7BleName; exports.normalizeTrezorBleUuid = normalizeTrezorBleUuid; exports.offSdkEvent = offSdkEvent; exports.onSdkEvent = onSdkEvent; exports.resolveTrezorBleConnectId = resolveTrezorBleConnectId;
|
|
1331
2114
|
//# sourceMappingURL=index.js.map
|