Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
address_book_crypto.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
29#include <string.h>
30#include <stdint.h>
31#include "address_book_crypto.h"
32#include "ledger_account.h"
33#include "identity.h"
34#include "lcx_sha256.h"
35#include "lcx_rng.h"
36#include "os_utils.h"
37#include "os_address_book.h"
38#include "io.h"
39
40#ifdef HAVE_ADDRESS_BOOK
41
49#define HMAC_MSG_MAX_SIZE \
50 (GID_SIZE + 1U + (SCOPE_LENGTH - 1U) + 1U + IDENTIFIER_MAX_LENGTH + 1U + 8U)
51
53#define HMAC_PROOF_MSG_SIZE (GID_SIZE + 1U + (CONTACT_NAME_LENGTH - 1U))
54
56#define HMAC_LEDGER_MSG_SIZE (1U + (ACCOUNT_NAME_LENGTH - 1U) + 1U + 8U)
57
58/* Private functions ---------------------------------------------------------*/
59
81static size_t serialize_hmac_msg(uint8_t *msg,
82 size_t msg_size,
83 const uint8_t *gid,
84 const char *str1,
85 const uint8_t *raw,
86 uint8_t raw_len,
87 bool include_family,
89 uint64_t chain_id)
90{
91 size_t offset = 0;
92
93 // Optional 32-byte GID prefix
94 if (gid != NULL) {
95 if (offset + GID_SIZE > msg_size) {
96 return SIZE_MAX;
97 }
98 memmove(&msg[offset], gid, GID_SIZE);
99 offset += GID_SIZE;
100 }
101
102 // Optional length-prefixed string
103 if (str1 != NULL) {
104 uint8_t len = (uint8_t) strlen(str1);
105 if (offset + 1U + (size_t) len > msg_size) {
106 return SIZE_MAX;
107 }
108 msg[offset++] = len;
109 if (len > 0) {
110 memmove(&msg[offset], str1, len);
111 offset += len;
112 }
113 }
114
115 // Optional length-prefixed raw bytes
116 if (raw != NULL) {
117 if (offset + 1U + (size_t) raw_len > msg_size) {
118 return SIZE_MAX;
119 }
120 msg[offset++] = raw_len;
121 memmove(&msg[offset], raw, raw_len);
122 offset += raw_len;
123 }
124
125 // Optional family byte + chain_id
126 if (include_family) {
127 if (offset + 1U > msg_size) {
128 return SIZE_MAX;
129 }
130 msg[offset++] = (uint8_t) family;
131 if (family == FAMILY_ETHEREUM) {
132 if (offset + 8U > msg_size) {
133 return SIZE_MAX;
134 }
135 U8BE_ENCODE(msg, offset, chain_id);
136 offset += 8U;
137 }
138 }
139
140 return offset;
141}
142
143/* Exported functions --------------------------------------------------------*/
144
154bool address_book_send_hmac_proof(uint8_t type, const uint8_t hmac_proof[CX_SHA256_SIZE])
155{
156 size_t tx = 0;
157
158 // Response format: type(1) | hmac(32)
159 G_io_tx_buffer[tx++] = type;
160 memmove(&G_io_tx_buffer[tx], hmac_proof, CX_SHA256_SIZE);
161 tx += CX_SHA256_SIZE;
162
163 io_send_response_pointer(G_io_tx_buffer, tx, SWO_SUCCESS);
164 return true;
165}
166
178bool address_book_send_register_identity_response(const uint8_t group_handle[GROUP_HANDLE_SIZE],
179 const uint8_t hmac_proof[CX_SHA256_SIZE],
180 const uint8_t hmac_rest[CX_SHA256_SIZE])
181{
182 size_t tx = 0;
183
184 G_io_tx_buffer[tx++] = TYPE_REGISTER_IDENTITY;
185 memmove(&G_io_tx_buffer[tx], group_handle, GROUP_HANDLE_SIZE);
186 tx += GROUP_HANDLE_SIZE;
187 memmove(&G_io_tx_buffer[tx], hmac_proof, CX_SHA256_SIZE);
188 tx += CX_SHA256_SIZE;
189 memmove(&G_io_tx_buffer[tx], hmac_rest, CX_SHA256_SIZE);
190 tx += CX_SHA256_SIZE;
191
192 io_send_response_pointer(G_io_tx_buffer, tx, SWO_SUCCESS);
193 return true;
194}
195
205bool address_book_generate_group_handle(uint8_t group_handle[GROUP_HANDLE_SIZE])
206{
207 bool success = false;
208 uint8_t *gid = group_handle;
209 uint8_t *mac = group_handle + GID_SIZE;
210
211 cx_rng_no_throw(gid, GID_SIZE);
212 if (!sys_address_book_hmac(ADDRESS_BOOK_SALT_GROUP, gid, GID_SIZE, mac)) {
213 goto end;
214 }
215 success = true;
216
217end:
218 return success;
219}
220
231bool address_book_verify_group_handle(const uint8_t group_handle[GROUP_HANDLE_SIZE],
232 uint8_t gid_out[GID_SIZE])
233{
234 bool success = false;
235 const uint8_t *gid = group_handle;
236 const uint8_t *mac = group_handle + GID_SIZE;
237
238 if (!sys_address_book_hmac_verify(ADDRESS_BOOK_SALT_GROUP, gid, GID_SIZE, mac)) {
239 PRINTF("[Address Book] Group handle MAC verification failed\n");
240 goto end;
241 }
242 memmove(gid_out, gid, GID_SIZE);
243 success = true;
244
245end:
246 return success;
247}
248
260bool address_book_compute_hmac_proof(const uint8_t gid[GID_SIZE],
261 const char *name,
262 uint8_t hmac_out[CX_SHA256_SIZE])
263{
264 uint8_t msg[HMAC_PROOF_MSG_SIZE] = {0};
265 bool success = false;
266 size_t msg_len = serialize_hmac_msg(msg, sizeof(msg), gid, name, NULL, 0, false, 0, 0);
267
268 if (msg_len == SIZE_MAX) {
269 goto end;
270 }
271 if (!sys_address_book_hmac(ADDRESS_BOOK_SALT_IDENTITY, msg, msg_len, hmac_out)) {
272 goto end;
273 }
274 success = true;
275
276end:
277 explicit_bzero(msg, sizeof(msg));
278 return success;
279}
280
289bool address_book_verify_hmac_proof(const uint8_t gid[GID_SIZE],
290 const char *name,
291 const uint8_t hmac_expected[CX_SHA256_SIZE])
292{
293 uint8_t msg[HMAC_PROOF_MSG_SIZE] = {0};
294 bool success = false;
295 size_t msg_len = serialize_hmac_msg(msg, sizeof(msg), gid, name, NULL, 0, false, 0, 0);
296
297 if (msg_len == SIZE_MAX) {
298 goto end;
299 }
300 if (!sys_address_book_hmac_verify(ADDRESS_BOOK_SALT_IDENTITY, msg, msg_len, hmac_expected)) {
301 PRINTF("HMAC_PROOF mismatch\n");
302 goto end;
303 }
304 success = true;
305
306end:
307 explicit_bzero(msg, sizeof(msg));
308 return success;
309}
310
327bool address_book_compute_hmac_rest(const uint8_t gid[GID_SIZE],
328 const char *scope,
329 const uint8_t *identifier,
330 uint8_t identifier_len,
331 blockchain_family_e family,
332 uint64_t chain_id,
333 uint8_t hmac_out[CX_SHA256_SIZE])
334{
335 uint8_t msg[HMAC_MSG_MAX_SIZE] = {0};
336 bool success = false;
337 size_t msg_len = serialize_hmac_msg(
338 msg, sizeof(msg), gid, scope, identifier, identifier_len, true, family, chain_id);
339
340 if (msg_len == SIZE_MAX) {
341 goto end;
342 }
343 if (!sys_address_book_hmac(ADDRESS_BOOK_SALT_IDENTITY, msg, msg_len, hmac_out)) {
344 goto end;
345 }
346 success = true;
347
348end:
349 explicit_bzero(msg, sizeof(msg));
350 return success;
351}
352
365bool address_book_verify_hmac_rest(const uint8_t gid[GID_SIZE],
366 const char *scope,
367 const uint8_t *identifier,
368 uint8_t identifier_len,
369 blockchain_family_e family,
370 uint64_t chain_id,
371 const uint8_t hmac_expected[CX_SHA256_SIZE])
372{
373 uint8_t msg[HMAC_MSG_MAX_SIZE] = {0};
374 bool success = false;
375 size_t msg_len = serialize_hmac_msg(
376 msg, sizeof(msg), gid, scope, identifier, identifier_len, true, family, chain_id);
377
378 if (msg_len == SIZE_MAX) {
379 goto end;
380 }
381 if (!sys_address_book_hmac_verify(ADDRESS_BOOK_SALT_IDENTITY, msg, msg_len, hmac_expected)) {
382 PRINTF("HMAC_REST mismatch\n");
383 goto end;
384 }
385 success = true;
386
387end:
388 explicit_bzero(msg, sizeof(msg));
389 return success;
390}
391
392#ifdef HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
393
407bool address_book_compute_hmac_proof_ledger_account(const path_bip32_t *bip32_path,
408 const char *name,
409 blockchain_family_e family,
410 uint64_t chain_id,
411 uint8_t hmac_out[CX_SHA256_SIZE])
412{
413 uint8_t msg[HMAC_LEDGER_MSG_SIZE] = {0};
414 bool success = false;
415 size_t msg_len
416 = serialize_hmac_msg(msg, sizeof(msg), NULL, name, NULL, 0, true, family, chain_id);
417
418 if (msg_len == SIZE_MAX) {
419 goto end;
420 }
421 if (!sys_address_book_hmac(ADDRESS_BOOK_SALT_LEDGER_ACCOUNT, msg, msg_len, hmac_out)) {
422 goto end;
423 }
424 success = true;
425
426end:
427 explicit_bzero(msg, sizeof(msg));
428 return success;
429}
430
441bool address_book_verify_hmac_proof_ledger_account(const path_bip32_t *bip32_path,
442 const char *name,
443 blockchain_family_e family,
444 uint64_t chain_id,
445 const uint8_t hmac_expected[CX_SHA256_SIZE])
446{
447 uint8_t msg[HMAC_LEDGER_MSG_SIZE] = {0};
448 bool success = false;
449 size_t msg_len
450 = serialize_hmac_msg(msg, sizeof(msg), NULL, name, NULL, 0, true, family, chain_id);
451
452 if (msg_len == SIZE_MAX) {
453 goto end;
454 }
455 if (!sys_address_book_hmac_verify(
456 ADDRESS_BOOK_SALT_LEDGER_ACCOUNT, msg, msg_len, hmac_expected)) {
457 PRINTF("HMAC proof mismatch\n");
458 goto end;
459 }
460 success = true;
461
462end:
463 explicit_bzero(msg, sizeof(msg));
464 return success;
465}
466
467#endif // HAVE_ADDRESS_BOOK_LEDGER_ACCOUNT
468#endif // HAVE_ADDRESS_BOOK
blockchain_family_e
@ FAMILY_ETHEREUM
Register / Edit Contact Name / Edit Scope / Edit Identifier.
static int io_send_response_pointer(const uint8_t *ptr, size_t size, uint16_t sw)
Definition io.h:79
Random Number Generation.
SHA-2 (Secure Hash Algorithm 2)