diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d28212e4..1be1df43 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -34,7 +34,7 @@ jobs: run: | aws s3 sync \ middleware/coverage/ \ - s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.1.x/middleware_coverage_report \ + s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.2.x/middleware_coverage_report \ --sse aws:kms --sse-kms-key-id ${{ secrets.CODECOVERAGE_KMS_KEY_ID }} \ --no-progress --follow-symlinks --delete --only-show-errors @@ -49,7 +49,7 @@ jobs: run: | aws s3 sync \ firmware/coverage/output/ \ - s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.1.x/firmware_coverage_report \ + s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.2.x/firmware_coverage_report \ --sse aws:kms --sse-kms-key-id ${{ secrets.CODECOVERAGE_KMS_KEY_ID }} \ --no-progress --follow-symlinks --delete --only-show-errors diff --git a/CHANGELOG.md b/CHANGELOG.md index 82e33d9f..d680f359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [5.2.0] - 09/09/2024 + +### Features/enhancements + +- Added "screen saver" mode to signer app to extend display lifetime +- Decoupled business and I/O (aka communication) layers in preparation for multiple platforms +- Improved HAL directory structure to accomodate for testing different platform implementations + +### Fixes + +- Fixed middleware docker image build +- Fixed verify_attestaion.py to allow distinct versions for UI and Signer +- Incidentally bumped urllib3, certifi to address dependabot findings + ## [5.1.0] - 01/07/2024 ### Features/enhancements diff --git a/README.md b/README.md index 86e9f533..ee086462 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ ![Tests](https://github.com/rsksmart/rsk-powhsm/actions/workflows/run-tests.yml/badge.svg) ![Python linter](https://github.com/rsksmart/rsk-powhsm/actions/workflows/lint-python.yml/badge.svg) ![C linter](https://github.com/rsksmart/rsk-powhsm/actions/workflows/lint-c.yml/badge.svg) -[![Middleware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.1.x/middleware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.1.x/middleware_coverage_report/index.html) -[![Firmware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.1.x/firmware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.1.x/firmware_coverage_report/index.html) +[![Middleware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/middleware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/middleware_coverage_report/index.html) +[![Firmware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/firmware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/firmware_coverage_report/index.html) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) diff --git a/docs/attestation.md b/docs/attestation.md index e5b56c14..3cc0ac25 100644 --- a/docs/attestation.md +++ b/docs/attestation.md @@ -56,7 +56,7 @@ Before diving into the UI attestation, it is important to recall a few relevant To generate the attestation, the UI uses the configured attestation scheme to sign a message generated by the concatenation of: -- A predefined header (`HSM:UI:5.1`). +- A predefined header (`HSM:UI:5.2`). - A 32 byte user-defined value. By default, the attestation generation client supplies the latest RSK block hash as this value, so it can then be used as a minimum timestamp reference for the attestation generation. - The compressed public key corresponding to the private key obtained by deriving the generated seed with the BIP32 path `m/44'/0'/0'/0/0` (normally used as the BTC key by the Signer application). - The hash of the currently authorized Signer version. @@ -66,7 +66,7 @@ As a consequence of the aforementioned features, this message guarantees that th ### Signer attestation -To generate the attestation, the Signer uses the configured attestation scheme to sign a message containing a predefined header (`HSM:SIGNER:5.1`) and the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. +To generate the attestation, the Signer uses the configured attestation scheme to sign a message containing a predefined header (`HSM:SIGNER:5.2`) and the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. ## Attestation file format diff --git a/docs/heartbeat.md b/docs/heartbeat.md index 3f81a567..6d4f5fdf 100644 --- a/docs/heartbeat.md +++ b/docs/heartbeat.md @@ -41,7 +41,7 @@ certification -- to verify. To generate the heartbeat, the Signer uses the configured endorsement scheme to sign a message generated by the concatenation of: -- A predefined header (`HSM:SIGNER:HB:5.1:`). +- A predefined header (`HSM:SIGNER:HB:5.2:`). - A 32 byte value corresponding to the currently known best block hash. - A value corresponding to the first 8 bytes of the last successful authorized signed operation's transaction hash. @@ -57,7 +57,7 @@ transactions. To generate the heartbeat, the UI uses the configured endorsement scheme to sign a message generated by the concatenation of: -- A predefined header (`HSM:UI:HB:5.1:`). +- A predefined header (`HSM:UI:HB:5.2:`). - A 32 byte user-defined value. This value can vary and could be, for example, used as a timestamp reference for the end user. - A 32 byte value corresponding to the currently authorized Signer hash. diff --git a/firmware/src/ledger/ui/src/attestation.h b/firmware/src/ledger/ui/src/attestation.h index 8eeb5413..bb9230e3 100644 --- a/firmware/src/ledger/ui/src/attestation.h +++ b/firmware/src/ledger/ui/src/attestation.h @@ -48,7 +48,7 @@ typedef enum { } err_code_att_t; // Attestation message prefix -#define ATT_MSG_PREFIX "HSM:UI:5.1" +#define ATT_MSG_PREFIX "HSM:UI:5.2" #define ATT_MSG_PREFIX_LENGTH (sizeof(ATT_MSG_PREFIX) - sizeof("")) // User defined value size diff --git a/firmware/src/ledger/ui/src/defs.h b/firmware/src/ledger/ui/src/defs.h index d9f2e9ff..afb7635b 100644 --- a/firmware/src/ledger/ui/src/defs.h +++ b/firmware/src/ledger/ui/src/defs.h @@ -30,7 +30,7 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 -#define VERSION_MINOR 0x01 +#define VERSION_MINOR 0x02 #define VERSION_PATCH 0x00 #endif // __DEFS_H diff --git a/firmware/src/ledger/ui/src/ui_heartbeat.h b/firmware/src/ledger/ui/src/ui_heartbeat.h index d5f873da..e42db887 100644 --- a/firmware/src/ledger/ui/src/ui_heartbeat.h +++ b/firmware/src/ledger/ui/src/ui_heartbeat.h @@ -46,7 +46,7 @@ typedef enum { } err_code_ui_heartbeat_t; // Heartbeat message prefix -#define UI_HEARTBEAT_MSG_PREFIX "HSM:UI:HB:5.1:" +#define UI_HEARTBEAT_MSG_PREFIX "HSM:UI:HB:5.2:" #define UI_HEARTBEAT_MSG_PREFIX_LENGTH \ (sizeof(UI_HEARTBEAT_MSG_PREFIX) - sizeof("")) diff --git a/firmware/src/ledger/ui/test/attestation/test_attestation.c b/firmware/src/ledger/ui/test/attestation/test_attestation.c index eae3b102..31333927 100644 --- a/firmware/src/ledger/ui/test/attestation/test_attestation.c +++ b/firmware/src/ledger/ui/test/attestation/test_attestation.c @@ -160,7 +160,7 @@ void test_get_attestation_ud_value() { assert(3 == get_attestation(rx, &G_att_ctx)); // PREFIX + UD_VALUE + Compressed pubkey + Signer hash + Iteration ASSERT_MEMCMP( - "HSM:UI:5.1" + "HSM:UI:5.2" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x02\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" @@ -208,7 +208,7 @@ void test_get_attestation_get_msg() { *N_onboarded_ui = 1; memcpy( G_att_ctx.msg, - "HSM:UI:5.1" + "HSM:UI:5.2" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x03\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" @@ -225,7 +225,7 @@ void test_get_attestation_get_msg() { assert((APDU_TOTAL_DATA_SIZE_OUT + 3) == get_attestation(rx, &G_att_ctx)); ASSERT_APDU( "\x80\x50\x02\x01" - "HSM:UI:5.1" + "HSM:UI:5.2" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x03\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" @@ -249,7 +249,7 @@ void test_get_attestation_get_msg_wrong_state() { *N_onboarded_ui = 1; memcpy( &G_att_ctx.msg, - "HSM:UI:5.1" + "HSM:UI:5.2" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x03\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" diff --git a/firmware/src/ledger/ui/test/onboard/test_onboard.c b/firmware/src/ledger/ui/test/onboard/test_onboard.c index fe686a05..1e9ccebc 100644 --- a/firmware/src/ledger/ui/test/onboard/test_onboard.c +++ b/firmware/src/ledger/ui/test/onboard/test_onboard.c @@ -313,11 +313,11 @@ void test_is_onboarded() { G_device_onboarded = true; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x01\x05\x01\x00"); + ASSERT_APDU("\x80\x01\x05\x02\x00"); G_device_onboarded = false; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x00\x05\x01\x00"); + ASSERT_APDU("\x80\x00\x05\x02\x00"); } int main() { diff --git a/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c b/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c index 810b6a0b..36fe5518 100644 --- a/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c +++ b/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c @@ -230,7 +230,7 @@ void test_op_ud_value() { assert_ok("\x80\x60\x01"); - const char expected_msg[] = "HSM:UI:HB:5.1:" // Prefix + const char expected_msg[] = "HSM:UI:HB:5.2:" // Prefix "\x11" // UD "\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22" // . "\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22" // . diff --git a/firmware/src/powhsm/src/attestation.h b/firmware/src/powhsm/src/attestation.h index 6d405300..23d1171b 100644 --- a/firmware/src/powhsm/src/attestation.h +++ b/firmware/src/powhsm/src/attestation.h @@ -33,7 +33,7 @@ // ----------------------------------------------------------------------- // Attestation message prefix -#define ATT_MSG_PREFIX "HSM:SIGNER:5.1" +#define ATT_MSG_PREFIX "HSM:SIGNER:5.2" #define ATT_MSG_PREFIX_LENGTH (sizeof(ATT_MSG_PREFIX) - sizeof("")) // ----------------------------------------------------------------------- diff --git a/firmware/src/powhsm/src/defs.h b/firmware/src/powhsm/src/defs.h index a78e7ca0..7413c6ee 100644 --- a/firmware/src/powhsm/src/defs.h +++ b/firmware/src/powhsm/src/defs.h @@ -29,7 +29,7 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 -#define VERSION_MINOR 0x01 +#define VERSION_MINOR 0x02 #define VERSION_PATCH 0x00 #endif // __DEFS_H diff --git a/firmware/src/powhsm/src/heartbeat.h b/firmware/src/powhsm/src/heartbeat.h index c9a52133..1026f2b1 100644 --- a/firmware/src/powhsm/src/heartbeat.h +++ b/firmware/src/powhsm/src/heartbeat.h @@ -45,7 +45,7 @@ typedef enum { } err_code_heartbeat_t; // Heartbeat message prefix -#define HEARTBEAT_MSG_PREFIX "HSM:SIGNER:HB:5.1:" +#define HEARTBEAT_MSG_PREFIX "HSM:SIGNER:HB:5.2:" #define HEARTBEAT_MSG_PREFIX_LENGTH (sizeof(HEARTBEAT_MSG_PREFIX) - sizeof("")) // User-defined value size diff --git a/firmware/src/powhsm/test/btcscript/btcscript.o b/firmware/src/powhsm/test/btcscript/btcscript.o deleted file mode 100644 index acae6192..00000000 Binary files a/firmware/src/powhsm/test/btcscript/btcscript.o and /dev/null differ diff --git a/firmware/src/powhsm/test/btcscript/hex_reader.o b/firmware/src/powhsm/test/btcscript/hex_reader.o deleted file mode 100644 index 4826ca38..00000000 Binary files a/firmware/src/powhsm/test/btcscript/hex_reader.o and /dev/null differ diff --git a/firmware/src/powhsm/test/btcscript/test.out b/firmware/src/powhsm/test/btcscript/test.out deleted file mode 100755 index c8500186..00000000 Binary files a/firmware/src/powhsm/test/btcscript/test.out and /dev/null differ diff --git a/firmware/src/powhsm/test/btcscript/test_btcscript.o b/firmware/src/powhsm/test/btcscript/test_btcscript.o deleted file mode 100644 index f665c504..00000000 Binary files a/firmware/src/powhsm/test/btcscript/test_btcscript.o and /dev/null differ diff --git a/firmware/src/powhsm/test/btcscript/test_fwk.o b/firmware/src/powhsm/test/btcscript/test_fwk.o deleted file mode 100644 index 4ebfd3ef..00000000 Binary files a/firmware/src/powhsm/test/btcscript/test_fwk.o and /dev/null differ diff --git a/firmware/src/powhsm/test/btctx/hex_reader.o b/firmware/src/powhsm/test/btctx/hex_reader.o deleted file mode 100644 index 4826ca38..00000000 Binary files a/firmware/src/powhsm/test/btctx/hex_reader.o and /dev/null differ diff --git a/firmware/src/powhsm/test/btctx/svarint.o b/firmware/src/powhsm/test/btctx/svarint.o deleted file mode 100644 index 64db7f1f..00000000 Binary files a/firmware/src/powhsm/test/btctx/svarint.o and /dev/null differ diff --git a/firmware/src/powhsm/test/btctx/test_fwk.o b/firmware/src/powhsm/test/btctx/test_fwk.o deleted file mode 100644 index 4ebfd3ef..00000000 Binary files a/firmware/src/powhsm/test/btctx/test_fwk.o and /dev/null differ diff --git a/firmware/src/powhsm/test/difficulty/test_difficulty.o b/firmware/src/powhsm/test/difficulty/test_difficulty.o deleted file mode 100644 index 8fd2864c..00000000 Binary files a/firmware/src/powhsm/test/difficulty/test_difficulty.o and /dev/null differ diff --git a/firmware/src/powhsm/test/difficulty/test_fwk.o b/firmware/src/powhsm/test/difficulty/test_fwk.o deleted file mode 100644 index 4ebfd3ef..00000000 Binary files a/firmware/src/powhsm/test/difficulty/test_fwk.o and /dev/null differ diff --git a/firmware/src/powhsm/test/sha256/sha256.o b/firmware/src/powhsm/test/sha256/sha256.o deleted file mode 100644 index fcb8c696..00000000 Binary files a/firmware/src/powhsm/test/sha256/sha256.o and /dev/null differ diff --git a/firmware/src/powhsm/test/sha256/test.out b/firmware/src/powhsm/test/sha256/test.out deleted file mode 100755 index b48a2106..00000000 Binary files a/firmware/src/powhsm/test/sha256/test.out and /dev/null differ diff --git a/firmware/src/powhsm/test/sha256/test_fwk.o b/firmware/src/powhsm/test/sha256/test_fwk.o deleted file mode 100644 index 4ebfd3ef..00000000 Binary files a/firmware/src/powhsm/test/sha256/test_fwk.o and /dev/null differ diff --git a/firmware/src/powhsm/test/sha256/test_sha256.o b/firmware/src/powhsm/test/sha256/test_sha256.o deleted file mode 100644 index 8746029e..00000000 Binary files a/firmware/src/powhsm/test/sha256/test_sha256.o and /dev/null differ diff --git a/firmware/src/powhsm/test/srlp/test_fwk.o b/firmware/src/powhsm/test/srlp/test_fwk.o deleted file mode 100644 index 4ebfd3ef..00000000 Binary files a/firmware/src/powhsm/test/srlp/test_fwk.o and /dev/null differ diff --git a/firmware/src/powhsm/test/srlp/test_srlp.o b/firmware/src/powhsm/test/srlp/test_srlp.o deleted file mode 100644 index 6ec09981..00000000 Binary files a/firmware/src/powhsm/test/srlp/test_srlp.o and /dev/null differ diff --git a/firmware/src/powhsm/test/svarint/svarint.o b/firmware/src/powhsm/test/svarint/svarint.o deleted file mode 100644 index 64db7f1f..00000000 Binary files a/firmware/src/powhsm/test/svarint/svarint.o and /dev/null differ diff --git a/firmware/src/powhsm/test/svarint/test.out b/firmware/src/powhsm/test/svarint/test.out deleted file mode 100755 index a23bc5af..00000000 Binary files a/firmware/src/powhsm/test/svarint/test.out and /dev/null differ diff --git a/firmware/src/powhsm/test/svarint/test_fwk.o b/firmware/src/powhsm/test/svarint/test_fwk.o deleted file mode 100644 index 4ebfd3ef..00000000 Binary files a/firmware/src/powhsm/test/svarint/test_fwk.o and /dev/null differ diff --git a/firmware/src/powhsm/test/svarint/test_svarint.o b/firmware/src/powhsm/test/svarint/test_svarint.o deleted file mode 100644 index a4f24c47..00000000 Binary files a/firmware/src/powhsm/test/svarint/test_svarint.o and /dev/null differ diff --git a/firmware/src/powhsm/test/trie/hex_reader.o b/firmware/src/powhsm/test/trie/hex_reader.o deleted file mode 100644 index 4826ca38..00000000 Binary files a/firmware/src/powhsm/test/trie/hex_reader.o and /dev/null differ diff --git a/firmware/src/powhsm/test/trie/svarint.o b/firmware/src/powhsm/test/trie/svarint.o deleted file mode 100644 index 64db7f1f..00000000 Binary files a/firmware/src/powhsm/test/trie/svarint.o and /dev/null differ diff --git a/firmware/src/powhsm/test/trie/test_fwk.o b/firmware/src/powhsm/test/trie/test_fwk.o deleted file mode 100644 index 4ebfd3ef..00000000 Binary files a/firmware/src/powhsm/test/trie/test_fwk.o and /dev/null differ diff --git a/firmware/src/powhsm/test/trie/test_trie.o b/firmware/src/powhsm/test/trie/test_trie.o deleted file mode 100644 index 7f9bf22b..00000000 Binary files a/firmware/src/powhsm/test/trie/test_trie.o and /dev/null differ diff --git a/firmware/test/cases/heartbeat.py b/firmware/test/cases/heartbeat.py index 3b838106..09bad8d2 100644 --- a/firmware/test/cases/heartbeat.py +++ b/firmware/test/cases/heartbeat.py @@ -27,7 +27,7 @@ class Heartbeat(TestCase): - EXPECTED_HEADER = "HSM:SIGNER:HB:5.1:" + EXPECTED_HEADER = "HSM:SIGNER:HB:5.2:" EHL = len(EXPECTED_HEADER) @classmethod diff --git a/middleware/admin/verify_attestation.py b/middleware/admin/verify_attestation.py index e22caf10..3d398267 100644 --- a/middleware/admin/verify_attestation.py +++ b/middleware/admin/verify_attestation.py @@ -23,13 +23,14 @@ import json import hashlib import secp256k1 as ec +import re from .misc import info, head, AdminError from .utils import is_nonempty_hex_string from .certificate import HSMCertificate -UI_MESSAGE_HEADER = b"HSM:UI:5.1" -SIGNER_MESSAGE_HEADER = b"HSM:SIGNER:5.1" +UI_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:UI:(5.[0-9])") +SIGNER_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:SIGNER:(5.[0-9])") UI_DERIVATION_PATH = "m/44'/0'/0'/0/0" UD_VALUE_LENGTH = 32 PUBKEY_COMPRESSED_LENGTH = 33 @@ -45,6 +46,14 @@ "dad609" +def match_ui_message_header(ui_message): + return UI_MESSAGE_HEADER_REGEX.match(ui_message) + + +def match_signer_message_header(signer_message): + return SIGNER_MESSAGE_HEADER_REGEX.match(signer_message) + + def do_verify_attestation(options): head("### -> Verify UI and Signer attestations", fill="#") @@ -121,12 +130,14 @@ def do_verify_attestation(options): ui_message = bytes.fromhex(ui_result[1]) ui_hash = bytes.fromhex(ui_result[2]) - mh_len = len(UI_MESSAGE_HEADER) - if ui_message[:mh_len] != UI_MESSAGE_HEADER: + mh_match = match_ui_message_header(ui_message) + if mh_match is None: raise AdminError( - f"Invalid UI attestation message header: {ui_message[:mh_len].hex()}") + f"Invalid UI attestation message header: {ui_message.hex()}") + mh_len = len(mh_match.group(0)) - # Extract UD value, UI public key and signer version from message + # Extract UI version, UD value, UI public key and signer version from message + ui_version = mh_match.group(1) ud_value = ui_message[mh_len:mh_len + UD_VALUE_LENGTH].hex() ui_public_key = ui_message[mh_len + UD_VALUE_LENGTH:mh_len + UD_VALUE_LENGTH + PUBKEY_COMPRESSED_LENGTH].hex() @@ -147,6 +158,7 @@ def do_verify_attestation(options): f"Authorized signer hash: {signer_hash}", f"Authorized signer iteration: {signer_iteration}", f"Installed UI hash: {ui_hash.hex()}", + f"Installed UI version: {ui_version.decode()}", ], fill="-", ) @@ -162,11 +174,12 @@ def do_verify_attestation(options): signer_message = bytes.fromhex(signer_result[1]) signer_hash = bytes.fromhex(signer_result[2]) - mh_len = len(SIGNER_MESSAGE_HEADER) - if signer_message[:mh_len] != SIGNER_MESSAGE_HEADER: + mh_match = match_signer_message_header(signer_message) + if mh_match is None: raise AdminError( - f"Invalid Signer attestation message header: {signer_message[:mh_len].hex()}") + f"Invalid Signer attestation message header: {signer_message.hex()}") + mh_len = len(mh_match.group(0)) if signer_message[mh_len:] != pubkeys_hash: reported = signer_message[mh_len:].hex() raise AdminError( @@ -174,11 +187,13 @@ def do_verify_attestation(options): f" but attestation reports {reported}" ) + signer_version = mh_match.group(1) head( ["Signer verified with public keys:"] + pubkeys_output + [ "", f"Hash: {signer_message[mh_len:].hex()}", f"Installed Signer hash: {signer_hash.hex()}", + f"Installed Signer version: {signer_version.decode()}", ], fill="-", ) diff --git a/middleware/ledger/protocol.py b/middleware/ledger/protocol.py index bf595796..4e6af5cc 100644 --- a/middleware/ledger/protocol.py +++ b/middleware/ledger/protocol.py @@ -38,8 +38,8 @@ class HSM2ProtocolLedger(HSM2Protocol): # Current manager supported versions for HSM UI and HSM SIGNER (<=) - UI_VERSION = HSM2FirmwareVersion(5, 1, 0) - APP_VERSION = HSM2FirmwareVersion(5, 1, 0) + UI_VERSION = HSM2FirmwareVersion(5, 2, 0) + APP_VERSION = HSM2FirmwareVersion(5, 2, 0) # Amount of time to wait to make sure the app is opened OPEN_APP_WAIT = 1 # second diff --git a/middleware/tests/admin/test_verify_attestation.py b/middleware/tests/admin/test_verify_attestation.py index 4da01987..3b1968ab 100644 --- a/middleware/tests/admin/test_verify_attestation.py +++ b/middleware/tests/admin/test_verify_attestation.py @@ -25,7 +25,11 @@ from unittest.mock import Mock, call, patch, mock_open from admin.misc import AdminError from admin.pubkeys import PATHS -from admin.verify_attestation import do_verify_attestation +from admin.verify_attestation import ( + do_verify_attestation, + match_ui_message_header, + match_signer_message_header +) import ecdsa import hashlib import logging @@ -33,6 +37,8 @@ logging.disable(logging.CRITICAL) EXPECTED_UI_DERIVATION_PATH = "m/44'/0'/0'/0/0" +SIGNER_HEADER = b"HSM:SIGNER:5.2" +UI_HEADER = b"HSM:UI:5.2" @patch("sys.stdout.write") @@ -65,14 +71,14 @@ def setUp(self): ) self.pubkeys_hash = pubkeys_hash.digest() - self.ui_msg = b"HSM:UI:5.1" + \ + self.ui_msg = UI_HEADER + \ bytes.fromhex("aa"*32) + \ bytes.fromhex("bb"*33) + \ bytes.fromhex("cc"*32) + \ bytes.fromhex("0123") self.ui_hash = bytes.fromhex("ee" * 32) - self.signer_msg = b"HSM:SIGNER:5.1" + \ + self.signer_msg = SIGNER_HEADER + \ bytes.fromhex(self.pubkeys_hash.hex()) self.signer_hash = bytes.fromhex("ff" * 32) @@ -108,6 +114,7 @@ def test_verify_attestation(self, f"Authorized signer hash: {'cc'*32}", "Authorized signer iteration: 291", f"Installed UI hash: {'ee'*32}", + "Installed UI version: 5.2", ], fill="-", ) @@ -118,6 +125,7 @@ def test_verify_attestation(self, "", f"Hash: {self.pubkeys_hash.hex()}", f"Installed Signer hash: {'ff'*32}", + "Installed Signer version: 5.2", ], fill="-", ) @@ -276,3 +284,45 @@ def test_verify_attestation_invalid_signer_att(self, self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) self.assertEqual(("Invalid Signer attestation: error validating 'signer'"), str(e.exception)) + + def test_match_ui_message_header_valid_header(self, _): + valid_headers = [ + UI_HEADER, + b"HSM:UI:5.0", + b"HSM:UI:5.5", + b"HSM:UI:5.9", + ] + for header in valid_headers: + ui_message = header + self.ui_msg[len(UI_HEADER):] + self.assertTrue(match_ui_message_header(ui_message)) + + def test_match_ui_message_header_invalid_header(self, _): + invalid_headers = [ + SIGNER_HEADER, + b"HSM:UI:4.0", + b"HSM:UI:5.X", + ] + for header in invalid_headers: + ui_message = header + self.ui_msg[len(UI_HEADER):] + self.assertFalse(match_ui_message_header(ui_message)) + + def test_match_signer_message_header_valid_header(self, _): + valid_headers = [ + SIGNER_HEADER, + b"HSM:SIGNER:5.0", + b"HSM:SIGNER:5.5", + b"HSM:SIGNER:5.9", + ] + for header in valid_headers: + signer_message = header + self.signer_msg[len(SIGNER_HEADER):] + self.assertTrue(match_signer_message_header(signer_message)) + + def test_match_signer_message_header_invalid_header(self, _): + invalid_headers = [ + UI_HEADER, + b"HSM:SIGNER:4.0", + b"HSM:SIGNER:5.X", + ] + for header in invalid_headers: + signer_message = header + self.signer_msg[len(SIGNER_HEADER):] + self.assertFalse(match_signer_message_header(signer_message)) diff --git a/middleware/tests/ledger/test_protocol.py b/middleware/tests/ledger/test_protocol.py index 3efb7ea6..13de3f4f 100644 --- a/middleware/tests/ledger/test_protocol.py +++ b/middleware/tests/ledger/test_protocol.py @@ -49,7 +49,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 1, 0)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 2, 0)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM2ProtocolLedger(self.pin, self.dongle) diff --git a/middleware/tests/ledger/test_protocol_v1.py b/middleware/tests/ledger/test_protocol_v1.py index be1d0cab..9a98ee65 100644 --- a/middleware/tests/ledger/test_protocol_v1.py +++ b/middleware/tests/ledger/test_protocol_v1.py @@ -47,7 +47,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 1, 0)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 2, 0)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM1ProtocolLedger(self.pin, self.dongle)