SFT-3834: added verify step for microsd message signing, fixed export format for sparrow parsing
What changed, and why it matters
This firmware update fixes two issues in the Passport hardware wallet's message-signing feature. First, it adds a user confirmation screen when signing a message from a microSD card in normal (non-health-check) mode, so the user can see the message and the address that will sign it before approving. Second, it corrects the exported message signature text format so wallet software like Sparrow can parse it properly. Previously, the signature block used generic BEGIN/END SIGNATURE labels instead of blockchain-specific ones, which could cause import failures.
Apply the firmware update. If running older firmware, avoid signing untrusted messages from microSD in normal mode without verifying the expected signing address through another channel, and verify exported signed messages manually before sharing them with external wallet software.
Security signals we found
Missing user confirmation before signing from microSD in normal mode
Address not shown to user prior to signature production
Exported signed-message format used mismatched/ambiguous delimiters
Patch adds explicit verify step and fixes delimiter constants
Evidence from the diff
In health_check_common_flow.py, the patch introduces a new show_message() async step that is invoked when self.normal_signing is true. It derives the signing address from the chosen subpath, displays the message text via LongTextPage, then asks the user to confirm signing with the derived address via LongQuestionPage. Only after confirmation does it proceed to sign_health_check(). In public_constants.py, the RFC_SIGNATURE_TEMPLATE is updated so the signature delimiters are ‘-----BEGIN {blockchain} SIGNATURE-----’ and ‘-----END {blockchain} SIGNATURE-----’ rather than the previous ‘-----BEGIN SIGNATURE-----’ / ‘-----END {blockchain} SIGNED MESSAGE-----’ mismatch. This aligns the exported signed-message format with the expected RFC-style structure for Sparrow and similar parsers.
Changed components
ports/stm32/boards/Passport/modules/flows/health_check_common_flow.pyports/stm32/boards/Passport/modules/public_constants.pyPassport firmware message-signing flowmicroSD message signing featureInspect captured patch +41 / −2
diff --git a/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py b/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py
index 58a7f82..6b028d1 100644
--- a/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py
+++ b/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py
@@ -42,6 +42,45 @@ class HealthCheckCommonFlow(Flow):
return
self.subpath = subpath
+
+ # User Interaction for non-health check signing
+ if self.normal_signing:
+ self.goto(self.show_message)
+ return
+
+ self.goto(self.sign_health_check)
+
+
+ async def show_message(self):
+ import stash
+ from utils import stylize_address
+ from pages import LongTextPage, LongQuestionPage
+ import microns
+ from public_constants import MARGIN_FOR_ADDRESSES
+
+ with stash.SensitiveValues() as sv:
+ node = sv.derive_path(self.subpath)
+ self.address = sv.chain.address(node, self.addr_type)
+
+ self.address = stylize_address(self.address)
+
+ result = await LongTextPage(centered=True,
+ text=('\n' + self.text),
+ card_header={'title': 'Message'}).show()
+
+ if not result:
+ self.set_result(False)
+ return
+
+ result = await LongQuestionPage(text='Sign message with this address?\n\n{}'.format(self.address),
+ right_micron=microns.Sign,
+ margins=MARGIN_FOR_ADDRESSES,
+ top_margin=8).show()
+
+ if not result:
+ self.set_result(False)
+ return
+
self.goto(self.sign_health_check)
async def sign_health_check(self):
diff --git a/ports/stm32/boards/Passport/modules/public_constants.py b/ports/stm32/boards/Passport/modules/public_constants.py
index 7f704fb..e7e33ff 100644
--- a/ports/stm32/boards/Passport/modules/public_constants.py
+++ b/ports/stm32/boards/Passport/modules/public_constants.py
@@ -146,10 +146,10 @@ NUM_DIGITS_FOR_SECURITY_WORDS = const(4)
RFC_SIGNATURE_TEMPLATE = '''\
-----BEGIN {blockchain} SIGNED MESSAGE-----
{msg}
------BEGIN SIGNATURE-----
+-----BEGIN {blockchain} SIGNATURE-----
{addr}
{sig}
------END {blockchain} SIGNED MESSAGE-----
+-----END {blockchain} SIGNATURE-----
'''
MULTISIG_EXPORT_TEMPLATE = '''\
Why this scored 34/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.