xref: /rk3399_rockchip-uboot/lib/avb/libavb_atx/avb_atx_validate.c (revision ab608f806ee1d7fa63a18cc035e8ea62b67634e5)
137a7bc39SJason Zhu /*
237a7bc39SJason Zhu  * Copyright (C) 2016 The Android Open Source Project
337a7bc39SJason Zhu  *
437a7bc39SJason Zhu  * Permission is hereby granted, free of charge, to any person
537a7bc39SJason Zhu  * obtaining a copy of this software and associated documentation
637a7bc39SJason Zhu  * files (the "Software"), to deal in the Software without
737a7bc39SJason Zhu  * restriction, including without limitation the rights to use, copy,
837a7bc39SJason Zhu  * modify, merge, publish, distribute, sublicense, and/or sell copies
937a7bc39SJason Zhu  * of the Software, and to permit persons to whom the Software is
1037a7bc39SJason Zhu  * furnished to do so, subject to the following conditions:
1137a7bc39SJason Zhu  *
1237a7bc39SJason Zhu  * The above copyright notice and this permission notice shall be
1337a7bc39SJason Zhu  * included in all copies or substantial portions of the Software.
1437a7bc39SJason Zhu  *
1537a7bc39SJason Zhu  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1637a7bc39SJason Zhu  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1737a7bc39SJason Zhu  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1837a7bc39SJason Zhu  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
1937a7bc39SJason Zhu  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2037a7bc39SJason Zhu  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2137a7bc39SJason Zhu  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2237a7bc39SJason Zhu  * SOFTWARE.
2337a7bc39SJason Zhu  */
2437a7bc39SJason Zhu 
2537a7bc39SJason Zhu #include <android_avb/avb_atx_validate.h>
2637a7bc39SJason Zhu 
2737a7bc39SJason Zhu #include <android_avb/avb_rsa.h>
2837a7bc39SJason Zhu #include <android_avb/avb_sha.h>
2937a7bc39SJason Zhu #include <android_avb/avb_sysdeps.h>
3037a7bc39SJason Zhu #include <android_avb/avb_util.h>
3137a7bc39SJason Zhu 
32*ab608f80SJason Zhu /* The most recent unlock challenge generated. */
33*ab608f80SJason Zhu static uint8_t last_unlock_challenge[AVB_ATX_UNLOCK_CHALLENGE_SIZE];
34*ab608f80SJason Zhu 
3537a7bc39SJason Zhu /* Computes the SHA256 |hash| of |length| bytes of |data|. */
3637a7bc39SJason Zhu static void sha256(const uint8_t* data,
3737a7bc39SJason Zhu                    uint32_t length,
3837a7bc39SJason Zhu                    uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
3937a7bc39SJason Zhu   AvbSHA256Ctx context;
4037a7bc39SJason Zhu   avb_sha256_init(&context);
4137a7bc39SJason Zhu   avb_sha256_update(&context, data, length);
4237a7bc39SJason Zhu   uint8_t* tmp = avb_sha256_final(&context);
4337a7bc39SJason Zhu   avb_memcpy(hash, tmp, AVB_SHA256_DIGEST_SIZE);
4437a7bc39SJason Zhu }
4537a7bc39SJason Zhu 
4637a7bc39SJason Zhu /* Computes the SHA512 |hash| of |length| bytes of |data|. */
4737a7bc39SJason Zhu static void sha512(const uint8_t* data,
4837a7bc39SJason Zhu                    uint32_t length,
4937a7bc39SJason Zhu                    uint8_t hash[AVB_SHA512_DIGEST_SIZE]) {
5037a7bc39SJason Zhu   AvbSHA512Ctx context;
5137a7bc39SJason Zhu   avb_sha512_init(&context);
5237a7bc39SJason Zhu   avb_sha512_update(&context, data, length);
5337a7bc39SJason Zhu   uint8_t* tmp = avb_sha512_final(&context);
5437a7bc39SJason Zhu   avb_memcpy(hash, tmp, AVB_SHA512_DIGEST_SIZE);
5537a7bc39SJason Zhu }
5637a7bc39SJason Zhu 
5737a7bc39SJason Zhu /* Computes the SHA256 |hash| of a NUL-terminated |str|. */
5837a7bc39SJason Zhu static void sha256_str(const char* str, uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
5937a7bc39SJason Zhu   sha256((const uint8_t*)str, avb_strlen(str), hash);
6037a7bc39SJason Zhu }
6137a7bc39SJason Zhu 
6237a7bc39SJason Zhu /* Verifies structure and |expected_hash| of permanent |attributes|. */
6337a7bc39SJason Zhu static bool verify_permanent_attributes(
6437a7bc39SJason Zhu     const AvbAtxPermanentAttributes* attributes,
65*ab608f80SJason Zhu     const uint8_t expected_hash[AVB_SHA256_DIGEST_SIZE]) {
6637a7bc39SJason Zhu   uint8_t hash[AVB_SHA256_DIGEST_SIZE];
6737a7bc39SJason Zhu 
6837a7bc39SJason Zhu   if (attributes->version != 1) {
6937a7bc39SJason Zhu     avb_error("Unsupported permanent attributes version.\n");
7037a7bc39SJason Zhu     return false;
7137a7bc39SJason Zhu   }
7237a7bc39SJason Zhu   sha256((const uint8_t*)attributes, sizeof(AvbAtxPermanentAttributes), hash);
7337a7bc39SJason Zhu   if (0 != avb_safe_memcmp(hash, expected_hash, AVB_SHA256_DIGEST_SIZE)) {
7437a7bc39SJason Zhu     avb_error("Invalid permanent attributes.\n");
7537a7bc39SJason Zhu     return false;
7637a7bc39SJason Zhu   }
7737a7bc39SJason Zhu   return true;
7837a7bc39SJason Zhu }
7937a7bc39SJason Zhu 
8037a7bc39SJason Zhu /* Verifies the format, key version, usage, and signature of a certificate. */
81*ab608f80SJason Zhu static bool verify_certificate(
82*ab608f80SJason Zhu     const AvbAtxCertificate* certificate,
83*ab608f80SJason Zhu     const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE],
8437a7bc39SJason Zhu     uint64_t minimum_key_version,
85*ab608f80SJason Zhu     const uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]) {
8637a7bc39SJason Zhu   const AvbAlgorithmData* algorithm_data;
8737a7bc39SJason Zhu   uint8_t certificate_hash[AVB_SHA512_DIGEST_SIZE];
8837a7bc39SJason Zhu 
8937a7bc39SJason Zhu   if (certificate->signed_data.version != 1) {
9037a7bc39SJason Zhu     avb_error("Unsupported certificate format.\n");
9137a7bc39SJason Zhu     return false;
9237a7bc39SJason Zhu   }
9337a7bc39SJason Zhu   algorithm_data = avb_get_algorithm_data(AVB_ALGORITHM_TYPE_SHA512_RSA4096);
9437a7bc39SJason Zhu   sha512((const uint8_t*)&certificate->signed_data,
9537a7bc39SJason Zhu          sizeof(AvbAtxCertificateSignedData),
9637a7bc39SJason Zhu          certificate_hash);
9737a7bc39SJason Zhu   if (!avb_rsa_verify(authority,
9837a7bc39SJason Zhu                       AVB_ATX_PUBLIC_KEY_SIZE,
9937a7bc39SJason Zhu                       certificate->signature,
10037a7bc39SJason Zhu                       AVB_RSA4096_NUM_BYTES,
10137a7bc39SJason Zhu                       certificate_hash,
10237a7bc39SJason Zhu                       AVB_SHA512_DIGEST_SIZE,
10337a7bc39SJason Zhu                       algorithm_data->padding,
10437a7bc39SJason Zhu                       algorithm_data->padding_len)) {
10537a7bc39SJason Zhu     avb_error("Invalid certificate signature.\n");
10637a7bc39SJason Zhu     return false;
10737a7bc39SJason Zhu   }
10837a7bc39SJason Zhu   if (certificate->signed_data.key_version < minimum_key_version) {
10937a7bc39SJason Zhu     avb_error("Key rollback detected.\n");
11037a7bc39SJason Zhu     return false;
11137a7bc39SJason Zhu   }
11237a7bc39SJason Zhu   if (0 != avb_safe_memcmp(certificate->signed_data.usage,
11337a7bc39SJason Zhu                            expected_usage,
11437a7bc39SJason Zhu                            AVB_SHA256_DIGEST_SIZE)) {
11537a7bc39SJason Zhu     avb_error("Invalid certificate usage.\n");
11637a7bc39SJason Zhu     return false;
11737a7bc39SJason Zhu   }
11837a7bc39SJason Zhu   return true;
11937a7bc39SJason Zhu }
12037a7bc39SJason Zhu 
12137a7bc39SJason Zhu /* Verifies signature and fields of a PIK certificate. */
122*ab608f80SJason Zhu static bool verify_pik_certificate(
123*ab608f80SJason Zhu     const AvbAtxCertificate* certificate,
124*ab608f80SJason Zhu     const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE],
12537a7bc39SJason Zhu     uint64_t minimum_version) {
12637a7bc39SJason Zhu   uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE];
12737a7bc39SJason Zhu 
12837a7bc39SJason Zhu   sha256_str("com.google.android.things.vboot.ca", expected_usage);
12937a7bc39SJason Zhu   if (!verify_certificate(
13037a7bc39SJason Zhu           certificate, authority, minimum_version, expected_usage)) {
13137a7bc39SJason Zhu     avb_error("Invalid PIK certificate.\n");
13237a7bc39SJason Zhu     return false;
13337a7bc39SJason Zhu   }
13437a7bc39SJason Zhu   return true;
13537a7bc39SJason Zhu }
13637a7bc39SJason Zhu 
13737a7bc39SJason Zhu /* Verifies signature and fields of a PSK certificate. */
13837a7bc39SJason Zhu static bool verify_psk_certificate(
139*ab608f80SJason Zhu     const AvbAtxCertificate* certificate,
140*ab608f80SJason Zhu     const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE],
14137a7bc39SJason Zhu     uint64_t minimum_version,
142*ab608f80SJason Zhu     const uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) {
14337a7bc39SJason Zhu   uint8_t expected_subject[AVB_SHA256_DIGEST_SIZE];
14437a7bc39SJason Zhu   uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE];
14537a7bc39SJason Zhu 
14637a7bc39SJason Zhu   sha256_str("com.google.android.things.vboot", expected_usage);
14737a7bc39SJason Zhu   if (!verify_certificate(
14837a7bc39SJason Zhu           certificate, authority, minimum_version, expected_usage)) {
14937a7bc39SJason Zhu     avb_error("Invalid PSK certificate.\n");
15037a7bc39SJason Zhu     return false;
15137a7bc39SJason Zhu   }
15237a7bc39SJason Zhu   sha256(product_id, AVB_ATX_PRODUCT_ID_SIZE, expected_subject);
15337a7bc39SJason Zhu   if (0 != avb_safe_memcmp(certificate->signed_data.subject,
15437a7bc39SJason Zhu                            expected_subject,
15537a7bc39SJason Zhu                            AVB_SHA256_DIGEST_SIZE)) {
156*ab608f80SJason Zhu     avb_error("PSK: Product ID mismatch.\n");
157*ab608f80SJason Zhu     return false;
158*ab608f80SJason Zhu   }
159*ab608f80SJason Zhu   return true;
160*ab608f80SJason Zhu }
161*ab608f80SJason Zhu 
162*ab608f80SJason Zhu /* Verifies signature and fields of a PUK certificate. */
163*ab608f80SJason Zhu static bool verify_puk_certificate(
164*ab608f80SJason Zhu     const AvbAtxCertificate* certificate,
165*ab608f80SJason Zhu     const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE],
166*ab608f80SJason Zhu     uint64_t minimum_version,
167*ab608f80SJason Zhu     const uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) {
168*ab608f80SJason Zhu   uint8_t expected_subject[AVB_SHA256_DIGEST_SIZE];
169*ab608f80SJason Zhu   uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE];
170*ab608f80SJason Zhu 
171*ab608f80SJason Zhu   sha256_str("com.google.android.things.vboot.unlock", expected_usage);
172*ab608f80SJason Zhu   if (!verify_certificate(
173*ab608f80SJason Zhu           certificate, authority, minimum_version, expected_usage)) {
174*ab608f80SJason Zhu     avb_error("Invalid PUK certificate.\n");
175*ab608f80SJason Zhu     return false;
176*ab608f80SJason Zhu   }
177*ab608f80SJason Zhu   sha256(product_id, AVB_ATX_PRODUCT_ID_SIZE, expected_subject);
178*ab608f80SJason Zhu   if (0 != avb_safe_memcmp(certificate->signed_data.subject,
179*ab608f80SJason Zhu                            expected_subject,
180*ab608f80SJason Zhu                            AVB_SHA256_DIGEST_SIZE)) {
181*ab608f80SJason Zhu     avb_error("PUK: Product ID mismatch.\n");
18237a7bc39SJason Zhu     return false;
18337a7bc39SJason Zhu   }
18437a7bc39SJason Zhu   return true;
18537a7bc39SJason Zhu }
18637a7bc39SJason Zhu 
18737a7bc39SJason Zhu AvbIOResult avb_atx_validate_vbmeta_public_key(
18837a7bc39SJason Zhu     AvbOps* ops,
18937a7bc39SJason Zhu     const uint8_t* public_key_data,
19037a7bc39SJason Zhu     size_t public_key_length,
19137a7bc39SJason Zhu     const uint8_t* public_key_metadata,
19237a7bc39SJason Zhu     size_t public_key_metadata_length,
19337a7bc39SJason Zhu     bool* out_is_trusted) {
19437a7bc39SJason Zhu   AvbIOResult result = AVB_IO_RESULT_OK;
19537a7bc39SJason Zhu   AvbAtxPermanentAttributes permanent_attributes;
19637a7bc39SJason Zhu   uint8_t permanent_attributes_hash[AVB_SHA256_DIGEST_SIZE];
19737a7bc39SJason Zhu   AvbAtxPublicKeyMetadata metadata;
19837a7bc39SJason Zhu   uint64_t minimum_version;
19937a7bc39SJason Zhu 
20037a7bc39SJason Zhu   /* Be pessimistic so we can exit early without having to remember to clear.
20137a7bc39SJason Zhu    */
20237a7bc39SJason Zhu   *out_is_trusted = false;
20337a7bc39SJason Zhu 
20437a7bc39SJason Zhu   /* Read and verify permanent attributes. */
20537a7bc39SJason Zhu   result = ops->atx_ops->read_permanent_attributes(ops->atx_ops,
20637a7bc39SJason Zhu                                                    &permanent_attributes);
20737a7bc39SJason Zhu   if (result != AVB_IO_RESULT_OK) {
20837a7bc39SJason Zhu     avb_error("Failed to read permanent attributes.\n");
20937a7bc39SJason Zhu     return result;
21037a7bc39SJason Zhu   }
21137a7bc39SJason Zhu   result = ops->atx_ops->read_permanent_attributes_hash(
21237a7bc39SJason Zhu       ops->atx_ops, permanent_attributes_hash);
21337a7bc39SJason Zhu   if (result != AVB_IO_RESULT_OK) {
21437a7bc39SJason Zhu     avb_error("Failed to read permanent attributes hash.\n");
21537a7bc39SJason Zhu     return result;
21637a7bc39SJason Zhu   }
21737a7bc39SJason Zhu   if (!verify_permanent_attributes(&permanent_attributes,
21837a7bc39SJason Zhu                                    permanent_attributes_hash)) {
21937a7bc39SJason Zhu     return AVB_IO_RESULT_OK;
22037a7bc39SJason Zhu   }
22137a7bc39SJason Zhu 
22237a7bc39SJason Zhu   /* Sanity check public key metadata. */
22337a7bc39SJason Zhu   if (public_key_metadata_length != sizeof(AvbAtxPublicKeyMetadata)) {
22437a7bc39SJason Zhu     avb_error("Invalid public key metadata.\n");
22537a7bc39SJason Zhu     return AVB_IO_RESULT_OK;
22637a7bc39SJason Zhu   }
22737a7bc39SJason Zhu   avb_memcpy(&metadata, public_key_metadata, sizeof(AvbAtxPublicKeyMetadata));
22837a7bc39SJason Zhu   if (metadata.version != 1) {
22937a7bc39SJason Zhu     avb_error("Unsupported public key metadata.\n");
23037a7bc39SJason Zhu     return AVB_IO_RESULT_OK;
23137a7bc39SJason Zhu   }
23237a7bc39SJason Zhu 
23337a7bc39SJason Zhu   /* Verify the PIK certificate. */
23437a7bc39SJason Zhu   result = ops->read_rollback_index(
23537a7bc39SJason Zhu       ops, AVB_ATX_PIK_VERSION_LOCATION, &minimum_version);
23637a7bc39SJason Zhu   if (result != AVB_IO_RESULT_OK) {
23737a7bc39SJason Zhu     avb_error("Failed to read PIK minimum version.\n");
23837a7bc39SJason Zhu     return result;
23937a7bc39SJason Zhu   }
24037a7bc39SJason Zhu   if (!verify_pik_certificate(&metadata.product_intermediate_key_certificate,
24137a7bc39SJason Zhu                               permanent_attributes.product_root_public_key,
24237a7bc39SJason Zhu                               minimum_version)) {
24337a7bc39SJason Zhu     return AVB_IO_RESULT_OK;
24437a7bc39SJason Zhu   }
24537a7bc39SJason Zhu 
24637a7bc39SJason Zhu   /* Verify the PSK certificate. */
24737a7bc39SJason Zhu   result = ops->read_rollback_index(
24837a7bc39SJason Zhu       ops, AVB_ATX_PSK_VERSION_LOCATION, &minimum_version);
24937a7bc39SJason Zhu   if (result != AVB_IO_RESULT_OK) {
25037a7bc39SJason Zhu     avb_error("Failed to read PSK minimum version.\n");
25137a7bc39SJason Zhu     return result;
25237a7bc39SJason Zhu   }
25337a7bc39SJason Zhu   if (!verify_psk_certificate(
25437a7bc39SJason Zhu           &metadata.product_signing_key_certificate,
25537a7bc39SJason Zhu           metadata.product_intermediate_key_certificate.signed_data.public_key,
25637a7bc39SJason Zhu           minimum_version,
25737a7bc39SJason Zhu           permanent_attributes.product_id)) {
25837a7bc39SJason Zhu     return AVB_IO_RESULT_OK;
25937a7bc39SJason Zhu   }
26037a7bc39SJason Zhu 
26137a7bc39SJason Zhu   /* Verify the PSK is the same key that verified vbmeta. */
26237a7bc39SJason Zhu   if (public_key_length != AVB_ATX_PUBLIC_KEY_SIZE) {
26337a7bc39SJason Zhu     avb_error("Public key length mismatch.\n");
26437a7bc39SJason Zhu     return AVB_IO_RESULT_OK;
26537a7bc39SJason Zhu   }
26637a7bc39SJason Zhu   if (0 != avb_safe_memcmp(
26737a7bc39SJason Zhu                metadata.product_signing_key_certificate.signed_data.public_key,
26837a7bc39SJason Zhu                public_key_data,
26937a7bc39SJason Zhu                AVB_ATX_PUBLIC_KEY_SIZE)) {
27037a7bc39SJason Zhu     avb_error("Public key mismatch.\n");
27137a7bc39SJason Zhu     return AVB_IO_RESULT_OK;
27237a7bc39SJason Zhu   }
27337a7bc39SJason Zhu 
27437a7bc39SJason Zhu   /* Report the key versions used during verification. */
27537a7bc39SJason Zhu   ops->atx_ops->set_key_version(
27637a7bc39SJason Zhu       ops->atx_ops,
27737a7bc39SJason Zhu       AVB_ATX_PIK_VERSION_LOCATION,
27837a7bc39SJason Zhu       metadata.product_intermediate_key_certificate.signed_data.key_version);
27937a7bc39SJason Zhu   ops->atx_ops->set_key_version(
28037a7bc39SJason Zhu       ops->atx_ops,
28137a7bc39SJason Zhu       AVB_ATX_PSK_VERSION_LOCATION,
28237a7bc39SJason Zhu       metadata.product_signing_key_certificate.signed_data.key_version);
28337a7bc39SJason Zhu 
28437a7bc39SJason Zhu   *out_is_trusted = true;
28537a7bc39SJason Zhu   return AVB_IO_RESULT_OK;
28637a7bc39SJason Zhu }
287*ab608f80SJason Zhu 
288*ab608f80SJason Zhu AvbIOResult avb_atx_generate_unlock_challenge(
289*ab608f80SJason Zhu     AvbAtxOps* atx_ops, AvbAtxUnlockChallenge* out_unlock_challenge) {
290*ab608f80SJason Zhu   AvbIOResult result = AVB_IO_RESULT_OK;
291*ab608f80SJason Zhu   AvbAtxPermanentAttributes permanent_attributes;
292*ab608f80SJason Zhu 
293*ab608f80SJason Zhu   /* We need the permanent attributes to compute the product_id_hash. */
294*ab608f80SJason Zhu   result = atx_ops->read_permanent_attributes(atx_ops, &permanent_attributes);
295*ab608f80SJason Zhu   if (result != AVB_IO_RESULT_OK) {
296*ab608f80SJason Zhu     avb_error("Failed to read permanent attributes.\n");
297*ab608f80SJason Zhu     return result;
298*ab608f80SJason Zhu   }
299*ab608f80SJason Zhu   result = atx_ops->get_random(
300*ab608f80SJason Zhu       atx_ops, AVB_ATX_UNLOCK_CHALLENGE_SIZE, last_unlock_challenge);
301*ab608f80SJason Zhu   if (result != AVB_IO_RESULT_OK) {
302*ab608f80SJason Zhu     avb_error("Failed to generate random challenge.\n");
303*ab608f80SJason Zhu     return result;
304*ab608f80SJason Zhu   }
305*ab608f80SJason Zhu   out_unlock_challenge->version = 1;
306*ab608f80SJason Zhu   sha256(permanent_attributes.product_id,
307*ab608f80SJason Zhu          AVB_ATX_PRODUCT_ID_SIZE,
308*ab608f80SJason Zhu          out_unlock_challenge->product_id_hash);
309*ab608f80SJason Zhu   avb_memcpy(out_unlock_challenge->challenge,
310*ab608f80SJason Zhu              last_unlock_challenge,
311*ab608f80SJason Zhu              AVB_ATX_UNLOCK_CHALLENGE_SIZE);
312*ab608f80SJason Zhu   return result;
313*ab608f80SJason Zhu }
314*ab608f80SJason Zhu 
315*ab608f80SJason Zhu AvbIOResult avb_atx_validate_unlock_credential(
316*ab608f80SJason Zhu     AvbAtxOps* atx_ops,
317*ab608f80SJason Zhu     const AvbAtxUnlockCredential* unlock_credential,
318*ab608f80SJason Zhu     bool* out_is_trusted) {
319*ab608f80SJason Zhu   AvbIOResult result = AVB_IO_RESULT_OK;
320*ab608f80SJason Zhu   AvbAtxPermanentAttributes permanent_attributes;
321*ab608f80SJason Zhu   uint8_t permanent_attributes_hash[AVB_SHA256_DIGEST_SIZE];
322*ab608f80SJason Zhu   uint64_t minimum_version;
323*ab608f80SJason Zhu   const AvbAlgorithmData* algorithm_data;
324*ab608f80SJason Zhu   uint8_t challenge_hash[AVB_SHA512_DIGEST_SIZE];
325*ab608f80SJason Zhu 
326*ab608f80SJason Zhu   /* Be pessimistic so we can exit early without having to remember to clear.
327*ab608f80SJason Zhu    */
328*ab608f80SJason Zhu   *out_is_trusted = false;
329*ab608f80SJason Zhu 
330*ab608f80SJason Zhu   /* Sanity check the credential. */
331*ab608f80SJason Zhu   if (unlock_credential->version != 1) {
332*ab608f80SJason Zhu     avb_error("Unsupported unlock credential format.\n");
333*ab608f80SJason Zhu     return AVB_IO_RESULT_OK;
334*ab608f80SJason Zhu   }
335*ab608f80SJason Zhu 
336*ab608f80SJason Zhu   /* Read and verify permanent attributes. */
337*ab608f80SJason Zhu   result = atx_ops->read_permanent_attributes(atx_ops, &permanent_attributes);
338*ab608f80SJason Zhu   if (result != AVB_IO_RESULT_OK) {
339*ab608f80SJason Zhu     avb_error("Failed to read permanent attributes.\n");
340*ab608f80SJason Zhu     return result;
341*ab608f80SJason Zhu   }
342*ab608f80SJason Zhu   result = atx_ops->read_permanent_attributes_hash(atx_ops,
343*ab608f80SJason Zhu                                                    permanent_attributes_hash);
344*ab608f80SJason Zhu   if (result != AVB_IO_RESULT_OK) {
345*ab608f80SJason Zhu     avb_error("Failed to read permanent attributes hash.\n");
346*ab608f80SJason Zhu     return result;
347*ab608f80SJason Zhu   }
348*ab608f80SJason Zhu   if (!verify_permanent_attributes(&permanent_attributes,
349*ab608f80SJason Zhu                                    permanent_attributes_hash)) {
350*ab608f80SJason Zhu     return AVB_IO_RESULT_OK;
351*ab608f80SJason Zhu   }
352*ab608f80SJason Zhu 
353*ab608f80SJason Zhu   /* Verify the PIK certificate. */
354*ab608f80SJason Zhu   result = atx_ops->ops->read_rollback_index(
355*ab608f80SJason Zhu       atx_ops->ops, AVB_ATX_PIK_VERSION_LOCATION, &minimum_version);
356*ab608f80SJason Zhu   if (result != AVB_IO_RESULT_OK) {
357*ab608f80SJason Zhu     avb_error("Failed to read PIK minimum version.\n");
358*ab608f80SJason Zhu     return result;
359*ab608f80SJason Zhu   }
360*ab608f80SJason Zhu   if (!verify_pik_certificate(
361*ab608f80SJason Zhu           &unlock_credential->product_intermediate_key_certificate,
362*ab608f80SJason Zhu           permanent_attributes.product_root_public_key,
363*ab608f80SJason Zhu           minimum_version)) {
364*ab608f80SJason Zhu     return AVB_IO_RESULT_OK;
365*ab608f80SJason Zhu   }
366*ab608f80SJason Zhu 
367*ab608f80SJason Zhu   /* Verify the PUK certificate. The minimum version is shared with the PSK. */
368*ab608f80SJason Zhu   result = atx_ops->ops->read_rollback_index(
369*ab608f80SJason Zhu       atx_ops->ops, AVB_ATX_PSK_VERSION_LOCATION, &minimum_version);
370*ab608f80SJason Zhu   if (result != AVB_IO_RESULT_OK) {
371*ab608f80SJason Zhu     avb_error("Failed to read PSK minimum version.\n");
372*ab608f80SJason Zhu     return result;
373*ab608f80SJason Zhu   }
374*ab608f80SJason Zhu   if (!verify_puk_certificate(
375*ab608f80SJason Zhu           &unlock_credential->product_unlock_key_certificate,
376*ab608f80SJason Zhu           unlock_credential->product_intermediate_key_certificate.signed_data
377*ab608f80SJason Zhu               .public_key,
378*ab608f80SJason Zhu           minimum_version,
379*ab608f80SJason Zhu           permanent_attributes.product_id)) {
380*ab608f80SJason Zhu     return AVB_IO_RESULT_OK;
381*ab608f80SJason Zhu   }
382*ab608f80SJason Zhu 
383*ab608f80SJason Zhu   /* Verify the challenge signature. */
384*ab608f80SJason Zhu   algorithm_data = avb_get_algorithm_data(AVB_ALGORITHM_TYPE_SHA512_RSA4096);
385*ab608f80SJason Zhu   sha512(last_unlock_challenge, AVB_ATX_UNLOCK_CHALLENGE_SIZE, challenge_hash);
386*ab608f80SJason Zhu   if (!avb_rsa_verify(unlock_credential->product_unlock_key_certificate
387*ab608f80SJason Zhu                           .signed_data.public_key,
388*ab608f80SJason Zhu                       AVB_ATX_PUBLIC_KEY_SIZE,
389*ab608f80SJason Zhu                       unlock_credential->challenge_signature,
390*ab608f80SJason Zhu                       AVB_RSA4096_NUM_BYTES,
391*ab608f80SJason Zhu                       challenge_hash,
392*ab608f80SJason Zhu                       AVB_SHA512_DIGEST_SIZE,
393*ab608f80SJason Zhu                       algorithm_data->padding,
394*ab608f80SJason Zhu                       algorithm_data->padding_len)) {
395*ab608f80SJason Zhu     avb_error("Invalid unlock challenge signature.\n");
396*ab608f80SJason Zhu     return AVB_IO_RESULT_OK;
397*ab608f80SJason Zhu   }
398*ab608f80SJason Zhu 
399*ab608f80SJason Zhu   *out_is_trusted = true;
400*ab608f80SJason Zhu   return AVB_IO_RESULT_OK;
401*ab608f80SJason Zhu }
402