Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
identity_edit_contact_name.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
35/* Includes ------------------------------------------------------------------*/
36#include <string.h>
37#include "os_utils.h"
38#include "os_apdu.h"
39#include "status_words.h"
40#include "tlv_library.h"
41#include "buffer.h"
42#include "bip32.h"
43#include "address_book.h"
45#include "address_book_crypto.h"
46#include "address_book_common.h"
47#include "identity.h"
48#include "io.h"
49#include "nbgl_use_case.h"
50
51#if defined(HAVE_ADDRESS_BOOK)
52
53/* Private defines------------------------------------------------------------*/
54#define STRUCT_VERSION 0x01
55
56/* Private types, structures, unions -----------------------------------------*/
57
58typedef struct {
59 edit_contact_name_t *edit;
60 TLV_reception_t received_tags;
61 uint8_t hmac_proof[CX_SHA256_SIZE];
62 uint8_t group_handle[GROUP_HANDLE_SIZE];
63} s_edit_contact_name_ctx;
64
65/* Private macros-------------------------------------------------------------*/
66#define EDIT_CONTACT_NAME_TAGS(X) \
67 X(0x01, TAG_STRUCTURE_TYPE, handle_struct_type, ENFORCE_UNIQUE_TAG) \
68 X(0x02, TAG_STRUCTURE_VERSION, handle_struct_version, ENFORCE_UNIQUE_TAG) \
69 X(0xf0, TAG_CONTACT_NAME, handle_contact_name, ENFORCE_UNIQUE_TAG) \
70 X(0xf3, TAG_PREVIOUS_NAME, handle_previous_name, ENFORCE_UNIQUE_TAG) \
71 X(0xf6, TAG_GROUP_HANDLE, handle_group_handle, ENFORCE_UNIQUE_TAG) \
72 X(0x29, TAG_HMAC_PROOF, handle_hmac_proof, ENFORCE_UNIQUE_TAG)
73
74/* Private variables ---------------------------------------------------------*/
75
76/* Private functions ---------------------------------------------------------*/
77
85static bool handle_struct_type(const tlv_data_t *data, s_edit_contact_name_ctx *context)
86{
87 UNUSED(context);
88 if (!tlv_enforce_u8_value(data, TYPE_EDIT_CONTACT_NAME)) {
89 PRINTF("[Edit Contact Name] Invalid STRUCTURE_TYPE value\n");
90 return false;
91 }
92 return true;
93}
94
102static bool handle_struct_version(const tlv_data_t *data, s_edit_contact_name_ctx *context)
103{
104 UNUSED(context);
105 if (!tlv_enforce_u8_value(data, STRUCT_VERSION)) {
106 PRINTF("[Edit Contact Name] Invalid STRUCTURE_VERSION value\n");
107 return false;
108 }
109 return true;
110}
111
119static bool handle_contact_name(const tlv_data_t *data, s_edit_contact_name_ctx *context)
120{
121 if (!address_book_handle_printable_string(
122 data, context->edit->contact_name, sizeof(context->edit->contact_name))) {
123 PRINTF("[Edit Contact Name] CONTACT_NAME: failed to parse\n");
124 return false;
125 }
126 return true;
127}
128
136static bool handle_previous_name(const tlv_data_t *data, s_edit_contact_name_ctx *context)
137{
138 if (!address_book_handle_printable_string(
139 data, context->edit->old_contact_name, sizeof(context->edit->old_contact_name))) {
140 PRINTF("[Edit Contact Name] PREVIOUS_CONTACT_NAME: failed to parse\n");
141 return false;
142 }
143 return true;
144}
145
153static bool handle_group_handle(const tlv_data_t *data, s_edit_contact_name_ctx *context)
154{
155 buffer_t buf = {0};
156 if (!get_buffer_from_tlv_data(data, &buf, GROUP_HANDLE_SIZE, GROUP_HANDLE_SIZE)) {
157 PRINTF("[Edit Contact Name] GROUP_HANDLE: invalid length (expected %d bytes)\n",
158 GROUP_HANDLE_SIZE);
159 return false;
160 }
161 memmove(context->group_handle, buf.ptr, GROUP_HANDLE_SIZE);
162 return true;
163}
164
172static bool handle_hmac_proof(const tlv_data_t *data, s_edit_contact_name_ctx *context)
173{
174 buffer_t buf = {0};
175 if (!get_buffer_from_tlv_data(data, &buf, CX_SHA256_SIZE, CX_SHA256_SIZE)) {
176 PRINTF("[Edit Contact Name] HMAC_PROOF: invalid length (expected %d bytes)\n",
177 CX_SHA256_SIZE);
178 return false;
179 }
180 memmove(context->hmac_proof, buf.ptr, CX_SHA256_SIZE);
181 return true;
182}
183
184DEFINE_TLV_PARSER(EDIT_CONTACT_NAME_TAGS, NULL, edit_contact_name_tlv_parser)
185
186
192static bool verify_fields(const s_edit_contact_name_ctx *context)
193{
194 bool result = TLV_CHECK_RECEIVED_TAGS(context->received_tags,
195 TAG_STRUCTURE_TYPE,
196 TAG_STRUCTURE_VERSION,
197 TAG_CONTACT_NAME,
198 TAG_PREVIOUS_NAME,
199 TAG_GROUP_HANDLE,
200 TAG_HMAC_PROOF);
201 if (!result) {
202 PRINTF("[Edit Contact Name] Missing mandatory fields!\n");
203 }
204 return result;
205}
206
213static void print_payload(const s_edit_contact_name_ctx *context)
214{
215 UNUSED(context);
216 PRINTF("****************************************************************************\n");
217 PRINTF("[Edit Contact Name] - Retrieved Descriptor:\n");
218 PRINTF("[Edit Contact Name] - Old name: %s\n", context->edit->old_contact_name);
219 PRINTF("[Edit Contact Name] - New name: %s\n", context->edit->contact_name);
220}
221
230static bool build_and_send_response(void)
231{
232 uint8_t hmac_proof[CX_SHA256_SIZE] = {0};
233
234 if (!address_book_compute_hmac_proof(g_ab_payload.edit_contact_name.gid,
235 g_ab_payload.edit_contact_name.contact_name,
236 hmac_proof)) {
237 PRINTF("[Edit Contact Name] Error: Failed to compute new HMAC_PROOF\n");
238 explicit_bzero(hmac_proof, sizeof(hmac_proof));
239 return false;
240 }
241
242 bool ok = address_book_send_hmac_proof(TYPE_EDIT_CONTACT_NAME, hmac_proof);
243 explicit_bzero(hmac_proof, sizeof(hmac_proof));
244 return ok;
245}
246
252static void review_choice(bool confirm)
253{
254 if (confirm) {
255 bool ok = build_and_send_response();
256 if (ok) {
257 on_edit_contact_name_applied(&g_ab_payload.edit_contact_name);
258 }
259 else {
260 PRINTF("[Edit Contact Name] Error: Failed to build and send HMAC proof\n");
261 }
262 address_book_finalize_review(
263 ok, "Contact name changed", "Error during update", finalize_ui_edit_contact_name);
264 }
265 else {
266 address_book_handle_review_rejected(finalize_ui_edit_contact_name);
267 }
268}
269
273static void ui_display(void)
274{
275 uint8_t nbPairs = 0;
276 memset(&g_ab_ui.list, 0, sizeof(g_ab_ui.list));
277 memset(g_ab_ui.pairs, 0, sizeof(g_ab_ui.pairs));
278 g_ab_ui.pairs[nbPairs].item = "Old name";
279 g_ab_ui.pairs[nbPairs].value = g_ab_payload.edit_contact_name.old_contact_name;
280 nbPairs++;
281 g_ab_ui.pairs[nbPairs].item = "New name";
282 g_ab_ui.pairs[nbPairs].value = g_ab_payload.edit_contact_name.contact_name;
283 nbPairs++;
284 g_ab_ui.list.pairs = g_ab_ui.pairs;
285 g_ab_ui.list.nbPairs = nbPairs;
286 address_book_display_review(&LARGE_ADDRESS_BOOK_ICON,
287 "Review change to contact details",
288#ifdef SCREEN_SIZE_WALLET
289 "Confirm change?",
290#else
291 "Confirm change",
292#endif
293 review_choice);
294}
295
296/* Exported functions --------------------------------------------------------*/
297
305bolos_err_t edit_contact_name(uint8_t *buffer_in, size_t buffer_in_length)
306{
307 const buffer_t payload = {.ptr = buffer_in, .size = buffer_in_length};
308 s_edit_contact_name_ctx ctx = {0};
309
310 // Init the structure
311 ctx.edit = &g_ab_payload.edit_contact_name;
312 memset(&g_ab_payload.edit_contact_name, 0, sizeof(g_ab_payload.edit_contact_name));
313
314 // Parse using SDK TLV parser
315 if (!edit_contact_name_tlv_parser(&payload, &ctx, &ctx.received_tags)) {
316 PRINTF("[Edit Contact Name] TLV parsing failed\n");
317 return SWO_INCORRECT_DATA;
318 }
319 if (!verify_fields(&ctx)) {
320 return SWO_INCORRECT_DATA;
321 }
322 print_payload(&ctx);
323
324 // Verify the group handle and extract the gid
325 if (!address_book_verify_group_handle(ctx.group_handle, g_ab_payload.edit_contact_name.gid)) {
326 PRINTF("[Edit Contact Name] Group handle verification failed\n");
327 return SWO_SECURITY_CONDITION_NOT_SATISFIED;
328 }
329
330 // Verify the wallet holds a valid HMAC_PROOF for the previous name
331 if (!address_book_verify_hmac_proof(g_ab_payload.edit_contact_name.gid,
332 g_ab_payload.edit_contact_name.old_contact_name,
333 ctx.hmac_proof)) {
334 PRINTF("[Edit Contact Name] HMAC_PROOF verification failed\n");
335 return SWO_SECURITY_CONDITION_NOT_SATISFIED;
336 }
337
338 // Display confirmation UI
339 ui_display();
340 return SWO_NO_RESPONSE;
341}
342
343#endif // HAVE_ADDRESS_BOOK
Register / Edit Contact Name / Edit Scope / Edit Identifier.
API of the Advanced BOLOS Graphical Library, for typical application use-cases.
uint8_t * ptr
Definition buffer.h:22
bool tlv_enforce_u8_value(const tlv_data_t *data, uint8_t expected_value)
Enforce that a TLV data contains the expected uint8 value.
Definition tlv_library.c:38
bool get_buffer_from_tlv_data(const tlv_data_t *data, buffer_t *out, uint16_t min_size, uint16_t max_size)
Extract a sized buffer from TLV data (zero-copy).
#define DEFINE_TLV_PARSER(TAG_LIST, COMMON_HANDLER, PARSE_FUNCTION_NAME)
Creates a parser function for a given TLV use case.
#define TLV_CHECK_RECEIVED_TAGS(received,...)