@ledgerhq/hw-bolos 6.31.4
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/.turbo/turbo-build.log +4 -0
- package/LICENSE.txt +21 -0
- package/README.md +25 -0
- package/jest.config.ts +7 -0
- package/jest.integ.config.ts +8 -0
- package/lib/PKIError.d.ts +54 -0
- package/lib/PKIError.d.ts.map +1 -0
- package/lib/PKIError.js +164 -0
- package/lib/PKIError.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/lib/loadPKI.d.ts +19 -0
- package/lib/loadPKI.d.ts.map +1 -0
- package/lib/loadPKI.integ.test.d.ts +2 -0
- package/lib/loadPKI.integ.test.d.ts.map +1 -0
- package/lib/loadPKI.integ.test.js +42 -0
- package/lib/loadPKI.integ.test.js.map +1 -0
- package/lib/loadPKI.js +48 -0
- package/lib/loadPKI.js.map +1 -0
- package/lib/loadPKI.test.d.ts +2 -0
- package/lib/loadPKI.test.d.ts.map +1 -0
- package/lib/loadPKI.test.js +37 -0
- package/lib/loadPKI.test.js.map +1 -0
- package/lib-es/PKIError.d.ts +54 -0
- package/lib-es/PKIError.d.ts.map +1 -0
- package/lib-es/PKIError.js +143 -0
- package/lib-es/PKIError.js.map +1 -0
- package/lib-es/index.d.ts +2 -0
- package/lib-es/index.d.ts.map +1 -0
- package/lib-es/index.js +2 -0
- package/lib-es/index.js.map +1 -0
- package/lib-es/loadPKI.d.ts +19 -0
- package/lib-es/loadPKI.d.ts.map +1 -0
- package/lib-es/loadPKI.integ.test.d.ts +2 -0
- package/lib-es/loadPKI.integ.test.d.ts.map +1 -0
- package/lib-es/loadPKI.integ.test.js +37 -0
- package/lib-es/loadPKI.integ.test.js.map +1 -0
- package/lib-es/loadPKI.js +46 -0
- package/lib-es/loadPKI.js.map +1 -0
- package/lib-es/loadPKI.test.d.ts +2 -0
- package/lib-es/loadPKI.test.d.ts.map +1 -0
- package/lib-es/loadPKI.test.js +32 -0
- package/lib-es/loadPKI.test.js.map +1 -0
- package/package.json +53 -0
- package/src/PKIError.ts +144 -0
- package/src/index.ts +1 -0
- package/src/loadPKI.integ.test.ts +40 -0
- package/src/loadPKI.test.ts +26 -0
- package/src/loadPKI.ts +54 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const ErrorCode = {
|
|
2
|
+
0x422f: "Incorrect structure type",
|
|
3
|
+
0x4230: "Incorrect certificate version",
|
|
4
|
+
0x4231: "Incorrect certificate validity",
|
|
5
|
+
0x4232: "Incorrect certificate validity index",
|
|
6
|
+
0x4233: "Unknown signer key ID",
|
|
7
|
+
0x4234: "Unknown signature algorithm",
|
|
8
|
+
0x4235: "Unknown public key ID",
|
|
9
|
+
0x4236: "Unknown public key usage",
|
|
10
|
+
0x4237: "Incorrect elliptic curve ID",
|
|
11
|
+
0x4238: "Incorrect signature algorithm associated to the public key",
|
|
12
|
+
0x4239: "Unknown target device",
|
|
13
|
+
0x422d: "Unknown certificate tag",
|
|
14
|
+
0x3301: "Failed to hash data",
|
|
15
|
+
0x422e: "expected_key_usage doesn't match certificate key usage",
|
|
16
|
+
0x5720: "Failed to verify signature",
|
|
17
|
+
0x4118: "trusted_name buffer is too small to contain the trusted name",
|
|
18
|
+
};
|
|
19
|
+
export const errorCodeValue = Object.keys(ErrorCode).map(v => parseInt(v));
|
|
20
|
+
export function throwError(code) {
|
|
21
|
+
switch (code) {
|
|
22
|
+
case 0x422f:
|
|
23
|
+
throw new PKIStructError();
|
|
24
|
+
case 0x4230:
|
|
25
|
+
throw new PKICertificateVersionError();
|
|
26
|
+
case 0x4231:
|
|
27
|
+
throw new PKICertificateValidityError();
|
|
28
|
+
case 0x4232:
|
|
29
|
+
throw new PKICertificateIndexError();
|
|
30
|
+
case 0x4233:
|
|
31
|
+
throw new PKIUnknownSignerIdError();
|
|
32
|
+
case 0x4234:
|
|
33
|
+
throw new PKIUnknownSignerAlgorithmError();
|
|
34
|
+
case 0x4235:
|
|
35
|
+
throw new PKIUnknownPublicIdError();
|
|
36
|
+
case 0x4236:
|
|
37
|
+
throw new PKIUnknownPublicUsageError();
|
|
38
|
+
case 0x4237:
|
|
39
|
+
throw new PKIIncorrectCurveError();
|
|
40
|
+
case 0x4238:
|
|
41
|
+
throw new PKIIncorrectSignatureError();
|
|
42
|
+
case 0x4239:
|
|
43
|
+
throw new PKIUnknownDeviceError();
|
|
44
|
+
case 0x422d:
|
|
45
|
+
throw new PKIUnknownCertificateTagError();
|
|
46
|
+
case 0x3301:
|
|
47
|
+
throw new PKIFailedHashError();
|
|
48
|
+
case 0x422e:
|
|
49
|
+
throw new PKIMismatchKeyError();
|
|
50
|
+
case 0x5720:
|
|
51
|
+
throw new PKIFailedVerificationError();
|
|
52
|
+
case 0x4118:
|
|
53
|
+
throw new PKITrustedNameTooSmallError();
|
|
54
|
+
default:
|
|
55
|
+
throw new PKIError("Unknown");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export class PKIError extends Error {
|
|
59
|
+
constructor(cause) {
|
|
60
|
+
super("PKIError due to " + cause);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export class PKIStructError extends PKIError {
|
|
64
|
+
constructor() {
|
|
65
|
+
super(ErrorCode[0x422f]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export class PKICertificateVersionError extends PKIError {
|
|
69
|
+
constructor() {
|
|
70
|
+
super(ErrorCode[0x4230]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export class PKICertificateValidityError extends PKIError {
|
|
74
|
+
constructor() {
|
|
75
|
+
super(ErrorCode[0x4231]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export class PKICertificateIndexError extends PKIError {
|
|
79
|
+
constructor() {
|
|
80
|
+
super(ErrorCode[0x4232]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export class PKIUnknownSignerIdError extends PKIError {
|
|
84
|
+
constructor() {
|
|
85
|
+
super(ErrorCode[0x4233]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export class PKIUnknownSignerAlgorithmError extends PKIError {
|
|
89
|
+
constructor() {
|
|
90
|
+
super(ErrorCode[0x4234]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class PKIUnknownPublicIdError extends PKIError {
|
|
94
|
+
constructor() {
|
|
95
|
+
super(ErrorCode[0x4235]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export class PKIUnknownPublicUsageError extends PKIError {
|
|
99
|
+
constructor() {
|
|
100
|
+
super(ErrorCode[0x4236]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export class PKIIncorrectCurveError extends PKIError {
|
|
104
|
+
constructor() {
|
|
105
|
+
super(ErrorCode[0x4237]);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export class PKIIncorrectSignatureError extends PKIError {
|
|
109
|
+
constructor() {
|
|
110
|
+
super(ErrorCode[0x4238]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export class PKIUnknownDeviceError extends PKIError {
|
|
114
|
+
constructor() {
|
|
115
|
+
super(ErrorCode[0x4239]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export class PKIUnknownCertificateTagError extends PKIError {
|
|
119
|
+
constructor() {
|
|
120
|
+
super(ErrorCode[0x422d]);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export class PKIFailedHashError extends PKIError {
|
|
124
|
+
constructor() {
|
|
125
|
+
super(ErrorCode[0x3301]);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export class PKIMismatchKeyError extends PKIError {
|
|
129
|
+
constructor() {
|
|
130
|
+
super(ErrorCode[0x422e]);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export class PKIFailedVerificationError extends PKIError {
|
|
134
|
+
constructor() {
|
|
135
|
+
super(ErrorCode[0x5720]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export class PKITrustedNameTooSmallError extends PKIError {
|
|
139
|
+
constructor() {
|
|
140
|
+
super(ErrorCode[0x4118]);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=PKIError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PKIError.js","sourceRoot":"","sources":["../src/PKIError.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC"}
|
package/lib-es/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
2
|
+
declare const keyUsage: {
|
|
3
|
+
GENUINE_CHECK: number;
|
|
4
|
+
EXCHANGE_PAYLOAD: number;
|
|
5
|
+
NFT_METADATA: number;
|
|
6
|
+
TRUSTED_NAME: number;
|
|
7
|
+
BACKUP_PROVIDER: number;
|
|
8
|
+
RECOVER_ORCHESTRATOR: number;
|
|
9
|
+
PLUGIN_METADATA: number;
|
|
10
|
+
COIN_META: number;
|
|
11
|
+
SEED_ID_AUTH: number;
|
|
12
|
+
UNKNOWN: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Load certificate
|
|
16
|
+
*/
|
|
17
|
+
declare const _default: (transport: Transport, key: keyof typeof keyUsage, descriptor: string, signature: string) => Promise<void>;
|
|
18
|
+
export default _default;
|
|
19
|
+
//# sourceMappingURL=loadPKI.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadPKI.d.ts","sourceRoot":"","sources":["../src/loadPKI.ts"],"names":[],"mappings":"AAAA,OAAO,SAA0B,MAAM,wBAAwB,CAAC;AAUhE,QAAA,MAAM,QAAQ;;;;;;;;;;;CAWb,CAAC;AAEF;;GAEG;oCAEU,SAAS,OACf,MAAM,eAAe,cACd,MAAM,aACP,MAAM,KAChB,QAAQ,IAAI,CAAC;AALhB,wBA2BE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadPKI.integ.test.d.ts","sourceRoot":"","sources":["../src/loadPKI.integ.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import TransportNodeHidSingleton from "@ledgerhq/hw-transport-node-hid-singleton";
|
|
11
|
+
import loadPKI from "./loadPKI";
|
|
12
|
+
import { PKIFailedVerificationError } from "./PKIError";
|
|
13
|
+
describe("loadPKI with real connected device", () => {
|
|
14
|
+
let transport;
|
|
15
|
+
beforeAll(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
transport = yield TransportNodeHidSingleton.open("");
|
|
17
|
+
}));
|
|
18
|
+
afterAll(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
+
yield transport.close();
|
|
20
|
+
}));
|
|
21
|
+
it.skip("returns an Ok", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
// Given
|
|
23
|
+
const descriptor = "0101010201023501043601021004010500001302000314010120086e66745f6d657461300200053101043201213401013321035e6c1020c14dc46442fe89f97c0b68cdb15976dc24f24c316e7b30fe4e8cc76b";
|
|
24
|
+
const signature = "30440220774aa1a064c9bd5ff2c820156b4af106d464d8ca0eb2de5f2956c8b52356496202205ef40dd54beb3c1534d011af9f581f426141d39338b3da6abf4023254cbef72c";
|
|
25
|
+
// When & Then
|
|
26
|
+
yield expect(loadPKI(transport, "TRUSTED_NAME", descriptor, signature)).rejects.not.toThrow();
|
|
27
|
+
yield (() => new Promise(f => setTimeout(f, 1000)))();
|
|
28
|
+
}));
|
|
29
|
+
it("returns an Verification Failed error", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
// Given
|
|
31
|
+
const descriptor = "0101010201023501043601021004010500001302000314010120086e66745f6d657461300200053101043201213401013321035e6c1020c14dc46442fe89f97c0b68cdb15976dc24f24c316e7b30fe4e8cc76b";
|
|
32
|
+
const signature = "30440220774aa1a064c9bd5ff2c820156b4af106d464d8ca0eb2de5f2956c8b52356496202205ef40dd54beb3c1534d011af9f581f426141d39338b3da6abf4023254cbef72c";
|
|
33
|
+
// When & Then
|
|
34
|
+
yield expect(loadPKI(transport, "TRUSTED_NAME", descriptor, signature)).rejects.toThrow(PKIFailedVerificationError);
|
|
35
|
+
}));
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=loadPKI.integ.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadPKI.integ.test.js","sourceRoot":"","sources":["../src/loadPKI.integ.test.ts"],"names":[],"mappings":";;;;;;;;;AACA,OAAO,yBAAyB,MAAM,2CAA2C,CAAC;AAClF,OAAO,OAAO,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAExD,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,IAAI,SAAoB,CAAC;IAEzB,SAAS,CAAC,GAAS,EAAE;QACnB,SAAS,GAAG,MAAM,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,CAAA,CAAC,CAAC;IACH,QAAQ,CAAC,GAAS,EAAE;QAClB,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC,CAAA,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,GAAS,EAAE;QAClC,QAAQ;QACR,MAAM,UAAU,GACd,wKAAwK,CAAC;QAC3K,MAAM,SAAS,GACb,8IAA8I,CAAC;QAEjJ,cAAc;QACd,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC9F,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,CAAC,CAAA,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAS,EAAE;QACpD,QAAQ;QACR,MAAM,UAAU,GACd,wKAAwK,CAAC;QAC3K,MAAM,SAAS,GACb,8IAA8I,CAAC;QAEjJ,cAAc;QACd,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACrF,0BAA0B,CAC3B,CAAC;IACJ,CAAC,CAAA,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { StatusCodes } from "@ledgerhq/hw-transport";
|
|
11
|
+
import { errorCodeValue, throwError } from "./PKIError";
|
|
12
|
+
const handledErrorCode = errorCodeValue.concat(StatusCodes.OK);
|
|
13
|
+
const CLA = 0xb0;
|
|
14
|
+
const INS = 0x06;
|
|
15
|
+
const P2 = 0x00;
|
|
16
|
+
// Extract from https://github.com/LedgerHQ/ledger-secure-sdk/blob/d59b21f8a1f2e78ad50b5a8a21d0daac68826643/include/os_pki.h#L74
|
|
17
|
+
const keyUsage = {
|
|
18
|
+
GENUINE_CHECK: 0x01,
|
|
19
|
+
EXCHANGE_PAYLOAD: 0x02,
|
|
20
|
+
NFT_METADATA: 0x03,
|
|
21
|
+
TRUSTED_NAME: 0x04,
|
|
22
|
+
BACKUP_PROVIDER: 0x05,
|
|
23
|
+
RECOVER_ORCHESTRATOR: 0x06,
|
|
24
|
+
PLUGIN_METADATA: 0x07,
|
|
25
|
+
COIN_META: 0x08,
|
|
26
|
+
SEED_ID_AUTH: 0x09,
|
|
27
|
+
UNKNOWN: 0x0a,
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Load certificate
|
|
31
|
+
*/
|
|
32
|
+
export default (transport, key, descriptor, signature) => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
|
+
const descriptorBuffer = Buffer.from(descriptor, "hex");
|
|
34
|
+
const signatureBuffer = Buffer.from(signature, "hex");
|
|
35
|
+
const result = yield transport.send(CLA, INS, keyUsage[key], P2, Buffer.concat([
|
|
36
|
+
new Uint8Array(descriptorBuffer),
|
|
37
|
+
new Uint8Array(Buffer.from("15", "hex")),
|
|
38
|
+
new Uint8Array(Buffer.from([signatureBuffer.length])),
|
|
39
|
+
new Uint8Array(signatureBuffer),
|
|
40
|
+
]), handledErrorCode);
|
|
41
|
+
const resultCode = result.readUInt16BE(result.length - 2);
|
|
42
|
+
if (resultCode !== StatusCodes.OK) {
|
|
43
|
+
throwError(resultCode);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=loadPKI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadPKI.js","sourceRoot":"","sources":["../src/loadPKI.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAkB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,gBAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;AAE/D,MAAM,GAAG,GAAG,IAAI,CAAC;AACjB,MAAM,GAAG,GAAG,IAAI,CAAC;AACjB,MAAM,EAAE,GAAG,IAAI,CAAC;AAEhB,gIAAgI;AAChI,MAAM,QAAQ,GAAG;IACf,aAAa,EAAE,IAAI;IACnB,gBAAgB,EAAE,IAAI;IACtB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,IAAI;IACrB,oBAAoB,EAAE,IAAI;IAC1B,eAAe,EAAE,IAAI;IACrB,SAAS,EAAE,IAAI;IACf,YAAY,EAAE,IAAI;IAClB,OAAO,EAAE,IAAI;CACd,CAAC;AAEF;;GAEG;AACH,eAAe,CACb,SAAoB,EACpB,GAA0B,EAC1B,UAAkB,EAClB,SAAiB,EACF,EAAE;IACjB,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACxD,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAEtD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CACjC,GAAG,EACH,GAAG,EACH,QAAQ,CAAC,GAAG,CAAC,EACb,EAAE,EACF,MAAM,CAAC,MAAM,CAAC;QACZ,IAAI,UAAU,CAAC,gBAAgB,CAAC;QAChC,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACxC,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;QACrD,IAAI,UAAU,CAAC,eAAe,CAAC;KAChC,CAAC,EACF,gBAAgB,CACjB,CAAC;IAEF,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,UAAU,KAAK,WAAW,CAAC,EAAE,EAAE,CAAC;QAClC,UAAU,CAAC,UAAU,CAAC,CAAC;IACzB,CAAC;AACH,CAAC,CAAA,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadPKI.test.d.ts","sourceRoot":"","sources":["../src/loadPKI.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { createTransportRecorder, MockTransport, RecordStore } from "@ledgerhq/hw-transport-mocker";
|
|
11
|
+
import loadPKI from "./loadPKI";
|
|
12
|
+
describe("loadPKI", () => {
|
|
13
|
+
const recordStore = new RecordStore();
|
|
14
|
+
const mockTransport = new MockTransport(Buffer.from([0, 0x90, 0x00]));
|
|
15
|
+
const TransportRecorder = createTransportRecorder(mockTransport, recordStore);
|
|
16
|
+
it("returns a new Challenge value", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
// Given
|
|
18
|
+
const descriptor = "010203";
|
|
19
|
+
const signature = "0a0b0c0d0e0f1a1b1c1d1e1f";
|
|
20
|
+
const signatureLengthInHex = "0c";
|
|
21
|
+
const transport = new TransportRecorder(mockTransport);
|
|
22
|
+
// When
|
|
23
|
+
yield loadPKI(transport, "GENUINE_CHECK", descriptor, signature);
|
|
24
|
+
// Then
|
|
25
|
+
const expectCommand = Buffer.from([0xb0, 0x06, 0x01, 0x00]).toString("hex");
|
|
26
|
+
const certSeparator = "15";
|
|
27
|
+
const data = descriptor + certSeparator + signatureLengthInHex + signature;
|
|
28
|
+
const dataLengthInHex = (data.length / 2).toString(16);
|
|
29
|
+
expect(recordStore.queue[0][0]).toBe(expectCommand + dataLengthInHex + data);
|
|
30
|
+
}));
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=loadPKI.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadPKI.test.js","sourceRoot":"","sources":["../src/loadPKI.test.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACpG,OAAO,OAAO,MAAM,WAAW,CAAC;AAEhC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACtC,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAE9E,EAAE,CAAC,+BAA+B,EAAE,GAAS,EAAE;QAC7C,QAAQ;QACR,MAAM,UAAU,GAAG,QAAQ,CAAC;QAC5B,MAAM,SAAS,GAAG,0BAA0B,CAAC;QAC7C,MAAM,oBAAoB,GAAG,IAAI,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,iBAAiB,CAAC,aAAa,CAAC,CAAC;QAEvD,OAAO;QACP,MAAM,OAAO,CAAC,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAEjE,OAAO;QACP,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC5E,MAAM,aAAa,GAAG,IAAI,CAAC;QAC3B,MAAM,IAAI,GAAG,UAAU,GAAG,aAAa,GAAG,oBAAoB,GAAG,SAAS,CAAC;QAC3E,MAAM,eAAe,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG,eAAe,GAAG,IAAI,CAAC,CAAC;IAC/E,CAAC,CAAA,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ledgerhq/hw-bolos",
|
|
3
|
+
"version": "6.31.4",
|
|
4
|
+
"description": "List of commands for Ledger Hardware Wallet OS",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"Ledger",
|
|
7
|
+
"LedgerWallet",
|
|
8
|
+
"Nano",
|
|
9
|
+
"BOLOS"
|
|
10
|
+
],
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/LedgerHQ/ledger-live.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/LedgerHQ/ledger-live/issues"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/ledgerjs/packages/hw-bolos",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"main": "lib/index.js",
|
|
23
|
+
"module": "lib-es/index.js",
|
|
24
|
+
"types": "lib/index.d.ts",
|
|
25
|
+
"license": "Apache-2.0",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@ledgerhq/hw-transport": "6.31.4"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/jest": "^29.5.10",
|
|
31
|
+
"@types/node": "^20.8.10",
|
|
32
|
+
"documentation": "14.0.2",
|
|
33
|
+
"jest": "^29.7.0",
|
|
34
|
+
"rimraf": "^4.4.1",
|
|
35
|
+
"ts-jest": "^29.1.1",
|
|
36
|
+
"ts-node": "^10.4.0",
|
|
37
|
+
"@ledgerhq/hw-transport-mocker": "6.29.4",
|
|
38
|
+
"@ledgerhq/hw-transport-node-hid-singleton": "^6.31.5"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"clean": "rimraf lib lib-es",
|
|
42
|
+
"build": "tsc && tsc -m ES6 --outDir lib-es",
|
|
43
|
+
"prewatch": "pnpm build",
|
|
44
|
+
"watch": "tsc --watch",
|
|
45
|
+
"watch:es": "tsc --watch -m ES6 --outDir lib-es",
|
|
46
|
+
"doc": "documentation readme src/** --section=API --pe ts --re ts --re d.ts",
|
|
47
|
+
"lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx --cache",
|
|
48
|
+
"lint:fix": "pnpm lint --fix",
|
|
49
|
+
"test": "jest",
|
|
50
|
+
"test-integ": "jest --config=jest.integ.config.ts --runInBand",
|
|
51
|
+
"unimported": "unimported"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/PKIError.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const ErrorCode: Record<number, string> = {
|
|
2
|
+
0x422f: "Incorrect structure type",
|
|
3
|
+
0x4230: "Incorrect certificate version",
|
|
4
|
+
0x4231: "Incorrect certificate validity",
|
|
5
|
+
0x4232: "Incorrect certificate validity index",
|
|
6
|
+
0x4233: "Unknown signer key ID",
|
|
7
|
+
0x4234: "Unknown signature algorithm",
|
|
8
|
+
0x4235: "Unknown public key ID",
|
|
9
|
+
0x4236: "Unknown public key usage",
|
|
10
|
+
0x4237: "Incorrect elliptic curve ID",
|
|
11
|
+
0x4238: "Incorrect signature algorithm associated to the public key",
|
|
12
|
+
0x4239: "Unknown target device",
|
|
13
|
+
0x422d: "Unknown certificate tag",
|
|
14
|
+
0x3301: "Failed to hash data",
|
|
15
|
+
0x422e: "expected_key_usage doesn't match certificate key usage",
|
|
16
|
+
0x5720: "Failed to verify signature",
|
|
17
|
+
0x4118: "trusted_name buffer is too small to contain the trusted name",
|
|
18
|
+
};
|
|
19
|
+
export const errorCodeValue = Object.keys(ErrorCode).map(v => parseInt(v));
|
|
20
|
+
|
|
21
|
+
export function throwError(code: number) {
|
|
22
|
+
switch (code) {
|
|
23
|
+
case 0x422f:
|
|
24
|
+
throw new PKIStructError();
|
|
25
|
+
case 0x4230:
|
|
26
|
+
throw new PKICertificateVersionError();
|
|
27
|
+
case 0x4231:
|
|
28
|
+
throw new PKICertificateValidityError();
|
|
29
|
+
case 0x4232:
|
|
30
|
+
throw new PKICertificateIndexError();
|
|
31
|
+
case 0x4233:
|
|
32
|
+
throw new PKIUnknownSignerIdError();
|
|
33
|
+
case 0x4234:
|
|
34
|
+
throw new PKIUnknownSignerAlgorithmError();
|
|
35
|
+
case 0x4235:
|
|
36
|
+
throw new PKIUnknownPublicIdError();
|
|
37
|
+
case 0x4236:
|
|
38
|
+
throw new PKIUnknownPublicUsageError();
|
|
39
|
+
case 0x4237:
|
|
40
|
+
throw new PKIIncorrectCurveError();
|
|
41
|
+
case 0x4238:
|
|
42
|
+
throw new PKIIncorrectSignatureError();
|
|
43
|
+
case 0x4239:
|
|
44
|
+
throw new PKIUnknownDeviceError();
|
|
45
|
+
case 0x422d:
|
|
46
|
+
throw new PKIUnknownCertificateTagError();
|
|
47
|
+
case 0x3301:
|
|
48
|
+
throw new PKIFailedHashError();
|
|
49
|
+
case 0x422e:
|
|
50
|
+
throw new PKIMismatchKeyError();
|
|
51
|
+
case 0x5720:
|
|
52
|
+
throw new PKIFailedVerificationError();
|
|
53
|
+
case 0x4118:
|
|
54
|
+
throw new PKITrustedNameTooSmallError();
|
|
55
|
+
default:
|
|
56
|
+
throw new PKIError("Unknown");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class PKIError extends Error {
|
|
61
|
+
constructor(cause: string) {
|
|
62
|
+
super("PKIError due to " + cause);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export class PKIStructError extends PKIError {
|
|
66
|
+
constructor() {
|
|
67
|
+
super(ErrorCode[0x422f]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class PKICertificateVersionError extends PKIError {
|
|
71
|
+
constructor() {
|
|
72
|
+
super(ErrorCode[0x4230]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export class PKICertificateValidityError extends PKIError {
|
|
76
|
+
constructor() {
|
|
77
|
+
super(ErrorCode[0x4231]);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export class PKICertificateIndexError extends PKIError {
|
|
81
|
+
constructor() {
|
|
82
|
+
super(ErrorCode[0x4232]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export class PKIUnknownSignerIdError extends PKIError {
|
|
86
|
+
constructor() {
|
|
87
|
+
super(ErrorCode[0x4233]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export class PKIUnknownSignerAlgorithmError extends PKIError {
|
|
91
|
+
constructor() {
|
|
92
|
+
super(ErrorCode[0x4234]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export class PKIUnknownPublicIdError extends PKIError {
|
|
96
|
+
constructor() {
|
|
97
|
+
super(ErrorCode[0x4235]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export class PKIUnknownPublicUsageError extends PKIError {
|
|
101
|
+
constructor() {
|
|
102
|
+
super(ErrorCode[0x4236]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export class PKIIncorrectCurveError extends PKIError {
|
|
106
|
+
constructor() {
|
|
107
|
+
super(ErrorCode[0x4237]);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export class PKIIncorrectSignatureError extends PKIError {
|
|
111
|
+
constructor() {
|
|
112
|
+
super(ErrorCode[0x4238]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export class PKIUnknownDeviceError extends PKIError {
|
|
116
|
+
constructor() {
|
|
117
|
+
super(ErrorCode[0x4239]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export class PKIUnknownCertificateTagError extends PKIError {
|
|
121
|
+
constructor() {
|
|
122
|
+
super(ErrorCode[0x422d]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export class PKIFailedHashError extends PKIError {
|
|
126
|
+
constructor() {
|
|
127
|
+
super(ErrorCode[0x3301]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export class PKIMismatchKeyError extends PKIError {
|
|
131
|
+
constructor() {
|
|
132
|
+
super(ErrorCode[0x422e]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export class PKIFailedVerificationError extends PKIError {
|
|
136
|
+
constructor() {
|
|
137
|
+
super(ErrorCode[0x5720]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export class PKITrustedNameTooSmallError extends PKIError {
|
|
141
|
+
constructor() {
|
|
142
|
+
super(ErrorCode[0x4118]);
|
|
143
|
+
}
|
|
144
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as loadPKI } from "./loadPKI";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
2
|
+
import TransportNodeHidSingleton from "@ledgerhq/hw-transport-node-hid-singleton";
|
|
3
|
+
import loadPKI from "./loadPKI";
|
|
4
|
+
import { PKIFailedVerificationError } from "./PKIError";
|
|
5
|
+
|
|
6
|
+
describe("loadPKI with real connected device", () => {
|
|
7
|
+
let transport: Transport;
|
|
8
|
+
|
|
9
|
+
beforeAll(async () => {
|
|
10
|
+
transport = await TransportNodeHidSingleton.open("");
|
|
11
|
+
});
|
|
12
|
+
afterAll(async () => {
|
|
13
|
+
await transport.close();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it.skip("returns an Ok", async () => {
|
|
17
|
+
// Given
|
|
18
|
+
const descriptor =
|
|
19
|
+
"0101010201023501043601021004010500001302000314010120086e66745f6d657461300200053101043201213401013321035e6c1020c14dc46442fe89f97c0b68cdb15976dc24f24c316e7b30fe4e8cc76b";
|
|
20
|
+
const signature =
|
|
21
|
+
"30440220774aa1a064c9bd5ff2c820156b4af106d464d8ca0eb2de5f2956c8b52356496202205ef40dd54beb3c1534d011af9f581f426141d39338b3da6abf4023254cbef72c";
|
|
22
|
+
|
|
23
|
+
// When & Then
|
|
24
|
+
await expect(loadPKI(transport, "TRUSTED_NAME", descriptor, signature)).rejects.not.toThrow();
|
|
25
|
+
await (() => new Promise(f => setTimeout(f, 1000)))();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns an Verification Failed error", async () => {
|
|
29
|
+
// Given
|
|
30
|
+
const descriptor =
|
|
31
|
+
"0101010201023501043601021004010500001302000314010120086e66745f6d657461300200053101043201213401013321035e6c1020c14dc46442fe89f97c0b68cdb15976dc24f24c316e7b30fe4e8cc76b";
|
|
32
|
+
const signature =
|
|
33
|
+
"30440220774aa1a064c9bd5ff2c820156b4af106d464d8ca0eb2de5f2956c8b52356496202205ef40dd54beb3c1534d011af9f581f426141d39338b3da6abf4023254cbef72c";
|
|
34
|
+
|
|
35
|
+
// When & Then
|
|
36
|
+
await expect(loadPKI(transport, "TRUSTED_NAME", descriptor, signature)).rejects.toThrow(
|
|
37
|
+
PKIFailedVerificationError,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createTransportRecorder, MockTransport, RecordStore } from "@ledgerhq/hw-transport-mocker";
|
|
2
|
+
import loadPKI from "./loadPKI";
|
|
3
|
+
|
|
4
|
+
describe("loadPKI", () => {
|
|
5
|
+
const recordStore = new RecordStore();
|
|
6
|
+
const mockTransport = new MockTransport(Buffer.from([0, 0x90, 0x00]));
|
|
7
|
+
const TransportRecorder = createTransportRecorder(mockTransport, recordStore);
|
|
8
|
+
|
|
9
|
+
it("returns a new Challenge value", async () => {
|
|
10
|
+
// Given
|
|
11
|
+
const descriptor = "010203";
|
|
12
|
+
const signature = "0a0b0c0d0e0f1a1b1c1d1e1f";
|
|
13
|
+
const signatureLengthInHex = "0c";
|
|
14
|
+
const transport = new TransportRecorder(mockTransport);
|
|
15
|
+
|
|
16
|
+
// When
|
|
17
|
+
await loadPKI(transport, "GENUINE_CHECK", descriptor, signature);
|
|
18
|
+
|
|
19
|
+
// Then
|
|
20
|
+
const expectCommand = Buffer.from([0xb0, 0x06, 0x01, 0x00]).toString("hex");
|
|
21
|
+
const certSeparator = "15";
|
|
22
|
+
const data = descriptor + certSeparator + signatureLengthInHex + signature;
|
|
23
|
+
const dataLengthInHex = (data.length / 2).toString(16);
|
|
24
|
+
expect(recordStore.queue[0][0]).toBe(expectCommand + dataLengthInHex + data);
|
|
25
|
+
});
|
|
26
|
+
});
|
package/src/loadPKI.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Transport, { StatusCodes } from "@ledgerhq/hw-transport";
|
|
2
|
+
import { errorCodeValue, throwError } from "./PKIError";
|
|
3
|
+
|
|
4
|
+
const handledErrorCode = errorCodeValue.concat(StatusCodes.OK);
|
|
5
|
+
|
|
6
|
+
const CLA = 0xb0;
|
|
7
|
+
const INS = 0x06;
|
|
8
|
+
const P2 = 0x00;
|
|
9
|
+
|
|
10
|
+
// Extract from https://github.com/LedgerHQ/ledger-secure-sdk/blob/d59b21f8a1f2e78ad50b5a8a21d0daac68826643/include/os_pki.h#L74
|
|
11
|
+
const keyUsage = {
|
|
12
|
+
GENUINE_CHECK: 0x01,
|
|
13
|
+
EXCHANGE_PAYLOAD: 0x02,
|
|
14
|
+
NFT_METADATA: 0x03,
|
|
15
|
+
TRUSTED_NAME: 0x04,
|
|
16
|
+
BACKUP_PROVIDER: 0x05,
|
|
17
|
+
RECOVER_ORCHESTRATOR: 0x06,
|
|
18
|
+
PLUGIN_METADATA: 0x07,
|
|
19
|
+
COIN_META: 0x08,
|
|
20
|
+
SEED_ID_AUTH: 0x09,
|
|
21
|
+
UNKNOWN: 0x0a,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Load certificate
|
|
26
|
+
*/
|
|
27
|
+
export default async (
|
|
28
|
+
transport: Transport,
|
|
29
|
+
key: keyof typeof keyUsage,
|
|
30
|
+
descriptor: string,
|
|
31
|
+
signature: string,
|
|
32
|
+
): Promise<void> => {
|
|
33
|
+
const descriptorBuffer = Buffer.from(descriptor, "hex");
|
|
34
|
+
const signatureBuffer = Buffer.from(signature, "hex");
|
|
35
|
+
|
|
36
|
+
const result = await transport.send(
|
|
37
|
+
CLA,
|
|
38
|
+
INS,
|
|
39
|
+
keyUsage[key],
|
|
40
|
+
P2,
|
|
41
|
+
Buffer.concat([
|
|
42
|
+
new Uint8Array(descriptorBuffer),
|
|
43
|
+
new Uint8Array(Buffer.from("15", "hex")),
|
|
44
|
+
new Uint8Array(Buffer.from([signatureBuffer.length])),
|
|
45
|
+
new Uint8Array(signatureBuffer),
|
|
46
|
+
]),
|
|
47
|
+
handledErrorCode,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const resultCode = result.readUInt16BE(result.length - 2);
|
|
51
|
+
if (resultCode !== StatusCodes.OK) {
|
|
52
|
+
throwError(resultCode);
|
|
53
|
+
}
|
|
54
|
+
};
|