Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
address_book.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2026 Ledger SAS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
43/* Includes ------------------------------------------------------------------*/
44#include <string.h>
45#include "os_apdu.h"
46#include "os_helpers.h"
47#include "os_print.h"
48#include "os_utils.h"
49#include "address_book.h"
50#include "status_words.h"
51#include "identity.h"
52#ifdef HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
53#include "ledger_account.h"
54#endif
55
56#if defined(HAVE_ADDRESS_BOOK)
57
58/* Private defines------------------------------------------------------------*/
59#define P1_REGISTER_IDENTITY 0x01
60#define P1_EDIT_CONTACT_NAME 0x02
61#define P1_EDIT_IDENTIFIER 0x03
62#define P1_EDIT_SCOPE 0x04
63#define P1_PROVIDE_CONTACT 0x20
64
65#ifdef HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
66#define P1_REGISTER_LEDGER_ACCOUNT 0x11
67#define P1_EDIT_LEDGER_ACCOUNT 0x12
68#define P1_PROVIDE_LEDGER_ACCOUNT_CONTACT 0x21
69#endif
70
72#define P2_FIRST_CHUNK 0x00
74#define P2_NEXT_CHUNK 0x80
75
86#ifdef CUSTOM_IO_APDU_BUFFER_SIZE
87#define ADDRESS_BOOK_MAX_CHUNKED_PAYLOAD (CUSTOM_IO_APDU_BUFFER_SIZE - 3 - 5)
88#else
89#define ADDRESS_BOOK_MAX_CHUNKED_PAYLOAD (OS_IO_SEPH_BUFFER_SIZE - 3 - 5)
90#endif
91
92/* Private types, structures, unions -----------------------------------------*/
93typedef enum {
94 REASSEMBLY_PENDING,
95 REASSEMBLY_COMPLETE,
96 REASSEMBLY_ERROR,
97} reassembly_status_t;
98
99/* Private variables ---------------------------------------------------------*/
100static uint8_t s_chunk_buf[ADDRESS_BOOK_MAX_CHUNKED_PAYLOAD] = {0};
101static uint16_t s_chunk_total = 0;
102static uint16_t s_chunk_received = 0;
103
104/* Private functions ---------------------------------------------------------*/
105
120static reassembly_status_t reassemble_chunks(uint8_t *data,
121 size_t len,
122 uint8_t p2,
123 uint8_t **out_buf,
124 size_t *out_len)
125{
126 if (p2 == P2_FIRST_CHUNK) {
127 if (len < 2) {
128 PRINTF("[Address Book] First chunk too short (no length header)\n");
129 return REASSEMBLY_ERROR;
130 }
131 s_chunk_total = U2BE(data, 0);
132 s_chunk_received = 0;
133 data += 2;
134 len -= 2;
135 if (s_chunk_total == 0 || s_chunk_total > sizeof(s_chunk_buf)) {
136 PRINTF("[Address Book] Invalid total length: %u\n", s_chunk_total);
137 s_chunk_total = 0;
138 return REASSEMBLY_ERROR;
139 }
140 }
141 else {
142 if (s_chunk_total == 0) {
143 PRINTF("[Address Book] Unexpected continuation chunk\n");
144 return REASSEMBLY_ERROR;
145 }
146 }
147
148 if ((s_chunk_received > s_chunk_total) || (len > (s_chunk_total - s_chunk_received))) {
149 PRINTF(
150 "[Address Book] Chunk overflow: %u + %zu > %u\n", s_chunk_received, len, s_chunk_total);
151 s_chunk_total = 0;
152 return REASSEMBLY_ERROR;
153 }
154 memmove(s_chunk_buf + s_chunk_received, data, len);
155 s_chunk_received += (uint16_t) len;
156
157 if (s_chunk_received < s_chunk_total) {
158 return REASSEMBLY_PENDING;
159 }
160
161 *out_buf = s_chunk_buf;
162 *out_len = s_chunk_received;
163 s_chunk_total = 0;
164 return REASSEMBLY_COMPLETE;
165}
166
167/* Exported functions --------------------------------------------------------*/
168bolos_err_t addr_book_handle_apdu(uint8_t *buffer, size_t buffer_len, uint8_t p1, uint8_t p2)
169{
170 bolos_err_t err = SWO_CONDITIONS_NOT_SATISFIED;
171 uint8_t *payload = NULL;
172 size_t payload_len = 0;
173
174 switch (p1) {
175 case P1_REGISTER_IDENTITY:
176 err = register_identity(buffer, buffer_len);
177 break;
178
179 case P1_EDIT_CONTACT_NAME:
180 err = edit_contact_name(buffer, buffer_len);
181 break;
182
183 case P1_EDIT_IDENTIFIER:
184 switch (reassemble_chunks(buffer, buffer_len, p2, &payload, &payload_len)) {
185 case REASSEMBLY_ERROR:
186 err = SWO_INCORRECT_DATA;
187 break;
188 case REASSEMBLY_PENDING:
189 err = SWO_SUCCESS;
190 break;
191 case REASSEMBLY_COMPLETE:
192 err = edit_identifier(payload, payload_len);
193 break;
194 }
195 break;
196
197 case P1_EDIT_SCOPE:
198 switch (reassemble_chunks(buffer, buffer_len, p2, &payload, &payload_len)) {
199 case REASSEMBLY_ERROR:
200 err = SWO_INCORRECT_DATA;
201 break;
202 case REASSEMBLY_PENDING:
203 err = SWO_SUCCESS;
204 break;
205 case REASSEMBLY_COMPLETE:
206 err = edit_scope(payload, payload_len);
207 break;
208 }
209 break;
210
211#ifdef HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
212 case P1_REGISTER_LEDGER_ACCOUNT:
213 err = register_ledger_account(buffer, buffer_len);
214 break;
215
216 case P1_EDIT_LEDGER_ACCOUNT:
217 err = edit_ledger_account(buffer, buffer_len);
218 break;
219#endif // HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
220
221 case P1_PROVIDE_CONTACT:
222 switch (reassemble_chunks(buffer, buffer_len, p2, &payload, &payload_len)) {
223 case REASSEMBLY_ERROR:
224 err = SWO_INCORRECT_DATA;
225 break;
226 case REASSEMBLY_PENDING:
227 err = SWO_SUCCESS;
228 break;
229 case REASSEMBLY_COMPLETE:
230 err = provide_contact(payload, payload_len);
231 break;
232 }
233 break;
234
235#ifdef HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
236 case P1_PROVIDE_LEDGER_ACCOUNT_CONTACT:
237 switch (reassemble_chunks(buffer, buffer_len, p2, &payload, &payload_len)) {
238 case REASSEMBLY_ERROR:
239 err = SWO_INCORRECT_DATA;
240 break;
241 case REASSEMBLY_PENDING:
242 err = SWO_SUCCESS;
243 break;
244 case REASSEMBLY_COMPLETE:
245 err = provide_ledger_account_contact(payload, payload_len);
246 break;
247 }
248 break;
249#endif // HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
250
251 default:
252 break;
253 }
254
255 return err;
256}
257#endif // HAVE_ADDRESS_BOOK
bolos_err_t addr_book_handle_apdu(uint8_t *buffer, size_t buffer_len, uint8_t p1, uint8_t p2)
Register / Edit Contact Name / Edit Scope / Edit Identifier.
bolos_err_t provide_ledger_account_contact(uint8_t *buffer_in, size_t buffer_in_length)
bolos_err_t register_ledger_account(uint8_t *buffer_in, size_t buffer_in_length)
bolos_err_t edit_ledger_account(uint8_t *buffer_in, size_t buffer_in_length)