Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include <string.h>
26 :
27 : #include "hal/platform.h"
28 : #include "hal/exceptions.h"
29 :
30 : #include "auth.h"
31 : #include "err.h"
32 : #include "mem.h"
33 : #include "compiletime.h"
34 : #include "util.h"
35 :
36 : #include "hal/log.h"
37 :
38 : /*
39 : * Transition to the given state, performing corresponding
40 : * initializations.
41 : *
42 : * @arg[in] state the state to transition to
43 : */
44 230 : void auth_transition_to(uint8_t state) {
45 230 : if (state == STATE_AUTH_START)
46 40 : memset(&auth, 0, sizeof(auth));
47 :
48 230 : auth.state = state;
49 :
50 : // Init shared state
51 230 : memset(&auth.tx, 0, sizeof(auth.tx));
52 230 : memset(&auth.receipt, 0, sizeof(auth.receipt));
53 230 : memset(&auth.trie, 0, sizeof(auth.trie));
54 230 : }
55 :
56 : /*
57 : * Implement the signing authorization protocol.
58 : *
59 : * @arg[in] rx number of received bytes from the host
60 : * @ret number of transmited bytes to the host
61 : */
62 2682 : unsigned int auth_sign(volatile unsigned int rx) {
63 : unsigned int tx;
64 : uint8_t sig_size;
65 :
66 : // Sanity check: tx hash size and
67 : // last auth signed tx hash size
68 : // must match
69 : COMPILE_TIME_ASSERT(sizeof(N_bc_state.last_auth_signed_btc_tx_hash) ==
70 : sizeof(auth.tx_hash));
71 :
72 : // Check we receive the amount of bytes we requested
73 : // (this is an extra check on the legacy protocol, not
74 : // really adding much validation)
75 2682 : if (auth.state != STATE_AUTH_START &&
76 2604 : auth.state != STATE_AUTH_MERKLEPROOF &&
77 2522 : APDU_DATA_SIZE(rx) != auth.expected_bytes)
78 0 : THROW(ERR_AUTH_INVALID_DATA_SIZE);
79 :
80 2682 : switch (APDU_OP() & 0xF) {
81 78 : case P1_PATH:
82 78 : if ((tx = auth_sign_handle_path(rx)) == 0)
83 8 : break;
84 58 : return tx;
85 2184 : case P1_BTC:
86 2184 : return auth_sign_handle_btctx(rx);
87 338 : case P1_RECEIPT:
88 338 : return auth_sign_handle_receipt(rx);
89 82 : case P1_MERKLEPROOF:
90 82 : if ((tx = auth_sign_handle_merkleproof(rx)) == 0)
91 32 : break;
92 40 : return tx;
93 0 : default:
94 : // Invalid OP
95 0 : THROW(ERR_AUTH_INVALID_DATA_SIZE);
96 : }
97 :
98 40 : if (auth.state != STATE_AUTH_SIGN)
99 0 : THROW(ERR_AUTH_INVALID_STATE); // Invalid state
100 :
101 40 : sig_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
102 40 : if (!seed_sign(auth.path,
103 : sizeof(auth.path) / sizeof(auth.path[0]),
104 : auth.sig_hash,
105 40 : APDU_DATA_PTR,
106 : &sig_size)) {
107 0 : THROW(ERR_INTERNAL);
108 : }
109 40 : tx = sig_size;
110 :
111 : // Save the BTC tx hash to NVM if this signature required authorization
112 40 : if (auth.auth_required) {
113 : // Avoid rewriting the same value to NVM multiple times
114 32 : if (memcmp(N_bc_state.last_auth_signed_btc_tx_hash,
115 : auth.tx_hash,
116 : sizeof(auth.tx_hash))) {
117 13 : NVM_WRITE(N_bc_state.last_auth_signed_btc_tx_hash,
118 : auth.tx_hash,
119 : sizeof(N_bc_state.last_auth_signed_btc_tx_hash));
120 :
121 : // Log hash for debugging purposes
122 13 : LOG_HEX("Saved BTC tx hash: ", auth.tx_hash, sizeof(auth.tx_hash));
123 : } else {
124 : // Log (already saved) hash for debugging purposes
125 19 : LOG_HEX("Did not rewrite already saved BTC tx hash: ",
126 : auth.tx_hash,
127 : sizeof(auth.tx_hash));
128 : }
129 : }
130 :
131 40 : SET_APDU_OP(P1_SUCCESS);
132 40 : auth_transition_to(STATE_AUTH_START);
133 40 : return TX_FOR_DATA_SIZE(tx);
134 : }
|