Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
identity_provide_contact.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
40/* Includes ------------------------------------------------------------------*/
41#include <string.h>
42#include "os_utils.h"
43#include "status_words.h"
44#include "tlv_library.h"
45#include "buffer.h"
46#include "bip32.h"
47#include "address_book.h"
49#include "address_book_crypto.h"
50#include "address_book_common.h"
51#include "identity.h"
52
53#if defined(HAVE_ADDRESS_BOOK)
54
55/* Private defines------------------------------------------------------------*/
56#define STRUCT_VERSION 0x01
57
58/* Private types, structures, unions -----------------------------------------*/
59typedef struct {
60 identity_t *identity;
61 TLV_reception_t received_tags;
62 uint8_t hmac_proof[CX_SHA256_SIZE];
63 uint8_t hmac_rest[CX_SHA256_SIZE];
64 uint8_t group_handle[GROUP_HANDLE_SIZE];
65} s_provide_contact_ctx;
66
67/* Private macros-------------------------------------------------------------*/
68#define PROVIDE_CONTACT_TAGS(X) \
69 X(0x01, TAG_STRUCTURE_TYPE, handle_struct_type, ENFORCE_UNIQUE_TAG) \
70 X(0x02, TAG_STRUCTURE_VERSION, handle_struct_version, ENFORCE_UNIQUE_TAG) \
71 X(0xf0, TAG_CONTACT_NAME, handle_contact_name, ENFORCE_UNIQUE_TAG) \
72 X(0xf1, TAG_SCOPE, handle_scope, ENFORCE_UNIQUE_TAG) \
73 X(0xf2, TAG_ACCOUNT_IDENTIFIER, handle_identifier, ENFORCE_UNIQUE_TAG) \
74 X(0xf6, TAG_GROUP_HANDLE, handle_group_handle, ENFORCE_UNIQUE_TAG) \
75 X(0x21, TAG_DERIVATION_PATH, handle_derivation_path, ENFORCE_UNIQUE_TAG) \
76 X(0x23, TAG_CHAIN_ID, handle_chain_id, ENFORCE_UNIQUE_TAG) \
77 X(0x51, TAG_BLOCKCHAIN_FAMILY, handle_blockchain_family, ENFORCE_UNIQUE_TAG) \
78 X(0x29, TAG_HMAC_PROOF, handle_hmac_proof, ENFORCE_UNIQUE_TAG) \
79 X(0xf7, TAG_HMAC_REST, handle_hmac_rest, ENFORCE_UNIQUE_TAG)
80
81/* Private variables ---------------------------------------------------------*/
82
83/* Private functions ---------------------------------------------------------*/
84
92static bool handle_struct_type(const tlv_data_t *data, s_provide_contact_ctx *context)
93{
94 UNUSED(context);
95 if (!tlv_enforce_u8_value(data, TYPE_PROVIDE_CONTACT)) {
96 PRINTF("[Provide Contact] Invalid STRUCTURE_TYPE value\n");
97 return false;
98 }
99 return true;
100}
101
109static bool handle_struct_version(const tlv_data_t *data, s_provide_contact_ctx *context)
110{
111 UNUSED(context);
112 if (!tlv_enforce_u8_value(data, STRUCT_VERSION)) {
113 PRINTF("[Provide Contact] Invalid STRUCTURE_VERSION value\n");
114 return false;
115 }
116 return true;
117}
118
126static bool handle_contact_name(const tlv_data_t *data, s_provide_contact_ctx *context)
127{
128 if (!address_book_handle_printable_string(
129 data, context->identity->contact_name, sizeof(context->identity->contact_name))) {
130 PRINTF("[Provide Contact] CONTACT_NAME: failed to parse\n");
131 return false;
132 }
133 return true;
134}
135
143static bool handle_scope(const tlv_data_t *data, s_provide_contact_ctx *context)
144{
145 if (!address_book_handle_printable_string(
146 data, context->identity->scope, sizeof(context->identity->scope))) {
147 PRINTF("[Provide Contact] SCOPE: failed to parse\n");
148 return false;
149 }
150 return true;
151}
152
160static bool handle_identifier(const tlv_data_t *data, s_provide_contact_ctx *context)
161{
162 buffer_t buf = {0};
163 if (!get_buffer_from_tlv_data(data, &buf, 1, IDENTIFIER_MAX_LENGTH)) {
164 PRINTF("[Provide Contact] IDENTIFIER: failed to extract\n");
165 return false;
166 }
167 memmove(context->identity->identifier, buf.ptr, buf.size);
168 context->identity->identifier_len = (uint8_t) buf.size;
169 return true;
170}
171
179static bool handle_group_handle(const tlv_data_t *data, s_provide_contact_ctx *context)
180{
181 buffer_t buf = {0};
182 if (!get_buffer_from_tlv_data(data, &buf, GROUP_HANDLE_SIZE, GROUP_HANDLE_SIZE)) {
183 PRINTF("[Provide Contact] GROUP_HANDLE: invalid length (expected %d bytes)\n",
184 GROUP_HANDLE_SIZE);
185 return false;
186 }
187 memmove(context->group_handle, buf.ptr, GROUP_HANDLE_SIZE);
188 return true;
189}
190
198static bool handle_derivation_path(const tlv_data_t *data, s_provide_contact_ctx *context)
199{
200 return address_book_handle_derivation_path(data, &context->identity->bip32_path);
201}
202
210static bool handle_chain_id(const tlv_data_t *data, s_provide_contact_ctx *context)
211{
212 return address_book_handle_chain_id(data, &context->identity->chain_id);
213}
214
222static bool handle_blockchain_family(const tlv_data_t *data, s_provide_contact_ctx *context)
223{
224 return address_book_handle_blockchain_family(data, &context->identity->blockchain_family);
225}
226
234static bool handle_hmac_proof(const tlv_data_t *data, s_provide_contact_ctx *context)
235{
236 buffer_t buf = {0};
237 if (!get_buffer_from_tlv_data(data, &buf, CX_SHA256_SIZE, CX_SHA256_SIZE)) {
238 PRINTF("[Provide Contact] HMAC_PROOF: invalid length (expected %d bytes)\n",
239 CX_SHA256_SIZE);
240 return false;
241 }
242 memmove(context->hmac_proof, buf.ptr, CX_SHA256_SIZE);
243 return true;
244}
245
253static bool handle_hmac_rest(const tlv_data_t *data, s_provide_contact_ctx *context)
254{
255 buffer_t buf = {0};
256 if (!get_buffer_from_tlv_data(data, &buf, CX_SHA256_SIZE, CX_SHA256_SIZE)) {
257 PRINTF("[Provide Contact] HMAC_REST: invalid length (expected %d bytes)\n", CX_SHA256_SIZE);
258 return false;
259 }
260 memmove(context->hmac_rest, buf.ptr, CX_SHA256_SIZE);
261 return true;
262}
263
264DEFINE_TLV_PARSER(PROVIDE_CONTACT_TAGS, NULL, provide_contact_tlv_parser)
265
266
272static bool verify_fields(const s_provide_contact_ctx *context)
273{
274 bool result = TLV_CHECK_RECEIVED_TAGS(context->received_tags,
275 TAG_STRUCTURE_TYPE,
276 TAG_STRUCTURE_VERSION,
277 TAG_CONTACT_NAME,
278 TAG_SCOPE,
279 TAG_ACCOUNT_IDENTIFIER,
280 TAG_GROUP_HANDLE,
281 TAG_DERIVATION_PATH,
282 TAG_BLOCKCHAIN_FAMILY,
283 TAG_HMAC_PROOF,
284 TAG_HMAC_REST);
285 if (!result) {
286 PRINTF("[Provide Contact] Missing mandatory fields!\n");
287 return false;
288 }
289 if (context->identity->blockchain_family == FAMILY_ETHEREUM) {
290 result = TLV_CHECK_RECEIVED_TAGS(context->received_tags, TAG_CHAIN_ID);
291 if (!result) {
292 PRINTF("[Provide Contact] Missing CHAIN_ID for Ethereum family!\n");
293 return false;
294 }
295 }
296 return true;
297}
298
305static void print_payload(const s_provide_contact_ctx *context)
306{
307 UNUSED(context);
308 PRINTF("****************************************************************************\n");
309 PRINTF("[Provide Contact] - Retrieved Descriptor:\n");
310 PRINTF("[Provide Contact] - Contact name: %s\n", context->identity->contact_name);
311 if (context->identity->scope[0] != '\0') {
312 PRINTF("[Provide Contact] - Scope: %s\n", context->identity->scope);
313 }
314 PRINTF("[Provide Contact] - Identifier len: %d\n", context->identity->identifier_len);
315 PRINTF("[Provide Contact] - Blockchain: %s\n",
316 FAMILY_AS_STR(context->identity->blockchain_family));
317}
318
319/* Exported functions --------------------------------------------------------*/
320
331bolos_err_t provide_contact(uint8_t *buffer_in, size_t buffer_in_length)
332{
333 const buffer_t payload = {.ptr = buffer_in, .size = buffer_in_length};
334 s_provide_contact_ctx ctx = {0};
335
336 // Init the structure
337 ctx.identity = &g_ab_payload.provide_contact;
338 memset(&g_ab_payload.provide_contact, 0, sizeof(g_ab_payload.provide_contact));
339
340 // Parse using SDK TLV parser
341 if (!provide_contact_tlv_parser(&payload, &ctx, &ctx.received_tags)) {
342 PRINTF("[Provide Contact] TLV parsing failed\n");
343 return SWO_INCORRECT_DATA;
344 }
345 if (!verify_fields(&ctx)) {
346 return SWO_INCORRECT_DATA;
347 }
348 print_payload(&ctx);
349
350 // Verify the group handle and extract the gid
351 if (!address_book_verify_group_handle(&g_ab_payload.provide_contact.bip32_path,
352 ctx.group_handle,
353 g_ab_payload.provide_contact.gid)) {
354 PRINTF("[Provide Contact] Group handle verification failed\n");
355 return SWO_SECURITY_CONDITION_NOT_SATISFIED;
356 }
357
358 // Verify HMAC_PROOF over (gid, contact_name)
359 if (!address_book_verify_hmac_proof(&g_ab_payload.provide_contact.bip32_path,
360 g_ab_payload.provide_contact.gid,
361 g_ab_payload.provide_contact.contact_name,
362 ctx.hmac_proof)) {
363 PRINTF("[Provide Contact] HMAC_PROOF verification failed\n");
364 return SWO_SECURITY_CONDITION_NOT_SATISFIED;
365 }
366
367 // Verify HMAC_REST over (gid, scope, identifier, family[, chain_id])
368 if (!address_book_verify_hmac_rest(&g_ab_payload.provide_contact.bip32_path,
369 g_ab_payload.provide_contact.gid,
370 g_ab_payload.provide_contact.scope,
371 g_ab_payload.provide_contact.identifier,
372 g_ab_payload.provide_contact.identifier_len,
373 g_ab_payload.provide_contact.blockchain_family,
374 g_ab_payload.provide_contact.chain_id,
375 ctx.hmac_rest)) {
376 PRINTF("[Provide Contact] HMAC_REST verification failed\n");
377 return SWO_SECURITY_CONDITION_NOT_SATISFIED;
378 }
379
380 // Pass verified contact to the coin app for storage
381 if (!handle_provide_identity(&g_ab_payload.provide_contact)) {
382 PRINTF("[Provide Contact] Rejected by coin application\n");
383 return SWO_WRONG_PARAMETER_VALUE;
384 }
385
386 return SWO_SUCCESS;
387}
388
389#endif // HAVE_ADDRESS_BOOK
@ FAMILY_ETHEREUM
#define FAMILY_AS_STR(x)
Register / Edit Contact Name / Edit Scope / Edit Identifier.
uint8_t * ptr
Definition buffer.h:22
size_t size
Pointer to byte buffer.
Definition buffer.h:23