]>
Commit | Line | Data |
---|---|---|
897a1d94 | 1 | // SPDX-License-Identifier: MIT |
d8f9d2af IO |
2 | /* |
3 | * Copyright (C) 2016 The Android Open Source Project | |
d8f9d2af IO |
4 | */ |
5 | ||
6 | #include "avb_vbmeta_image.h" | |
7 | #include "avb_crypto.h" | |
8 | #include "avb_rsa.h" | |
9 | #include "avb_sha.h" | |
10 | #include "avb_util.h" | |
11 | #include "avb_version.h" | |
12 | ||
13 | AvbVBMetaVerifyResult avb_vbmeta_image_verify( | |
14 | const uint8_t* data, | |
15 | size_t length, | |
16 | const uint8_t** out_public_key_data, | |
17 | size_t* out_public_key_length) { | |
18 | AvbVBMetaVerifyResult ret; | |
19 | AvbVBMetaImageHeader h; | |
20 | uint8_t* computed_hash; | |
21 | const AvbAlgorithmData* algorithm; | |
22 | AvbSHA256Ctx sha256_ctx; | |
23 | AvbSHA512Ctx sha512_ctx; | |
24 | const uint8_t* header_block; | |
25 | const uint8_t* authentication_block; | |
26 | const uint8_t* auxiliary_block; | |
27 | int verification_result; | |
28 | ||
29 | ret = AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER; | |
30 | ||
31 | if (out_public_key_data != NULL) { | |
32 | *out_public_key_data = NULL; | |
33 | } | |
34 | if (out_public_key_length != NULL) { | |
35 | *out_public_key_length = 0; | |
36 | } | |
37 | ||
4d579a43 SP |
38 | /* Before we byteswap or compare Magic, ensure length is long enough. */ |
39 | if (length < sizeof(AvbVBMetaImageHeader)) { | |
40 | avb_error("Length is smaller than header.\n"); | |
41 | goto out; | |
42 | } | |
43 | ||
d8f9d2af IO |
44 | /* Ensure magic is correct. */ |
45 | if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { | |
46 | avb_error("Magic is incorrect.\n"); | |
47 | goto out; | |
48 | } | |
49 | ||
d8f9d2af IO |
50 | avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data, |
51 | &h); | |
52 | ||
53 | /* Ensure we don't attempt to access any fields if we do not meet | |
54 | * the specified minimum version of libavb. | |
55 | */ | |
56 | if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) || | |
57 | (h.required_libavb_version_minor > AVB_VERSION_MINOR)) { | |
58 | avb_error("Mismatch between image version and libavb version.\n"); | |
59 | ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION; | |
60 | goto out; | |
61 | } | |
62 | ||
63 | /* Ensure |release_string| ends with a NUL byte. */ | |
64 | if (h.release_string[AVB_RELEASE_STRING_SIZE - 1] != '\0') { | |
65 | avb_error("Release string does not end with a NUL byte.\n"); | |
66 | goto out; | |
67 | } | |
68 | ||
69 | /* Ensure inner block sizes are multiple of 64. */ | |
70 | if ((h.authentication_data_block_size & 0x3f) != 0 || | |
71 | (h.auxiliary_data_block_size & 0x3f) != 0) { | |
72 | avb_error("Block size is not a multiple of 64.\n"); | |
73 | goto out; | |
74 | } | |
75 | ||
76 | /* Ensure block sizes all add up to at most |length|. */ | |
77 | uint64_t block_total = sizeof(AvbVBMetaImageHeader); | |
78 | if (!avb_safe_add_to(&block_total, h.authentication_data_block_size) || | |
79 | !avb_safe_add_to(&block_total, h.auxiliary_data_block_size)) { | |
80 | avb_error("Overflow while computing size of boot image.\n"); | |
81 | goto out; | |
82 | } | |
83 | if (block_total > length) { | |
84 | avb_error("Block sizes add up to more than given length.\n"); | |
85 | goto out; | |
86 | } | |
87 | ||
88 | uintptr_t data_ptr = (uintptr_t)data; | |
89 | /* Ensure passed in memory doesn't wrap. */ | |
90 | if (!avb_safe_add(NULL, (uint64_t)data_ptr, length)) { | |
91 | avb_error("Boot image location and length mismatch.\n"); | |
92 | goto out; | |
93 | } | |
94 | ||
95 | /* Ensure hash and signature are entirely in the Authentication data block. */ | |
96 | uint64_t hash_end; | |
97 | if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) || | |
98 | hash_end > h.authentication_data_block_size) { | |
99 | avb_error("Hash is not entirely in its block.\n"); | |
100 | goto out; | |
101 | } | |
102 | uint64_t signature_end; | |
103 | if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) || | |
104 | signature_end > h.authentication_data_block_size) { | |
105 | avb_error("Signature is not entirely in its block.\n"); | |
106 | goto out; | |
107 | } | |
108 | ||
109 | /* Ensure public key is entirely in the Auxiliary data block. */ | |
110 | uint64_t pubkey_end; | |
111 | if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) || | |
112 | pubkey_end > h.auxiliary_data_block_size) { | |
113 | avb_error("Public key is not entirely in its block.\n"); | |
114 | goto out; | |
115 | } | |
116 | ||
117 | /* Ensure public key metadata (if set) is entirely in the Auxiliary | |
118 | * data block. */ | |
119 | if (h.public_key_metadata_size > 0) { | |
120 | uint64_t pubkey_md_end; | |
121 | if (!avb_safe_add(&pubkey_md_end, | |
122 | h.public_key_metadata_offset, | |
123 | h.public_key_metadata_size) || | |
124 | pubkey_md_end > h.auxiliary_data_block_size) { | |
125 | avb_error("Public key metadata is not entirely in its block.\n"); | |
126 | goto out; | |
127 | } | |
128 | } | |
129 | ||
130 | /* Bail early if there's no hash or signature. */ | |
131 | if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) { | |
132 | ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED; | |
133 | goto out; | |
134 | } | |
135 | ||
136 | /* Ensure algorithm field is supported. */ | |
137 | algorithm = avb_get_algorithm_data(h.algorithm_type); | |
138 | if (!algorithm) { | |
139 | avb_error("Invalid or unknown algorithm.\n"); | |
140 | goto out; | |
141 | } | |
142 | ||
143 | /* Bail if the embedded hash size doesn't match the chosen algorithm. */ | |
144 | if (h.hash_size != algorithm->hash_len) { | |
145 | avb_error("Embedded hash has wrong size.\n"); | |
146 | goto out; | |
147 | } | |
148 | ||
149 | /* No overflow checks needed from here-on after since all block | |
150 | * sizes and offsets have been verified above. | |
151 | */ | |
152 | ||
153 | header_block = data; | |
154 | authentication_block = header_block + sizeof(AvbVBMetaImageHeader); | |
155 | auxiliary_block = authentication_block + h.authentication_data_block_size; | |
156 | ||
157 | switch (h.algorithm_type) { | |
158 | /* Explicit fall-through: */ | |
159 | case AVB_ALGORITHM_TYPE_SHA256_RSA2048: | |
160 | case AVB_ALGORITHM_TYPE_SHA256_RSA4096: | |
161 | case AVB_ALGORITHM_TYPE_SHA256_RSA8192: | |
162 | avb_sha256_init(&sha256_ctx); | |
163 | avb_sha256_update( | |
164 | &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader)); | |
165 | avb_sha256_update( | |
166 | &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size); | |
167 | computed_hash = avb_sha256_final(&sha256_ctx); | |
168 | break; | |
169 | /* Explicit fall-through: */ | |
170 | case AVB_ALGORITHM_TYPE_SHA512_RSA2048: | |
171 | case AVB_ALGORITHM_TYPE_SHA512_RSA4096: | |
172 | case AVB_ALGORITHM_TYPE_SHA512_RSA8192: | |
173 | avb_sha512_init(&sha512_ctx); | |
174 | avb_sha512_update( | |
175 | &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader)); | |
176 | avb_sha512_update( | |
177 | &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size); | |
178 | computed_hash = avb_sha512_final(&sha512_ctx); | |
179 | break; | |
180 | default: | |
181 | avb_error("Unknown algorithm.\n"); | |
182 | goto out; | |
183 | } | |
184 | ||
185 | if (avb_safe_memcmp(authentication_block + h.hash_offset, | |
186 | computed_hash, | |
187 | h.hash_size) != 0) { | |
188 | avb_error("Hash does not match!\n"); | |
189 | ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH; | |
190 | goto out; | |
191 | } | |
192 | ||
193 | verification_result = | |
194 | avb_rsa_verify(auxiliary_block + h.public_key_offset, | |
195 | h.public_key_size, | |
196 | authentication_block + h.signature_offset, | |
197 | h.signature_size, | |
198 | authentication_block + h.hash_offset, | |
199 | h.hash_size, | |
200 | algorithm->padding, | |
201 | algorithm->padding_len); | |
202 | ||
203 | if (verification_result == 0) { | |
204 | ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH; | |
205 | goto out; | |
206 | } | |
207 | ||
208 | if (h.public_key_size > 0) { | |
209 | if (out_public_key_data != NULL) { | |
210 | *out_public_key_data = auxiliary_block + h.public_key_offset; | |
211 | } | |
212 | if (out_public_key_length != NULL) { | |
213 | *out_public_key_length = h.public_key_size; | |
214 | } | |
215 | } | |
216 | ||
217 | ret = AVB_VBMETA_VERIFY_RESULT_OK; | |
218 | ||
219 | out: | |
220 | return ret; | |
221 | } | |
222 | ||
223 | void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src, | |
224 | AvbVBMetaImageHeader* dest) { | |
225 | avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader)); | |
226 | ||
227 | dest->required_libavb_version_major = | |
228 | avb_be32toh(dest->required_libavb_version_major); | |
229 | dest->required_libavb_version_minor = | |
230 | avb_be32toh(dest->required_libavb_version_minor); | |
231 | ||
232 | dest->authentication_data_block_size = | |
233 | avb_be64toh(dest->authentication_data_block_size); | |
234 | dest->auxiliary_data_block_size = | |
235 | avb_be64toh(dest->auxiliary_data_block_size); | |
236 | ||
237 | dest->algorithm_type = avb_be32toh(dest->algorithm_type); | |
238 | ||
239 | dest->hash_offset = avb_be64toh(dest->hash_offset); | |
240 | dest->hash_size = avb_be64toh(dest->hash_size); | |
241 | ||
242 | dest->signature_offset = avb_be64toh(dest->signature_offset); | |
243 | dest->signature_size = avb_be64toh(dest->signature_size); | |
244 | ||
245 | dest->public_key_offset = avb_be64toh(dest->public_key_offset); | |
246 | dest->public_key_size = avb_be64toh(dest->public_key_size); | |
247 | ||
248 | dest->public_key_metadata_offset = | |
249 | avb_be64toh(dest->public_key_metadata_offset); | |
250 | dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size); | |
251 | ||
252 | dest->descriptors_offset = avb_be64toh(dest->descriptors_offset); | |
253 | dest->descriptors_size = avb_be64toh(dest->descriptors_size); | |
254 | ||
255 | dest->rollback_index = avb_be64toh(dest->rollback_index); | |
256 | dest->flags = avb_be32toh(dest->flags); | |
257 | } | |
258 | ||
259 | const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) { | |
260 | const char* ret = NULL; | |
261 | ||
262 | switch (result) { | |
263 | case AVB_VBMETA_VERIFY_RESULT_OK: | |
264 | ret = "OK"; | |
265 | break; | |
266 | case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED: | |
267 | ret = "OK_NOT_SIGNED"; | |
268 | break; | |
269 | case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER: | |
270 | ret = "INVALID_VBMETA_HEADER"; | |
271 | break; | |
272 | case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION: | |
273 | ret = "UNSUPPORTED_VERSION"; | |
274 | break; | |
275 | case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH: | |
276 | ret = "HASH_MISMATCH"; | |
277 | break; | |
278 | case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH: | |
279 | ret = "SIGNATURE_MISMATCH"; | |
280 | break; | |
281 | /* Do not add a 'default:' case here because of -Wswitch. */ | |
282 | } | |
283 | ||
284 | if (ret == NULL) { | |
285 | avb_error("Unknown AvbVBMetaVerifyResult value.\n"); | |
286 | ret = "(unknown)"; | |
287 | } | |
288 | ||
289 | return ret; | |
290 | } |