Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
tlv_use_case_dynamic_descriptor.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2025 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
17#include <stdint.h>
18#include <string.h>
19#include <ctype.h>
20
21#include "os_utils.h"
22#include "ox_ec.h"
23#include "os_pic.h"
24#include "os_app.h"
25#include "cx.h"
26#include "os_pki.h"
27#include "ledger_pki.h"
29
30#define TYPE_DYNAMIC_TOKEN 0x90
31
32// Parsed TLV data
33typedef struct tlv_extracted_s {
34 // Received tags set by the parser
36
37 // Dynamic descriptor output data
39
40 // Tags handled by the use case API and not the caller
42 char application_name[BOLOS_APPNAME_MAX_SIZE_B + 1];
43
45
46 // Progressive hash of the received TLVs (except the signature type)
47 cx_sha256_t hash_ctx;
49
50static bool handle_structure_type(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
51{
52 return get_uint8_t_from_tlv_data(data, &tlv_extracted->structure_type);
53}
54
55static bool handle_version(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
56{
57 return get_uint8_t_from_tlv_data(data, &tlv_extracted->output->version);
58}
59
60static bool handle_coin_type(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
61{
62 return get_uint32_t_from_tlv_data(data, &tlv_extracted->output->coin_type);
63}
64
65static bool handle_application_name(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
66{
68 data, tlv_extracted->application_name, 1, sizeof(tlv_extracted->application_name));
69}
70
71static bool handle_ticker(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
72{
74 data, tlv_extracted->output->ticker, 1, sizeof(tlv_extracted->output->ticker));
75}
76
77static bool handle_magnitude(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
78{
79 return get_uint8_t_from_tlv_data(data, &tlv_extracted->output->magnitude);
80}
81
82static bool handle_tuid(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
83{
84 return get_buffer_from_tlv_data(data, &tlv_extracted->output->TUID, 0, 0);
85}
86
87static bool handle_signature(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
88{
91}
92
93static bool handle_common(const tlv_data_t *data, tlv_extracted_t *tlv_extracted);
94
95// clang-format off
96// List of TLV tags recognized by the Solana application
97#define TLV_TAGS(X) \
98 X(0x01, TAG_STRUCTURE_TYPE, handle_structure_type, ENFORCE_UNIQUE_TAG) \
99 X(0x02, TAG_VERSION, handle_version, ENFORCE_UNIQUE_TAG) \
100 X(0x03, TAG_COIN_TYPE, handle_coin_type, ENFORCE_UNIQUE_TAG) \
101 X(0x04, TAG_APPLICATION_NAME, handle_application_name, ENFORCE_UNIQUE_TAG) \
102 X(0x05, TAG_TICKER, handle_ticker, ENFORCE_UNIQUE_TAG) \
103 X(0x06, TAG_MAGNITUDE, handle_magnitude, ENFORCE_UNIQUE_TAG) \
104 X(0x07, TAG_TUID, handle_tuid, ENFORCE_UNIQUE_TAG) \
105 X(0x08, TAG_SIGNATURE, handle_signature, ENFORCE_UNIQUE_TAG)
106// clang-format on
107
108DEFINE_TLV_PARSER(TLV_TAGS, &handle_common, parse_dynamic_token_tag)
109
110static bool handle_common(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
111{
112 if (data->tag != TAG_SIGNATURE) {
113 CX_ASSERT(
114 cx_hash_update((cx_hash_t *) &tlv_extracted->hash_ctx, data->raw.ptr, data->raw.size));
115 }
116 return true;
117}
118
121{
122 // Parser output
123 tlv_extracted_t tlv_extracted = {0};
124 tlv_extracted.output = out;
125
126 // The parser will fill it with the hash of the whole TLV payload (except SIGN tag)
127 cx_sha256_init(&tlv_extracted.hash_ctx);
128
129 // Call the function created by the macro from the TLV lib
130 if (!parse_dynamic_token_tag(payload, &tlv_extracted, &tlv_extracted.received_tags)) {
131 PRINTF("Failed to parse tlv payload\n");
133 }
134
135 if (!TLV_CHECK_RECEIVED_TAGS(tlv_extracted.received_tags, TAG_STRUCTURE_TYPE)) {
136 PRINTF("Error: no struct type specified!\n");
138 }
139
140 if (tlv_extracted.structure_type != TYPE_DYNAMIC_TOKEN) {
141 PRINTF("Error: unexpected struct type %d\n", tlv_extracted.structure_type);
143 }
144
145 if (!TLV_CHECK_RECEIVED_TAGS(tlv_extracted.received_tags,
146 TAG_VERSION,
147 TAG_COIN_TYPE,
148 TAG_APPLICATION_NAME,
149 TAG_TICKER,
150 TAG_MAGNITUDE,
151 TAG_TUID,
152 TAG_SIGNATURE)) {
153 PRINTF("Error: missing required fields in struct version 1\n");
155 }
156
157 if (strcmp(tlv_extracted.application_name, APPNAME) != 0) {
158 PRINTF("Error: unsupported application name %s\n", tlv_extracted.application_name);
160 }
161
162 if (tlv_extracted.output->version == 0 || tlv_extracted.output->version > 1) {
163 PRINTF("Error: unsupported struct version %d\n", tlv_extracted.output->version);
165 }
166
167 // Finalize hash object filled by the parser
168 uint8_t tlv_hash[CX_SHA256_SIZE] = {0};
169 CX_ASSERT(cx_hash_final((cx_hash_t *) &tlv_extracted.hash_ctx, tlv_hash));
170 buffer_t hash = {.ptr = tlv_hash, .size = sizeof(tlv_hash)};
171
172 // Verify that the signature field of the TLV is the signature of the TLV hash by the key
173 // loaded by the PKI
175 uint8_t expected_key_usage = CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META;
176 cx_curve_t expected_curve = CX_CURVE_SECP256K1;
178 hash, &expected_key_usage, &expected_curve, tlv_extracted.input_sig);
180 PRINTF("Failed to verify signature of dynamic token info\n");
182 }
183
185}
check_signature_with_pki_status_t check_signature_with_pki(const buffer_t hash, const uint8_t *expected_key_usage, const cx_curve_t *expected_curve, const buffer_t signature)
Checks a signature using the PKI certificate.
Definition ledger_pki.c:5
@ CHECK_SIGNATURE_WITH_PKI_SUCCESS
Definition ledger_pki.h:7
enum check_signature_with_pki_status_e check_signature_with_pki_status_t
uint8_t * ptr
Definition buffer.h:22
char application_name[BOLOS_APPNAME_MAX_SIZE_B+1]
tlv_dynamic_descriptor_out_t * output
bool get_string_from_tlv_data(const tlv_data_t *data, char *out, uint16_t min_length, uint16_t out_size)
Copy a NUL-terminated string from TLV data.
bool get_uint8_t_from_tlv_data(const tlv_data_t *data, uint8_t *value)
Extract a uint8_t value from TLV data.
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).
bool get_uint32_t_from_tlv_data(const tlv_data_t *data, uint32_t *value)
Extract a uint32_t value from TLV data.
Definition tlv_library.c:96
#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,...)
static bool handle_signature(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
static bool handle_coin_type(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
static bool handle_application_name(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
struct tlv_extracted_s tlv_extracted_t
#define TLV_TAGS(X)
#define TYPE_DYNAMIC_TOKEN
static bool handle_tuid(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
static bool handle_version(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
static bool handle_magnitude(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
static bool handle_ticker(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
static bool handle_structure_type(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
tlv_dynamic_descriptor_status_t tlv_use_case_dynamic_descriptor(const buffer_t *payload, tlv_dynamic_descriptor_out_t *out)
Processes a TLV dynamic descriptor use case.
static bool handle_common(const tlv_data_t *data, tlv_extracted_t *tlv_extracted)
@ TLV_DYNAMIC_DESCRIPTOR_MISSING_STRUCTURE_TAG
@ TLV_DYNAMIC_DESCRIPTOR_SIGNATURE_ERROR
@ TLV_DYNAMIC_DESCRIPTOR_PARSING_ERROR
@ TLV_DYNAMIC_DESCRIPTOR_WRONG_APPLICATION_NAME
@ TLV_DYNAMIC_DESCRIPTOR_WRONG_TYPE
@ TLV_DYNAMIC_DESCRIPTOR_UNKNOWN_VERSION
@ TLV_DYNAMIC_DESCRIPTOR_MISSING_TAG
#define DER_SIGNATURE_MIN_SIZE
enum tlv_dynamic_descriptor_status_e tlv_dynamic_descriptor_status_t
#define DER_SIGNATURE_MAX_SIZE