1*d289c2baSAndroid Build Coastguard Worker /*
2*d289c2baSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*d289c2baSAndroid Build Coastguard Worker *
4*d289c2baSAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person
5*d289c2baSAndroid Build Coastguard Worker * obtaining a copy of this software and associated documentation
6*d289c2baSAndroid Build Coastguard Worker * files (the "Software"), to deal in the Software without
7*d289c2baSAndroid Build Coastguard Worker * restriction, including without limitation the rights to use, copy,
8*d289c2baSAndroid Build Coastguard Worker * modify, merge, publish, distribute, sublicense, and/or sell copies
9*d289c2baSAndroid Build Coastguard Worker * of the Software, and to permit persons to whom the Software is
10*d289c2baSAndroid Build Coastguard Worker * furnished to do so, subject to the following conditions:
11*d289c2baSAndroid Build Coastguard Worker *
12*d289c2baSAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be
13*d289c2baSAndroid Build Coastguard Worker * included in all copies or substantial portions of the Software.
14*d289c2baSAndroid Build Coastguard Worker *
15*d289c2baSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*d289c2baSAndroid Build Coastguard Worker * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*d289c2baSAndroid Build Coastguard Worker * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*d289c2baSAndroid Build Coastguard Worker * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19*d289c2baSAndroid Build Coastguard Worker * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20*d289c2baSAndroid Build Coastguard Worker * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21*d289c2baSAndroid Build Coastguard Worker * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*d289c2baSAndroid Build Coastguard Worker * SOFTWARE.
23*d289c2baSAndroid Build Coastguard Worker */
24*d289c2baSAndroid Build Coastguard Worker
25*d289c2baSAndroid Build Coastguard Worker #include "avb_property_descriptor.h"
26*d289c2baSAndroid Build Coastguard Worker #include "avb_util.h"
27*d289c2baSAndroid Build Coastguard Worker
avb_property_descriptor_validate_and_byteswap(const AvbPropertyDescriptor * src,AvbPropertyDescriptor * dest)28*d289c2baSAndroid Build Coastguard Worker bool avb_property_descriptor_validate_and_byteswap(
29*d289c2baSAndroid Build Coastguard Worker const AvbPropertyDescriptor* src, AvbPropertyDescriptor* dest) {
30*d289c2baSAndroid Build Coastguard Worker uint64_t expected_size;
31*d289c2baSAndroid Build Coastguard Worker
32*d289c2baSAndroid Build Coastguard Worker avb_memcpy(dest, src, sizeof(AvbPropertyDescriptor));
33*d289c2baSAndroid Build Coastguard Worker
34*d289c2baSAndroid Build Coastguard Worker if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
35*d289c2baSAndroid Build Coastguard Worker (AvbDescriptor*)dest))
36*d289c2baSAndroid Build Coastguard Worker return false;
37*d289c2baSAndroid Build Coastguard Worker
38*d289c2baSAndroid Build Coastguard Worker if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
39*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid tag for property descriptor.\n");
40*d289c2baSAndroid Build Coastguard Worker return false;
41*d289c2baSAndroid Build Coastguard Worker }
42*d289c2baSAndroid Build Coastguard Worker
43*d289c2baSAndroid Build Coastguard Worker dest->key_num_bytes = avb_be64toh(dest->key_num_bytes);
44*d289c2baSAndroid Build Coastguard Worker dest->value_num_bytes = avb_be64toh(dest->value_num_bytes);
45*d289c2baSAndroid Build Coastguard Worker
46*d289c2baSAndroid Build Coastguard Worker /* Check that key and value are fully contained. */
47*d289c2baSAndroid Build Coastguard Worker expected_size = sizeof(AvbPropertyDescriptor) - sizeof(AvbDescriptor) + 2;
48*d289c2baSAndroid Build Coastguard Worker if (!avb_safe_add_to(&expected_size, dest->key_num_bytes) ||
49*d289c2baSAndroid Build Coastguard Worker !avb_safe_add_to(&expected_size, dest->value_num_bytes)) {
50*d289c2baSAndroid Build Coastguard Worker avb_error("Overflow while adding up sizes.\n");
51*d289c2baSAndroid Build Coastguard Worker return false;
52*d289c2baSAndroid Build Coastguard Worker }
53*d289c2baSAndroid Build Coastguard Worker if (expected_size > dest->parent_descriptor.num_bytes_following) {
54*d289c2baSAndroid Build Coastguard Worker avb_error("Descriptor payload size overflow.\n");
55*d289c2baSAndroid Build Coastguard Worker return false;
56*d289c2baSAndroid Build Coastguard Worker }
57*d289c2baSAndroid Build Coastguard Worker
58*d289c2baSAndroid Build Coastguard Worker return true;
59*d289c2baSAndroid Build Coastguard Worker }
60*d289c2baSAndroid Build Coastguard Worker
61*d289c2baSAndroid Build Coastguard Worker typedef struct {
62*d289c2baSAndroid Build Coastguard Worker const char* key;
63*d289c2baSAndroid Build Coastguard Worker size_t key_size;
64*d289c2baSAndroid Build Coastguard Worker const char* ret_value;
65*d289c2baSAndroid Build Coastguard Worker size_t ret_value_size;
66*d289c2baSAndroid Build Coastguard Worker } PropertyIteratorData;
67*d289c2baSAndroid Build Coastguard Worker
property_lookup_desc_foreach(const AvbDescriptor * header,void * user_data)68*d289c2baSAndroid Build Coastguard Worker static bool property_lookup_desc_foreach(const AvbDescriptor* header,
69*d289c2baSAndroid Build Coastguard Worker void* user_data) {
70*d289c2baSAndroid Build Coastguard Worker PropertyIteratorData* data = (PropertyIteratorData*)user_data;
71*d289c2baSAndroid Build Coastguard Worker AvbPropertyDescriptor prop_desc;
72*d289c2baSAndroid Build Coastguard Worker const uint8_t* p;
73*d289c2baSAndroid Build Coastguard Worker bool ret = true;
74*d289c2baSAndroid Build Coastguard Worker
75*d289c2baSAndroid Build Coastguard Worker if (header->tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
76*d289c2baSAndroid Build Coastguard Worker goto out;
77*d289c2baSAndroid Build Coastguard Worker }
78*d289c2baSAndroid Build Coastguard Worker
79*d289c2baSAndroid Build Coastguard Worker if (!avb_property_descriptor_validate_and_byteswap(
80*d289c2baSAndroid Build Coastguard Worker (const AvbPropertyDescriptor*)header, &prop_desc)) {
81*d289c2baSAndroid Build Coastguard Worker goto out;
82*d289c2baSAndroid Build Coastguard Worker }
83*d289c2baSAndroid Build Coastguard Worker
84*d289c2baSAndroid Build Coastguard Worker p = (const uint8_t*)header;
85*d289c2baSAndroid Build Coastguard Worker if (p[sizeof(AvbPropertyDescriptor) + prop_desc.key_num_bytes] != 0) {
86*d289c2baSAndroid Build Coastguard Worker avb_error("No terminating NUL byte in key.\n");
87*d289c2baSAndroid Build Coastguard Worker goto out;
88*d289c2baSAndroid Build Coastguard Worker }
89*d289c2baSAndroid Build Coastguard Worker
90*d289c2baSAndroid Build Coastguard Worker if (data->key_size == prop_desc.key_num_bytes) {
91*d289c2baSAndroid Build Coastguard Worker if (avb_memcmp(p + sizeof(AvbPropertyDescriptor),
92*d289c2baSAndroid Build Coastguard Worker data->key,
93*d289c2baSAndroid Build Coastguard Worker data->key_size) == 0) {
94*d289c2baSAndroid Build Coastguard Worker data->ret_value = (const char*)(p + sizeof(AvbPropertyDescriptor) +
95*d289c2baSAndroid Build Coastguard Worker prop_desc.key_num_bytes + 1);
96*d289c2baSAndroid Build Coastguard Worker data->ret_value_size = prop_desc.value_num_bytes;
97*d289c2baSAndroid Build Coastguard Worker /* Stop iterating. */
98*d289c2baSAndroid Build Coastguard Worker ret = false;
99*d289c2baSAndroid Build Coastguard Worker goto out;
100*d289c2baSAndroid Build Coastguard Worker }
101*d289c2baSAndroid Build Coastguard Worker }
102*d289c2baSAndroid Build Coastguard Worker
103*d289c2baSAndroid Build Coastguard Worker out:
104*d289c2baSAndroid Build Coastguard Worker return ret;
105*d289c2baSAndroid Build Coastguard Worker }
106*d289c2baSAndroid Build Coastguard Worker
avb_property_lookup(const uint8_t * image_data,size_t image_size,const char * key,size_t key_size,size_t * out_value_size)107*d289c2baSAndroid Build Coastguard Worker const char* avb_property_lookup(const uint8_t* image_data,
108*d289c2baSAndroid Build Coastguard Worker size_t image_size,
109*d289c2baSAndroid Build Coastguard Worker const char* key,
110*d289c2baSAndroid Build Coastguard Worker size_t key_size,
111*d289c2baSAndroid Build Coastguard Worker size_t* out_value_size) {
112*d289c2baSAndroid Build Coastguard Worker PropertyIteratorData data;
113*d289c2baSAndroid Build Coastguard Worker
114*d289c2baSAndroid Build Coastguard Worker if (key_size == 0) {
115*d289c2baSAndroid Build Coastguard Worker key_size = avb_strlen(key);
116*d289c2baSAndroid Build Coastguard Worker }
117*d289c2baSAndroid Build Coastguard Worker
118*d289c2baSAndroid Build Coastguard Worker data.key = key;
119*d289c2baSAndroid Build Coastguard Worker data.key_size = key_size;
120*d289c2baSAndroid Build Coastguard Worker
121*d289c2baSAndroid Build Coastguard Worker if (avb_descriptor_foreach(
122*d289c2baSAndroid Build Coastguard Worker image_data, image_size, property_lookup_desc_foreach, &data) == 0) {
123*d289c2baSAndroid Build Coastguard Worker if (out_value_size != NULL) {
124*d289c2baSAndroid Build Coastguard Worker *out_value_size = data.ret_value_size;
125*d289c2baSAndroid Build Coastguard Worker }
126*d289c2baSAndroid Build Coastguard Worker return data.ret_value;
127*d289c2baSAndroid Build Coastguard Worker }
128*d289c2baSAndroid Build Coastguard Worker
129*d289c2baSAndroid Build Coastguard Worker if (out_value_size != NULL) {
130*d289c2baSAndroid Build Coastguard Worker *out_value_size = 0;
131*d289c2baSAndroid Build Coastguard Worker }
132*d289c2baSAndroid Build Coastguard Worker return NULL;
133*d289c2baSAndroid Build Coastguard Worker }
134*d289c2baSAndroid Build Coastguard Worker
avb_property_lookup_uint64(const uint8_t * image_data,size_t image_size,const char * key,size_t key_size,uint64_t * out_value)135*d289c2baSAndroid Build Coastguard Worker bool avb_property_lookup_uint64(const uint8_t* image_data,
136*d289c2baSAndroid Build Coastguard Worker size_t image_size,
137*d289c2baSAndroid Build Coastguard Worker const char* key,
138*d289c2baSAndroid Build Coastguard Worker size_t key_size,
139*d289c2baSAndroid Build Coastguard Worker uint64_t* out_value) {
140*d289c2baSAndroid Build Coastguard Worker const char* value;
141*d289c2baSAndroid Build Coastguard Worker bool ret = false;
142*d289c2baSAndroid Build Coastguard Worker uint64_t parsed_val;
143*d289c2baSAndroid Build Coastguard Worker int base;
144*d289c2baSAndroid Build Coastguard Worker int n;
145*d289c2baSAndroid Build Coastguard Worker
146*d289c2baSAndroid Build Coastguard Worker value = avb_property_lookup(image_data, image_size, key, key_size, NULL);
147*d289c2baSAndroid Build Coastguard Worker if (value == NULL) {
148*d289c2baSAndroid Build Coastguard Worker goto out;
149*d289c2baSAndroid Build Coastguard Worker }
150*d289c2baSAndroid Build Coastguard Worker
151*d289c2baSAndroid Build Coastguard Worker base = 10;
152*d289c2baSAndroid Build Coastguard Worker if (avb_memcmp(value, "0x", 2) == 0) {
153*d289c2baSAndroid Build Coastguard Worker base = 16;
154*d289c2baSAndroid Build Coastguard Worker value += 2;
155*d289c2baSAndroid Build Coastguard Worker }
156*d289c2baSAndroid Build Coastguard Worker
157*d289c2baSAndroid Build Coastguard Worker parsed_val = 0;
158*d289c2baSAndroid Build Coastguard Worker for (n = 0; value[n] != '\0'; n++) {
159*d289c2baSAndroid Build Coastguard Worker int c = value[n];
160*d289c2baSAndroid Build Coastguard Worker int digit;
161*d289c2baSAndroid Build Coastguard Worker
162*d289c2baSAndroid Build Coastguard Worker parsed_val *= base;
163*d289c2baSAndroid Build Coastguard Worker
164*d289c2baSAndroid Build Coastguard Worker if (c >= '0' && c <= '9') {
165*d289c2baSAndroid Build Coastguard Worker digit = c - '0';
166*d289c2baSAndroid Build Coastguard Worker } else if (base == 16 && c >= 'a' && c <= 'f') {
167*d289c2baSAndroid Build Coastguard Worker digit = c - 'a' + 10;
168*d289c2baSAndroid Build Coastguard Worker } else if (base == 16 && c >= 'A' && c <= 'F') {
169*d289c2baSAndroid Build Coastguard Worker digit = c - 'A' + 10;
170*d289c2baSAndroid Build Coastguard Worker } else {
171*d289c2baSAndroid Build Coastguard Worker avb_error("Invalid digit.\n");
172*d289c2baSAndroid Build Coastguard Worker goto out;
173*d289c2baSAndroid Build Coastguard Worker }
174*d289c2baSAndroid Build Coastguard Worker
175*d289c2baSAndroid Build Coastguard Worker parsed_val += digit;
176*d289c2baSAndroid Build Coastguard Worker }
177*d289c2baSAndroid Build Coastguard Worker
178*d289c2baSAndroid Build Coastguard Worker ret = true;
179*d289c2baSAndroid Build Coastguard Worker if (out_value != NULL) {
180*d289c2baSAndroid Build Coastguard Worker *out_value = parsed_val;
181*d289c2baSAndroid Build Coastguard Worker }
182*d289c2baSAndroid Build Coastguard Worker
183*d289c2baSAndroid Build Coastguard Worker out:
184*d289c2baSAndroid Build Coastguard Worker return ret;
185*d289c2baSAndroid Build Coastguard Worker }
186