Commit 449f9048e6f7870385b4fbecb18c846478a8305f
Committed by
Ji Luo
1 parent
fed4a26ead
Exists in
smarc_8mm-imx_v2018.03_4.14.98_2.0.0_ga
and in
5 other branches
[iot] Update libavb in u-boot
This commit did: 1. Sync AVB lib with external/avb, head of commit is: commit 6d5326a945c2d17d5d0e7718d5cb97663c3b33a2 Author: Neal Ostrem <nealo@google.com> Date: Tue Apr 24 13:09:45 2018 -0700 Merge fix/changes required after merge from AOSP ToT. Change library name to one used by AT. Test: Built successfully and unit tests pass. Change-Id: I5e5fc9a6010d96cfecfc6faf0858ba930cba65a0 2. Change product id in ATX to be full zeros to sync with external/avb. 3. Fix build errors and implement ops fsl_set_key_version. 4. Move most nxp modified code to lib/avb/fsl/. Test: build and boot successfully for imx7d_pico and imx8m_phanbell. Change-Id: I199a035fe8267b10955299a4b745458d40a2e754 Signed-off-by: Luo Ji <ji.luo@nxp.com>
Showing 57 changed files with 1918 additions and 865 deletions Side-by-side Diff
- drivers/usb/gadget/Makefile
- drivers/usb/gadget/f_fastboot.c
- include/configs/imx8mm_evk_android.h
- include/configs/imx8mq_evk_android.h
- include/configs/imx8mq_evk_androidthings.h
- include/configs/imx8qm_arm2_android.h
- include/configs/imx8qm_mek_android.h
- include/configs/imx8qm_mek_android_auto.h
- include/configs/imx8qm_mek_android_auto_xen.h
- include/configs/imx8qxp_arm2_android.h
- include/configs/imx8qxp_mek_android.h
- include/configs/imx8qxp_mek_android_auto.h
- include/configs/multa-imx7d_androidthings.h
- include/configs/mx6sabreandroid_common.h
- include/configs/mx6slevkandroid.h
- include/configs/mx6sxsabreautoandroid.h
- include/configs/mx6sxsabresdandroid.h
- include/configs/mx6ul_nxpu_iopb_android_things.h
- include/configs/mx6ul_spriot_android_things.h
- include/configs/mx7dsabresdandroid.h
- include/configs/mx7ulp_evk_android.h
- include/configs/pico-imx7dandroidthings.h
- include/configs/picosom-imx6ul_android_things.h
- include/fsl_avb.h
- lib/avb/Makefile
- lib/avb/fsl/Makefile
- lib/avb/fsl/fsl_atx_attributes.h
- lib/avb/fsl/fsl_avb_ab_flow.c
- lib/avb/fsl/fsl_avb_sysdeps_uboot.c
- lib/avb/fsl/fsl_avbkey.c
- lib/avb/libavb/Makefile
- lib/avb/libavb/avb_cmdline.c
- lib/avb/libavb/avb_cmdline.h
- lib/avb/libavb/avb_crypto.c
- lib/avb/libavb/avb_crypto.h
- lib/avb/libavb/avb_hash_descriptor.c
- lib/avb/libavb/avb_hash_descriptor.h
- lib/avb/libavb/avb_hashtree_descriptor.c
- lib/avb/libavb/avb_hashtree_descriptor.h
- lib/avb/libavb/avb_ops.h
- lib/avb/libavb/avb_slot_verify.c
- lib/avb/libavb/avb_slot_verify.h
- lib/avb/libavb/avb_sysdeps.h
- lib/avb/libavb/avb_sysdeps_posix.c
- lib/avb/libavb/avb_sysdeps_uboot.c
- lib/avb/libavb/avb_util.c
- lib/avb/libavb/avb_util.h
- lib/avb/libavb/avb_version.h
- lib/avb/libavb_ab/avb_ab_flow.c
- lib/avb/libavb_ab/avb_ab_flow.h
- lib/avb/libavb_ab/avb_ab_ops.h
- lib/avb/libavb_ab/libavb_ab.h
- lib/avb/libavb_atx/avb_atx_ops.h
- lib/avb/libavb_atx/avb_atx_types.h
- lib/avb/libavb_atx/avb_atx_validate.c
- lib/avb/libavb_atx/avb_atx_validate.h
- lib/avb/libavb_atx/libavb_atx.h
drivers/usb/gadget/Makefile
drivers/usb/gadget/f_fastboot.c
... | ... | @@ -1628,7 +1628,8 @@ |
1628 | 1628 | static AvbAtxOps fsl_avb_atx_ops = { |
1629 | 1629 | .ops = NULL, |
1630 | 1630 | .read_permanent_attributes = fsl_read_permanent_attributes, |
1631 | - .read_permanent_attributes_hash = fsl_read_permanent_attributes_hash | |
1631 | + .read_permanent_attributes_hash = fsl_read_permanent_attributes_hash, | |
1632 | + .set_key_version = fsl_set_key_version | |
1632 | 1633 | }; |
1633 | 1634 | #endif |
1634 | 1635 | static AvbOps fsl_avb_ops = { |
include/configs/imx8mm_evk_android.h
include/configs/imx8mq_evk_android.h
include/configs/imx8mq_evk_androidthings.h
include/configs/imx8qm_arm2_android.h
include/configs/imx8qm_mek_android.h
include/configs/imx8qm_mek_android_auto.h
include/configs/imx8qm_mek_android_auto_xen.h
include/configs/imx8qxp_arm2_android.h
include/configs/imx8qxp_mek_android.h
include/configs/imx8qxp_mek_android_auto.h
include/configs/multa-imx7d_androidthings.h
include/configs/mx6sabreandroid_common.h
include/configs/mx6slevkandroid.h
include/configs/mx6sxsabreautoandroid.h
include/configs/mx6sxsabresdandroid.h
include/configs/mx6ul_nxpu_iopb_android_things.h
include/configs/mx6ul_spriot_android_things.h
include/configs/mx7dsabresdandroid.h
include/configs/mx7ulp_evk_android.h
include/configs/pico-imx7dandroidthings.h
... | ... | @@ -61,7 +61,7 @@ |
61 | 61 | |
62 | 62 | #ifdef CONFIG_SYS_MALLOC_LEN |
63 | 63 | #undef CONFIG_SYS_MALLOC_LEN |
64 | -#define CONFIG_SYS_MALLOC_LEN (32 * SZ_1M) | |
64 | +#define CONFIG_SYS_MALLOC_LEN (64 * SZ_1M) | |
65 | 65 | #endif |
66 | 66 | /* fuse bank size in word */ |
67 | 67 | /* infact 7D have no enough bits |
... | ... | @@ -71,6 +71,8 @@ |
71 | 71 | #define CONFIG_AVB_FUSE_BANK_START 14 |
72 | 72 | #define CONFIG_AVB_FUSE_BANK_END 14 |
73 | 73 | #endif |
74 | + | |
75 | +#define AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED | |
74 | 76 | |
75 | 77 | /* Disable U-Boot logo */ |
76 | 78 | #undef CONFIG_VIDEO_LOGO |
include/configs/picosom-imx6ul_android_things.h
include/fsl_avb.h
... | ... | @@ -195,5 +195,29 @@ |
195 | 195 | */ |
196 | 196 | AvbIOResult fsl_read_permanent_attributes_hash( |
197 | 197 | AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]); |
198 | + | |
199 | +/* Provides the key version of a key used during verification. This may be | |
200 | + * useful for managing the minimum key version. | |
201 | + */ | |
202 | +void fsl_set_key_version(AvbAtxOps* atx_ops, | |
203 | + size_t rollback_index_location, | |
204 | + uint64_t key_version); | |
205 | + | |
206 | +/* This is the fast version of avb_ab_flow(), this function will | |
207 | + * not check another slot if one slot can pass the verify (or verify | |
208 | + * fail is acceptable). */ | |
209 | +AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops, | |
210 | + const char* const* requested_partitions, | |
211 | + AvbSlotVerifyFlags flags, | |
212 | + AvbHashtreeErrorMode hashtree_error_mode, | |
213 | + AvbSlotVerifyData** out_data); | |
214 | + | |
215 | +/* This is for legacy i.mx6/7 which don't enable A/B but want to | |
216 | + * verify boot/recovery with AVB */ | |
217 | +AvbABFlowResult avb_single_flow(AvbABOps* ab_ops, | |
218 | + const char* const* requested_partitions, | |
219 | + AvbSlotVerifyFlags flags, | |
220 | + AvbHashtreeErrorMode hashtree_error_mode, | |
221 | + AvbSlotVerifyData** out_data); | |
198 | 222 | #endif /* __FSL_AVB_H__ */ |
lib/avb/Makefile
lib/avb/fsl/Makefile
lib/avb/fsl/fsl_atx_attributes.h
... | ... | @@ -11,8 +11,8 @@ |
11 | 11 | /* This product_id is generated from |
12 | 12 | * extern/avb/test/data/atx_product_id.bin */ |
13 | 13 | unsigned char fsl_atx_product_id[] = { |
14 | - 0x3f,0x38,0x9c,0xcb,0xbe,0x56,0xcc,0x3d, | |
15 | - 0x0b,0xd0,0xbb,0x35,0x01,0x85,0xa7,0xd2 | |
14 | + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
15 | + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 | |
16 | 16 | }; |
17 | 17 | /* This product_root_public_key is generated form |
18 | 18 | * extern/avb/test/data/testkey_atx_prk.pem */ |
lib/avb/fsl/fsl_avb_ab_flow.c
1 | +/* | |
2 | + * Copyright 2018 NXP | |
3 | + */ | |
4 | + | |
5 | +#include <common.h> | |
6 | +#include <fsl_avb.h> | |
7 | + | |
8 | +static const char* slot_suffixes[2] = {"_a", "_b"}; | |
9 | + | |
10 | +/* This is a copy of slot_set_unbootable() form | |
11 | + * lib/avb/libavb_ab/avb_ab_flow.c. | |
12 | + */ | |
13 | +static void fsl_slot_set_unbootable(AvbABSlotData* slot) { | |
14 | + slot->priority = 0; | |
15 | + slot->tries_remaining = 0; | |
16 | + slot->successful_boot = 0; | |
17 | +} | |
18 | + | |
19 | +/* Ensure all unbootable and/or illegal states are marked as the | |
20 | + * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0, | |
21 | + * and successful_boot=0. This is a copy of fsl_slot_normalize from | |
22 | + * lib/avb/libavb_ab/avb_ab_flow.c. | |
23 | + */ | |
24 | +static void fsl_slot_normalize(AvbABSlotData* slot) { | |
25 | + if (slot->priority > 0) { | |
26 | + if ((slot->tries_remaining == 0) && (!slot->successful_boot)) { | |
27 | + /* We've exhausted all tries -> unbootable. */ | |
28 | + fsl_slot_set_unbootable(slot); | |
29 | + } | |
30 | + if ((slot->tries_remaining > 0) && (slot->successful_boot)) { | |
31 | + /* Illegal state - avb_ab_mark_slot_successful() will clear | |
32 | + * tries_remaining when setting successful_boot. | |
33 | + */ | |
34 | + fsl_slot_set_unbootable(slot); | |
35 | + } | |
36 | + } else { | |
37 | + fsl_slot_set_unbootable(slot); | |
38 | + } | |
39 | +} | |
40 | + | |
41 | +/* Writes A/B metadata to disk only if it has changed - returns | |
42 | + * AVB_IO_RESULT_OK on success, error code otherwise. This is a | |
43 | + * copy of save_metadata_if_changed form lib/avb/libavb_ab/avb_ab_flow.c. | |
44 | + */ | |
45 | +static AvbIOResult fsl_save_metadata_if_changed(AvbABOps* ab_ops, | |
46 | + AvbABData* ab_data, | |
47 | + AvbABData* ab_data_orig) { | |
48 | + if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) { | |
49 | + avb_debug("Writing A/B metadata to disk.\n"); | |
50 | + return ab_ops->write_ab_metadata(ab_ops, ab_data); | |
51 | + } | |
52 | + return AVB_IO_RESULT_OK; | |
53 | +} | |
54 | + | |
55 | +/* This is a copy of slot_is_bootable() from | |
56 | + * lib/avb/libavb_ab/avb_ab_flow.c. | |
57 | + */ | |
58 | +static bool fsl_slot_is_bootable(AvbABSlotData* slot) { | |
59 | + return (slot->priority > 0) && | |
60 | + (slot->successful_boot || (slot->tries_remaining > 0)); | |
61 | +} | |
62 | + | |
63 | +/* Helper function to load metadata - returns AVB_IO_RESULT_OK on | |
64 | + * success, error code otherwise. This is a copy of load_metadata() | |
65 | + * from /lib/avb/libavb_ab/avb_ab_flow.c. | |
66 | + */ | |
67 | +static AvbIOResult fsl_load_metadata(AvbABOps* ab_ops, | |
68 | + AvbABData* ab_data, | |
69 | + AvbABData* ab_data_orig) { | |
70 | + AvbIOResult io_ret; | |
71 | + | |
72 | + io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data); | |
73 | + if (io_ret != AVB_IO_RESULT_OK) { | |
74 | + avb_error("I/O error while loading A/B metadata.\n"); | |
75 | + return io_ret; | |
76 | + } | |
77 | + *ab_data_orig = *ab_data; | |
78 | + | |
79 | + /* Ensure data is normalized, e.g. illegal states will be marked as | |
80 | + * unbootable and all unbootable states are represented with | |
81 | + * (priority=0, tries_remaining=0, successful_boot=0). | |
82 | + */ | |
83 | + fsl_slot_normalize(&ab_data->slots[0]); | |
84 | + fsl_slot_normalize(&ab_data->slots[1]); | |
85 | + return AVB_IO_RESULT_OK; | |
86 | +} | |
87 | + | |
88 | +/* For legacy i.mx6/7, we won't enable A/B due to the limitation of | |
89 | + * storage capacity, but we still want to verify boot/recovery with | |
90 | + * AVB. */ | |
91 | +AvbABFlowResult avb_single_flow(AvbABOps* ab_ops, | |
92 | + const char* const* requested_partitions, | |
93 | + AvbSlotVerifyFlags flags, | |
94 | + AvbHashtreeErrorMode hashtree_error_mode, | |
95 | + AvbSlotVerifyData** out_data) { | |
96 | + AvbOps* ops = ab_ops->ops; | |
97 | + AvbSlotVerifyData* slot_data = NULL; | |
98 | + AvbSlotVerifyData* data = NULL; | |
99 | + AvbABFlowResult ret; | |
100 | + bool saw_and_allowed_verification_error = false; | |
101 | + | |
102 | + /* Validate boot/recovery. */ | |
103 | + AvbSlotVerifyResult verify_result; | |
104 | + | |
105 | + verify_result = avb_slot_verify(ops, | |
106 | + requested_partitions, | |
107 | + "", | |
108 | + flags, | |
109 | + hashtree_error_mode, | |
110 | + &slot_data); | |
111 | + switch (verify_result) { | |
112 | + case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
113 | + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
114 | + goto out; | |
115 | + | |
116 | + case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
117 | + ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
118 | + goto out; | |
119 | + | |
120 | + case AVB_SLOT_VERIFY_RESULT_OK: | |
121 | + break; | |
122 | + | |
123 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
124 | + case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
125 | + /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR | |
126 | + * these mean game over. | |
127 | + */ | |
128 | + ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; | |
129 | + goto out; | |
130 | + | |
131 | + /* explicit fallthrough. */ | |
132 | + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
133 | + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
134 | + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
135 | + if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { | |
136 | + /* Do nothing since we allow this. */ | |
137 | + avb_debugv("Allowing slot ", | |
138 | + slot_suffixes[n], | |
139 | + " which verified " | |
140 | + "with result ", | |
141 | + avb_slot_verify_result_to_string(verify_result), | |
142 | + " because " | |
143 | + "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " | |
144 | + "is set.\n", | |
145 | + NULL); | |
146 | + saw_and_allowed_verification_error = true; | |
147 | + } else { | |
148 | + ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; | |
149 | + goto out; | |
150 | + } | |
151 | + break; | |
152 | + | |
153 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
154 | + ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; | |
155 | + goto out; | |
156 | + /* Do not add a 'default:' case here because of -Wswitch. */ | |
157 | + } | |
158 | + | |
159 | + avb_assert(slot_data != NULL); | |
160 | + data = slot_data; | |
161 | + slot_data = NULL; | |
162 | + if (saw_and_allowed_verification_error) { | |
163 | + avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); | |
164 | + ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; | |
165 | + } else { | |
166 | + ret = AVB_AB_FLOW_RESULT_OK; | |
167 | + } | |
168 | + | |
169 | +out: | |
170 | + if (slot_data != NULL) { | |
171 | + avb_slot_verify_data_free(slot_data); | |
172 | + } | |
173 | + | |
174 | + if (out_data != NULL) { | |
175 | + *out_data = data; | |
176 | + } else { | |
177 | + if (data != NULL) { | |
178 | + avb_slot_verify_data_free(data); | |
179 | + } | |
180 | + } | |
181 | + | |
182 | + return ret; | |
183 | +} | |
184 | + | |
185 | +AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops, | |
186 | + const char* const* requested_partitions, | |
187 | + AvbSlotVerifyFlags flags, | |
188 | + AvbHashtreeErrorMode hashtree_error_mode, | |
189 | + AvbSlotVerifyData** out_data) { | |
190 | + AvbOps* ops = ab_ops->ops; | |
191 | + AvbSlotVerifyData* slot_data[2] = {NULL, NULL}; | |
192 | + AvbSlotVerifyData* data = NULL; | |
193 | + AvbABFlowResult ret; | |
194 | + AvbABData ab_data, ab_data_orig; | |
195 | + size_t slot_index_to_boot, n; | |
196 | + AvbIOResult io_ret; | |
197 | + bool saw_and_allowed_verification_error = false; | |
198 | + size_t target_slot; | |
199 | + AvbSlotVerifyResult verify_result; | |
200 | + bool set_slot_unbootable = false; | |
201 | + | |
202 | + io_ret = fsl_load_metadata(ab_ops, &ab_data, &ab_data_orig); | |
203 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
204 | + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
205 | + goto out; | |
206 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
207 | + ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
208 | + goto out; | |
209 | + } | |
210 | + | |
211 | + slot_index_to_boot = 2; // Means not 0 or 1 | |
212 | + target_slot = | |
213 | + (ab_data.slots[1].priority > ab_data.slots[0].priority) ? 1 : 0; | |
214 | + | |
215 | + for (n = 0; n < 2; n++) { | |
216 | + if (!fsl_slot_is_bootable(&ab_data.slots[target_slot])) { | |
217 | + target_slot = (target_slot == 1 ? 0 : 1); | |
218 | + continue; | |
219 | + } | |
220 | + verify_result = avb_slot_verify(ops, | |
221 | + requested_partitions, | |
222 | + slot_suffixes[target_slot], | |
223 | + flags, | |
224 | + hashtree_error_mode, | |
225 | + &slot_data[target_slot]); | |
226 | + switch (verify_result) { | |
227 | + case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
228 | + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
229 | + goto out; | |
230 | + | |
231 | + case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
232 | + ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
233 | + goto out; | |
234 | + | |
235 | + case AVB_SLOT_VERIFY_RESULT_OK: | |
236 | + slot_index_to_boot = target_slot; | |
237 | + n = 2; | |
238 | + break; | |
239 | + | |
240 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
241 | + case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
242 | + /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR | |
243 | + * these mean game over. | |
244 | + */ | |
245 | + set_slot_unbootable = true; | |
246 | + break; | |
247 | + | |
248 | + /* explicit fallthrough. */ | |
249 | + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
250 | + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
251 | + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
252 | + if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { | |
253 | + /* Do nothing since we allow this. */ | |
254 | + avb_debugv("Allowing slot ", | |
255 | + slot_suffixes[target_slot], | |
256 | + " which verified " | |
257 | + "with result ", | |
258 | + avb_slot_verify_result_to_string(verify_result), | |
259 | + " because " | |
260 | + "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " | |
261 | + "is set.\n", | |
262 | + NULL); | |
263 | + saw_and_allowed_verification_error = | |
264 | + true; | |
265 | + slot_index_to_boot = target_slot; | |
266 | + n = 2; | |
267 | + } else { | |
268 | + set_slot_unbootable = true; | |
269 | + } | |
270 | + break; | |
271 | + | |
272 | + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
273 | + ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; | |
274 | + goto out; | |
275 | + /* Do not add a 'default:' case here because | |
276 | + * of -Wswitch. | |
277 | + */ | |
278 | + } | |
279 | + | |
280 | + if (set_slot_unbootable) { | |
281 | + avb_errorv("Error verifying slot ", | |
282 | + slot_suffixes[target_slot], | |
283 | + " with result ", | |
284 | + avb_slot_verify_result_to_string(verify_result), | |
285 | + " - setting unbootable.\n", | |
286 | + NULL); | |
287 | + fsl_slot_set_unbootable(&ab_data.slots[target_slot]); | |
288 | + set_slot_unbootable = false; | |
289 | + } | |
290 | + /* switch to another slot */ | |
291 | + target_slot = (target_slot == 1 ? 0 : 1); | |
292 | + } | |
293 | + | |
294 | + if (slot_index_to_boot == 2) { | |
295 | + /* No bootable slots! */ | |
296 | + avb_error("No bootable slots found.\n"); | |
297 | + ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; | |
298 | + goto out; | |
299 | + } | |
300 | + | |
301 | + /* Update stored rollback index such that the stored rollback index | |
302 | + * is the largest value supporting all currently bootable slots. Do | |
303 | + * this for every rollback index location. | |
304 | + */ | |
305 | + for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) { | |
306 | + uint64_t rollback_index_value = 0; | |
307 | + | |
308 | + if ((slot_data[0] != NULL) && (slot_data[1] != NULL)) { | |
309 | + uint64_t a_rollback_index = | |
310 | + slot_data[0]->rollback_indexes[n]; | |
311 | + uint64_t b_rollback_index = | |
312 | + slot_data[1]->rollback_indexes[n]; | |
313 | + rollback_index_value = | |
314 | + (a_rollback_index < b_rollback_index ? | |
315 | + a_rollback_index : b_rollback_index); | |
316 | + } else if (slot_data[0] != NULL) { | |
317 | + rollback_index_value = | |
318 | + slot_data[0]->rollback_indexes[n]; | |
319 | + } else if (slot_data[1] != NULL) { | |
320 | + rollback_index_value = | |
321 | + slot_data[1]->rollback_indexes[n]; | |
322 | + } | |
323 | + | |
324 | + if (rollback_index_value != 0) { | |
325 | + uint64_t current_rollback_index_value; | |
326 | + io_ret = ops->read_rollback_index( | |
327 | + ops, n, ¤t_rollback_index_value); | |
328 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
329 | + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
330 | + goto out; | |
331 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
332 | + avb_error("Error getting rollback index for slot.\n"); | |
333 | + ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
334 | + goto out; | |
335 | + } | |
336 | + if (current_rollback_index_value != rollback_index_value) { | |
337 | + io_ret = ops->write_rollback_index( | |
338 | + ops, n, rollback_index_value); | |
339 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
340 | + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
341 | + goto out; | |
342 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
343 | + avb_error("Error setting stored rollback index.\n"); | |
344 | + ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
345 | + goto out; | |
346 | + } | |
347 | + } | |
348 | + } | |
349 | + } | |
350 | + | |
351 | + /* Finally, select this slot. */ | |
352 | + avb_assert(slot_data[slot_index_to_boot] != NULL); | |
353 | + data = slot_data[slot_index_to_boot]; | |
354 | + slot_data[slot_index_to_boot] = NULL; | |
355 | + if (saw_and_allowed_verification_error) { | |
356 | + avb_assert( | |
357 | + flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); | |
358 | + ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; | |
359 | + } else { | |
360 | + ret = AVB_AB_FLOW_RESULT_OK; | |
361 | + } | |
362 | + | |
363 | + /* ... and decrement tries remaining, if applicable. */ | |
364 | + if (!ab_data.slots[slot_index_to_boot].successful_boot && | |
365 | + (ab_data.slots[slot_index_to_boot].tries_remaining > 0)) { | |
366 | + ab_data.slots[slot_index_to_boot].tries_remaining -= 1; | |
367 | + } | |
368 | + | |
369 | +out: | |
370 | + io_ret = fsl_save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); | |
371 | + if (io_ret != AVB_IO_RESULT_OK) { | |
372 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
373 | + ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
374 | + } else { | |
375 | + ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
376 | + } | |
377 | + if (data != NULL) { | |
378 | + avb_slot_verify_data_free(data); | |
379 | + data = NULL; | |
380 | + } | |
381 | + } | |
382 | + | |
383 | + for (n = 0; n < 2; n++) { | |
384 | + if (slot_data[n] != NULL) { | |
385 | + avb_slot_verify_data_free(slot_data[n]); | |
386 | + } | |
387 | + } | |
388 | + | |
389 | + if (out_data != NULL) { | |
390 | + *out_data = data; | |
391 | + } else { | |
392 | + if (data != NULL) { | |
393 | + avb_slot_verify_data_free(data); | |
394 | + } | |
395 | + } | |
396 | + | |
397 | + return ret; | |
398 | +} |
lib/avb/fsl/fsl_avb_sysdeps_uboot.c
1 | +/* | |
2 | + * Copyright (C) 2016 The Android Open Source Project | |
3 | + * | |
4 | + * Permission is hereby granted, free of charge, to any person | |
5 | + * obtaining a copy of this software and associated documentation | |
6 | + * files (the "Software"), to deal in the Software without | |
7 | + * restriction, including without limitation the rights to use, copy, | |
8 | + * modify, merge, publish, distribute, sublicense, and/or sell copies | |
9 | + * of the Software, and to permit persons to whom the Software is | |
10 | + * furnished to do so, subject to the following conditions: | |
11 | + * | |
12 | + * The above copyright notice and this permission notice shall be | |
13 | + * included in all copies or substantial portions of the Software. | |
14 | + * | |
15 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
16 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
17 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
18 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
19 | + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
20 | + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
21 | + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
22 | + * SOFTWARE. | |
23 | + */ | |
24 | + | |
25 | +#include <common.h> | |
26 | +#include <stdlib.h> | |
27 | +#include <linux/string.h> | |
28 | + | |
29 | +#include "../libavb/libavb.h" | |
30 | + | |
31 | +int avb_memcmp(const void* src1, const void* src2, size_t n) { | |
32 | + return memcmp(src1, src2, n); | |
33 | +} | |
34 | + | |
35 | +void* avb_memcpy(void* dest, const void* src, size_t n) { | |
36 | + return memcpy(dest, src, n); | |
37 | +} | |
38 | + | |
39 | +void* avb_memset(void* dest, const int c, size_t n) { | |
40 | + return memset(dest, c, n); | |
41 | +} | |
42 | + | |
43 | +int avb_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); } | |
44 | + | |
45 | +size_t avb_strlen(const char* str) { return strlen(str); } | |
46 | + | |
47 | +void avb_abort(void) { panic("avb_abort!\n"); } | |
48 | + | |
49 | +void avb_print(const char* message) { printf("%s", message); } | |
50 | + | |
51 | +void avb_printv(const char* message, ...) { | |
52 | + va_list ap; | |
53 | + const char* m; | |
54 | + | |
55 | + va_start(ap, message); | |
56 | + for (m = message; m != NULL; m = va_arg(ap, const char*)) { | |
57 | + printf("%s", m); | |
58 | + } | |
59 | + va_end(ap); | |
60 | +} | |
61 | + | |
62 | +void* avb_malloc_(size_t size) { return malloc(size); } | |
63 | + | |
64 | +void avb_free(void* ptr) { free(ptr); } | |
65 | + | |
66 | +uint32_t avb_div_by_10(uint64_t* dividend) { | |
67 | + uint32_t rem = (uint32_t)(*dividend % 10); | |
68 | + *dividend /= 10; | |
69 | + return rem; | |
70 | +} |
lib/avb/fsl/fsl_avbkey.c
... | ... | @@ -1108,7 +1108,8 @@ |
1108 | 1108 | *plain_idx = rollback_index; |
1109 | 1109 | |
1110 | 1110 | /* write rollback_index keyblob */ |
1111 | - if (rpmb_write(mmc_dev, (uint8_t *)plain_idx, rbk->len, rbk->offset) != 0) { | |
1111 | + if (rpmb_write(mmc_dev, (uint8_t *)plain_idx, rbk->len, rbk->offset) != | |
1112 | + 0) { | |
1112 | 1113 | ERR("write rollback index error\n"); |
1113 | 1114 | ret = AVB_IO_RESULT_ERROR_IO; |
1114 | 1115 | goto fail; |
... | ... | @@ -1131,8 +1132,9 @@ |
1131 | 1132 | /* use hard code permanent attributes due to limited fuse and RPMB */ |
1132 | 1133 | attributes->version = fsl_version; |
1133 | 1134 | memcpy(attributes->product_root_public_key, fsl_product_root_public_key, |
1134 | - sizeof(fsl_product_root_public_key)); | |
1135 | - memcpy(attributes->product_id, fsl_atx_product_id, sizeof(fsl_atx_product_id)); | |
1135 | + sizeof(fsl_product_root_public_key)); | |
1136 | + memcpy(attributes->product_id, fsl_atx_product_id, | |
1137 | + sizeof(fsl_atx_product_id)); | |
1136 | 1138 | |
1137 | 1139 | return AVB_IO_RESULT_OK; |
1138 | 1140 | } |
... | ... | @@ -1148,8 +1150,9 @@ |
1148 | 1150 | |
1149 | 1151 | /* read first 112 bits of sha256(permanent attributes) from fuse */ |
1150 | 1152 | if (fsl_fuse_read(sha256_hash_fuse, ATX_FUSE_BANK_NUM, |
1151 | - PERMANENT_ATTRIBUTE_HASH_OFFSET)) { | |
1152 | - printf("ERROR - read permanent attributes hash from fuse error\n"); | |
1153 | + PERMANENT_ATTRIBUTE_HASH_OFFSET)) { | |
1154 | + printf("ERROR - read permanent attributes hash from " | |
1155 | + "fuse error\n"); | |
1153 | 1156 | return AVB_IO_RESULT_ERROR_IO; |
1154 | 1157 | } |
1155 | 1158 | /* only take the lower 2 bytes of last bank */ |
... | ... | @@ -1168,5 +1171,55 @@ |
1168 | 1171 | memcpy(hash, sha256_hash_buf, AVB_SHA256_DIGEST_SIZE); |
1169 | 1172 | return AVB_IO_RESULT_OK; |
1170 | 1173 | } |
1174 | + | |
1175 | +/* Provides the key version of a key used during verification. This may be | |
1176 | + * useful for managing the minimum key version. | |
1177 | + */ | |
1178 | +void fsl_set_key_version(AvbAtxOps* atx_ops, | |
1179 | + size_t rollback_index_location, | |
1180 | + uint64_t key_version) { | |
1181 | + kblb_hdr_t hdr; | |
1182 | + kblb_tag_t *rbk; | |
1183 | + uint64_t *plain_idx = NULL; | |
1184 | + struct mmc *mmc_dev; | |
1185 | + static const uint32_t kTypeMask = 0xF000; | |
1186 | + | |
1187 | + DEBUGAVB("[rpmb] write to rollback slot: (%zu, %" PRIu64 ")\n", | |
1188 | + rollback_index_location, key_version); | |
1189 | + | |
1190 | + assert(atx_ops != NULL); | |
1191 | + | |
1192 | + if ((mmc_dev = get_mmc()) == NULL) { | |
1193 | + ERR("err get mmc device\n"); | |
1194 | + } | |
1195 | + /* read the kblb header */ | |
1196 | + if (rpmb_read(mmc_dev, (uint8_t *)&hdr, sizeof(hdr), 0) != 0) { | |
1197 | + ERR("read RPMB error\n"); | |
1198 | + } | |
1199 | + | |
1200 | + if (memcmp(hdr.magic, AVB_KBLB_MAGIC, AVB_KBLB_MAGIC_LEN) != 0) { | |
1201 | + ERR("magic not match\n"); | |
1202 | + } | |
1203 | + | |
1204 | + /* rollback index for Android Things key versions */ | |
1205 | + rbk = &hdr.atx_rbk_tags[rollback_index_location & ~kTypeMask]; | |
1206 | + | |
1207 | + plain_idx = malloc(rbk->len); | |
1208 | + if (plain_idx == NULL) | |
1209 | + printf("\nError! allocate memory fail!\n"); | |
1210 | + memset(plain_idx, 0, rbk->len); | |
1211 | + *plain_idx = key_version; | |
1212 | + | |
1213 | + /* write rollback_index keyblob */ | |
1214 | + if (rpmb_write(mmc_dev, (uint8_t *)plain_idx, rbk->len, rbk->offset) != | |
1215 | + 0) { | |
1216 | + ERR("write rollback index error\n"); | |
1217 | + goto fail; | |
1218 | + } | |
1219 | +fail: | |
1220 | + if (plain_idx != NULL) | |
1221 | + free(plain_idx); | |
1222 | +} | |
1223 | + | |
1171 | 1224 | #endif |
lib/avb/libavb/Makefile
lib/avb/libavb/avb_cmdline.c
1 | +/* | |
2 | + * Copyright (C) 2016 The Android Open Source Project | |
3 | + * | |
4 | + * Permission is hereby granted, free of charge, to any person | |
5 | + * obtaining a copy of this software and associated documentation | |
6 | + * files (the "Software"), to deal in the Software without | |
7 | + * restriction, including without limitation the rights to use, copy, | |
8 | + * modify, merge, publish, distribute, sublicense, and/or sell copies | |
9 | + * of the Software, and to permit persons to whom the Software is | |
10 | + * furnished to do so, subject to the following conditions: | |
11 | + * | |
12 | + * The above copyright notice and this permission notice shall be | |
13 | + * included in all copies or substantial portions of the Software. | |
14 | + * | |
15 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
16 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
17 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
18 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
19 | + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
20 | + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
21 | + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
22 | + * SOFTWARE. | |
23 | + */ | |
24 | + | |
25 | +#include "avb_cmdline.h" | |
26 | +#include "avb_sha.h" | |
27 | +#include "avb_util.h" | |
28 | +#include "avb_version.h" | |
29 | + | |
30 | +#define NUM_GUIDS 3 | |
31 | + | |
32 | +/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with | |
33 | + * values. Returns NULL on OOM, otherwise the cmdline with values | |
34 | + * replaced. | |
35 | + */ | |
36 | +char* avb_sub_cmdline(AvbOps* ops, | |
37 | + const char* cmdline, | |
38 | + const char* ab_suffix, | |
39 | + bool using_boot_for_vbmeta, | |
40 | + const AvbCmdlineSubstList* additional_substitutions) { | |
41 | + const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"}; | |
42 | + const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)", | |
43 | + "$(ANDROID_BOOT_PARTUUID)", | |
44 | + "$(ANDROID_VBMETA_PARTUUID)"}; | |
45 | + char* ret = NULL; | |
46 | + AvbIOResult io_ret; | |
47 | + size_t n; | |
48 | + | |
49 | + /* Special-case for when the top-level vbmeta struct is in the boot | |
50 | + * partition. | |
51 | + */ | |
52 | + if (using_boot_for_vbmeta) { | |
53 | + part_name_str[2] = "boot"; | |
54 | + } | |
55 | + | |
56 | + /* Replace unique partition GUIDs */ | |
57 | + for (n = 0; n < NUM_GUIDS; n++) { | |
58 | + char part_name[AVB_PART_NAME_MAX_SIZE]; | |
59 | + char guid_buf[37]; | |
60 | + | |
61 | + if (!avb_str_concat(part_name, | |
62 | + sizeof part_name, | |
63 | + part_name_str[n], | |
64 | + avb_strlen(part_name_str[n]), | |
65 | + ab_suffix, | |
66 | + avb_strlen(ab_suffix))) { | |
67 | + avb_error("Partition name and suffix does not fit.\n"); | |
68 | + goto fail; | |
69 | + } | |
70 | + | |
71 | + io_ret = ops->get_unique_guid_for_partition( | |
72 | + ops, part_name, guid_buf, sizeof guid_buf); | |
73 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
74 | + goto fail; | |
75 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
76 | + avb_error("Error getting unique GUID for partition.\n"); | |
77 | + goto fail; | |
78 | + } | |
79 | + | |
80 | + if (ret == NULL) { | |
81 | + ret = avb_replace(cmdline, replace_str[n], guid_buf); | |
82 | + } else { | |
83 | + char* new_ret = avb_replace(ret, replace_str[n], guid_buf); | |
84 | + avb_free(ret); | |
85 | + ret = new_ret; | |
86 | + } | |
87 | + if (ret == NULL) { | |
88 | + goto fail; | |
89 | + } | |
90 | + } | |
91 | + | |
92 | + avb_assert(ret != NULL); | |
93 | + | |
94 | + /* Replace any additional substitutions. */ | |
95 | + if (additional_substitutions != NULL) { | |
96 | + for (n = 0; n < additional_substitutions->size; ++n) { | |
97 | + char* new_ret = avb_replace(ret, | |
98 | + additional_substitutions->tokens[n], | |
99 | + additional_substitutions->values[n]); | |
100 | + avb_free(ret); | |
101 | + ret = new_ret; | |
102 | + if (ret == NULL) { | |
103 | + goto fail; | |
104 | + } | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + return ret; | |
109 | + | |
110 | +fail: | |
111 | + if (ret != NULL) { | |
112 | + avb_free(ret); | |
113 | + } | |
114 | + return NULL; | |
115 | +} | |
116 | + | |
117 | +static int cmdline_append_option(AvbSlotVerifyData* slot_data, | |
118 | + const char* key, | |
119 | + const char* value) { | |
120 | + size_t offset, key_len, value_len; | |
121 | + char* new_cmdline; | |
122 | + | |
123 | + key_len = avb_strlen(key); | |
124 | + value_len = avb_strlen(value); | |
125 | + | |
126 | + offset = 0; | |
127 | + if (slot_data->cmdline != NULL) { | |
128 | + offset = avb_strlen(slot_data->cmdline); | |
129 | + if (offset > 0) { | |
130 | + offset += 1; | |
131 | + } | |
132 | + } | |
133 | + | |
134 | + new_cmdline = avb_calloc(offset + key_len + value_len + 2); | |
135 | + if (new_cmdline == NULL) { | |
136 | + return 0; | |
137 | + } | |
138 | + if (offset > 0) { | |
139 | + avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1); | |
140 | + new_cmdline[offset - 1] = ' '; | |
141 | + } | |
142 | + avb_memcpy(new_cmdline + offset, key, key_len); | |
143 | + new_cmdline[offset + key_len] = '='; | |
144 | + avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len); | |
145 | + if (slot_data->cmdline != NULL) { | |
146 | + avb_free(slot_data->cmdline); | |
147 | + } | |
148 | + slot_data->cmdline = new_cmdline; | |
149 | + | |
150 | + return 1; | |
151 | +} | |
152 | + | |
153 | +#define AVB_MAX_DIGITS_UINT64 32 | |
154 | + | |
155 | +/* Writes |value| to |digits| in base 10 followed by a NUL byte. | |
156 | + * Returns number of characters written excluding the NUL byte. | |
157 | + */ | |
158 | +static size_t uint64_to_base10(uint64_t value, | |
159 | + char digits[AVB_MAX_DIGITS_UINT64]) { | |
160 | + char rev_digits[AVB_MAX_DIGITS_UINT64]; | |
161 | + size_t n, num_digits; | |
162 | + | |
163 | + for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) { | |
164 | + rev_digits[num_digits++] = avb_div_by_10(&value) + '0'; | |
165 | + if (value == 0) { | |
166 | + break; | |
167 | + } | |
168 | + } | |
169 | + | |
170 | + for (n = 0; n < num_digits; n++) { | |
171 | + digits[n] = rev_digits[num_digits - 1 - n]; | |
172 | + } | |
173 | + digits[n] = '\0'; | |
174 | + return n; | |
175 | +} | |
176 | + | |
177 | +static int cmdline_append_version(AvbSlotVerifyData* slot_data, | |
178 | + const char* key, | |
179 | + uint64_t major_version, | |
180 | + uint64_t minor_version) { | |
181 | + char major_digits[AVB_MAX_DIGITS_UINT64]; | |
182 | + char minor_digits[AVB_MAX_DIGITS_UINT64]; | |
183 | + char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1]; | |
184 | + size_t num_major_digits, num_minor_digits; | |
185 | + | |
186 | + num_major_digits = uint64_to_base10(major_version, major_digits); | |
187 | + num_minor_digits = uint64_to_base10(minor_version, minor_digits); | |
188 | + avb_memcpy(combined, major_digits, num_major_digits); | |
189 | + combined[num_major_digits] = '.'; | |
190 | + avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits); | |
191 | + combined[num_major_digits + 1 + num_minor_digits] = '\0'; | |
192 | + | |
193 | + return cmdline_append_option(slot_data, key, combined); | |
194 | +} | |
195 | + | |
196 | +static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data, | |
197 | + const char* key, | |
198 | + uint64_t value) { | |
199 | + char digits[AVB_MAX_DIGITS_UINT64]; | |
200 | + uint64_to_base10(value, digits); | |
201 | + return cmdline_append_option(slot_data, key, digits); | |
202 | +} | |
203 | + | |
204 | +static int cmdline_append_hex(AvbSlotVerifyData* slot_data, | |
205 | + const char* key, | |
206 | + const uint8_t* data, | |
207 | + size_t data_len) { | |
208 | + int ret; | |
209 | + char* hex_data = avb_bin2hex(data, data_len); | |
210 | + if (hex_data == NULL) { | |
211 | + return 0; | |
212 | + } | |
213 | + ret = cmdline_append_option(slot_data, key, hex_data); | |
214 | + avb_free(hex_data); | |
215 | + return ret; | |
216 | +} | |
217 | + | |
218 | +AvbSlotVerifyResult avb_append_options( | |
219 | + AvbOps* ops, | |
220 | + AvbSlotVerifyData* slot_data, | |
221 | + AvbVBMetaImageHeader* toplevel_vbmeta, | |
222 | + AvbAlgorithmType algorithm_type, | |
223 | + AvbHashtreeErrorMode hashtree_error_mode) { | |
224 | + AvbSlotVerifyResult ret; | |
225 | + const char* verity_mode; | |
226 | + bool is_device_unlocked; | |
227 | + AvbIOResult io_ret; | |
228 | + | |
229 | + /* Add androidboot.vbmeta.device option. */ | |
230 | + if (!cmdline_append_option(slot_data, | |
231 | + "androidboot.vbmeta.device", | |
232 | + "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { | |
233 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
234 | + goto out; | |
235 | + } | |
236 | + | |
237 | + /* Add androidboot.vbmeta.avb_version option. */ | |
238 | + if (!cmdline_append_version(slot_data, | |
239 | + "androidboot.vbmeta.avb_version", | |
240 | + AVB_VERSION_MAJOR, | |
241 | + AVB_VERSION_MINOR)) { | |
242 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
243 | + goto out; | |
244 | + } | |
245 | + | |
246 | + /* Set androidboot.avb.device_state to "locked" or "unlocked". */ | |
247 | + io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); | |
248 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
249 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
250 | + goto out; | |
251 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
252 | + avb_error("Error getting device state.\n"); | |
253 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
254 | + goto out; | |
255 | + } | |
256 | + if (!cmdline_append_option(slot_data, | |
257 | + "androidboot.vbmeta.device_state", | |
258 | + is_device_unlocked ? "unlocked" : "locked")) { | |
259 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
260 | + goto out; | |
261 | + } | |
262 | + | |
263 | + /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash | |
264 | + * function as is used to sign vbmeta. | |
265 | + */ | |
266 | + switch (algorithm_type) { | |
267 | + /* Explicit fallthrough. */ | |
268 | + case AVB_ALGORITHM_TYPE_NONE: | |
269 | + case AVB_ALGORITHM_TYPE_SHA256_RSA2048: | |
270 | + case AVB_ALGORITHM_TYPE_SHA256_RSA4096: | |
271 | + case AVB_ALGORITHM_TYPE_SHA256_RSA8192: { | |
272 | + size_t n, total_size = 0; | |
273 | + uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE]; | |
274 | + avb_slot_verify_data_calculate_vbmeta_digest( | |
275 | + slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest); | |
276 | + for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
277 | + total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
278 | + } | |
279 | + if (!cmdline_append_option( | |
280 | + slot_data, "androidboot.vbmeta.hash_alg", "sha256") || | |
281 | + !cmdline_append_uint64_base10( | |
282 | + slot_data, "androidboot.vbmeta.size", total_size) || | |
283 | + !cmdline_append_hex(slot_data, | |
284 | + "androidboot.vbmeta.digest", | |
285 | + vbmeta_digest, | |
286 | + AVB_SHA256_DIGEST_SIZE)) { | |
287 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
288 | + goto out; | |
289 | + } | |
290 | + } break; | |
291 | + /* Explicit fallthrough. */ | |
292 | + case AVB_ALGORITHM_TYPE_SHA512_RSA2048: | |
293 | + case AVB_ALGORITHM_TYPE_SHA512_RSA4096: | |
294 | + case AVB_ALGORITHM_TYPE_SHA512_RSA8192: { | |
295 | + size_t n, total_size = 0; | |
296 | + uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE]; | |
297 | + avb_slot_verify_data_calculate_vbmeta_digest( | |
298 | + slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest); | |
299 | + for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
300 | + total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
301 | + } | |
302 | + if (!cmdline_append_option( | |
303 | + slot_data, "androidboot.vbmeta.hash_alg", "sha512") || | |
304 | + !cmdline_append_uint64_base10( | |
305 | + slot_data, "androidboot.vbmeta.size", total_size) || | |
306 | + !cmdline_append_hex(slot_data, | |
307 | + "androidboot.vbmeta.digest", | |
308 | + vbmeta_digest, | |
309 | + AVB_SHA512_DIGEST_SIZE)) { | |
310 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
311 | + goto out; | |
312 | + } | |
313 | + } break; | |
314 | + case _AVB_ALGORITHM_NUM_TYPES: | |
315 | + avb_assert_not_reached(); | |
316 | + break; | |
317 | + } | |
318 | + | |
319 | + /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */ | |
320 | + if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) { | |
321 | + verity_mode = "disabled"; | |
322 | + } else { | |
323 | + const char* dm_verity_mode; | |
324 | + char* new_ret; | |
325 | + | |
326 | + switch (hashtree_error_mode) { | |
327 | + case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE: | |
328 | + if (!cmdline_append_option( | |
329 | + slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) { | |
330 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
331 | + goto out; | |
332 | + } | |
333 | + verity_mode = "enforcing"; | |
334 | + dm_verity_mode = "restart_on_corruption"; | |
335 | + break; | |
336 | + case AVB_HASHTREE_ERROR_MODE_RESTART: | |
337 | + verity_mode = "enforcing"; | |
338 | + dm_verity_mode = "restart_on_corruption"; | |
339 | + break; | |
340 | + case AVB_HASHTREE_ERROR_MODE_EIO: | |
341 | + verity_mode = "eio"; | |
342 | + /* For now there's no option to specify the EIO mode. So | |
343 | + * just use 'ignore_zero_blocks' since that's already set | |
344 | + * and dm-verity-target.c supports specifying this multiple | |
345 | + * times. | |
346 | + */ | |
347 | + dm_verity_mode = "ignore_zero_blocks"; | |
348 | + break; | |
349 | + case AVB_HASHTREE_ERROR_MODE_LOGGING: | |
350 | + verity_mode = "logging"; | |
351 | + dm_verity_mode = "ignore_corruption"; | |
352 | + break; | |
353 | + } | |
354 | + new_ret = avb_replace( | |
355 | + slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode); | |
356 | + avb_free(slot_data->cmdline); | |
357 | + slot_data->cmdline = new_ret; | |
358 | + if (slot_data->cmdline == NULL) { | |
359 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
360 | + goto out; | |
361 | + } | |
362 | + } | |
363 | + if (!cmdline_append_option( | |
364 | + slot_data, "androidboot.veritymode", verity_mode)) { | |
365 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
366 | + goto out; | |
367 | + } | |
368 | + | |
369 | + ret = AVB_SLOT_VERIFY_RESULT_OK; | |
370 | + | |
371 | +out: | |
372 | + | |
373 | + return ret; | |
374 | +} | |
375 | + | |
376 | +AvbCmdlineSubstList* avb_new_cmdline_subst_list() { | |
377 | + return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList)); | |
378 | +} | |
379 | + | |
380 | +void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) { | |
381 | + size_t i; | |
382 | + for (i = 0; i < cmdline_subst->size; ++i) { | |
383 | + avb_free(cmdline_subst->tokens[i]); | |
384 | + avb_free(cmdline_subst->values[i]); | |
385 | + } | |
386 | + cmdline_subst->size = 0; | |
387 | + avb_free(cmdline_subst); | |
388 | +} | |
389 | + | |
390 | +AvbSlotVerifyResult avb_add_root_digest_substitution( | |
391 | + const char* part_name, | |
392 | + const uint8_t* digest, | |
393 | + size_t digest_size, | |
394 | + AvbCmdlineSubstList* out_cmdline_subst) { | |
395 | + const char* kDigestSubPrefix = "$(AVB_"; | |
396 | + const char* kDigestSubSuffix = "_ROOT_DIGEST)"; | |
397 | + size_t part_name_len = avb_strlen(part_name); | |
398 | + size_t list_index = out_cmdline_subst->size; | |
399 | + | |
400 | + avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE); | |
401 | + avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE); | |
402 | + if (part_name_len >= AVB_PART_NAME_MAX_SIZE || | |
403 | + digest_size > AVB_SHA512_DIGEST_SIZE) { | |
404 | + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
405 | + } | |
406 | + | |
407 | + if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) { | |
408 | + /* The list is full. Currently dynamic growth of this list is not supported. | |
409 | + */ | |
410 | + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
411 | + } | |
412 | + | |
413 | + /* Construct the token to replace in the command line based on the partition | |
414 | + * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'. | |
415 | + */ | |
416 | + out_cmdline_subst->tokens[list_index] = | |
417 | + avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL); | |
418 | + if (out_cmdline_subst->tokens[list_index] == NULL) { | |
419 | + goto fail; | |
420 | + } | |
421 | + avb_uppercase(out_cmdline_subst->tokens[list_index]); | |
422 | + | |
423 | + /* The digest value is hex encoded when inserted in the command line. */ | |
424 | + out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size); | |
425 | + if (out_cmdline_subst->values[list_index] == NULL) { | |
426 | + goto fail; | |
427 | + } | |
428 | + | |
429 | + out_cmdline_subst->size++; | |
430 | + return AVB_SLOT_VERIFY_RESULT_OK; | |
431 | + | |
432 | +fail: | |
433 | + if (out_cmdline_subst->tokens[list_index]) { | |
434 | + avb_free(out_cmdline_subst->tokens[list_index]); | |
435 | + } | |
436 | + if (out_cmdline_subst->values[list_index]) { | |
437 | + avb_free(out_cmdline_subst->values[list_index]); | |
438 | + } | |
439 | + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
440 | +} |
lib/avb/libavb/avb_cmdline.h
1 | +/* | |
2 | + * Copyright (C) 2016 The Android Open Source Project | |
3 | + * | |
4 | + * Permission is hereby granted, free of charge, to any person | |
5 | + * obtaining a copy of this software and associated documentation | |
6 | + * files (the "Software"), to deal in the Software without | |
7 | + * restriction, including without limitation the rights to use, copy, | |
8 | + * modify, merge, publish, distribute, sublicense, and/or sell copies | |
9 | + * of the Software, and to permit persons to whom the Software is | |
10 | + * furnished to do so, subject to the following conditions: | |
11 | + * | |
12 | + * The above copyright notice and this permission notice shall be | |
13 | + * included in all copies or substantial portions of the Software. | |
14 | + * | |
15 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
16 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
17 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
18 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
19 | + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
20 | + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
21 | + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
22 | + * SOFTWARE. | |
23 | + */ | |
24 | + | |
25 | +#ifdef AVB_INSIDE_LIBAVB_H | |
26 | +#error "You can't include avb_sha.h in the public header libavb.h." | |
27 | +#endif | |
28 | + | |
29 | +#ifndef AVB_COMPILATION | |
30 | +#error "Never include this file, it may only be used from internal avb code." | |
31 | +#endif | |
32 | + | |
33 | +#ifndef AVB_CMDLINE_H_ | |
34 | +#define AVB_CMDLINE_H_ | |
35 | + | |
36 | +#include "avb_ops.h" | |
37 | +#include "avb_slot_verify.h" | |
38 | + | |
39 | +/* Maximum allow length (in bytes) of a partition name, including | |
40 | + * ab_suffix. | |
41 | + */ | |
42 | +#define AVB_PART_NAME_MAX_SIZE 32 | |
43 | + | |
44 | +#define AVB_MAX_NUM_CMDLINE_SUBST 10 | |
45 | + | |
46 | +/* Holds information about command-line substitutions. */ | |
47 | +typedef struct AvbCmdlineSubstList { | |
48 | + size_t size; | |
49 | + char* tokens[AVB_MAX_NUM_CMDLINE_SUBST]; | |
50 | + char* values[AVB_MAX_NUM_CMDLINE_SUBST]; | |
51 | +} AvbCmdlineSubstList; | |
52 | + | |
53 | +/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with | |
54 | + * values. Returns NULL on OOM, otherwise the cmdline with values | |
55 | + * replaced. | |
56 | + */ | |
57 | +char* avb_sub_cmdline(AvbOps* ops, | |
58 | + const char* cmdline, | |
59 | + const char* ab_suffix, | |
60 | + bool using_boot_for_vbmeta, | |
61 | + const AvbCmdlineSubstList* additional_substitutions); | |
62 | + | |
63 | +AvbSlotVerifyResult avb_append_options( | |
64 | + AvbOps* ops, | |
65 | + AvbSlotVerifyData* slot_data, | |
66 | + AvbVBMetaImageHeader* toplevel_vbmeta, | |
67 | + AvbAlgorithmType algorithm_type, | |
68 | + AvbHashtreeErrorMode hashtree_error_mode); | |
69 | + | |
70 | +/* Allocates and initializes a new command line substitution list. Free with | |
71 | + * |avb_free_cmdline_subst_list|. | |
72 | + */ | |
73 | +AvbCmdlineSubstList* avb_new_cmdline_subst_list(void); | |
74 | + | |
75 | +/* Use this instead of |avb_free| to deallocate a AvbCmdlineSubstList. */ | |
76 | +void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst); | |
77 | + | |
78 | +/* Adds a hashtree root digest to be substituted in $(AVB_*_ROOT_DIGEST) | |
79 | + * variables. The partition name differentiates the variable. For example, if | |
80 | + * |part_name| is "foo" then $(AVB_FOO_ROOT_DIGEST) will be substituted with the | |
81 | + * hex encoding of the digest. The substitution will be added to | |
82 | + * |out_cmdline_subst|. Returns AVB_SLOT_VERIFY_RESULT_OK on success. | |
83 | + */ | |
84 | +AvbSlotVerifyResult avb_add_root_digest_substitution( | |
85 | + const char* part_name, | |
86 | + const uint8_t* digest, | |
87 | + size_t digest_size, | |
88 | + AvbCmdlineSubstList* out_cmdline_subst); | |
89 | + | |
90 | +#endif |
lib/avb/libavb/avb_crypto.c
... | ... | @@ -355,8 +355,7 @@ |
355 | 355 | }; |
356 | 356 | |
357 | 357 | const AvbAlgorithmData* avb_get_algorithm_data(AvbAlgorithmType algorithm) { |
358 | - if (algorithm >= AVB_ALGORITHM_TYPE_NONE && | |
359 | - algorithm < _AVB_ALGORITHM_NUM_TYPES) { | |
358 | + if ((size_t)algorithm < _AVB_ALGORITHM_NUM_TYPES) { | |
360 | 359 | return &algorithm_data[algorithm]; |
361 | 360 | } |
362 | 361 | return NULL; |
lib/avb/libavb/avb_crypto.h
... | ... | @@ -44,11 +44,20 @@ |
44 | 44 | /* Size of a RSA-8192 signature. */ |
45 | 45 | #define AVB_RSA8192_NUM_BYTES 1024 |
46 | 46 | |
47 | +/* Size in bytes of a SHA-1 digest. */ | |
48 | +#define AVB_SHA1_DIGEST_SIZE 20 | |
49 | + | |
47 | 50 | /* Size in bytes of a SHA-256 digest. */ |
48 | 51 | #define AVB_SHA256_DIGEST_SIZE 32 |
49 | 52 | |
50 | 53 | /* Size in bytes of a SHA-512 digest. */ |
51 | 54 | #define AVB_SHA512_DIGEST_SIZE 64 |
55 | + | |
56 | +/* Possible digest types supported by libavb routines. */ | |
57 | +typedef enum { | |
58 | + AVB_DIGEST_TYPE_SHA256, | |
59 | + AVB_DIGEST_TYPE_SHA512, | |
60 | +} AvbDigestType; | |
52 | 61 | |
53 | 62 | /* Algorithms that can be used in the vbmeta image for |
54 | 63 | * verification. An algorithm consists of a hash type and a signature |
lib/avb/libavb/avb_hash_descriptor.c
... | ... | @@ -44,6 +44,7 @@ |
44 | 44 | dest->partition_name_len = avb_be32toh(dest->partition_name_len); |
45 | 45 | dest->salt_len = avb_be32toh(dest->salt_len); |
46 | 46 | dest->digest_len = avb_be32toh(dest->digest_len); |
47 | + dest->flags = avb_be32toh(dest->flags); | |
47 | 48 | |
48 | 49 | /* Check that partition_name, salt, and digest are fully contained. */ |
49 | 50 | expected_size = sizeof(AvbHashDescriptor) - sizeof(AvbDescriptor); |
lib/avb/libavb/avb_hash_descriptor.h
... | ... | @@ -35,6 +35,16 @@ |
35 | 35 | extern "C" { |
36 | 36 | #endif |
37 | 37 | |
38 | +/* Flags for hash descriptors. | |
39 | + * | |
40 | + * AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B | |
41 | + * partition logic to this partition. This is intentionally a negative boolean | |
42 | + * because A/B should be both the default and most used in practice. | |
43 | + */ | |
44 | +typedef enum { | |
45 | + AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), | |
46 | +} AvbHashDescriptorFlags; | |
47 | + | |
38 | 48 | /* A descriptor containing information about hash for an image. |
39 | 49 | * |
40 | 50 | * This descriptor is typically used for boot partitions to verify the |
... | ... | @@ -46,6 +56,10 @@ |
46 | 56 | * |
47 | 57 | * The |reserved| field is for future expansion and must be set to NUL |
48 | 58 | * bytes. |
59 | + * | |
60 | + * Changes in v1.1: | |
61 | + * - flags field is added which supports AVB_HASH_DESCRIPTOR_FLAGS_USE_AB | |
62 | + * - digest_len may be zero, which indicates the use of a persistent digest | |
49 | 63 | */ |
50 | 64 | typedef struct AvbHashDescriptor { |
51 | 65 | AvbDescriptor parent_descriptor; |
... | ... | @@ -54,7 +68,8 @@ |
54 | 68 | uint32_t partition_name_len; |
55 | 69 | uint32_t salt_len; |
56 | 70 | uint32_t digest_len; |
57 | - uint8_t reserved[64]; | |
71 | + uint32_t flags; | |
72 | + uint8_t reserved[60]; | |
58 | 73 | } AVB_ATTR_PACKED AvbHashDescriptor; |
59 | 74 | |
60 | 75 | /* Copies |src| to |dest| and validates, byte-swapping fields in the |
lib/avb/libavb/avb_hashtree_descriptor.c
... | ... | @@ -52,6 +52,7 @@ |
52 | 52 | dest->partition_name_len = avb_be32toh(dest->partition_name_len); |
53 | 53 | dest->salt_len = avb_be32toh(dest->salt_len); |
54 | 54 | dest->root_digest_len = avb_be32toh(dest->root_digest_len); |
55 | + dest->flags = avb_be32toh(dest->flags); | |
55 | 56 | |
56 | 57 | /* Check that partition_name, salt, and root_digest are fully contained. */ |
57 | 58 | expected_size = sizeof(AvbHashtreeDescriptor) - sizeof(AvbDescriptor); |
lib/avb/libavb/avb_hashtree_descriptor.h
... | ... | @@ -35,6 +35,16 @@ |
35 | 35 | extern "C" { |
36 | 36 | #endif |
37 | 37 | |
38 | +/* Flags for hashtree descriptors. | |
39 | + * | |
40 | + * AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B | |
41 | + * partition logic to this partition. This is intentionally a negative boolean | |
42 | + * because A/B should be both the default and most used in practice. | |
43 | + */ | |
44 | +typedef enum { | |
45 | + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), | |
46 | +} AvbHashtreeDescriptorFlags; | |
47 | + | |
38 | 48 | /* A descriptor containing information about a dm-verity hashtree. |
39 | 49 | * |
40 | 50 | * Hash-trees are used to verify large partitions typically containing |
... | ... | @@ -48,6 +58,10 @@ |
48 | 58 | * |
49 | 59 | * The |reserved| field is for future expansion and must be set to NUL |
50 | 60 | * bytes. |
61 | + * | |
62 | + * Changes in v1.1: | |
63 | + * - flags field is added which supports AVB_HASHTREE_DESCRIPTOR_FLAGS_USE_AB | |
64 | + * - digest_len may be zero, which indicates the use of a persistent digest | |
51 | 65 | */ |
52 | 66 | typedef struct AvbHashtreeDescriptor { |
53 | 67 | AvbDescriptor parent_descriptor; |
... | ... | @@ -64,7 +78,8 @@ |
64 | 78 | uint32_t partition_name_len; |
65 | 79 | uint32_t salt_len; |
66 | 80 | uint32_t root_digest_len; |
67 | - uint8_t reserved[64]; | |
81 | + uint32_t flags; | |
82 | + uint8_t reserved[60]; | |
68 | 83 | } AVB_ATTR_PACKED AvbHashtreeDescriptor; |
69 | 84 | |
70 | 85 | /* Copies |src| to |dest| and validates, byte-swapping fields in the |
lib/avb/libavb/avb_ops.h
... | ... | @@ -35,6 +35,9 @@ |
35 | 35 | extern "C" { |
36 | 36 | #endif |
37 | 37 | |
38 | +/* Well-known names of named persistent values. */ | |
39 | +#define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest." | |
40 | + | |
38 | 41 | /* Return codes used for I/O operations. |
39 | 42 | * |
40 | 43 | * AVB_IO_RESULT_OK is returned if the requested operation was |
41 | 44 | |
... | ... | @@ -51,13 +54,25 @@ |
51 | 54 | * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION is returned if the |
52 | 55 | * range of bytes requested to be read or written is outside the range |
53 | 56 | * of the partition. |
57 | + * | |
58 | + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE is returned if a named persistent value | |
59 | + * does not exist. | |
60 | + * | |
61 | + * AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE is returned if a named persistent | |
62 | + * value size is not supported or does not match the expected size. | |
63 | + * | |
64 | + * AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned if a buffer is too small | |
65 | + * for the requested operation. | |
54 | 66 | */ |
55 | 67 | typedef enum { |
56 | 68 | AVB_IO_RESULT_OK, |
57 | 69 | AVB_IO_RESULT_ERROR_OOM, |
58 | 70 | AVB_IO_RESULT_ERROR_IO, |
59 | 71 | AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, |
60 | - AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION | |
72 | + AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION, | |
73 | + AVB_IO_RESULT_ERROR_NO_SUCH_VALUE, | |
74 | + AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE, | |
75 | + AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE, | |
61 | 76 | } AvbIOResult; |
62 | 77 | |
63 | 78 | struct AvbOps; |
... | ... | @@ -117,6 +132,27 @@ |
117 | 132 | void* buffer, |
118 | 133 | size_t* out_num_read); |
119 | 134 | |
135 | + /* Gets the starting pointer of a partition that is pre-loaded in memory, and | |
136 | + * save it to |out_pointer|. The preloaded partition is expected to be | |
137 | + * |num_bytes|, where the actual preloaded byte count is returned in | |
138 | + * |out_num_bytes_preloaded|. |out_num_bytes_preloaded| must be no larger than | |
139 | + * |num_bytes|. | |
140 | + * | |
141 | + * This provides an alternative way to access a partition that is preloaded | |
142 | + * into memory without a full memory copy. When this function pointer is not | |
143 | + * set (has value NULL), or when the |out_pointer| is set to NULL as a result, | |
144 | + * |read_from_partition| will be used as the fallback. This function is mainly | |
145 | + * used for accessing the entire partition content to calculate its hash. | |
146 | + * | |
147 | + * Preloaded partition data must outlive the lifespan of the | |
148 | + * |AvbSlotVerifyData| structure that |avb_slot_verify| outputs. | |
149 | + */ | |
150 | + AvbIOResult (*get_preloaded_partition)(AvbOps* ops, | |
151 | + const char* partition, | |
152 | + size_t num_bytes, | |
153 | + uint8_t** out_pointer, | |
154 | + size_t* out_num_bytes_preloaded); | |
155 | + | |
120 | 156 | /* Writes |num_bytes| from |bffer| at offset |offset| to partition |
121 | 157 | * with name |partition| (NUL-terminated UTF-8 string). If |offset| |
122 | 158 | * is negative, its absolute value should be interpreted as the |
... | ... | @@ -219,6 +255,53 @@ |
219 | 255 | AvbIOResult (*get_size_of_partition)(AvbOps* ops, |
220 | 256 | const char* partition, |
221 | 257 | uint64_t* out_size_num_bytes); |
258 | + | |
259 | + /* Reads a persistent value corresponding to the given |name|. The value is | |
260 | + * returned in |out_buffer| which must point to |buffer_size| bytes. On | |
261 | + * success |out_num_bytes_read| contains the number of bytes read into | |
262 | + * |out_buffer|. If AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned, | |
263 | + * |out_num_bytes_read| contains the number of bytes that would have been read | |
264 | + * which can be used to allocate a buffer. | |
265 | + * | |
266 | + * The |buffer_size| may be zero and the |out_buffer| may be NULL, but if | |
267 | + * |out_buffer| is NULL then |buffer_size| *must* be zero. | |
268 | + * | |
269 | + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. | |
270 | + * | |
271 | + * If the value does not exist, is not supported, or is not populated, returns | |
272 | + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the | |
273 | + * size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE. | |
274 | + * | |
275 | + * This operation is currently only used to support persistent digests. If a | |
276 | + * device does not use persistent digests this function pointer can be set to | |
277 | + * NULL. | |
278 | + */ | |
279 | + AvbIOResult (*read_persistent_value)(AvbOps* ops, | |
280 | + const char* name, | |
281 | + size_t buffer_size, | |
282 | + uint8_t* out_buffer, | |
283 | + size_t* out_num_bytes_read); | |
284 | + | |
285 | + /* Writes a persistent value corresponding to the given |name|. The value is | |
286 | + * supplied in |value| which must point to |value_size| bytes. Any existing | |
287 | + * value with the same name is overwritten. If |value_size| is zero, future | |
288 | + * calls to |read_persistent_value| will return | |
289 | + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. | |
290 | + * | |
291 | + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. | |
292 | + * | |
293 | + * If the value |name| is not supported, returns | |
294 | + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported, | |
295 | + * returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE. | |
296 | + * | |
297 | + * This operation is currently only used to support persistent digests. If a | |
298 | + * device does not use persistent digests this function pointer can be set to | |
299 | + * NULL. | |
300 | + */ | |
301 | + AvbIOResult (*write_persistent_value)(AvbOps* ops, | |
302 | + const char* name, | |
303 | + size_t value_size, | |
304 | + const uint8_t* value); | |
222 | 305 | }; |
223 | 306 | |
224 | 307 | #ifdef __cplusplus |
lib/avb/libavb/avb_slot_verify.c
Changes suppressed. Click to show
... | ... | @@ -24,19 +24,16 @@ |
24 | 24 | |
25 | 25 | #include "avb_slot_verify.h" |
26 | 26 | #include "avb_chain_partition_descriptor.h" |
27 | +#include "avb_cmdline.h" | |
27 | 28 | #include "avb_footer.h" |
28 | 29 | #include "avb_hash_descriptor.h" |
30 | +#include "avb_hashtree_descriptor.h" | |
29 | 31 | #include "avb_kernel_cmdline_descriptor.h" |
30 | 32 | #include "avb_sha.h" |
31 | 33 | #include "avb_util.h" |
32 | 34 | #include "avb_vbmeta_image.h" |
33 | 35 | #include "avb_version.h" |
34 | 36 | |
35 | -/* Maximum allow length (in bytes) of a partition name, including | |
36 | - * ab_suffix. | |
37 | - */ | |
38 | -#define PART_NAME_MAX_SIZE 32 | |
39 | - | |
40 | 37 | /* Maximum number of partitions that can be loaded with avb_slot_verify(). */ |
41 | 38 | #define MAX_NUMBER_OF_LOADED_PARTITIONS 32 |
42 | 39 | |
... | ... | @@ -69,6 +66,114 @@ |
69 | 66 | return false; |
70 | 67 | } |
71 | 68 | |
69 | +static AvbSlotVerifyResult load_full_partition(AvbOps* ops, | |
70 | + const char* part_name, | |
71 | + uint64_t image_size, | |
72 | + uint8_t** out_image_buf, | |
73 | + bool* out_image_preloaded) { | |
74 | + size_t part_num_read; | |
75 | + AvbIOResult io_ret; | |
76 | + | |
77 | + /* Make sure that we do not overwrite existing data. */ | |
78 | + avb_assert(*out_image_buf == NULL); | |
79 | + avb_assert(!*out_image_preloaded); | |
80 | + | |
81 | + /* We are going to implicitly cast image_size from uint64_t to size_t in the | |
82 | + * following code, so we need to make sure that the cast is safe. */ | |
83 | + if (image_size != (size_t)(image_size)) { | |
84 | + avb_errorv(part_name, ": Partition size too large to load.\n", NULL); | |
85 | + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
86 | + } | |
87 | + | |
88 | + /* Try use a preloaded one. */ | |
89 | + if (ops->get_preloaded_partition != NULL) { | |
90 | + io_ret = ops->get_preloaded_partition( | |
91 | + ops, part_name, image_size, out_image_buf, &part_num_read); | |
92 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
93 | + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
94 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
95 | + avb_errorv(part_name, ": Error loading data from partition.\n", NULL); | |
96 | + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
97 | + } | |
98 | + | |
99 | + if (*out_image_buf != NULL) { | |
100 | + if (part_num_read != image_size) { | |
101 | + avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL); | |
102 | + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
103 | + } | |
104 | + *out_image_preloaded = true; | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + /* Allocate and copy the partition. */ | |
109 | + if (!*out_image_preloaded) { | |
110 | + *out_image_buf = avb_malloc(image_size); | |
111 | + if (*out_image_buf == NULL) { | |
112 | + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
113 | + } | |
114 | + | |
115 | + io_ret = ops->read_from_partition(ops, | |
116 | + part_name, | |
117 | + 0 /* offset */, | |
118 | + image_size, | |
119 | + *out_image_buf, | |
120 | + &part_num_read); | |
121 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
122 | + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
123 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
124 | + avb_errorv(part_name, ": Error loading data from partition.\n", NULL); | |
125 | + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
126 | + } | |
127 | + if (part_num_read != image_size) { | |
128 | + avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL); | |
129 | + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
130 | + } | |
131 | + } | |
132 | + | |
133 | + return AVB_SLOT_VERIFY_RESULT_OK; | |
134 | +} | |
135 | + | |
136 | +static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops, | |
137 | + const char* part_name, | |
138 | + size_t expected_digest_size, | |
139 | + uint8_t* out_digest) { | |
140 | + char* persistent_value_name = NULL; | |
141 | + AvbIOResult io_ret = AVB_IO_RESULT_OK; | |
142 | + size_t stored_digest_size = 0; | |
143 | + | |
144 | + if (ops->read_persistent_value == NULL) { | |
145 | + avb_errorv(part_name, ": Persistent values are not implemented.\n", NULL); | |
146 | + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
147 | + } | |
148 | + persistent_value_name = | |
149 | + avb_strdupv(AVB_NPV_PERSISTENT_DIGEST_PREFIX, part_name, NULL); | |
150 | + if (persistent_value_name == NULL) { | |
151 | + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
152 | + } | |
153 | + io_ret = ops->read_persistent_value(ops, | |
154 | + persistent_value_name, | |
155 | + expected_digest_size, | |
156 | + out_digest, | |
157 | + &stored_digest_size); | |
158 | + avb_free(persistent_value_name); | |
159 | + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
160 | + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
161 | + } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) { | |
162 | + avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL); | |
163 | + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
164 | + } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE || | |
165 | + io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE || | |
166 | + expected_digest_size != stored_digest_size) { | |
167 | + avb_errorv( | |
168 | + part_name, ": Persistent digest is not of expected size.\n", NULL); | |
169 | + return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
170 | + } else if (io_ret != AVB_IO_RESULT_OK) { | |
171 | + avb_errorv(part_name, ": Error reading persistent digest.\n", NULL); | |
172 | + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
173 | + } | |
174 | + return AVB_SLOT_VERIFY_RESULT_OK; | |
175 | +} | |
176 | + | |
72 | 177 | static AvbSlotVerifyResult load_and_verify_hash_partition( |
73 | 178 | AvbOps* ops, |
74 | 179 | const char* const* requested_partitions, |
75 | 180 | |
76 | 181 | |
... | ... | @@ -80,15 +185,18 @@ |
80 | 185 | const uint8_t* desc_partition_name = NULL; |
81 | 186 | const uint8_t* desc_salt; |
82 | 187 | const uint8_t* desc_digest; |
83 | - char part_name[PART_NAME_MAX_SIZE]; | |
188 | + char part_name[AVB_PART_NAME_MAX_SIZE]; | |
84 | 189 | AvbSlotVerifyResult ret; |
85 | 190 | AvbIOResult io_ret; |
86 | 191 | uint8_t* image_buf = NULL; |
87 | - size_t part_num_read; | |
192 | + bool image_preloaded = false; | |
88 | 193 | uint8_t* digest; |
89 | 194 | size_t digest_len; |
90 | 195 | const char* found; |
91 | 196 | uint64_t image_size; |
197 | + size_t expected_digest_len = 0; | |
198 | + uint8_t expected_digest_buf[AVB_SHA512_DIGEST_SIZE]; | |
199 | + const uint8_t* expected_digest = NULL; | |
92 | 200 | |
93 | 201 | if (!avb_hash_descriptor_validate_and_byteswap( |
94 | 202 | (const AvbHashDescriptor*)descriptor, &hash_desc)) { |
95 | 203 | |
... | ... | @@ -118,15 +226,35 @@ |
118 | 226 | goto out; |
119 | 227 | } |
120 | 228 | |
121 | - if (!avb_str_concat(part_name, | |
122 | - sizeof part_name, | |
123 | - (const char*)desc_partition_name, | |
124 | - hash_desc.partition_name_len, | |
125 | - ab_suffix, | |
126 | - avb_strlen(ab_suffix))) { | |
127 | - avb_error("Partition name and suffix does not fit.\n"); | |
229 | + if ((hash_desc.flags & AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) != 0) { | |
230 | + /* No ab_suffix, just copy the partition name as is. */ | |
231 | + if (hash_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) { | |
232 | + avb_error("Partition name does not fit.\n"); | |
233 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
234 | + goto out; | |
235 | + } | |
236 | + avb_memcpy(part_name, desc_partition_name, hash_desc.partition_name_len); | |
237 | + part_name[hash_desc.partition_name_len] = '\0'; | |
238 | + } else if (hash_desc.digest_len == 0 && avb_strlen(ab_suffix) != 0) { | |
239 | + /* No ab_suffix allowed for partitions without a digest in the descriptor | |
240 | + * because these partitions hold data unique to this device and are not | |
241 | + * updated using an A/B scheme. | |
242 | + */ | |
243 | + avb_error("Cannot use A/B with a persistent digest.\n"); | |
128 | 244 | ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; |
129 | 245 | goto out; |
246 | + } else { | |
247 | + /* Add ab_suffix to the partition name. */ | |
248 | + if (!avb_str_concat(part_name, | |
249 | + sizeof part_name, | |
250 | + (const char*)desc_partition_name, | |
251 | + hash_desc.partition_name_len, | |
252 | + ab_suffix, | |
253 | + avb_strlen(ab_suffix))) { | |
254 | + avb_error("Partition name and suffix does not fit.\n"); | |
255 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
256 | + goto out; | |
257 | + } | |
130 | 258 | } |
131 | 259 | |
132 | 260 | /* If we're allowing verification errors then hash_desc.image_size |
133 | 261 | |
... | ... | @@ -159,28 +287,12 @@ |
159 | 287 | } |
160 | 288 | } |
161 | 289 | |
162 | - image_buf = avb_malloc(image_size); | |
163 | - if (image_buf == NULL) { | |
164 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
290 | + ret = load_full_partition( | |
291 | + ops, part_name, image_size, &image_buf, &image_preloaded); | |
292 | + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { | |
165 | 293 | goto out; |
166 | 294 | } |
167 | 295 | |
168 | - io_ret = ops->read_from_partition( | |
169 | - ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read); | |
170 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
171 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
172 | - goto out; | |
173 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
174 | - avb_errorv(part_name, ": Error loading data from partition.\n", NULL); | |
175 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
176 | - goto out; | |
177 | - } | |
178 | - if (part_num_read != image_size) { | |
179 | - avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL); | |
180 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
181 | - goto out; | |
182 | - } | |
183 | - | |
184 | 296 | if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) { |
185 | 297 | AvbSHA256Ctx sha256_ctx; |
186 | 298 | avb_sha256_init(&sha256_ctx); |
187 | 299 | |
... | ... | @@ -201,14 +313,31 @@ |
201 | 313 | goto out; |
202 | 314 | } |
203 | 315 | |
204 | - if (digest_len != hash_desc.digest_len) { | |
316 | + if (hash_desc.digest_len == 0) { | |
317 | + // Expect a match to a persistent digest. | |
318 | + avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL); | |
319 | + expected_digest_len = digest_len; | |
320 | + expected_digest = expected_digest_buf; | |
321 | + avb_assert(expected_digest_len <= sizeof(expected_digest_buf)); | |
322 | + ret = | |
323 | + read_persistent_digest(ops, part_name, digest_len, expected_digest_buf); | |
324 | + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { | |
325 | + goto out; | |
326 | + } | |
327 | + } else { | |
328 | + // Expect a match to the digest in the descriptor. | |
329 | + expected_digest_len = hash_desc.digest_len; | |
330 | + expected_digest = desc_digest; | |
331 | + } | |
332 | + | |
333 | + if (digest_len != expected_digest_len) { | |
205 | 334 | avb_errorv( |
206 | 335 | part_name, ": Digest in descriptor not of expected size.\n", NULL); |
207 | 336 | ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; |
208 | 337 | goto out; |
209 | 338 | } |
210 | 339 | |
211 | - if (avb_safe_memcmp(digest, desc_digest, digest_len) != 0) { | |
340 | + if (avb_safe_memcmp(digest, expected_digest, digest_len) != 0) { | |
212 | 341 | avb_errorv(part_name, |
213 | 342 | ": Hash of data does not match digest in descriptor.\n", |
214 | 343 | NULL); |
215 | 344 | |
... | ... | @@ -234,11 +363,12 @@ |
234 | 363 | loaded_partition->partition_name = avb_strdup(found); |
235 | 364 | loaded_partition->data_size = image_size; |
236 | 365 | loaded_partition->data = image_buf; |
366 | + loaded_partition->preloaded = image_preloaded; | |
237 | 367 | image_buf = NULL; |
238 | 368 | } |
239 | 369 | |
240 | 370 | fail: |
241 | - if (image_buf != NULL) { | |
371 | + if (image_buf != NULL && !image_preloaded) { | |
242 | 372 | avb_free(image_buf); |
243 | 373 | } |
244 | 374 | return ret; |
... | ... | @@ -251,6 +381,7 @@ |
251 | 381 | AvbSlotVerifyData* slot_data) { |
252 | 382 | AvbSlotVerifyResult ret; |
253 | 383 | uint8_t* image_buf = NULL; |
384 | + bool image_preloaded = false; | |
254 | 385 | size_t n; |
255 | 386 | |
256 | 387 | if (ops->get_size_of_partition == NULL) { |
257 | 388 | |
... | ... | @@ -260,10 +391,9 @@ |
260 | 391 | } |
261 | 392 | |
262 | 393 | for (n = 0; requested_partitions[n] != NULL; n++) { |
263 | - char part_name[PART_NAME_MAX_SIZE]; | |
394 | + char part_name[AVB_PART_NAME_MAX_SIZE]; | |
264 | 395 | AvbIOResult io_ret; |
265 | 396 | uint64_t image_size; |
266 | - size_t part_num_read; | |
267 | 397 | AvbPartitionData* loaded_partition; |
268 | 398 | |
269 | 399 | if (!avb_str_concat(part_name, |
270 | 400 | |
... | ... | @@ -288,28 +418,12 @@ |
288 | 418 | } |
289 | 419 | avb_debugv(part_name, ": Loading entire partition.\n", NULL); |
290 | 420 | |
291 | - image_buf = avb_malloc(image_size); | |
292 | - if (image_buf == NULL) { | |
293 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
421 | + ret = load_full_partition( | |
422 | + ops, part_name, image_size, &image_buf, &image_preloaded); | |
423 | + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { | |
294 | 424 | goto out; |
295 | 425 | } |
296 | 426 | |
297 | - io_ret = ops->read_from_partition( | |
298 | - ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read); | |
299 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
300 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
301 | - goto out; | |
302 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
303 | - avb_errorv(part_name, ": Error loading data from partition.\n", NULL); | |
304 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
305 | - goto out; | |
306 | - } | |
307 | - if (part_num_read != image_size) { | |
308 | - avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL); | |
309 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
310 | - goto out; | |
311 | - } | |
312 | - | |
313 | 427 | /* Move to slot_data. */ |
314 | 428 | if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) { |
315 | 429 | avb_errorv(part_name, ": Too many loaded partitions.\n", NULL); |
316 | 430 | |
317 | 431 | |
318 | 432 | |
... | ... | @@ -324,16 +438,21 @@ |
324 | 438 | goto out; |
325 | 439 | } |
326 | 440 | loaded_partition->data_size = image_size; |
327 | - loaded_partition->data = image_buf; | |
441 | + loaded_partition->data = image_buf; /* Transferring the owner. */ | |
442 | + loaded_partition->preloaded = image_preloaded; | |
328 | 443 | image_buf = NULL; |
444 | + image_preloaded = false; | |
329 | 445 | } |
330 | 446 | |
331 | 447 | ret = AVB_SLOT_VERIFY_RESULT_OK; |
332 | 448 | |
333 | 449 | out: |
334 | - if (image_buf != NULL) { | |
450 | + /* Free the current buffer if any. */ | |
451 | + if (image_buf != NULL && !image_preloaded) { | |
335 | 452 | avb_free(image_buf); |
336 | 453 | } |
454 | + /* Buffers that are already saved in slot_data will be handled by the caller | |
455 | + * even on failure. */ | |
337 | 456 | return ret; |
338 | 457 | } |
339 | 458 | |
... | ... | @@ -349,8 +468,9 @@ |
349 | 468 | const uint8_t* expected_public_key, |
350 | 469 | size_t expected_public_key_length, |
351 | 470 | AvbSlotVerifyData* slot_data, |
352 | - AvbAlgorithmType* out_algorithm_type) { | |
353 | - char full_partition_name[PART_NAME_MAX_SIZE]; | |
471 | + AvbAlgorithmType* out_algorithm_type, | |
472 | + AvbCmdlineSubstList* out_additional_cmdline_subst) { | |
473 | + char full_partition_name[AVB_PART_NAME_MAX_SIZE]; | |
354 | 474 | AvbSlotVerifyResult ret; |
355 | 475 | AvbIOResult io_ret; |
356 | 476 | size_t vbmeta_offset; |
... | ... | @@ -485,7 +605,8 @@ |
485 | 605 | NULL /* expected_public_key */, |
486 | 606 | 0 /* expected_public_key_length */, |
487 | 607 | slot_data, |
488 | - out_algorithm_type); | |
608 | + out_algorithm_type, | |
609 | + out_additional_cmdline_subst); | |
489 | 610 | goto out; |
490 | 611 | } else { |
491 | 612 | avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL); |
... | ... | @@ -681,7 +802,8 @@ |
681 | 802 | * checks that it matches what's in the hash descriptor. |
682 | 803 | * |
683 | 804 | * - hashtree descriptor: Do nothing since verification happens |
684 | - * on-the-fly from within the OS. | |
805 | + * on-the-fly from within the OS. (Unless the descriptor uses a | |
806 | + * persistent digest, in which case we need to find it). | |
685 | 807 | * |
686 | 808 | * - chained partition descriptor: Load the footer, load the vbmeta |
687 | 809 | * image, verify vbmeta image (includes rollback checks, hash |
... | ... | @@ -752,18 +874,20 @@ |
752 | 874 | sizeof(AvbChainPartitionDescriptor); |
753 | 875 | chain_public_key = chain_partition_name + chain_desc.partition_name_len; |
754 | 876 | |
755 | - sub_ret = load_and_verify_vbmeta(ops, | |
756 | - requested_partitions, | |
757 | - ab_suffix, | |
758 | - allow_verification_error, | |
759 | - toplevel_vbmeta_flags, | |
760 | - chain_desc.rollback_index_location, | |
761 | - (const char*)chain_partition_name, | |
762 | - chain_desc.partition_name_len, | |
763 | - chain_public_key, | |
764 | - chain_desc.public_key_len, | |
765 | - slot_data, | |
766 | - NULL /* out_algorithm_type */); | |
877 | + sub_ret = | |
878 | + load_and_verify_vbmeta(ops, | |
879 | + requested_partitions, | |
880 | + ab_suffix, | |
881 | + allow_verification_error, | |
882 | + toplevel_vbmeta_flags, | |
883 | + chain_desc.rollback_index_location, | |
884 | + (const char*)chain_partition_name, | |
885 | + chain_desc.partition_name_len, | |
886 | + chain_public_key, | |
887 | + chain_desc.public_key_len, | |
888 | + slot_data, | |
889 | + NULL, /* out_algorithm_type */ | |
890 | + NULL /* out_additional_cmdline_subst */); | |
767 | 891 | if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { |
768 | 892 | ret = sub_ret; |
769 | 893 | if (!result_should_continue(ret)) { |
770 | 894 | |
... | ... | @@ -849,9 +973,90 @@ |
849 | 973 | } |
850 | 974 | } break; |
851 | 975 | |
852 | - /* Explicit fall-through */ | |
976 | + case AVB_DESCRIPTOR_TAG_HASHTREE: { | |
977 | + AvbHashtreeDescriptor hashtree_desc; | |
978 | + | |
979 | + if (!avb_hashtree_descriptor_validate_and_byteswap( | |
980 | + (AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) { | |
981 | + avb_errorv( | |
982 | + full_partition_name, ": Hashtree descriptor is invalid.\n", NULL); | |
983 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
984 | + goto out; | |
985 | + } | |
986 | + | |
987 | + /* We only need to continue when there is no digest in the descriptor. | |
988 | + * This is because the only processing here is to find the digest and | |
989 | + * make it available on the kernel command line. | |
990 | + */ | |
991 | + if (hashtree_desc.root_digest_len == 0) { | |
992 | + char part_name[AVB_PART_NAME_MAX_SIZE]; | |
993 | + size_t digest_len = 0; | |
994 | + uint8_t digest_buf[AVB_SHA512_DIGEST_SIZE]; | |
995 | + const uint8_t* desc_partition_name = | |
996 | + ((const uint8_t*)descriptors[n]) + sizeof(AvbHashtreeDescriptor); | |
997 | + | |
998 | + if (!avb_validate_utf8(desc_partition_name, | |
999 | + hashtree_desc.partition_name_len)) { | |
1000 | + avb_error("Partition name is not valid UTF-8.\n"); | |
1001 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
1002 | + goto out; | |
1003 | + } | |
1004 | + | |
1005 | + /* No ab_suffix for partitions without a digest in the descriptor | |
1006 | + * because these partitions hold data unique to this device and are | |
1007 | + * not updated using an A/B scheme. | |
1008 | + */ | |
1009 | + if ((hashtree_desc.flags & | |
1010 | + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) == 0 && | |
1011 | + avb_strlen(ab_suffix) != 0) { | |
1012 | + avb_error("Cannot use A/B with a persistent root digest.\n"); | |
1013 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
1014 | + goto out; | |
1015 | + } | |
1016 | + if (hashtree_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) { | |
1017 | + avb_error("Partition name does not fit.\n"); | |
1018 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
1019 | + goto out; | |
1020 | + } | |
1021 | + avb_memcpy( | |
1022 | + part_name, desc_partition_name, hashtree_desc.partition_name_len); | |
1023 | + part_name[hashtree_desc.partition_name_len] = '\0'; | |
1024 | + | |
1025 | + /* Determine the expected digest size from the hash algorithm. */ | |
1026 | + if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, "sha1") == | |
1027 | + 0) { | |
1028 | + digest_len = AVB_SHA1_DIGEST_SIZE; | |
1029 | + } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, | |
1030 | + "sha256") == 0) { | |
1031 | + digest_len = AVB_SHA256_DIGEST_SIZE; | |
1032 | + } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, | |
1033 | + "sha512") == 0) { | |
1034 | + digest_len = AVB_SHA512_DIGEST_SIZE; | |
1035 | + } else { | |
1036 | + avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL); | |
1037 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; | |
1038 | + goto out; | |
1039 | + } | |
1040 | + | |
1041 | + ret = read_persistent_digest(ops, part_name, digest_len, digest_buf); | |
1042 | + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { | |
1043 | + goto out; | |
1044 | + } | |
1045 | + | |
1046 | + if (out_additional_cmdline_subst) { | |
1047 | + ret = | |
1048 | + avb_add_root_digest_substitution(part_name, | |
1049 | + digest_buf, | |
1050 | + digest_len, | |
1051 | + out_additional_cmdline_subst); | |
1052 | + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { | |
1053 | + goto out; | |
1054 | + } | |
1055 | + } | |
1056 | + } | |
1057 | + } break; | |
1058 | + | |
853 | 1059 | case AVB_DESCRIPTOR_TAG_PROPERTY: |
854 | - case AVB_DESCRIPTOR_TAG_HASHTREE: | |
855 | 1060 | /* Do nothing. */ |
856 | 1061 | break; |
857 | 1062 | } |
... | ... | @@ -886,350 +1091,6 @@ |
886 | 1091 | return ret; |
887 | 1092 | } |
888 | 1093 | |
889 | -#define NUM_GUIDS 3 | |
890 | - | |
891 | -/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with | |
892 | - * values. Returns NULL on OOM, otherwise the cmdline with values | |
893 | - * replaced. | |
894 | - */ | |
895 | -static char* sub_cmdline(AvbOps* ops, | |
896 | - const char* cmdline, | |
897 | - const char* ab_suffix, | |
898 | - bool using_boot_for_vbmeta) { | |
899 | - const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"}; | |
900 | - const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)", | |
901 | - "$(ANDROID_BOOT_PARTUUID)", | |
902 | - "$(ANDROID_VBMETA_PARTUUID)"}; | |
903 | - char* ret = NULL; | |
904 | - AvbIOResult io_ret; | |
905 | - | |
906 | - /* Special-case for when the top-level vbmeta struct is in the boot | |
907 | - * partition. | |
908 | - */ | |
909 | - if (using_boot_for_vbmeta) { | |
910 | - part_name_str[2] = "boot"; | |
911 | - } | |
912 | - | |
913 | - /* Replace unique partition GUIDs */ | |
914 | - for (size_t n = 0; n < NUM_GUIDS; n++) { | |
915 | - char part_name[PART_NAME_MAX_SIZE]; | |
916 | - char guid_buf[37]; | |
917 | - | |
918 | - if (!avb_str_concat(part_name, | |
919 | - sizeof part_name, | |
920 | - part_name_str[n], | |
921 | - avb_strlen(part_name_str[n]), | |
922 | - ab_suffix, | |
923 | - avb_strlen(ab_suffix))) { | |
924 | - avb_error("Partition name and suffix does not fit.\n"); | |
925 | - goto fail; | |
926 | - } | |
927 | - | |
928 | - io_ret = ops->get_unique_guid_for_partition( | |
929 | - ops, part_name, guid_buf, sizeof guid_buf); | |
930 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
931 | - return NULL; | |
932 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
933 | - avb_error("Error getting unique GUID for partition.\n"); | |
934 | - goto fail; | |
935 | - } | |
936 | - | |
937 | - if (ret == NULL) { | |
938 | - ret = avb_replace(cmdline, replace_str[n], guid_buf); | |
939 | - } else { | |
940 | - char* new_ret = avb_replace(ret, replace_str[n], guid_buf); | |
941 | - avb_free(ret); | |
942 | - ret = new_ret; | |
943 | - } | |
944 | - if (ret == NULL) { | |
945 | - goto fail; | |
946 | - } | |
947 | - } | |
948 | - | |
949 | - return ret; | |
950 | - | |
951 | -fail: | |
952 | - if (ret != NULL) { | |
953 | - avb_free(ret); | |
954 | - } | |
955 | - return NULL; | |
956 | -} | |
957 | - | |
958 | -static int cmdline_append_option(AvbSlotVerifyData* slot_data, | |
959 | - const char* key, | |
960 | - const char* value) { | |
961 | - size_t offset, key_len, value_len; | |
962 | - char* new_cmdline; | |
963 | - | |
964 | - key_len = avb_strlen(key); | |
965 | - value_len = avb_strlen(value); | |
966 | - | |
967 | - offset = 0; | |
968 | - if (slot_data->cmdline != NULL) { | |
969 | - offset = avb_strlen(slot_data->cmdline); | |
970 | - if (offset > 0) { | |
971 | - offset += 1; | |
972 | - } | |
973 | - } | |
974 | - | |
975 | - new_cmdline = avb_calloc(offset + key_len + value_len + 2); | |
976 | - if (new_cmdline == NULL) { | |
977 | - return 0; | |
978 | - } | |
979 | - if (offset > 0) { | |
980 | - avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1); | |
981 | - new_cmdline[offset - 1] = ' '; | |
982 | - } | |
983 | - avb_memcpy(new_cmdline + offset, key, key_len); | |
984 | - new_cmdline[offset + key_len] = '='; | |
985 | - avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len); | |
986 | - if (slot_data->cmdline != NULL) { | |
987 | - avb_free(slot_data->cmdline); | |
988 | - } | |
989 | - slot_data->cmdline = new_cmdline; | |
990 | - | |
991 | - return 1; | |
992 | -} | |
993 | - | |
994 | -#define AVB_MAX_DIGITS_UINT64 32 | |
995 | - | |
996 | -/* Writes |value| to |digits| in base 10 followed by a NUL byte. | |
997 | - * Returns number of characters written excluding the NUL byte. | |
998 | - */ | |
999 | -static size_t uint64_to_base10(uint64_t value, | |
1000 | - char digits[AVB_MAX_DIGITS_UINT64]) { | |
1001 | - char rev_digits[AVB_MAX_DIGITS_UINT64]; | |
1002 | - size_t n, num_digits; | |
1003 | - | |
1004 | - for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) { | |
1005 | - rev_digits[num_digits++] = (value % 10) + '0'; | |
1006 | - value /= 10; | |
1007 | - if (value == 0) { | |
1008 | - break; | |
1009 | - } | |
1010 | - } | |
1011 | - | |
1012 | - for (n = 0; n < num_digits; n++) { | |
1013 | - digits[n] = rev_digits[num_digits - 1 - n]; | |
1014 | - } | |
1015 | - digits[n] = '\0'; | |
1016 | - return n; | |
1017 | -} | |
1018 | - | |
1019 | -static int cmdline_append_version(AvbSlotVerifyData* slot_data, | |
1020 | - const char* key, | |
1021 | - uint64_t major_version, | |
1022 | - uint64_t minor_version) { | |
1023 | - char major_digits[AVB_MAX_DIGITS_UINT64]; | |
1024 | - char minor_digits[AVB_MAX_DIGITS_UINT64]; | |
1025 | - char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1]; | |
1026 | - size_t num_major_digits, num_minor_digits; | |
1027 | - | |
1028 | - num_major_digits = uint64_to_base10(major_version, major_digits); | |
1029 | - num_minor_digits = uint64_to_base10(minor_version, minor_digits); | |
1030 | - avb_memcpy(combined, major_digits, num_major_digits); | |
1031 | - combined[num_major_digits] = '.'; | |
1032 | - avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits); | |
1033 | - combined[num_major_digits + 1 + num_minor_digits] = '\0'; | |
1034 | - | |
1035 | - return cmdline_append_option(slot_data, key, combined); | |
1036 | -} | |
1037 | - | |
1038 | -static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data, | |
1039 | - const char* key, | |
1040 | - uint64_t value) { | |
1041 | - char digits[AVB_MAX_DIGITS_UINT64]; | |
1042 | - uint64_to_base10(value, digits); | |
1043 | - return cmdline_append_option(slot_data, key, digits); | |
1044 | -} | |
1045 | - | |
1046 | -static int cmdline_append_hex(AvbSlotVerifyData* slot_data, | |
1047 | - const char* key, | |
1048 | - const uint8_t* data, | |
1049 | - size_t data_len) { | |
1050 | - char hex_digits[17] = "0123456789abcdef"; | |
1051 | - char* hex_data; | |
1052 | - int ret; | |
1053 | - size_t n; | |
1054 | - | |
1055 | - hex_data = avb_malloc(data_len * 2 + 1); | |
1056 | - if (hex_data == NULL) { | |
1057 | - return 0; | |
1058 | - } | |
1059 | - | |
1060 | - for (n = 0; n < data_len; n++) { | |
1061 | - hex_data[n * 2] = hex_digits[data[n] >> 4]; | |
1062 | - hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f]; | |
1063 | - } | |
1064 | - hex_data[n * 2] = '\0'; | |
1065 | - | |
1066 | - ret = cmdline_append_option(slot_data, key, hex_data); | |
1067 | - avb_free(hex_data); | |
1068 | - return ret; | |
1069 | -} | |
1070 | - | |
1071 | -static AvbSlotVerifyResult append_options( | |
1072 | - AvbOps* ops, | |
1073 | - AvbSlotVerifyData* slot_data, | |
1074 | - AvbVBMetaImageHeader* toplevel_vbmeta, | |
1075 | - AvbAlgorithmType algorithm_type, | |
1076 | - AvbHashtreeErrorMode hashtree_error_mode) { | |
1077 | - AvbSlotVerifyResult ret; | |
1078 | - const char* verity_mode = NULL; | |
1079 | - bool is_device_unlocked; | |
1080 | - AvbIOResult io_ret; | |
1081 | - | |
1082 | - /* Add androidboot.vbmeta.device option. */ | |
1083 | - if (!cmdline_append_option(slot_data, | |
1084 | - "androidboot.vbmeta.device", | |
1085 | - "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { | |
1086 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1087 | - goto out; | |
1088 | - } | |
1089 | - | |
1090 | - /* Add androidboot.vbmeta.avb_version option. */ | |
1091 | - if (!cmdline_append_version(slot_data, | |
1092 | - "androidboot.vbmeta.avb_version", | |
1093 | - AVB_VERSION_MAJOR, | |
1094 | - AVB_VERSION_MINOR)) { | |
1095 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1096 | - goto out; | |
1097 | - } | |
1098 | - | |
1099 | - /* Set androidboot.avb.device_state to "locked" or "unlocked". */ | |
1100 | - io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked); | |
1101 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
1102 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1103 | - goto out; | |
1104 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
1105 | - avb_error("Error getting device state.\n"); | |
1106 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO; | |
1107 | - goto out; | |
1108 | - } | |
1109 | - if (!cmdline_append_option(slot_data, | |
1110 | - "androidboot.vbmeta.device_state", | |
1111 | - is_device_unlocked ? "unlocked" : "locked")) { | |
1112 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1113 | - goto out; | |
1114 | - } | |
1115 | - | |
1116 | - /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash | |
1117 | - * function as is used to sign vbmeta. | |
1118 | - */ | |
1119 | - switch (algorithm_type) { | |
1120 | - /* Explicit fallthrough. */ | |
1121 | - case AVB_ALGORITHM_TYPE_NONE: | |
1122 | - case AVB_ALGORITHM_TYPE_SHA256_RSA2048: | |
1123 | - case AVB_ALGORITHM_TYPE_SHA256_RSA4096: | |
1124 | - case AVB_ALGORITHM_TYPE_SHA256_RSA8192: { | |
1125 | - AvbSHA256Ctx ctx; | |
1126 | - size_t n, total_size = 0; | |
1127 | - avb_sha256_init(&ctx); | |
1128 | - for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
1129 | - avb_sha256_update(&ctx, | |
1130 | - slot_data->vbmeta_images[n].vbmeta_data, | |
1131 | - slot_data->vbmeta_images[n].vbmeta_size); | |
1132 | - total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
1133 | - } | |
1134 | - if (!cmdline_append_option( | |
1135 | - slot_data, "androidboot.vbmeta.hash_alg", "sha256") || | |
1136 | - !cmdline_append_uint64_base10( | |
1137 | - slot_data, "androidboot.vbmeta.size", total_size) || | |
1138 | - !cmdline_append_hex(slot_data, | |
1139 | - "androidboot.vbmeta.digest", | |
1140 | - avb_sha256_final(&ctx), | |
1141 | - AVB_SHA256_DIGEST_SIZE)) { | |
1142 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1143 | - goto out; | |
1144 | - } | |
1145 | - } break; | |
1146 | - /* Explicit fallthrough. */ | |
1147 | - case AVB_ALGORITHM_TYPE_SHA512_RSA2048: | |
1148 | - case AVB_ALGORITHM_TYPE_SHA512_RSA4096: | |
1149 | - case AVB_ALGORITHM_TYPE_SHA512_RSA8192: { | |
1150 | - AvbSHA512Ctx ctx; | |
1151 | - size_t n, total_size = 0; | |
1152 | - avb_sha512_init(&ctx); | |
1153 | - for (n = 0; n < slot_data->num_vbmeta_images; n++) { | |
1154 | - avb_sha512_update(&ctx, | |
1155 | - slot_data->vbmeta_images[n].vbmeta_data, | |
1156 | - slot_data->vbmeta_images[n].vbmeta_size); | |
1157 | - total_size += slot_data->vbmeta_images[n].vbmeta_size; | |
1158 | - } | |
1159 | - if (!cmdline_append_option( | |
1160 | - slot_data, "androidboot.vbmeta.hash_alg", "sha512") || | |
1161 | - !cmdline_append_uint64_base10( | |
1162 | - slot_data, "androidboot.vbmeta.size", total_size) || | |
1163 | - !cmdline_append_hex(slot_data, | |
1164 | - "androidboot.vbmeta.digest", | |
1165 | - avb_sha512_final(&ctx), | |
1166 | - AVB_SHA512_DIGEST_SIZE)) { | |
1167 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1168 | - goto out; | |
1169 | - } | |
1170 | - } break; | |
1171 | - case _AVB_ALGORITHM_NUM_TYPES: | |
1172 | - avb_assert_not_reached(); | |
1173 | - break; | |
1174 | - } | |
1175 | - | |
1176 | - /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */ | |
1177 | - if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) { | |
1178 | - verity_mode = "disabled"; | |
1179 | - } else { | |
1180 | - const char* dm_verity_mode = NULL; | |
1181 | - char* new_ret; | |
1182 | - | |
1183 | - switch (hashtree_error_mode) { | |
1184 | - case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE: | |
1185 | - if (!cmdline_append_option( | |
1186 | - slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) { | |
1187 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1188 | - goto out; | |
1189 | - } | |
1190 | - verity_mode = "enforcing"; | |
1191 | - dm_verity_mode = "restart_on_corruption"; | |
1192 | - break; | |
1193 | - case AVB_HASHTREE_ERROR_MODE_RESTART: | |
1194 | - verity_mode = "enforcing"; | |
1195 | - dm_verity_mode = "restart_on_corruption"; | |
1196 | - break; | |
1197 | - case AVB_HASHTREE_ERROR_MODE_EIO: | |
1198 | - verity_mode = "eio"; | |
1199 | - /* For now there's no option to specify the EIO mode. So | |
1200 | - * just use 'ignore_zero_blocks' since that's already set | |
1201 | - * and dm-verity-target.c supports specifying this multiple | |
1202 | - * times. | |
1203 | - */ | |
1204 | - dm_verity_mode = "ignore_zero_blocks"; | |
1205 | - break; | |
1206 | - case AVB_HASHTREE_ERROR_MODE_LOGGING: | |
1207 | - verity_mode = "logging"; | |
1208 | - dm_verity_mode = "ignore_corruption"; | |
1209 | - break; | |
1210 | - } | |
1211 | - new_ret = avb_replace( | |
1212 | - slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode); | |
1213 | - avb_free(slot_data->cmdline); | |
1214 | - slot_data->cmdline = new_ret; | |
1215 | - if (slot_data->cmdline == NULL) { | |
1216 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1217 | - goto out; | |
1218 | - } | |
1219 | - } | |
1220 | - if (!cmdline_append_option( | |
1221 | - slot_data, "androidboot.veritymode", verity_mode)) { | |
1222 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1223 | - goto out; | |
1224 | - } | |
1225 | - | |
1226 | - ret = AVB_SLOT_VERIFY_RESULT_OK; | |
1227 | - | |
1228 | -out: | |
1229 | - | |
1230 | - return ret; | |
1231 | -} | |
1232 | - | |
1233 | 1094 | AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, |
1234 | 1095 | const char* const* requested_partitions, |
1235 | 1096 | const char* ab_suffix, |
... | ... | @@ -1243,6 +1104,7 @@ |
1243 | 1104 | AvbVBMetaImageHeader toplevel_vbmeta; |
1244 | 1105 | bool allow_verification_error = |
1245 | 1106 | (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); |
1107 | + AvbCmdlineSubstList* additional_cmdline_subst = NULL; | |
1246 | 1108 | |
1247 | 1109 | /* Fail early if we're missing the AvbOps needed for slot verification. |
1248 | 1110 | * |
... | ... | @@ -1254,7 +1116,6 @@ |
1254 | 1116 | avb_assert(ops->validate_vbmeta_public_key != NULL); |
1255 | 1117 | avb_assert(ops->read_rollback_index != NULL); |
1256 | 1118 | avb_assert(ops->get_unique_guid_for_partition != NULL); |
1257 | - /* avb_assert(ops->get_size_of_partition != NULL); */ | |
1258 | 1119 | |
1259 | 1120 | if (out_data != NULL) { |
1260 | 1121 | *out_data = NULL; |
... | ... | @@ -1288,6 +1149,12 @@ |
1288 | 1149 | goto fail; |
1289 | 1150 | } |
1290 | 1151 | |
1152 | + additional_cmdline_subst = avb_new_cmdline_subst_list(); | |
1153 | + if (additional_cmdline_subst == NULL) { | |
1154 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1155 | + goto fail; | |
1156 | + } | |
1157 | + | |
1291 | 1158 | ret = load_and_verify_vbmeta(ops, |
1292 | 1159 | requested_partitions, |
1293 | 1160 | ab_suffix, |
... | ... | @@ -1299,7 +1166,8 @@ |
1299 | 1166 | NULL /* expected_public_key */, |
1300 | 1167 | 0 /* expected_public_key_length */, |
1301 | 1168 | slot_data, |
1302 | - &algorithm_type); | |
1169 | + &algorithm_type, | |
1170 | + additional_cmdline_subst); | |
1303 | 1171 | if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) { |
1304 | 1172 | goto fail; |
1305 | 1173 | } |
1306 | 1174 | |
... | ... | @@ -1341,14 +1209,14 @@ |
1341 | 1209 | goto fail; |
1342 | 1210 | } |
1343 | 1211 | } else { |
1344 | - /* Add options - any failure in append_options() is either an | |
1212 | + /* Add options - any failure in avb_append_options() is either an | |
1345 | 1213 | * I/O or OOM error. |
1346 | 1214 | */ |
1347 | - AvbSlotVerifyResult sub_ret = append_options(ops, | |
1348 | - slot_data, | |
1349 | - &toplevel_vbmeta, | |
1350 | - algorithm_type, | |
1351 | - hashtree_error_mode); | |
1215 | + AvbSlotVerifyResult sub_ret = avb_append_options(ops, | |
1216 | + slot_data, | |
1217 | + &toplevel_vbmeta, | |
1218 | + algorithm_type, | |
1219 | + hashtree_error_mode); | |
1352 | 1220 | if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { |
1353 | 1221 | ret = sub_ret; |
1354 | 1222 | goto fail; |
1355 | 1223 | |
... | ... | @@ -1358,14 +1226,19 @@ |
1358 | 1226 | /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */ |
1359 | 1227 | if (slot_data->cmdline != NULL) { |
1360 | 1228 | char* new_cmdline; |
1361 | - new_cmdline = sub_cmdline( | |
1362 | - ops, slot_data->cmdline, ab_suffix, using_boot_for_vbmeta); | |
1363 | - if (new_cmdline == NULL) { | |
1364 | - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1365 | - goto fail; | |
1229 | + new_cmdline = avb_sub_cmdline(ops, | |
1230 | + slot_data->cmdline, | |
1231 | + ab_suffix, | |
1232 | + using_boot_for_vbmeta, | |
1233 | + additional_cmdline_subst); | |
1234 | + if (new_cmdline != slot_data->cmdline) { | |
1235 | + if (new_cmdline == NULL) { | |
1236 | + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; | |
1237 | + goto fail; | |
1238 | + } | |
1239 | + avb_free(slot_data->cmdline); | |
1240 | + slot_data->cmdline = new_cmdline; | |
1366 | 1241 | } |
1367 | - avb_free(slot_data->cmdline); | |
1368 | - slot_data->cmdline = new_cmdline; | |
1369 | 1242 | } |
1370 | 1243 | |
1371 | 1244 | if (out_data != NULL) { |
... | ... | @@ -1375,6 +1248,9 @@ |
1375 | 1248 | } |
1376 | 1249 | } |
1377 | 1250 | |
1251 | + avb_free_cmdline_subst_list(additional_cmdline_subst); | |
1252 | + additional_cmdline_subst = NULL; | |
1253 | + | |
1378 | 1254 | if (!allow_verification_error) { |
1379 | 1255 | avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK); |
1380 | 1256 | } |
... | ... | @@ -1385,6 +1261,9 @@ |
1385 | 1261 | if (slot_data != NULL) { |
1386 | 1262 | avb_slot_verify_data_free(slot_data); |
1387 | 1263 | } |
1264 | + if (additional_cmdline_subst != NULL) { | |
1265 | + avb_free_cmdline_subst_list(additional_cmdline_subst); | |
1266 | + } | |
1388 | 1267 | return ret; |
1389 | 1268 | } |
1390 | 1269 | |
... | ... | @@ -1415,7 +1294,7 @@ |
1415 | 1294 | if (loaded_partition->partition_name != NULL) { |
1416 | 1295 | avb_free(loaded_partition->partition_name); |
1417 | 1296 | } |
1418 | - if (loaded_partition->data != NULL) { | |
1297 | + if (loaded_partition->data != NULL && !loaded_partition->preloaded) { | |
1419 | 1298 | avb_free(loaded_partition->data); |
1420 | 1299 | } |
1421 | 1300 | } |
... | ... | @@ -1464,5 +1343,44 @@ |
1464 | 1343 | } |
1465 | 1344 | |
1466 | 1345 | return ret; |
1346 | +} | |
1347 | + | |
1348 | +void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data, | |
1349 | + AvbDigestType digest_type, | |
1350 | + uint8_t* out_digest) { | |
1351 | + bool ret = false; | |
1352 | + size_t n; | |
1353 | + | |
1354 | + switch (digest_type) { | |
1355 | + case AVB_DIGEST_TYPE_SHA256: { | |
1356 | + AvbSHA256Ctx ctx; | |
1357 | + avb_sha256_init(&ctx); | |
1358 | + for (n = 0; n < data->num_vbmeta_images; n++) { | |
1359 | + avb_sha256_update(&ctx, | |
1360 | + data->vbmeta_images[n].vbmeta_data, | |
1361 | + data->vbmeta_images[n].vbmeta_size); | |
1362 | + } | |
1363 | + avb_memcpy(out_digest, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE); | |
1364 | + ret = true; | |
1365 | + } break; | |
1366 | + | |
1367 | + case AVB_DIGEST_TYPE_SHA512: { | |
1368 | + AvbSHA512Ctx ctx; | |
1369 | + avb_sha512_init(&ctx); | |
1370 | + for (n = 0; n < data->num_vbmeta_images; n++) { | |
1371 | + avb_sha512_update(&ctx, | |
1372 | + data->vbmeta_images[n].vbmeta_data, | |
1373 | + data->vbmeta_images[n].vbmeta_size); | |
1374 | + } | |
1375 | + avb_memcpy(out_digest, avb_sha512_final(&ctx), AVB_SHA512_DIGEST_SIZE); | |
1376 | + ret = true; | |
1377 | + } break; | |
1378 | + | |
1379 | + /* Do not add a 'default:' case here because of -Wswitch. */ | |
1380 | + } | |
1381 | + | |
1382 | + if (!ret) { | |
1383 | + avb_fatal("Unknown digest type"); | |
1384 | + } | |
1467 | 1385 | } |
lib/avb/libavb/avb_slot_verify.h
... | ... | @@ -114,7 +114,10 @@ |
114 | 114 | /* AvbPartitionData contains data loaded from partitions when using |
115 | 115 | * avb_slot_verify(). The |partition_name| field contains the name of |
116 | 116 | * the partition (without A/B suffix), |data| points to the loaded |
117 | - * data which is |data_size| bytes long. | |
117 | + * data which is |data_size| bytes long. If |preloaded| is set to true, | |
118 | + * this structure dose not own |data|. The caller of |avb_slot_verify| | |
119 | + * needs to make sure that the preloaded data outlives this | |
120 | + * |AvbPartitionData| structure. | |
118 | 121 | * |
119 | 122 | * Note that this is strictly less than the partition size - it's only |
120 | 123 | * the image stored there, not the entire partition nor any of the |
... | ... | @@ -124,6 +127,7 @@ |
124 | 127 | char* partition_name; |
125 | 128 | uint8_t* data; |
126 | 129 | size_t data_size; |
130 | + bool preloaded; | |
127 | 131 | } AvbPartitionData; |
128 | 132 | |
129 | 133 | /* AvbVBMetaData contains a vbmeta struct loaded from a partition when |
... | ... | @@ -256,9 +260,15 @@ |
256 | 260 | uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS]; |
257 | 261 | } AvbSlotVerifyData; |
258 | 262 | |
259 | -/* Fast version of avb_slot_verify_data_free, this method will not | |
260 | - * free bootimage */ | |
261 | -void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data); | |
263 | +/* Calculates a digest of all vbmeta images in |data| using | |
264 | + * the digest indicated by |digest_type|. Stores the result | |
265 | + * in |out_digest| which must be large enough to hold a digest | |
266 | + * of the requested type. | |
267 | + */ | |
268 | +void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data, | |
269 | + AvbDigestType digest_type, | |
270 | + uint8_t* out_digest); | |
271 | + | |
262 | 272 | /* Frees a |AvbSlotVerifyData| including all data it points to. */ |
263 | 273 | void avb_slot_verify_data_free(AvbSlotVerifyData* data); |
264 | 274 |
lib/avb/libavb/avb_sysdeps.h
... | ... | @@ -108,6 +108,10 @@ |
108 | 108 | /* Returns the lenght of |str|, excluding the terminating NUL-byte. */ |
109 | 109 | size_t avb_strlen(const char* str) AVB_ATTR_WARN_UNUSED_RESULT; |
110 | 110 | |
111 | +/* Divide the |dividend| by 10 and saves back to the pointer. Return the | |
112 | + * remainder. */ | |
113 | +uint32_t avb_div_by_10(uint64_t* dividend); | |
114 | + | |
111 | 115 | #ifdef __cplusplus |
112 | 116 | } |
113 | 117 | #endif |
lib/avb/libavb/avb_sysdeps_posix.c
lib/avb/libavb/avb_sysdeps_uboot.c
1 | -/* | |
2 | - * Copyright (C) 2016 The Android Open Source Project | |
3 | - * | |
4 | - * Permission is hereby granted, free of charge, to any person | |
5 | - * obtaining a copy of this software and associated documentation | |
6 | - * files (the "Software"), to deal in the Software without | |
7 | - * restriction, including without limitation the rights to use, copy, | |
8 | - * modify, merge, publish, distribute, sublicense, and/or sell copies | |
9 | - * of the Software, and to permit persons to whom the Software is | |
10 | - * furnished to do so, subject to the following conditions: | |
11 | - * | |
12 | - * The above copyright notice and this permission notice shall be | |
13 | - * included in all copies or substantial portions of the Software. | |
14 | - * | |
15 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
16 | - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
17 | - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
18 | - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
19 | - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
20 | - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
21 | - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
22 | - * SOFTWARE. | |
23 | - */ | |
24 | - | |
25 | -#include <common.h> | |
26 | -#include <stdlib.h> | |
27 | -#include <linux/string.h> | |
28 | - | |
29 | -#include "avb_sysdeps.h" | |
30 | - | |
31 | -int avb_memcmp(const void* src1, const void* src2, size_t n) { | |
32 | - return memcmp(src1, src2, n); | |
33 | -} | |
34 | - | |
35 | -void* avb_memcpy(void* dest, const void* src, size_t n) { | |
36 | - return memcpy(dest, src, n); | |
37 | -} | |
38 | - | |
39 | -void* avb_memset(void* dest, const int c, size_t n) { | |
40 | - return memset(dest, c, n); | |
41 | -} | |
42 | - | |
43 | -int avb_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); } | |
44 | - | |
45 | -size_t avb_strlen(const char* str) { return strlen(str); } | |
46 | - | |
47 | -void avb_abort(void) { panic("avb_abort!\n"); } | |
48 | - | |
49 | -void avb_print(const char* message) { printf("%s", message); } | |
50 | - | |
51 | -void avb_printv(const char* message, ...) { | |
52 | - va_list ap; | |
53 | - const char* m; | |
54 | - | |
55 | - va_start(ap, message); | |
56 | - for (m = message; m != NULL; m = va_arg(ap, const char*)) { | |
57 | - printf("%s", m); | |
58 | - } | |
59 | - va_end(ap); | |
60 | -} | |
61 | - | |
62 | -void* avb_malloc_(size_t size) { return malloc(size); } | |
63 | - | |
64 | -void avb_free(void* ptr) { free(ptr); } |
lib/avb/libavb/avb_util.c
... | ... | @@ -299,7 +299,7 @@ |
299 | 299 | char* new_str; |
300 | 300 | num_new = ret_len + num_before + replace_len + 1; |
301 | 301 | new_str = avb_malloc(num_new); |
302 | - if (ret == NULL) { | |
302 | + if (new_str == NULL) { | |
303 | 303 | goto out; |
304 | 304 | } |
305 | 305 | avb_memcpy(new_str, ret, ret_len); |
... | ... | @@ -324,7 +324,7 @@ |
324 | 324 | size_t num_remaining = avb_strlen(str_after_last_replace); |
325 | 325 | size_t num_new = ret_len + num_remaining + 1; |
326 | 326 | char* new_str = avb_malloc(num_new); |
327 | - if (ret == NULL) { | |
327 | + if (new_str == NULL) { | |
328 | 328 | goto out; |
329 | 329 | } |
330 | 330 | avb_memcpy(new_str, ret, ret_len); |
... | ... | @@ -400,5 +400,32 @@ |
400 | 400 | } |
401 | 401 | } |
402 | 402 | return str; |
403 | +} | |
404 | + | |
405 | +void avb_uppercase(char* str) { | |
406 | + size_t i; | |
407 | + for (i = 0; str[i] != '\0'; ++i) { | |
408 | + if (str[i] <= 0x7A && str[i] >= 0x61) { | |
409 | + str[i] -= 0x20; | |
410 | + } | |
411 | + } | |
412 | +} | |
413 | + | |
414 | +char* avb_bin2hex(const uint8_t* data, size_t data_len) { | |
415 | + const char hex_digits[17] = "0123456789abcdef"; | |
416 | + char* hex_data; | |
417 | + size_t n; | |
418 | + | |
419 | + hex_data = avb_malloc(data_len * 2 + 1); | |
420 | + if (hex_data == NULL) { | |
421 | + return NULL; | |
422 | + } | |
423 | + | |
424 | + for (n = 0; n < data_len; n++) { | |
425 | + hex_data[n * 2] = hex_digits[data[n] >> 4]; | |
426 | + hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f]; | |
427 | + } | |
428 | + hex_data[n * 2] = '\0'; | |
429 | + return hex_data; | |
403 | 430 | } |
lib/avb/libavb/avb_util.h
... | ... | @@ -270,6 +270,16 @@ |
270 | 270 | */ |
271 | 271 | const char* avb_basename(const char* str); |
272 | 272 | |
273 | +/* Converts any ascii lowercase characters in |str| to uppercase in-place. | |
274 | + * |str| must be NUL-terminated and valid UTF-8. | |
275 | + */ | |
276 | +void avb_uppercase(char* str); | |
277 | + | |
278 | +/* Converts |data_len| bytes of |data| to hex and returns the result. Returns | |
279 | + * NULL on OOM. Caller must free the returned string with avb_free. | |
280 | + */ | |
281 | +char* avb_bin2hex(const uint8_t* data, size_t data_len); | |
282 | + | |
273 | 283 | #ifdef __cplusplus |
274 | 284 | } |
275 | 285 | #endif |
lib/avb/libavb/avb_version.h
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | |
38 | 38 | /* The version number of AVB - keep in sync with avbtool. */ |
39 | 39 | #define AVB_VERSION_MAJOR 1 |
40 | -#define AVB_VERSION_MINOR 0 | |
40 | +#define AVB_VERSION_MINOR 1 | |
41 | 41 | #define AVB_VERSION_SUB 0 |
42 | 42 | |
43 | 43 | /* Returns a NUL-terminated string for the libavb version in use. The |
lib/avb/libavb_ab/avb_ab_flow.c
... | ... | @@ -406,307 +406,6 @@ |
406 | 406 | return ret; |
407 | 407 | } |
408 | 408 | |
409 | -/* For legacy i.mx6/7, we won't enable A/B due to the limitation of | |
410 | - * storage capacity, but we still want to verify boot/recovery with | |
411 | - * AVB. */ | |
412 | -AvbABFlowResult avb_single_flow(AvbABOps* ab_ops, | |
413 | - const char* const* requested_partitions, | |
414 | - AvbSlotVerifyFlags flags, | |
415 | - AvbHashtreeErrorMode hashtree_error_mode, | |
416 | - AvbSlotVerifyData** out_data) { | |
417 | - AvbOps* ops = ab_ops->ops; | |
418 | - AvbSlotVerifyData* slot_data = NULL; | |
419 | - AvbSlotVerifyData* data = NULL; | |
420 | - AvbABFlowResult ret; | |
421 | - bool saw_and_allowed_verification_error = false; | |
422 | - | |
423 | - /* Validate boot/recovery. */ | |
424 | - AvbSlotVerifyResult verify_result; | |
425 | - | |
426 | - verify_result = avb_slot_verify(ops, | |
427 | - requested_partitions, | |
428 | - "", | |
429 | - flags, | |
430 | - hashtree_error_mode, | |
431 | - &slot_data); | |
432 | - switch (verify_result) { | |
433 | - case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
434 | - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
435 | - goto out; | |
436 | - | |
437 | - case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
438 | - ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
439 | - goto out; | |
440 | - | |
441 | - case AVB_SLOT_VERIFY_RESULT_OK: | |
442 | - break; | |
443 | - | |
444 | - case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
445 | - case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
446 | - /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR | |
447 | - * these mean game over. | |
448 | - */ | |
449 | - ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; | |
450 | - goto out; | |
451 | - | |
452 | - /* explicit fallthrough. */ | |
453 | - case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
454 | - case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
455 | - case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
456 | - if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { | |
457 | - /* Do nothing since we allow this. */ | |
458 | - avb_debugv("Allowing slot ", | |
459 | - slot_suffixes[n], | |
460 | - " which verified " | |
461 | - "with result ", | |
462 | - avb_slot_verify_result_to_string(verify_result), | |
463 | - " because " | |
464 | - "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " | |
465 | - "is set.\n", | |
466 | - NULL); | |
467 | - saw_and_allowed_verification_error = true; | |
468 | - } else { | |
469 | - ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; | |
470 | - goto out; | |
471 | - } | |
472 | - break; | |
473 | - | |
474 | - case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
475 | - ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; | |
476 | - goto out; | |
477 | - /* Do not add a 'default:' case here because of -Wswitch. */ | |
478 | - } | |
479 | - | |
480 | - avb_assert(slot_data != NULL); | |
481 | - data = slot_data; | |
482 | - slot_data = NULL; | |
483 | - if (saw_and_allowed_verification_error) { | |
484 | - avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); | |
485 | - ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; | |
486 | - } else { | |
487 | - ret = AVB_AB_FLOW_RESULT_OK; | |
488 | - } | |
489 | - | |
490 | -out: | |
491 | - if (slot_data != NULL) { | |
492 | - avb_slot_verify_data_free(slot_data); | |
493 | - } | |
494 | - | |
495 | - if (out_data != NULL) { | |
496 | - *out_data = data; | |
497 | - } else { | |
498 | - if (data != NULL) { | |
499 | - avb_slot_verify_data_free(data); | |
500 | - } | |
501 | - } | |
502 | - | |
503 | - return ret; | |
504 | -} | |
505 | - | |
506 | -AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops, | |
507 | - const char* const* requested_partitions, | |
508 | - AvbSlotVerifyFlags flags, | |
509 | - AvbHashtreeErrorMode hashtree_error_mode, | |
510 | - AvbSlotVerifyData** out_data) { | |
511 | - AvbOps* ops = ab_ops->ops; | |
512 | - AvbSlotVerifyData* slot_data[2] = {NULL, NULL}; | |
513 | - AvbSlotVerifyData* data = NULL; | |
514 | - AvbABFlowResult ret; | |
515 | - AvbABData ab_data, ab_data_orig; | |
516 | - size_t slot_index_to_boot, n; | |
517 | - AvbIOResult io_ret; | |
518 | - bool saw_and_allowed_verification_error = false; | |
519 | - size_t target_slot; | |
520 | - AvbSlotVerifyResult verify_result; | |
521 | - bool set_slot_unbootable = false; | |
522 | - | |
523 | - io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig); | |
524 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
525 | - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
526 | - goto out; | |
527 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
528 | - ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
529 | - goto out; | |
530 | - } | |
531 | - | |
532 | - slot_index_to_boot = 2; // Means not 0 or 1 | |
533 | - target_slot = (ab_data.slots[1].priority > ab_data.slots[0].priority? 1 : 0); | |
534 | - | |
535 | - for (n = 0; n < 2; n++) { | |
536 | - if (!slot_is_bootable(&ab_data.slots[target_slot])) { | |
537 | - target_slot = (target_slot == 1 ? 0 : 1); | |
538 | - continue; | |
539 | - } | |
540 | - verify_result = avb_slot_verify(ops, | |
541 | - requested_partitions, | |
542 | - slot_suffixes[target_slot], | |
543 | - flags, | |
544 | - hashtree_error_mode, | |
545 | - &slot_data[target_slot]); | |
546 | - switch (verify_result) { | |
547 | - case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: | |
548 | - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
549 | - goto out; | |
550 | - | |
551 | - case AVB_SLOT_VERIFY_RESULT_ERROR_IO: | |
552 | - ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
553 | - goto out; | |
554 | - | |
555 | - case AVB_SLOT_VERIFY_RESULT_OK: | |
556 | - slot_index_to_boot = target_slot; | |
557 | - n = 2; | |
558 | - break; | |
559 | - | |
560 | - case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: | |
561 | - case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: | |
562 | - /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR | |
563 | - * these mean game over. | |
564 | - */ | |
565 | - set_slot_unbootable = true; | |
566 | - break; | |
567 | - | |
568 | - /* explicit fallthrough. */ | |
569 | - case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: | |
570 | - case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: | |
571 | - case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: | |
572 | - if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) { | |
573 | - /* Do nothing since we allow this. */ | |
574 | - avb_debugv("Allowing slot ", | |
575 | - slot_suffixes[target_slot], | |
576 | - " which verified " | |
577 | - "with result ", | |
578 | - avb_slot_verify_result_to_string(verify_result), | |
579 | - " because " | |
580 | - "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR " | |
581 | - "is set.\n", | |
582 | - NULL); | |
583 | - saw_and_allowed_verification_error = true; | |
584 | - slot_index_to_boot = target_slot; | |
585 | - n = 2; | |
586 | - } else { | |
587 | - set_slot_unbootable = true; | |
588 | - } | |
589 | - break; | |
590 | - | |
591 | - case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT: | |
592 | - ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT; | |
593 | - goto out; | |
594 | - /* Do not add a 'default:' case here because of -Wswitch. */ | |
595 | - } | |
596 | - | |
597 | - if (set_slot_unbootable) { | |
598 | - avb_errorv("Error verifying slot ", | |
599 | - slot_suffixes[target_slot], | |
600 | - " with result ", | |
601 | - avb_slot_verify_result_to_string(verify_result), | |
602 | - " - setting unbootable.\n", | |
603 | - NULL); | |
604 | - slot_set_unbootable(&ab_data.slots[target_slot]); | |
605 | - set_slot_unbootable = false; | |
606 | - } | |
607 | - /* switch to another slot */ | |
608 | - target_slot = (target_slot == 1 ? 0 : 1); | |
609 | - } | |
610 | - | |
611 | - if (slot_index_to_boot == 2) { | |
612 | - /* No bootable slots! */ | |
613 | - avb_error("No bootable slots found.\n"); | |
614 | - ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS; | |
615 | - goto out; | |
616 | - } | |
617 | - | |
618 | - /* Update stored rollback index such that the stored rollback index | |
619 | - * is the largest value supporting all currently bootable slots. Do | |
620 | - * this for every rollback index location. | |
621 | - */ | |
622 | - for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) { | |
623 | - uint64_t rollback_index_value = 0; | |
624 | - | |
625 | - if (slot_data[0] != NULL && slot_data[1] != NULL) { | |
626 | - uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n]; | |
627 | - uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n]; | |
628 | - rollback_index_value = | |
629 | - (a_rollback_index < b_rollback_index ? a_rollback_index | |
630 | - : b_rollback_index); | |
631 | - } else if (slot_data[0] != NULL) { | |
632 | - rollback_index_value = slot_data[0]->rollback_indexes[n]; | |
633 | - } else if (slot_data[1] != NULL) { | |
634 | - rollback_index_value = slot_data[1]->rollback_indexes[n]; | |
635 | - } | |
636 | - | |
637 | - if (rollback_index_value != 0) { | |
638 | - uint64_t current_rollback_index_value; | |
639 | - io_ret = ops->read_rollback_index(ops, n, ¤t_rollback_index_value); | |
640 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
641 | - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
642 | - goto out; | |
643 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
644 | - avb_error("Error getting rollback index for slot.\n"); | |
645 | - ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
646 | - goto out; | |
647 | - } | |
648 | - if (current_rollback_index_value != rollback_index_value) { | |
649 | - io_ret = ops->write_rollback_index(ops, n, rollback_index_value); | |
650 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
651 | - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
652 | - goto out; | |
653 | - } else if (io_ret != AVB_IO_RESULT_OK) { | |
654 | - avb_error("Error setting stored rollback index.\n"); | |
655 | - ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
656 | - goto out; | |
657 | - } | |
658 | - } | |
659 | - } | |
660 | - } | |
661 | - | |
662 | - /* Finally, select this slot. */ | |
663 | - avb_assert(slot_data[slot_index_to_boot] != NULL); | |
664 | - data = slot_data[slot_index_to_boot]; | |
665 | - slot_data[slot_index_to_boot] = NULL; | |
666 | - if (saw_and_allowed_verification_error) { | |
667 | - avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR); | |
668 | - ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR; | |
669 | - } else { | |
670 | - ret = AVB_AB_FLOW_RESULT_OK; | |
671 | - } | |
672 | - | |
673 | - /* ... and decrement tries remaining, if applicable. */ | |
674 | - if (!ab_data.slots[slot_index_to_boot].successful_boot && | |
675 | - ab_data.slots[slot_index_to_boot].tries_remaining > 0) { | |
676 | - ab_data.slots[slot_index_to_boot].tries_remaining -= 1; | |
677 | - } | |
678 | - | |
679 | -out: | |
680 | - io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig); | |
681 | - if (io_ret != AVB_IO_RESULT_OK) { | |
682 | - if (io_ret == AVB_IO_RESULT_ERROR_OOM) { | |
683 | - ret = AVB_AB_FLOW_RESULT_ERROR_OOM; | |
684 | - } else { | |
685 | - ret = AVB_AB_FLOW_RESULT_ERROR_IO; | |
686 | - } | |
687 | - if (data != NULL) { | |
688 | - avb_slot_verify_data_free(data); | |
689 | - data = NULL; | |
690 | - } | |
691 | - } | |
692 | - | |
693 | - for (n = 0; n < 2; n++) { | |
694 | - if (slot_data[n] != NULL) { | |
695 | - avb_slot_verify_data_free(slot_data[n]); | |
696 | - } | |
697 | - } | |
698 | - | |
699 | - if (out_data != NULL) { | |
700 | - *out_data = data; | |
701 | - } else { | |
702 | - if (data != NULL) { | |
703 | - avb_slot_verify_data_free(data); | |
704 | - } | |
705 | - } | |
706 | - | |
707 | - return ret; | |
708 | -} | |
709 | - | |
710 | 409 | AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops, |
711 | 410 | unsigned int slot_number) { |
712 | 411 | AvbABData ab_data, ab_data_orig; |
lib/avb/libavb_ab/avb_ab_flow.h
... | ... | @@ -223,19 +223,6 @@ |
223 | 223 | AvbHashtreeErrorMode hashtree_error_mode, |
224 | 224 | AvbSlotVerifyData** out_data); |
225 | 225 | |
226 | -AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops, | |
227 | - const char* const* requested_partitions, | |
228 | - AvbSlotVerifyFlags flags, | |
229 | - AvbHashtreeErrorMode hashtree_error_mode, | |
230 | - AvbSlotVerifyData** out_data); | |
231 | -/* This is for legacy i.mx6/7 which don't enable A/B but want to | |
232 | - * verify boot/recovery with AVB */ | |
233 | -AvbABFlowResult avb_single_flow(AvbABOps* ab_ops, | |
234 | - const char* const* requested_partitions, | |
235 | - AvbSlotVerifyFlags flags, | |
236 | - AvbHashtreeErrorMode hashtree_error_mode, | |
237 | - AvbSlotVerifyData** out_data); | |
238 | - | |
239 | 226 | /* Marks the slot with the given slot number as active. Returns |
240 | 227 | * AVB_IO_RESULT_OK on success, error code otherwise. |
241 | 228 | * |
lib/avb/libavb_ab/avb_ab_ops.h
lib/avb/libavb_ab/libavb_ab.h
... | ... | @@ -25,7 +25,18 @@ |
25 | 25 | #ifndef LIBAVB_AB_H_ |
26 | 26 | #define LIBAVB_AB_H_ |
27 | 27 | |
28 | -#include "../libavb/libavb.h" | |
28 | +#include <libavb/libavb.h> | |
29 | + | |
30 | +/* The libavb_ab/ and boot_control/ code has been marked for some time | |
31 | + * as experimental in anticipation of being removed in the future. It | |
32 | + * is now deprecated and to continue using it you must define | |
33 | + * AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED. It will be removed Jun | |
34 | + * 1 2018. | |
35 | + */ | |
36 | +#ifndef AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED | |
37 | +#error \ | |
38 | + "You must define AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED to use this library." | |
39 | +#endif | |
29 | 40 | |
30 | 41 | /* The AVB_INSIDE_LIBAVB_AB_H preprocessor symbol is used to enforce |
31 | 42 | * library users to include only this file. All public interfaces, and |
lib/avb/libavb_atx/avb_atx_ops.h
... | ... | @@ -30,9 +30,9 @@ |
30 | 30 | #ifndef AVB_ATX_OPS_H_ |
31 | 31 | #define AVB_ATX_OPS_H_ |
32 | 32 | |
33 | -#include "../libavb/libavb.h" | |
33 | +#include <libavb/libavb.h> | |
34 | 34 | |
35 | -#include "../libavb_atx/avb_atx_types.h" | |
35 | +#include "avb_atx_types.h" | |
36 | 36 | |
37 | 37 | #ifdef __cplusplus |
38 | 38 | extern "C" { |
... | ... | @@ -59,6 +59,22 @@ |
59 | 59 | */ |
60 | 60 | AvbIOResult (*read_permanent_attributes_hash)( |
61 | 61 | AvbAtxOps* atx_ops, uint8_t hash[AVB_SHA256_DIGEST_SIZE]); |
62 | + | |
63 | + /* Provides the key version of a key used during verification. This may be | |
64 | + * useful for managing the minimum key version. | |
65 | + */ | |
66 | + void (*set_key_version)(AvbAtxOps* atx_ops, | |
67 | + size_t rollback_index_location, | |
68 | + uint64_t key_version); | |
69 | + | |
70 | + /* Generates |num_bytes| random bytes and stores them in |output|, | |
71 | + * which must point to a buffer large enough to store the bytes. | |
72 | + * | |
73 | + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. | |
74 | + */ | |
75 | + AvbIOResult (*get_random)(AvbAtxOps* atx_ops, | |
76 | + size_t num_bytes, | |
77 | + uint8_t* output); | |
62 | 78 | }; |
63 | 79 | |
64 | 80 | #ifdef __cplusplus |
lib/avb/libavb_atx/avb_atx_types.h
... | ... | @@ -30,7 +30,7 @@ |
30 | 30 | #ifndef AVB_ATX_TYPES_H_ |
31 | 31 | #define AVB_ATX_TYPES_H_ |
32 | 32 | |
33 | -#include "../libavb/libavb.h" | |
33 | +#include <libavb/libavb.h> | |
34 | 34 | |
35 | 35 | #ifdef __cplusplus |
36 | 36 | extern "C" { |
... | ... | @@ -39,6 +39,9 @@ |
39 | 39 | /* Size in bytes of an Android Things product ID. */ |
40 | 40 | #define AVB_ATX_PRODUCT_ID_SIZE 16 |
41 | 41 | |
42 | +/* Size in bytes of an Android Things unlock challenge. */ | |
43 | +#define AVB_ATX_UNLOCK_CHALLENGE_SIZE 16 | |
44 | + | |
42 | 45 | /* Size in bytes of a serialized public key with a 4096-bit modulus. */ |
43 | 46 | #define AVB_ATX_PUBLIC_KEY_SIZE (sizeof(AvbRSAPublicKeyHeader) + 1024) |
44 | 47 | |
... | ... | @@ -70,6 +73,21 @@ |
70 | 73 | AvbAtxCertificate product_intermediate_key_certificate; |
71 | 74 | AvbAtxCertificate product_signing_key_certificate; |
72 | 75 | } AVB_ATTR_PACKED AvbAtxPublicKeyMetadata; |
76 | + | |
77 | +/* Data structure of an Android Things unlock challenge. */ | |
78 | +typedef struct AvbAtxUnlockChallenge { | |
79 | + uint32_t version; | |
80 | + uint8_t product_id_hash[AVB_SHA256_DIGEST_SIZE]; | |
81 | + uint8_t challenge[AVB_ATX_UNLOCK_CHALLENGE_SIZE]; | |
82 | +} AVB_ATTR_PACKED AvbAtxUnlockChallenge; | |
83 | + | |
84 | +/* Data structure of an Android Things unlock credential. */ | |
85 | +typedef struct AvbAtxUnlockCredential { | |
86 | + uint32_t version; | |
87 | + AvbAtxCertificate product_intermediate_key_certificate; | |
88 | + AvbAtxCertificate product_unlock_key_certificate; | |
89 | + uint8_t challenge_signature[AVB_RSA4096_NUM_BYTES]; | |
90 | +} AVB_ATTR_PACKED AvbAtxUnlockCredential; | |
73 | 91 | |
74 | 92 | #ifdef __cplusplus |
75 | 93 | } |
lib/avb/libavb_atx/avb_atx_validate.c
... | ... | @@ -22,13 +22,16 @@ |
22 | 22 | * SOFTWARE. |
23 | 23 | */ |
24 | 24 | |
25 | -#include "../libavb_atx/avb_atx_validate.h" | |
25 | +#include "avb_atx_validate.h" | |
26 | 26 | |
27 | -#include "../libavb/avb_rsa.h" | |
28 | -#include "../libavb/avb_sha.h" | |
29 | -#include "../libavb/avb_sysdeps.h" | |
30 | -#include "../libavb/avb_util.h" | |
27 | +#include <libavb/avb_rsa.h> | |
28 | +#include <libavb/avb_sha.h> | |
29 | +#include <libavb/avb_sysdeps.h> | |
30 | +#include <libavb/avb_util.h> | |
31 | 31 | |
32 | +/* The most recent unlock challenge generated. */ | |
33 | +static uint8_t last_unlock_challenge[AVB_ATX_UNLOCK_CHALLENGE_SIZE]; | |
34 | + | |
32 | 35 | /* Computes the SHA256 |hash| of |length| bytes of |data|. */ |
33 | 36 | static void sha256(const uint8_t* data, |
34 | 37 | uint32_t length, |
... | ... | @@ -59,7 +62,7 @@ |
59 | 62 | /* Verifies structure and |expected_hash| of permanent |attributes|. */ |
60 | 63 | static bool verify_permanent_attributes( |
61 | 64 | const AvbAtxPermanentAttributes* attributes, |
62 | - uint8_t expected_hash[AVB_SHA256_DIGEST_SIZE]) { | |
65 | + const uint8_t expected_hash[AVB_SHA256_DIGEST_SIZE]) { | |
63 | 66 | uint8_t hash[AVB_SHA256_DIGEST_SIZE]; |
64 | 67 | |
65 | 68 | if (attributes->version != 1) { |
... | ... | @@ -75,10 +78,11 @@ |
75 | 78 | } |
76 | 79 | |
77 | 80 | /* Verifies the format, key version, usage, and signature of a certificate. */ |
78 | -static bool verify_certificate(AvbAtxCertificate* certificate, | |
79 | - uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], | |
80 | - uint64_t minimum_key_version, | |
81 | - uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]) { | |
81 | +static bool verify_certificate( | |
82 | + const AvbAtxCertificate* certificate, | |
83 | + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], | |
84 | + uint64_t minimum_key_version, | |
85 | + const uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]) { | |
82 | 86 | const AvbAlgorithmData* algorithm_data; |
83 | 87 | uint8_t certificate_hash[AVB_SHA512_DIGEST_SIZE]; |
84 | 88 | |
... | ... | @@ -115,9 +119,10 @@ |
115 | 119 | } |
116 | 120 | |
117 | 121 | /* Verifies signature and fields of a PIK certificate. */ |
118 | -static bool verify_pik_certificate(AvbAtxCertificate* certificate, | |
119 | - uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], | |
120 | - uint64_t minimum_version) { | |
122 | +static bool verify_pik_certificate( | |
123 | + const AvbAtxCertificate* certificate, | |
124 | + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], | |
125 | + uint64_t minimum_version) { | |
121 | 126 | uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]; |
122 | 127 | |
123 | 128 | sha256_str("com.google.android.things.vboot.ca", expected_usage); |
124 | 129 | |
... | ... | @@ -131,10 +136,10 @@ |
131 | 136 | |
132 | 137 | /* Verifies signature and fields of a PSK certificate. */ |
133 | 138 | static bool verify_psk_certificate( |
134 | - AvbAtxCertificate* certificate, | |
135 | - uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], | |
139 | + const AvbAtxCertificate* certificate, | |
140 | + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], | |
136 | 141 | uint64_t minimum_version, |
137 | - uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) { | |
142 | + const uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) { | |
138 | 143 | uint8_t expected_subject[AVB_SHA256_DIGEST_SIZE]; |
139 | 144 | uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]; |
140 | 145 | |
141 | 146 | |
... | ... | @@ -148,12 +153,37 @@ |
148 | 153 | if (0 != avb_safe_memcmp(certificate->signed_data.subject, |
149 | 154 | expected_subject, |
150 | 155 | AVB_SHA256_DIGEST_SIZE)) { |
151 | - avb_error("Product ID mismatch.\n"); | |
156 | + avb_error("PSK: Product ID mismatch.\n"); | |
152 | 157 | return false; |
153 | 158 | } |
154 | 159 | return true; |
155 | 160 | } |
156 | 161 | |
162 | +/* Verifies signature and fields of a PUK certificate. */ | |
163 | +static bool verify_puk_certificate( | |
164 | + const AvbAtxCertificate* certificate, | |
165 | + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], | |
166 | + uint64_t minimum_version, | |
167 | + const uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) { | |
168 | + uint8_t expected_subject[AVB_SHA256_DIGEST_SIZE]; | |
169 | + uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]; | |
170 | + | |
171 | + sha256_str("com.google.android.things.vboot.unlock", expected_usage); | |
172 | + if (!verify_certificate( | |
173 | + certificate, authority, minimum_version, expected_usage)) { | |
174 | + avb_error("Invalid PUK certificate.\n"); | |
175 | + return false; | |
176 | + } | |
177 | + sha256(product_id, AVB_ATX_PRODUCT_ID_SIZE, expected_subject); | |
178 | + if (0 != avb_safe_memcmp(certificate->signed_data.subject, | |
179 | + expected_subject, | |
180 | + AVB_SHA256_DIGEST_SIZE)) { | |
181 | + avb_error("PUK: Product ID mismatch.\n"); | |
182 | + return false; | |
183 | + } | |
184 | + return true; | |
185 | +} | |
186 | + | |
157 | 187 | AvbIOResult avb_atx_validate_vbmeta_public_key( |
158 | 188 | AvbOps* ops, |
159 | 189 | const uint8_t* public_key_data, |
... | ... | @@ -238,6 +268,131 @@ |
238 | 268 | public_key_data, |
239 | 269 | AVB_ATX_PUBLIC_KEY_SIZE)) { |
240 | 270 | avb_error("Public key mismatch.\n"); |
271 | + return AVB_IO_RESULT_OK; | |
272 | + } | |
273 | + | |
274 | + /* Report the key versions used during verification. */ | |
275 | + ops->atx_ops->set_key_version( | |
276 | + ops->atx_ops, | |
277 | + AVB_ATX_PIK_VERSION_LOCATION, | |
278 | + metadata.product_intermediate_key_certificate.signed_data.key_version); | |
279 | + ops->atx_ops->set_key_version( | |
280 | + ops->atx_ops, | |
281 | + AVB_ATX_PSK_VERSION_LOCATION, | |
282 | + metadata.product_signing_key_certificate.signed_data.key_version); | |
283 | + | |
284 | + *out_is_trusted = true; | |
285 | + return AVB_IO_RESULT_OK; | |
286 | +} | |
287 | + | |
288 | +AvbIOResult avb_atx_generate_unlock_challenge( | |
289 | + AvbAtxOps* atx_ops, AvbAtxUnlockChallenge* out_unlock_challenge) { | |
290 | + AvbIOResult result = AVB_IO_RESULT_OK; | |
291 | + AvbAtxPermanentAttributes permanent_attributes; | |
292 | + | |
293 | + /* We need the permanent attributes to compute the product_id_hash. */ | |
294 | + result = atx_ops->read_permanent_attributes(atx_ops, &permanent_attributes); | |
295 | + if (result != AVB_IO_RESULT_OK) { | |
296 | + avb_error("Failed to read permanent attributes.\n"); | |
297 | + return result; | |
298 | + } | |
299 | + result = atx_ops->get_random( | |
300 | + atx_ops, AVB_ATX_UNLOCK_CHALLENGE_SIZE, last_unlock_challenge); | |
301 | + if (result != AVB_IO_RESULT_OK) { | |
302 | + avb_error("Failed to generate random challenge.\n"); | |
303 | + return result; | |
304 | + } | |
305 | + out_unlock_challenge->version = 1; | |
306 | + sha256(permanent_attributes.product_id, | |
307 | + AVB_ATX_PRODUCT_ID_SIZE, | |
308 | + out_unlock_challenge->product_id_hash); | |
309 | + avb_memcpy(out_unlock_challenge->challenge, | |
310 | + last_unlock_challenge, | |
311 | + AVB_ATX_UNLOCK_CHALLENGE_SIZE); | |
312 | + return result; | |
313 | +} | |
314 | + | |
315 | +AvbIOResult avb_atx_validate_unlock_credential( | |
316 | + AvbAtxOps* atx_ops, | |
317 | + const AvbAtxUnlockCredential* unlock_credential, | |
318 | + bool* out_is_trusted) { | |
319 | + AvbIOResult result = AVB_IO_RESULT_OK; | |
320 | + AvbAtxPermanentAttributes permanent_attributes; | |
321 | + uint8_t permanent_attributes_hash[AVB_SHA256_DIGEST_SIZE]; | |
322 | + uint64_t minimum_version; | |
323 | + const AvbAlgorithmData* algorithm_data; | |
324 | + uint8_t challenge_hash[AVB_SHA512_DIGEST_SIZE]; | |
325 | + | |
326 | + /* Be pessimistic so we can exit early without having to remember to clear. | |
327 | + */ | |
328 | + *out_is_trusted = false; | |
329 | + | |
330 | + /* Sanity check the credential. */ | |
331 | + if (unlock_credential->version != 1) { | |
332 | + avb_error("Unsupported unlock credential format.\n"); | |
333 | + return AVB_IO_RESULT_OK; | |
334 | + } | |
335 | + | |
336 | + /* Read and verify permanent attributes. */ | |
337 | + result = atx_ops->read_permanent_attributes(atx_ops, &permanent_attributes); | |
338 | + if (result != AVB_IO_RESULT_OK) { | |
339 | + avb_error("Failed to read permanent attributes.\n"); | |
340 | + return result; | |
341 | + } | |
342 | + result = atx_ops->read_permanent_attributes_hash(atx_ops, | |
343 | + permanent_attributes_hash); | |
344 | + if (result != AVB_IO_RESULT_OK) { | |
345 | + avb_error("Failed to read permanent attributes hash.\n"); | |
346 | + return result; | |
347 | + } | |
348 | + if (!verify_permanent_attributes(&permanent_attributes, | |
349 | + permanent_attributes_hash)) { | |
350 | + return AVB_IO_RESULT_OK; | |
351 | + } | |
352 | + | |
353 | + /* Verify the PIK certificate. */ | |
354 | + result = atx_ops->ops->read_rollback_index( | |
355 | + atx_ops->ops, AVB_ATX_PIK_VERSION_LOCATION, &minimum_version); | |
356 | + if (result != AVB_IO_RESULT_OK) { | |
357 | + avb_error("Failed to read PIK minimum version.\n"); | |
358 | + return result; | |
359 | + } | |
360 | + if (!verify_pik_certificate( | |
361 | + &unlock_credential->product_intermediate_key_certificate, | |
362 | + permanent_attributes.product_root_public_key, | |
363 | + minimum_version)) { | |
364 | + return AVB_IO_RESULT_OK; | |
365 | + } | |
366 | + | |
367 | + /* Verify the PUK certificate. The minimum version is shared with the PSK. */ | |
368 | + result = atx_ops->ops->read_rollback_index( | |
369 | + atx_ops->ops, AVB_ATX_PSK_VERSION_LOCATION, &minimum_version); | |
370 | + if (result != AVB_IO_RESULT_OK) { | |
371 | + avb_error("Failed to read PSK minimum version.\n"); | |
372 | + return result; | |
373 | + } | |
374 | + if (!verify_puk_certificate( | |
375 | + &unlock_credential->product_unlock_key_certificate, | |
376 | + unlock_credential->product_intermediate_key_certificate.signed_data | |
377 | + .public_key, | |
378 | + minimum_version, | |
379 | + permanent_attributes.product_id)) { | |
380 | + return AVB_IO_RESULT_OK; | |
381 | + } | |
382 | + | |
383 | + /* Verify the challenge signature. */ | |
384 | + algorithm_data = avb_get_algorithm_data(AVB_ALGORITHM_TYPE_SHA512_RSA4096); | |
385 | + sha512(last_unlock_challenge, AVB_ATX_UNLOCK_CHALLENGE_SIZE, challenge_hash); | |
386 | + if (!avb_rsa_verify(unlock_credential->product_unlock_key_certificate | |
387 | + .signed_data.public_key, | |
388 | + AVB_ATX_PUBLIC_KEY_SIZE, | |
389 | + unlock_credential->challenge_signature, | |
390 | + AVB_RSA4096_NUM_BYTES, | |
391 | + challenge_hash, | |
392 | + AVB_SHA512_DIGEST_SIZE, | |
393 | + algorithm_data->padding, | |
394 | + algorithm_data->padding_len)) { | |
395 | + avb_error("Invalid unlock challenge signature.\n"); | |
241 | 396 | return AVB_IO_RESULT_OK; |
242 | 397 | } |
243 | 398 |
lib/avb/libavb_atx/avb_atx_validate.h
... | ... | @@ -30,8 +30,8 @@ |
30 | 30 | #ifndef AVB_ATX_VALIDATE_H_ |
31 | 31 | #define AVB_ATX_VALIDATE_H_ |
32 | 32 | |
33 | -#include "../libavb_atx/avb_atx_ops.h" | |
34 | -#include "../libavb_atx/avb_atx_types.h" | |
33 | +#include "avb_atx_ops.h" | |
34 | +#include "avb_atx_types.h" | |
35 | 35 | |
36 | 36 | #ifdef __cplusplus |
37 | 37 | extern "C" { |
... | ... | @@ -68,6 +68,20 @@ |
68 | 68 | size_t public_key_length, |
69 | 69 | const uint8_t* public_key_metadata, |
70 | 70 | size_t public_key_metadata_length, |
71 | + bool* out_is_trusted); | |
72 | + | |
73 | +/* Generates a challenge which can be used to create an unlock credential. */ | |
74 | +AvbIOResult avb_atx_generate_unlock_challenge( | |
75 | + AvbAtxOps* atx_ops, AvbAtxUnlockChallenge* out_unlock_challenge); | |
76 | + | |
77 | +/* Validates an unlock credential. The certificate validation is very similar to | |
78 | + * the validation of public key metadata except in place of the PSK is a Product | |
79 | + * Unlock Key (PUK) and the certificate usage field identifies it as such. The | |
80 | + * challenge signature field is verified against this PUK. | |
81 | + */ | |
82 | +AvbIOResult avb_atx_validate_unlock_credential( | |
83 | + AvbAtxOps* atx_ops, | |
84 | + const AvbAtxUnlockCredential* unlock_credential, | |
71 | 85 | bool* out_is_trusted); |
72 | 86 | |
73 | 87 | #ifdef __cplusplus |
lib/avb/libavb_atx/libavb_atx.h
... | ... | @@ -25,7 +25,7 @@ |
25 | 25 | #ifndef LIBAVB_ATX_H_ |
26 | 26 | #define LIBAVB_ATX_H_ |
27 | 27 | |
28 | -#include "../libavb/libavb.h" | |
28 | +#include <libavb/libavb.h> | |
29 | 29 | |
30 | 30 | /* The AVB_INSIDE_LIBAVB_ATX_H preprocessor symbol is used to enforce |
31 | 31 | * library users to include only this file. All public interfaces, and |