@trezor/connect 9.3.0 → 9.3.1-beta.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +63 -8
  2. package/README.md +1 -1
  3. package/lib/api/checkFirmwareAuthenticity.d.ts +2 -1
  4. package/lib/api/checkFirmwareAuthenticity.js +34 -26
  5. package/lib/api/ethereum/api/ethereumSignTypedData.d.ts +1 -0
  6. package/lib/api/ethereum/ethereumDefinitions.js +1 -0
  7. package/lib/api/firmware/getBinary.d.ts +4 -4
  8. package/lib/api/firmware/getBinary.js +4 -15
  9. package/lib/api/firmware/getBinaryForFirmwareUpgrade.d.ts +11 -0
  10. package/lib/api/firmware/getBinaryForFirmwareUpgrade.js +32 -0
  11. package/lib/api/firmware/index.d.ts +1 -0
  12. package/lib/api/firmware/index.js +3 -1
  13. package/lib/api/firmware/verifyAuthenticityProof.d.ts +1 -1
  14. package/lib/api/firmware/verifyAuthenticityProof.js +37 -2
  15. package/lib/api/firmware/x509certificate.d.ts +20 -6
  16. package/lib/api/firmware/x509certificate.js +82 -13
  17. package/lib/api/getCoinInfo.d.ts +3 -0
  18. package/lib/api/getFeatures.d.ts +1 -0
  19. package/lib/backend/Blockchain.js +10 -1
  20. package/lib/core/AbstractMethod.js +1 -0
  21. package/lib/core/index.d.ts +3 -3
  22. package/lib/core/index.js +23 -6
  23. package/lib/core/onCallFirmwareUpdate.js +25 -14
  24. package/lib/data/DataManager.d.ts +11 -0
  25. package/lib/data/DataManager.js +1 -1
  26. package/lib/data/coinInfo.d.ts +14 -0
  27. package/lib/data/config.d.ts +11 -0
  28. package/lib/data/config.js +17 -1
  29. package/lib/data/connectSettings.js +3 -2
  30. package/lib/data/deviceAuthenticityConfig.d.ts +1 -28
  31. package/lib/data/deviceAuthenticityConfig.js +25 -24
  32. package/lib/data/deviceAuthenticityConfigTypes.d.ts +38 -0
  33. package/lib/data/deviceAuthenticityConfigTypes.js +28 -0
  34. package/lib/data/models.d.ts +10 -0
  35. package/lib/data/models.js +12 -10
  36. package/lib/data/version.d.ts +1 -1
  37. package/lib/data/version.js +1 -1
  38. package/lib/device/Device.d.ts +1 -3
  39. package/lib/device/Device.js +7 -21
  40. package/lib/device/DeviceCommands.js +1 -26
  41. package/lib/events/core.d.ts +2 -2
  42. package/lib/events/transport.d.ts +5 -0
  43. package/lib/index.js +20 -20
  44. package/lib/types/api/authenticateDevice.d.ts +9 -0
  45. package/lib/types/api/authenticateDevice.js +2 -2
  46. package/lib/types/api/checkFirmwareAuthenticity.d.ts +4 -1
  47. package/lib/types/api/init.d.ts +2 -2
  48. package/lib/types/coinInfo.d.ts +7 -0
  49. package/lib/types/firmware.d.ts +2 -2
  50. package/lib/types/settings.d.ts +7 -3
  51. package/lib/utils/assetUtils.js +1 -0
  52. package/package.json +9 -10
  53. package/lib/core/coreManager.d.ts +0 -16
  54. package/lib/core/coreManager.js +0 -55
package/CHANGELOG.md CHANGED
@@ -1,15 +1,70 @@
1
- | Package | Stable | Canary |
2
- | :------------------------------: | :----: | :----: |
3
- | npm @trezor/connect | 9.3.0 | - |
4
- | npm @trezor/connect-web | 9.3.0 | - |
5
- | npm @trezor/connect-webextension | 9.3.0 | - |
1
+ | Package | Stable | Canary |
2
+ | :------------------------------: | :----: | :----------: |
3
+ | npm @trezor/connect | 9.3.0 | 9.3.1-beta.1 |
4
+ | npm @trezor/connect-web | 9.3.0 | 9.3.1-beta.1 |
5
+ | npm @trezor/connect-webextension | 9.3.0 | 9.3.1-beta.1 |
6
6
 
7
- | Deployment | Stable | Canary |
8
- | :----------------: | :----: | :----: |
9
- | connect.trezor.io/ | 9.3.0 | - |
7
+ | Deployment | Stable | Canary |
8
+ | :----------------: | :----: | :----------: |
9
+ | connect.trezor.io/ | 9.3.0 | 9.3.1-beta.1 |
10
10
 
