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