diff --git a/docs/firmware-versions.md b/docs/firmware-versions.md index 84656b7..1ac3ec4 100644 --- a/docs/firmware-versions.md +++ b/docs/firmware-versions.md @@ -59,22 +59,26 @@ Addons ver. - first HaLo Addons version to support the indicated driver. ## Command compatibility table ### Commands available in HaLo OSS -| Command | Core ver. | Comment | -|--------------------|-----------|-----------------------------------------------| -| `version` | 01.C1 | Only for PCSC/React Native drivers. | -| `sign` | 01.C1 | Only with `command.legacySignCommand = true`. | -| `get_pkeys` | 01.C1 | | -| `write_latch` | 01.C3 | | -| `sign` | 01.C4 | All combinations of options. | -| `sign_random` | 01.C4 | | -| `get_key_info` | 01.C6 | | -| `gen_key` | 01.C7 | | -| `gen_key_confirm` | 01.C7 | | -| `gen_key_finalize` | 01.C7 | | -| `set_password` | 01.C7 | | -| `replace_password` | 01.C7 | | -| `unset_password` | 01.C7 | | -| `pcsc_detect` | 01.C1 | Only with CLI tool. | +| Command | Core ver. | Comment | +|---------------------|-----------|--------------------------------------------------------| +| `version` | 01.C1 | Only for PCSC/React Native drivers. | +| `sign` | 01.C1 | Only with `command.legacySignCommand = true`. | +| `get_pkeys` | 01.C1 | | +| `write_latch` | 01.C3 | | +| `sign` | 01.C4 | All combinations of options. | +| `sign_random` | 01.C4 | | +| `get_key_info` | 01.C6 | | +| `gen_key` | 01.C7 | | +| `gen_key_confirm` | 01.C7 | | +| `gen_key_finalize` | 01.C7 | | +| `set_password` | 01.C7 | | +| `replace_password` | 01.C7 | | +| `unset_password` | 01.C7 | | +| `get_transport_pk` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. | +| `load_transport_pk` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. | +| `export_key` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. | +| `import_key` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. | +| `pcsc_detect` | 01.C1 | Only with CLI tool. | Core ver. - first HaLo Core version to officially support the indicated command. diff --git a/drivers/common.js b/drivers/common.js index 38718eb..9f5f33c 100644 --- a/drivers/common.js +++ b/drivers/common.js @@ -10,15 +10,14 @@ const { } = require("../halo/exceptions"); const { cmdGetPkeys, cmdSign, cmdCfgNDEF, cmdWriteLatch, cmdSignRandom, cmdGenKey, cmdGenKeyConfirm, cmdGenKeyFinalize, - cmdSignChallenge, cmdSetURLSubdomain, cmdSetPassword, cmdUnsetPassword, cmdReplacePassword, cmdGetKeyInfo + cmdSignChallenge, cmdSetURLSubdomain, cmdSetPassword, cmdUnsetPassword, cmdReplacePassword, cmdGetKeyInfo, + cmdGetTransportPK, cmdLoadTransportPK, cmdExportKey, cmdImportKey } = require("../halo/commands"); const {ERROR_CODES} = require("../halo/errors"); async function execHaloCmd(command, options) { command = Object.assign({}, command); - console.log(command); - let commandName = command.name; delete command['name']; @@ -51,6 +50,14 @@ async function execHaloCmd(command, options) { return await cmdUnsetPassword(options, command); case 'get_key_info': return await cmdGetKeyInfo(options, command); + case 'get_transport_pk': + return await cmdGetTransportPK(options, command); + case 'load_transport_pk': + return await cmdLoadTransportPK(options, command); + case 'export_key': + return await cmdExportKey(options, command); + case 'import_key': + return await cmdImportKey(options, command); default: throw new HaloLogicError("Unsupported command.name parameter specified."); } diff --git a/halo/cmdcodes.js b/halo/cmdcodes.js index c3777e1..1d47a2f 100644 --- a/halo/cmdcodes.js +++ b/halo/cmdcodes.js @@ -37,6 +37,11 @@ const CMD_CODES = { "SHARED_CMD_GET_DATA_VERSION": 0xD7, "SHARED_CMD_GET_URL_SUBDOMAIN": 0xD6, "SHARED_CMD_SET_NDEF_MODE": 0xD8, + + "CRED_CMD_GET_TRANSPORT_PK_ATT": 0xA6, + "CRED_CMD_EXPORT_KEY": 0xA7, + "CRED_CMD_IMPORT_KEY": 0xA8, + "CRED_CMD_LOAD_TRANSPORT_PK": 0xA9, }; module.exports = {CMD_CODES}; diff --git a/halo/commands.js b/halo/commands.js index 4d1d790..3a0d066 100644 --- a/halo/commands.js +++ b/halo/commands.js @@ -546,6 +546,88 @@ async function cmdReplacePassword(options, args) { return {"status": "ok"}; } +async function cmdGetTransportPK(options, args) { + if (options.method !== "credential" && options.method !== "pcsc") { + throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'."); + } + + let payload = Buffer.concat([ + Buffer.from([CMD.CRED_CMD_GET_TRANSPORT_PK_ATT]) + ]); + + let resp = await options.exec(payload); + + return { + "data": resp.result.toString('hex') + } +} + +async function cmdLoadTransportPK(options, args) { + if (options.method !== "credential" && options.method !== "pcsc") { + throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'."); + } + + let payload = Buffer.concat([ + Buffer.from([CMD.CRED_CMD_LOAD_TRANSPORT_PK]), + Buffer.from(args.data, 'hex') + ]); + + let resp = await options.exec(payload); + + return { + "data": resp.result.toString('hex') + } +} + +async function cmdExportKey(options, args) { + if (options.method !== "credential" && options.method !== "pcsc") { + throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'."); + } + + let derivedKey = pbkdf2.pbkdf2Sync(args.password, 'HaLoChipSalt', 5000, 16, 'sha512'); + let dataBuf = Buffer.from(args.data, 'hex'); + let sigLen = dataBuf[1] + 2; + + let pwdHash = Buffer.from(sha256(Buffer.concat([ + Buffer.from([0x19]), + Buffer.from("Key backup:\n"), + Buffer.from([args.keyNo]), + derivedKey, + dataBuf.slice(sigLen), + ])), "hex"); + + let payload = Buffer.concat([ + Buffer.from([CMD.CRED_CMD_EXPORT_KEY]), + Buffer.from([args.keyNo]), + dataBuf, + pwdHash + ]); + + let resp = await options.exec(payload); + + return { + "data": resp.result.toString('hex') + } +} + +async function cmdImportKey(options, args) { + if (options.method !== "credential" && options.method !== "pcsc") { + throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'."); + } + + let payload = Buffer.concat([ + Buffer.from([CMD.CRED_CMD_IMPORT_KEY]), + Buffer.from([args.keyNo]), + Buffer.from(args.data, 'hex') + ]); + + let resp = await options.exec(payload); + + return { + "publicKey": resp.result.toString('hex') + } +} + module.exports = { cmdSign, cmdSignRandom, @@ -560,5 +642,9 @@ module.exports = { cmdSetPassword, cmdUnsetPassword, cmdReplacePassword, - cmdGetKeyInfo + cmdGetKeyInfo, + cmdGetTransportPK, + cmdLoadTransportPK, + cmdExportKey, + cmdImportKey, }; diff --git a/web/examples/index.html b/web/examples/index.html index e732202..75effe5 100644 --- a/web/examples/index.html +++ b/web/examples/index.html @@ -22,6 +22,7 @@
Supported key slots: 8, 9. The key on the source card must already exist.
+Source card's key password.
+Please click on one of the buttons below.+ +
diff --git a/web/examples/key_backup.html b/web/examples/key_backup.html new file mode 100644 index 0000000..6121cca --- /dev/null +++ b/web/examples/key_backup.html @@ -0,0 +1,115 @@ + + +
+ +
+ + + + + + +
+