11
11
  Use the persistent link [connect.trezor.io/9](https://connect.trezor.io/9/) to access the latest stable version of Connect Explorer.
12
12
 
13
+ # 9.3.1-beta.1
14
+
15
+ We introduce a new init option `coreMode`, which allows websites to interact either using the existing `iframe` mode or the new `popup` mode. The `popup` mode is allows to use WebUSB even on third-party websites, which is not possible with the `iframe` mode. By default, the `coreMode` is set to `auto`, which means that the library will automatically choose the best mode based on the environment. More information can be found in [init method documentation](https://connect.trezor.io/9.3.1-beta.1/methods/other/init/).
16
+
17
+ Remove support for legacy passphrase, users with Firmware version smaller than 1.0.9 and 2.3.0 will be requested to update in order to use @trezor/connect (7bb57cf)
18
+
19
+ AuthenticateDevice verify CA cert extensions (4ba4445)
20
+
21
+ Add support for T3B1 (f7f1705)
22
+
23
+ - chore(connect): Add Ambire Browser Extension to knownHosts (cbe81ab)
24
+ - chore(connect): remove ethereum-cryptography (18851d1)
25
+ - chore(connect): split public and internal settings type (3aab4ea)
26
+ - chore(connect): remove useCoreInPopup from explorer and tests (fee60c1)
27
+ - chore(connect): add new CA pubkeys and update timestamp (48ec951)
28
+ - chore(connect): refactoring of the CheckFirmwareAuthenticity to support local binary (and wont download it from web, when its available in the suite) (82ab513)
29
+ - docs(connect): describe coreMode (a5238d6)
30
+ - fix(connect): disallow interaction-less fw update when switching fw type (4936939)
31
+ - fix(connect): validate x509 asn1 component (bc13fe2)
32
+ - fix(connect): handle missing language binary (954dbb9)
33
+ - fix(connect): proceed with fw install even when language data fails to download (b40d1b7)
34
+ - test(connect): x509 extensions parser (163c82c)
35
+ - test(connect): update to min version fw 1.0.9 and 2.3.0 (544c311)
36
+
37
+ ## connect-ui
38
+
39
+ - remove bridge references, deeplink to suite desktop (98e98a4)
40
+
41
+ ## connect-plugin-stellar
42
+
43
+ - update stellar sdk (89cf20e)
44
+ - update trends libs (70b9c11)
45
+
46
+ ## connect-web
47
+
48
+ - default coreMode to auto (e45d47e)
49
+ - automatic fallback to core in popup (e4e1fcc)
50
+
51
+ ## connect-webextension
52
+
53
+ - link changelog to the one in connect (a02ec72)
54
+
55
+ ## connect-explorer
56
+
57
+ - applySettings optional values (0bcd83a)
58
+ - hide extra headings from toc in homepage (14f89c4)
59
+ - show success message in settings (0ca7c0c)
60
+ - remove MTT for firmwareUpdate (ebbe96c)
61
+ - bad styled-components prop (e2b7fc7)
62
+
63
+ ## connect-common
64
+
65
+ - add new fw 2.8.0 (314052b)
66
+ - fw version 1.9.0 and 2.3.0 required (ee623e4)
67
+
13
68
  # 9.3.0
14
69
 
15
70
  Improved reliability of popup handshake mechanism.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @trezor/connect
2
2
 
3
- API version 9.3.0
3
+ API version 9.3.1-beta.1
4
4
 
5
5
  [![Build Status](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml/badge.svg)](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml)
6
6
  [![NPM](https://img.shields.io/npm/v/@trezor/connect.svg)](https://www.npmjs.org/package/@trezor/connect)
@@ -1,5 +1,6 @@
1
1
  import { AbstractMethod } from '../core/AbstractMethod';
2
- export default class CheckFirmwareAuthenticity extends AbstractMethod<'checkFirmwareAuthenticity'> {
2
+ import { CheckFirmwareAuthenticityParams } from '../types/api/checkFirmwareAuthenticity';
3
+ export default class CheckFirmwareAuthenticity extends AbstractMethod<'checkFirmwareAuthenticity', CheckFirmwareAuthenticityParams> {
3
4
  init(): void;
4
5
  run(): Promise<{
5
6
  expectedFirmwareHash: string;
@@ -5,43 +5,51 @@ const AbstractMethod_1 = require("../core/AbstractMethod");
5
5
  const firmware_1 = require("./firmware");
6
6
  const firmwareInfo_1 = require("../data/firmwareInfo");
7
7
  const constants_1 = require("../constants");
8
- const assets_1 = require("../utils/assets");
9
8
  const types_1 = require("../types");
9
+ const paramsValidator_1 = require("./common/paramsValidator");
10
10
  class CheckFirmwareAuthenticity extends AbstractMethod_1.AbstractMethod {
11
11
  init() {
12
12
  this.useEmptyPassphrase = true;
13
13
  this.requiredPermissions = ['management'];
14
14
  this.useDeviceState = false;
15
+ const { payload } = this;
16
+ (0, paramsValidator_1.validateParams)(payload, [{ name: 'baseUrl', type: 'string' }]);
17
+ this.params = { baseUrl: payload.baseUrl };
15
18
  }
16
19
  async run() {
17
- var _a;
20
+ var _a, _b;
18
21
  const { device } = this;
19
- const firmwareVersion = `${device.features.major_version}.${device.features.minor_version}.${device.features.patch_version}`;
20
- const releases = (0, firmwareInfo_1.getReleases)((_a = device.features) === null || _a === void 0 ? void 0 : _a.internal_model);
21
- const release = releases.find(release => release.version.join('.') === firmwareVersion);
22
- if (!release) {
23
- throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: No release found for device firmware');
22
+ if (!device.firmwareRelease) {
23
+ throw constants_1.ERRORS.TypedError('Runtime', 'device.firmwareRelease is not set');
24
24
  }
25
- const deviceModelPath = `${device.features.internal_model}`.toLowerCase();
26
- const baseUrl = `https://data.trezor.io/firmware/${deviceModelPath}`;
27
- const fwUrl = `${baseUrl}/trezor-${deviceModelPath}-${firmwareVersion}${device.firmwareType === types_1.FirmwareType.BitcoinOnly ? '-bitcoinonly.bin' : '.bin'}`;
28
- const fw = await (0, assets_1.httpRequest)(fwUrl, 'binary');
29
- if (!fw) {
30
- throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: firmware binary not found');
25
+ const btcOnly = device.firmwareType === types_1.FirmwareType.BitcoinOnly;
26
+ try {
27
+ const fw = await (0, firmware_1.getBinary)({
28
+ releases: (0, firmwareInfo_1.getReleases)((_a = device.features) === null || _a === void 0 ? void 0 : _a.internal_model),
29
+ baseUrl: (_b = this.params.baseUrl) !== null && _b !== void 0 ? _b : 'https://data.trezor.io',
30
+ version: device.getVersion(),
31
+ btcOnly,
32
+ });
33
+ if (!fw) {
34
+ throw constants_1.ERRORS.TypedError('Runtime', 'checkFirmwareAuthenticity: firmware binary not found');
35
+ }
36
+ const { hash: expectedFirmwareHash, challenge } = (0, firmware_1.calculateFirmwareHash)(device.features.major_version, (0, firmware_1.stripFwHeaders)(fw), (0, crypto_1.randomBytes)(32));
37
+ const result = await this.device
38
+ .getCommands()
39
+ .typedCall('GetFirmwareHash', 'FirmwareHash', {
40
+ challenge,
41
+ });
42
+ const { message } = result;
43
+ const { hash: actualFirmwareHash } = message;
44
+ return {
45
+ expectedFirmwareHash,
46
+ actualFirmwareHash,
47
+ valid: actualFirmwareHash === expectedFirmwareHash,
48
+ };
49
+ }
50
+ catch (e) {
51
+ throw constants_1.ERRORS.TypedError('Runtime', `${e}`);
31
52
  }
32
- const { hash: expectedFirmwareHash, challenge } = (0, firmware_1.calculateFirmwareHash)(device.features.major_version, (0, firmware_1.stripFwHeaders)(fw), (0, crypto_1.randomBytes)(32));
33
- const result = await this.device
34
- .getCommands()
35
- .typedCall('GetFirmwareHash', 'FirmwareHash', {
36
- challenge,
37
- });
38
- const { message } = result;
39
- const { hash: actualFirmwareHash } = message;
40
- return {
41
- expectedFirmwareHash,
42
- actualFirmwareHash,
43
- valid: actualFirmwareHash === expectedFirmwareHash,
44
- };
45
53
  }
46
54
  }
47
55
  exports.default = CheckFirmwareAuthenticity;
@@ -60,6 +60,7 @@ declare const Params: import("@sinclair/typebox").TIntersect<[import("@sinclair/
60
60
  T1B1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
61
61
  T2T1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
62
62
  T2B1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
63
+ T3B1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
63
64
  T3T1: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TLiteral<false>]>;
64
65
  connect: import("@sinclair/typebox").TBoolean;
65
66
  }>;
@@ -102,6 +102,7 @@ const ethereumNetworkInfoFromDefinition = (definition) => ({
102
102
  T1B1: '1.6.2',
103
103
  T2T1: '2.0.7',
104
104
  T2B1: '2.6.1',
105
+ T3B1: '2.8.1',
105
106
  T3T1: '2.7.1',
106
107
  },
107
108
  blockchainLink: undefined,
@@ -1,11 +1,11 @@
1
- import { GetInfoProps } from '../../data/firmwareInfo';
2
- import { IntermediaryVersion } from '../../types';
3
- interface GetBinaryProps extends GetInfoProps {
1
+ import { FirmwareRelease, IntermediaryVersion } from '../../types';
2
+ interface GetBinaryProps {
4
3
  baseUrl: string;
5
4
  btcOnly?: boolean;
6
5
  version?: number[];
7
6
  intermediaryVersion?: IntermediaryVersion;
7
+ releases: FirmwareRelease[];
8
8
  }
9
- export declare const getBinary: ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }: GetBinaryProps) => Promise<ArrayBuffer>;
9
+ export declare const getBinary: ({ releases, baseUrl, version, btcOnly, intermediaryVersion, }: GetBinaryProps) => Promise<ArrayBuffer>;
10
10
  export {};
11
11
  //# sourceMappingURL=getBinary.d.ts.map
@@ -3,30 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getBinary = void 0;
4
4
  const utils_1 = require("@trezor/utils");
5
5
  const assets_1 = require("../../utils/assets");
6
- const firmwareUtils_1 = require("../../utils/firmwareUtils");
7
- const firmwareInfo_1 = require("../../data/firmwareInfo");
8
- const getBinary = ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }) => {
9
- if (!(0, firmwareUtils_1.isStrictFeatures)(features)) {
10
- throw new Error('Features of unexpected shape provided');
11
- }
6
+ const getBinary = ({ releases, baseUrl, version, btcOnly, intermediaryVersion, }) => {
12
7
  if (intermediaryVersion) {
13
8
  return (0, assets_1.httpRequest)(`${baseUrl}/firmware/t1b1/trezor-t1b1-inter-v${intermediaryVersion}.bin`, 'binary');
14
9
  }
15
- const infoByBootloader = (0, firmwareInfo_1.getInfo)({ features, releases });
16
10
  const releaseByFirmware = releases.find(r => version &&
17
11
  utils_1.versionUtils.isVersionArray(version) &&
18
12
  utils_1.versionUtils.isEqual(r.version, version));
19
- if (!infoByBootloader || !releaseByFirmware) {
13
+ if (releaseByFirmware === undefined) {
20
14
  throw new Error('no firmware found for this device');
21
15
  }
22
- if (btcOnly && !releaseByFirmware.url_bitcoinonly) {
23
- throw new Error(`firmware version ${version} does not exist in btc only variant`);
24
- }
25
- if (!utils_1.versionUtils.isEqual(releaseByFirmware.version, infoByBootloader.release.version)) {
26
- throw new Error('version provided as param does not match firmware version found by features in bootloader');
27
- }
28
16
  const fwUrl = releaseByFirmware[btcOnly ? 'url_bitcoinonly' : 'url'];
29
- return (0, assets_1.httpRequest)(`${baseUrl}/${fwUrl}`, 'binary');
17
+ const url = `${baseUrl}/${fwUrl}`;
18
+ return (0, assets_1.httpRequest)(url, 'binary');
30
19
  };
31
20
  exports.getBinary = getBinary;
32
21
  //# sourceMappingURL=getBinary.js.map
@@ -0,0 +1,11 @@
1
+ import { GetInfoProps } from '../../data/firmwareInfo';
2
+ import { IntermediaryVersion } from '../../types';
3
+ interface GetBinaryForFirmwareUpgradeProps extends GetInfoProps {
4
+ baseUrl: string;
5
+ btcOnly?: boolean;
6
+ version?: number[];
7
+ intermediaryVersion?: IntermediaryVersion;
8
+ }
9
+ export declare const getBinaryForFirmwareUpgrade: ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }: GetBinaryForFirmwareUpgradeProps) => Promise<ArrayBuffer>;
10
+ export {};
11
+ //# sourceMappingURL=getBinaryForFirmwareUpgrade.d.ts.map
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBinaryForFirmwareUpgrade = void 0;
4
+ const utils_1 = require("@trezor/utils");
5
+ const assets_1 = require("../../utils/assets");
6
+ const firmwareUtils_1 = require("../../utils/firmwareUtils");
7
+ const firmwareInfo_1 = require("../../data/firmwareInfo");
8
+ const getBinary_1 = require("./getBinary");
9
+ const getBinaryForFirmwareUpgrade = ({ features, releases, baseUrl, version, btcOnly, intermediaryVersion, }) => {
10
+ if (!(0, firmwareUtils_1.isStrictFeatures)(features)) {
11
+ throw new Error('Features of unexpected shape provided');
12
+ }
13
+ if (intermediaryVersion) {
14
+ return (0, assets_1.httpRequest)(`${baseUrl}/firmware/t1b1/trezor-t1b1-inter-v${intermediaryVersion}.bin`, 'binary');
15
+ }
16
+ const infoByBootloader = (0, firmwareInfo_1.getInfo)({ features, releases });
17
+ const releaseByFirmware = releases.find(r => version &&
18
+ utils_1.versionUtils.isVersionArray(version) &&
19
+ utils_1.versionUtils.isEqual(r.version, version));
20
+ if (!infoByBootloader || !releaseByFirmware) {
21
+ throw new Error('no firmware found for this device');
22
+ }
23
+ if (btcOnly && !releaseByFirmware.url_bitcoinonly) {
24
+ throw new Error(`firmware version ${version} does not exist in btc only variant`);
25
+ }
26
+ if (!utils_1.versionUtils.isEqual(releaseByFirmware.version, infoByBootloader.release.version)) {
27
+ throw new Error(`version provided as param (${releaseByFirmware.version}) does not match firmware version found by features in bootloader (${infoByBootloader.release.version})`);
28
+ }
29
+ return (0, getBinary_1.getBinary)({ releases, baseUrl, version, btcOnly, intermediaryVersion });
30
+ };
31
+ exports.getBinaryForFirmwareUpgrade = getBinaryForFirmwareUpgrade;
32
+ //# sourceMappingURL=getBinaryForFirmwareUpgrade.js.map
@@ -1,3 +1,4 @@
1
+ export { getBinaryForFirmwareUpgrade } from './getBinaryForFirmwareUpgrade';
1
2
  export { getBinary } from './getBinary';
2
3
  export { getLanguage } from '../../data/getLanguage';
3
4
  export { shouldStripFwHeaders, stripFwHeaders } from './modifyFirmware';
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseFirmwareHeaders = exports.calculateFirmwareHash = exports.uploadFirmware = exports.stripFwHeaders = exports.shouldStripFwHeaders = exports.getLanguage = exports.getBinary = void 0;
3
+ exports.parseFirmwareHeaders = exports.calculateFirmwareHash = exports.uploadFirmware = exports.stripFwHeaders = exports.shouldStripFwHeaders = exports.getLanguage = exports.getBinary = exports.getBinaryForFirmwareUpgrade = void 0;
4
+ var getBinaryForFirmwareUpgrade_1 = require("./getBinaryForFirmwareUpgrade");
5
+ Object.defineProperty(exports, "getBinaryForFirmwareUpgrade", { enumerable: true, get: function () { return getBinaryForFirmwareUpgrade_1.getBinaryForFirmwareUpgrade; } });
4
6
  var getBinary_1 = require("./getBinary");
5
7
  Object.defineProperty(exports, "getBinary", { enumerable: true, get: function () { return getBinary_1.getBinary; } });
6
8
  var getLanguage_1 = require("../../data/getLanguage");
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { PROTO } from '../../constants';
3
- import { DeviceAuthenticityConfig } from '../../data/deviceAuthenticityConfig';
4
3
  import { AuthenticateDeviceResult } from '../../types/api/authenticateDevice';
4
+ import { DeviceAuthenticityConfig } from '../../data/deviceAuthenticityConfigTypes';
5
5
  interface AuthenticityProofData extends PROTO.AuthenticityProof {
6
6
  challenge: Buffer;
7
7
  config: DeviceAuthenticityConfig;
@@ -19,15 +19,50 @@ const verifySignature = async (rawKey, data, signature) => {
19
19
  };
20
20
  const getRandomChallenge = () => crypto.randomBytes(32);
21
21
  exports.getRandomChallenge = getRandomChallenge;
22
+ const validateCaCertExtensions = (cert, pathLen) => {
23
+ let hasKeyUsage, hasBasicConstraints = false;
24
+ cert.tbsCertificate.extensions.forEach(ext => {
25
+ if (ext.key === 'keyUsage') {
26
+ if (ext.keyCertSign !== '1') {
27
+ throw new Error(`CA keyCertSign not set`);
28
+ }
29
+ hasKeyUsage = true;
30
+ }
31
+ else if (ext.key === 'basicConstraints') {
32
+ if (!ext.cA) {
33
+ throw new Error(`CA basicConstraints.cA not set`);
34
+ }
35
+ if (typeof ext.pathLenConstraint != 'number') {
36
+ throw new Error('CA basicConstraints.pathLenConstraint not set');
37
+ }
38
+ if (ext.pathLenConstraint < pathLen) {
39
+ throw new Error('Issuer was not permitted to issue certificate');
40
+ }
41
+ hasBasicConstraints = true;
42
+ }
43
+ else if (ext.critical) {
44
+ throw new Error(`Unknown critical extension ${ext.key} in CA certificate`);
45
+ }
46
+ });
47
+ if (!hasKeyUsage || !hasBasicConstraints) {
48
+ throw new Error(`CA missing extensions keyUsage: ${hasKeyUsage}, basicConstraints: ${hasBasicConstraints}`);
49
+ }
50
+ };
22
51
  const verifyAuthenticityProof = async ({ certificates, signature, challenge, config, allowDebugKeys, deviceModel, }) => {
23
52
  const modelConfig = config[deviceModel];
24
53
  if (!modelConfig) {
25
54
  throw new Error(`Pubkeys for ${deviceModel} not found in config`);
26
55
  }
27
56
  const { caPubKeys, debug } = modelConfig;
28
- const caCert = (0, x509certificate_1.parseCertificate)(new Uint8Array(Buffer.from(certificates[1], 'hex')));
57
+ const [deviceCert, caCert] = certificates.map((c, i) => {
58
+ const cert = (0, x509certificate_1.parseCertificate)(new Uint8Array(Buffer.from(c, 'hex')));
59
+ if (i === 0) {
60
+ return cert;
61
+ }
62
+ validateCaCertExtensions(cert, i - 1);
63
+ return cert;
64
+ });
29
65
  const caPubKey = Buffer.from(caCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes).toString('hex');
30
- const deviceCert = (0, x509certificate_1.parseCertificate)(new Uint8Array(Buffer.from(certificates[0], 'hex')));
31
66
  const rootPubKeys = allowDebugKeys
32
67
  ? modelConfig.rootPubKeys.concat((debug === null || debug === void 0 ? void 0 : debug.rootPubKeys) || [])
33
68
  : modelConfig.rootPubKeys;
@@ -6,10 +6,24 @@ interface Asn1 {
6
6
  contents: Uint8Array;
7
7
  raw: Uint8Array;
8
8
  }
9
+ type Oid = `${number}.${number}.${number}.${number}`;
10
+ type Extension = {
11
+ key: 'keyUsage';
12
+ critical?: boolean;
13
+ keyCertSign: '0' | '1';
14
+ } | {
15
+ key: 'basicConstraints';
16
+ critical?: boolean;
17
+ cA: boolean;
18
+ pathLenConstraint?: number;
19
+ } | (Asn1 & {
20
+ key: Oid;
21
+ critical?: boolean;
22
+ });
9
23
  export declare const fixSignature: (byteArray: Uint8Array) => Uint8Array;
10
24
  export declare const parseName: (asn1: Asn1) => {
11
25
  asn1: Asn1;
12
- algorithm: string;
26
+ algorithm: `${number}.${number}.${number}.${number}`;
13
27
  parameters: {
14
28
  asn1: Asn1;
15
29
  } | null;
@@ -22,7 +36,7 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
22
36
  serialNumber: Asn1;
23
37
  signature: {
24
38
  asn1: Asn1;
25
- algorithm: string;
39
+ algorithm: `${number}.${number}.${number}.${number}`;
26
40
  parameters: {
27
41
  asn1: Asn1;
28
42
  } | null;
@@ -34,7 +48,7 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
34
48
  };
35
49
  subject: {
36
50
  asn1: Asn1;
37
- algorithm: string;
51
+ algorithm: `${number}.${number}.${number}.${number}`;
38
52
  parameters: {
39
53
  asn1: Asn1;
40
54
  } | null;
@@ -43,7 +57,7 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
43
57
  asn1: Asn1;
44
58
  algorithm: {
45
59
  asn1: Asn1;
46
- algorithm: string;
60
+ algorithm: `${number}.${number}.${number}.${number}`;
47
61
  parameters: {
48
62
  asn1: Asn1;
49
63
  } | null;
@@ -53,11 +67,11 @@ export declare const parseCertificate: (byteArray: Uint8Array) => {
53
67
  bytes: Uint8Array;
54
68
  };
55
69
  };
56
- extensions: Asn1;
70
+ extensions: Extension[];
57
71
  };
58
72
  signatureAlgorithm: {
59
73
  asn1: Asn1;
60
- algorithm: string;
74
+ algorithm: `${number}.${number}.${number}.${number}`;
61
75
  parameters: {
62
76
  asn1: Asn1;
63
77
  } | null;
@@ -37,21 +37,14 @@ const derToAsn1 = (byteArray) => {
37
37
  const cls = (byteArray[0] & 0xc0) / 64;
38
38
  const structured = (byteArray[0] & 0x20) === 0x20;
39
39
  const tag = getTag();
40
+ if (byteArray[position] === 0x80) {
41
+ throw new Error('Unsupported length encoding');
42
+ }
40
43
  let length = getLength();
41
44
  let byteLength;
42
45
  let contents;
43
- if (length === 0x80) {
44
- length = 0;
45
- while (byteArray[position + length] !== 0 || byteArray[position + length + 1] !== 0) {
46
- length += 1;
47
- }
48
- byteLength = position + length + 2;
49
- contents = byteArray.subarray(position, position + length);
50
- }
51
- else {
52
- byteLength = position + length;
53
- contents = byteArray.subarray(position, byteLength);
54
- }
46
+ byteLength = position + length;
47
+ contents = byteArray.subarray(position, byteLength);
55
48
  const raw = byteArray.subarray(0, byteLength);
56
49
  return {
57
50
  cls,
@@ -195,6 +188,82 @@ const parseValidity = (asn1) => {
195
188
  to: parseUtcTime(to),
196
189
  };
197
190
  };
191
+ const parseExtensions = (data) => {
192
+ const asn1 = derToAsn1(data.contents);
193
+ if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
194
+ throw new Error("This can't be a Extension. Wrong data type.");
195
+ }
196
+ const readBoolean = (value) => {
197
+ if (!value)
198
+ return false;
199
+ if (value.cls !== 0 || value.tag !== 1 || value.contents.length !== 1 || value.structured) {
200
+ throw new Error("This can't be a boolean. Wrong data type.");
201
+ }
202
+ if (![0x00, 0xff].includes(value.contents[0])) {
203
+ throw new Error('Invalid boolean value.');
204
+ }
205
+ return value.contents[0] === 0xff;
206
+ };
207
+ const readBitString = (uint8Array) => {
208
+ const buffer = Buffer.from(uint8Array);
209
+ const tag = buffer.readUInt8(0);
210
+ if (tag !== 3) {
211
+ throw new Error("This can't be a bit string. Wrong data type.");
212
+ }
213
+ const length = buffer.readUInt8(1);
214
+ const unusedBits = buffer.readUInt8(2);
215
+ const bitStringBytes = buffer.subarray(3, 3 + length - 1);
216
+ const bitString = bitStringBytes.reduce((str, byte) => str + byte.toString(2).padStart(8, '0'), '');
217
+ return bitString.slice(0, bitString.length - unusedBits);
218
+ };
219
+ const readInteger = (value) => {
220
+ if (!value)
221
+ return undefined;
222
+ if (value.cls !== 0 || value.tag !== 2 || value.contents.length !== 1 || value.structured) {
223
+ throw new Error("This can't be a integer. Wrong data type.");
224
+ }
225
+ return Buffer.from(value.contents).readInt8();
226
+ };
227
+ const extensions = [];
228
+ derToAsn1List(asn1.contents).forEach(item => {
229
+ const [id, ...pieces] = derToAsn1List(item.contents);
230
+ if (id.cls !== 0 || id.tag !== 6 || id.structured) {
231
+ throw new Error('Bad extension. Does not begin with an OBJECT IDENTIFIER.');
232
+ }
233
+ const algorithm = derObjectIdentifierValue(id.contents);
234
+ const critical = pieces.length > 1 ? readBoolean(pieces[0]) : false;
235
+ const extnValue = pieces.length > 1 ? pieces[1] : pieces[0];
236
+ if (extnValue.cls !== 0 || extnValue.tag !== 4 || extnValue.structured) {
237
+ throw new Error("This can't be a octet string. Wrong data type.");
238
+ }
239
+ if (algorithm === '2.5.29.15') {
240
+ extensions.push({
241
+ key: 'keyUsage',
242
+ critical,
243
+ keyCertSign: readBitString(extnValue.contents)[5],
244
+ });
245
+ }
246
+ else if (algorithm === '2.5.29.19') {
247
+ const fields = derToAsn1List(derToAsn1(extnValue.contents).contents);
248
+ const ca = fields.length > 0 && fields[0].tag === 1 ? fields[0] : undefined;
249
+ const len = fields.length > 0 && fields[0].tag === 2 ? fields[0] : fields[1];
250
+ extensions.push({
251
+ key: 'basicConstraints',
252
+ critical,
253
+ cA: readBoolean(ca),
254
+ pathLenConstraint: readInteger(len),
255
+ });
256
+ }
257
+ else {
258
+ extensions.push({
259
+ key: algorithm,
260
+ critical,
261
+ ...item,
262
+ });
263
+ }
264
+ });
265
+ return extensions;
266
+ };
198
267
  const parseTBSCertificate = (asn1) => {
199
268
  if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {
200
269
  throw new Error("This can't be a TBSCertificate. Wrong data type.");
@@ -212,7 +281,7 @@ const parseTBSCertificate = (asn1) => {
212
281
  validity: parseValidity(pieces[4]),
213
282
  subject: (0, exports.parseName)(pieces[5]),
214
283
  subjectPublicKeyInfo: parseSubjectPublicKeyInfo(pieces[6]),
215
- extensions: pieces[7],
284
+ extensions: parseExtensions(pieces[7]),
216
285
  };
217
286
  };
218
287
  const parseCertificate = (byteArray) => {
@@ -21,6 +21,7 @@ export default class GetCoinInfo extends AbstractMethod<'getCoinInfo', Params> {
21
21
  T1B1: string | false;
22
22
  T2T1: string | false;
23
23
  T2B1: string | false;
24
+ T3B1: string | false;
24
25
  T3T1: string | false;
25
26
  connect: boolean;
26
27
  };
@@ -77,6 +78,7 @@ export default class GetCoinInfo extends AbstractMethod<'getCoinInfo', Params> {
77
78
  T1B1: string | false;
78
79
  T2T1: string | false;
79
80
  T2B1: string | false;
81
+ T3B1: string | false;
80
82
  T3T1: string | false;
81
83
  connect: boolean;
82
84
  };
@@ -108,6 +110,7 @@ export default class GetCoinInfo extends AbstractMethod<'getCoinInfo', Params> {
108
110
  T1B1: string | false;
109
111
  T2T1: string | false;
110
112
  T2B1: string | false;
113
+ T3B1: string | false;
111
114
  T3T1: string | false;
112
115
  connect: boolean;
113
116
  };
@@ -15,6 +15,7 @@ export default class GetFeatures extends AbstractMethod<'getFeatures'> {
15
15
  language_version_matches?: boolean | undefined;
16
16
  unit_packaging?: number | undefined;
17
17
  recovery_type?: "NormalRecovery" | "DryRun" | "UnlockRepeatedBackup" | undefined;
18
+ optiga_sec?: number | undefined;
18
19
  flags: number | null;
19
20
  language: string | null;
20
21
  label: string | null;
@@ -22,6 +22,15 @@ const getWorker = (type) => {
22
22
  return null;
23
23
  }
24
24
  };
25
+ const getNormalizedShortcut = (shortcut) => {
26
+ if (shortcut === 'tXRP') {
27
+ return 'XRP';
28
+ }
29
+ if (shortcut.toLowerCase() === 'bsc') {
30
+ return 'bnb';
31
+ }
32
+ return shortcut;
33
+ };
25
34
  class Blockchain {
26
35
  constructor(options) {
27
36
  this.feeForBlock = [];
@@ -72,7 +81,7 @@ class Blockchain {
72
81
  throw constants_1.ERRORS.TypedError('Backend_Error', error.message);
73
82
  }
74
83
  this.serverInfo = info;
75
- const shortcut = this.coinInfo.shortcut === 'tXRP' ? 'XRP' : this.coinInfo.shortcut;
84
+ const shortcut = getNormalizedShortcut(this.coinInfo.shortcut);
76
85
  if (info.shortcut.toLowerCase() !== shortcut.toLowerCase()) {
77
86
  throw constants_1.ERRORS.TypedError('Backend_Invalid');
78
87
  }
@@ -11,6 +11,7 @@ exports.DEFAULT_FIRMWARE_RANGE = {
11
11
  T1B1: { min: '1.0.0', max: '0' },
12
12
  T2T1: { min: '2.0.0', max: '0' },
13
13
  T2B1: { min: '2.6.1', max: '0' },
14
+ T3B1: { min: '2.8.1', max: '0' },
14
15
  T3T1: { min: '2.7.1', max: '0' },
15
16
  };
16
17
  class AbstractMethod {
@@ -14,9 +14,9 @@ export declare class Core extends EventEmitter {
14
14
  init(settings: ConnectSettings, onCoreEvent: (message: CoreEventMessage) => void, logWriterFactory?: () => LogWriter | undefined): Promise<void>;
15
15
  }
16
16
  export declare const initCoreState: () => {
17
- getOrInitCore: (settings: ConnectSettings, onCoreEvent: (message: CoreEventMessage) => void, logWriterFactory?: (() => LogWriter | undefined) | undefined) => Promise<Core>;
18
- getCore: () => Core | undefined;
19
- getInitPromise: () => Promise<Core> | undefined;
17
+ get: () => Core | undefined;
18
+ getPending: () => Promise<Core> | undefined;
19
+ getOrInit: (settings: ConnectSettings, onCoreEvent: (message: CoreEventMessage) => void, logWriterFactory?: (() => LogWriter) | undefined) => Promise<Core>;
20
20
  dispose: () => void;
21
21
  };
22
22
  //# sourceMappingURL=index.d.ts.map