diff --git a/app/src/apdu_sign.c b/app/src/apdu_sign.c index c44b96aed..d10c59962 100644 --- a/app/src/apdu_sign.c +++ b/app/src/apdu_sign.c @@ -153,6 +153,7 @@ refill() tz_parser_state *st = &global.apdu.sign.u.clear.parser_state; TZ_PREAMBLE(("void")); +skip: while (!TZ_IS_BLOCKED(tz_operation_parser_step(st))) ; PRINTF("[DEBUG] refill(errno: %s) \n", tz_parser_result_name(st->errno)); @@ -165,6 +166,13 @@ refill() tz_parser_flush_up_to(st, global.line_buf, TZ_UI_STREAM_CONTENTS_SIZE, wrote); + + // Do as much parsing as we can in one go when skipping. + // TODO: perhaps when skipping we could only skip the current + // operation, rather than the whole rest-of-batch + if (global.apdu.sign.u.clear.skip_to_sign) + goto skip; + break; case TZ_BLO_FEED_ME: TZ_CHECK(send_continue()); diff --git a/app/src/apdu_sign.h b/app/src/apdu_sign.h index c509c6bea..d08f884e3 100644 --- a/app/src/apdu_sign.h +++ b/app/src/apdu_sign.h @@ -50,6 +50,7 @@ typedef struct { struct { size_t total_length; tz_parser_state parser_state; + bool skip_to_sign; } clear; struct { uint8_t tag; diff --git a/app/src/ui_stream.c b/app/src/ui_stream.c index 280ebb5d3..4d222c16f 100644 --- a/app/src/ui_stream.c +++ b/app/src/ui_stream.c @@ -62,6 +62,7 @@ tz_ui_stream_push_accept_reject(void) FUNC_LEAVE(); } +#ifdef HAVE_BAGL void tz_ui_stream_close() { @@ -75,6 +76,7 @@ tz_ui_stream_close() s->full = true; FUNC_LEAVE(); } +#endif // HAVE_BAGL uint8_t tz_ui_max_line_chars(const char *value, int length) diff --git a/app/src/ui_stream_nbgl.c b/app/src/ui_stream_nbgl.c index 40d271838..d92fd0f71 100644 --- a/app/src/ui_stream_nbgl.c +++ b/app/src/ui_stream_nbgl.c @@ -150,6 +150,25 @@ tz_ui_current_screen(__attribute__((unused)) uint8_t pairIndex) return &c->pair; } +void +tz_ui_stream_close() +{ + tz_ui_stream_t *s = &global.stream; + + FUNC_ENTER(("void")); + if (s->full) { + PRINTF("trying to close already closed stream display"); + THROW(EXC_UNKNOWN); + } + s->full = true; + + if (global.apdu.sign.u.clear.skip_to_sign) { + tz_ui_start(); + } + + FUNC_LEAVE(); +} + bool tz_ui_nav_cb(uint8_t page, nbgl_pageContent_t *content) { @@ -169,11 +188,17 @@ tz_ui_nav_cb(uint8_t page, nbgl_pageContent_t *content) PRINTF("pressed_right=%d, current=%d, total=%d, full=%d\n", s->pressed_right, s->current, s->total, s->full); + if (page == LAST_PAGE_FOR_REVIEW) { + // skipped + PRINTF("Skip requested"); + global.apdu.sign.u.clear.skip_to_sign = true; + tz_ui_continue(); + } if ((s->current == s->total) && !s->full) { tz_ui_continue(); } - if (!s->full) { + if (!s->full && !global.apdu.sign.u.clear.skip_to_sign) { c->list.pairs = NULL; c->list.callback = tz_ui_current_screen; c->list.startIndex = 0; diff --git a/tests/integration/stax/snapshots/skip_to_signing.png b/tests/integration/stax/snapshots/skip_to_signing.png new file mode 100644 index 000000000..a4eb4501a Binary files /dev/null and b/tests/integration/stax/snapshots/skip_to_signing.png differ diff --git a/tests/integration/stax/test_sign_execute_outbox_messages_skip.py b/tests/integration/stax/test_sign_execute_outbox_messages_skip.py new file mode 100755 index 000000000..0d9257691 --- /dev/null +++ b/tests/integration/stax/test_sign_execute_outbox_messages_skip.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# Copyright 2023 Trilitech + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from utils import * + +# full input: 0000000000000000000000000000000000000000000000000000000000000000ce00ffdd6102321bc251e4a5190ad5b12b251069d9b4904e02030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c6396630396632393532643334353238633733336639343631356366633339626335353536313966633535306464346136376261323230386365386538363761613364313361366566393964666265333263363937346161396132313530643231656361323963333334396535396331336239303831663163313162343430616334643334353564656462653465653064653135613861663632306434633836323437643964313332646531626236646132336435666639643864666664613232626139613834 +# signer: tz1dyX3B1CFYa2DfdFLyPtiJCfQRUgPVME6E + +if __name__ == "__main__": + app = stax_app() + + app.assert_screen(SCREEN_HOME_DEFAULT) + + app.send_apdu("800f000011048000002c800006c18000000080000000"); + app.expect_apdu_return("9000"); + + app.assert_screen("review_request_sign_operation"); + + app.send_apdu("800f0100eb030000000000000000000000000000000000000000000000000000000000000000ce00ffdd6102321bc251e4a5190ad5b12b251069d9b4904e02030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c63966303966323935326433343532386337333366393436313563666333396263353535363139666335353064643461363762613232303863653865383637616133643133613665663939646662653332633639373461613961323135306432316563613239633333343965353963313362393038316631"); + + app.review.tap() + app.assert_screen("operation_0_sr_outbox") + + app.review_skip_to_signing() + + app.expect_apdu_return("9000") + app.send_apdu("800f82004f63313162343430616334643334353564656462653465653064653135613861663632306434633836323437643964313332646531626236646132336435666639643864666664613232626139613834") + + app.assert_screen("operation_sign") + + expected_apdu = "c08f5e1a02d15b05c4066b43fc31aa1ccad30f6c7a18f44723e5af0b6584292236e919219e90793ef502e8883f5317206277607438695933fcb954f4ef451db19628a114880836193c755ddda4bf188b9764231975b2c5ecb64bc4bdc9c459039000" + app.review_confirm_signing(expected_apdu) + + app.assert_screen(SCREEN_HOME_DEFAULT) + app.welcome.quit() diff --git a/tests/integration/stax/test_sign_transfer_skip.py b/tests/integration/stax/test_sign_transfer_skip.py new file mode 100755 index 000000000..681f86994 --- /dev/null +++ b/tests/integration/stax/test_sign_transfer_skip.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# Copyright 2023 Trilitech + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from utils import * + +# full input: 0300000000000000000000000000000000000000000000000000000000000000006c016e8874874d31c3fbd636e924d5a036a43ec8faa7d0860308362d80d30e01000000000000000000000000000000000000000000ff02000000020316 +# full output: CAR +# signer: tz1dyX3B1CFYa2DfdFLyPtiJCfQRUgPVME6E +# path: m/44'/1729'/0'/0' + +if __name__ == "__main__": + app = stax_app() + + app.assert_screen(SCREEN_HOME_DEFAULT) + + app.send_apdu("800f000011048000002c800006c18000000080000000"); + app.expect_apdu_return("9000"); + + app.assert_screen("review_request_sign_operation"); + + app.send_apdu("800f81005e0300000000000000000000000000000000000000000000000000000000000000006c016e8874874d31c3fbd636e924d5a036a43ec8faa7d0860308362d80d30e01000000000000000000000000000000000000000000ff02000000020316"); + + app.review.tap() + app.assert_screen("operation_0_transaction") + + app.review_skip_to_signing() + app.assert_screen("operation_sign") + + expected_apdu = "f6d5fa0e79cac216e25104938ac873ca17ee9d7f06763719293b413cf2ed475cf63d045a1cc9f73eee5775c5d496fa9d3aa9ae57fb97217f746a8728639795b7b2220e84ce5759ed111399ea3263d810c230d6a4fffcb6e82797c5ca673a17089000" + + app.review_confirm_signing(expected_apdu) + + app.assert_screen(SCREEN_HOME_DEFAULT) + app.welcome.quit() diff --git a/tests/integration/stax/utils.py b/tests/integration/stax/utils.py index ef7e39511..1f8a6db60 100644 --- a/tests/integration/stax/utils.py +++ b/tests/integration/stax/utils.py @@ -21,6 +21,7 @@ from ragger.firmware.stax.screen import MetaScreen from ragger.firmware.stax.use_cases import UseCaseHomeExt, UseCaseSettings, UseCaseAddressConfirmation, UseCaseReview from ragger.firmware.stax.layouts import ChoiceList +from ragger.firmware.stax.positions import BUTTON_LOWER_LEFT, BUTTON_LOWER_RIGHT, BUTTON_ABOVE_LOWER_MIDDLE MAX_ATTEMPTS = 100 @@ -122,6 +123,11 @@ def review_reject_signing(self): self.review.tap() self.welcome.client.resume_ticker() + def review_skip_to_signing(self): + self.welcome.client.finger_touch(BUTTON_LOWER_RIGHT.x, BUTTON_LOWER_RIGHT.y) + self.assert_screen("skip_to_signing") + self.welcome.client.finger_touch(BUTTON_ABOVE_LOWER_MIDDLE.x, BUTTON_ABOVE_LOWER_MIDDLE.y) + def stax_app() -> TezosAppScreen: port = os.environ["PORT"] golden = os.getenv("GOLDEN") != None