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