1 #include "avb_tools.h" 2 3 #include "gtest/gtest.h" 4 #include "nugget/app/avb/avb.pb.h" 5 6 #include <app_nugget.h> 7 #include "Avb.client.h" 8 #include <avb.h> 9 #include <nos/NuggetClient.h> 10 11 #include <chrono> 12 #include <iostream> 13 #include <thread> 14 #include <vector> 15 16 #ifdef ANDROID 17 #include <android-base/endian.h> 18 #include "nos/CitadeldProxyClient.h" 19 #else 20 #include "gflags/gflags.h" 21 #endif // ANDROID 22 23 using namespace nugget::app::avb; 24 25 namespace avb_tools { 26 27 void SetBootloader(nos::NuggetClientInterface *client) 28 { 29 // Force AVB to believe that the AP is in the BIOS. 30 ::nos::AppClient app(*client, APP_ID_AVB_TEST); 31 32 /* We have to have a buffer, because it's called by reference. */ 33 std::vector<uint8_t> buffer; 34 35 // No params, no args needed. This is all that the fake "AVB_TEST" app does. 36 uint32_t retval = app.Call(0, buffer, &buffer); 37 38 EXPECT_EQ(retval, APP_SUCCESS); 39 } 40 41 void BootloaderDone(nos::NuggetClientInterface *client) 42 { 43 BootloaderDoneRequest request; 44 45 Avb service(*client); 46 ASSERT_NO_ERROR(service.BootloaderDone(request, nullptr), ""); 47 } 48 49 void GetState(nos::NuggetClientInterface *client, bool *bootloader, 50 bool *production, uint8_t *locks) { 51 GetStateRequest request; 52 GetStateResponse response; 53 54 Avb service(*client); 55 ASSERT_NO_ERROR(service.GetState(request, &response), ""); 56 EXPECT_EQ(response.number_of_locks(), 4U); 57 58 if (bootloader != NULL) 59 *bootloader = response.bootloader(); 60 if (production != NULL) 61 *production = response.production(); 62 63 auto response_locks = response.locks(); 64 if (locks != NULL) { 65 for (size_t i = 0; i < response_locks.size(); i++) 66 locks[i] = response_locks[i]; 67 } 68 } 69 70 int Reset(nos::NuggetClientInterface *client, ResetRequest_ResetKind kind, 71 const uint8_t *sig, size_t size) { 72 ResetRequest request; 73 74 request.set_kind(kind); 75 request.mutable_token()->set_selector(ResetToken::CURRENT); 76 if (sig && size) { 77 request.mutable_token()->set_signature(sig, size); 78 } else { 79 uint8_t empty[AVB_SIGNATURE_SIZE]; 80 memset(empty, 0, sizeof(empty)); 81 request.mutable_token()->set_signature(empty, sizeof(empty)); 82 } 83 84 Avb service(*client); 85 return service.Reset(request, nullptr); 86 } 87 88 int GetResetChallenge(nos::NuggetClientInterface *client, 89 uint32_t *selector, uint64_t *nonce, 90 uint8_t *device_data, size_t *len) { 91 GetResetChallengeRequest request; 92 GetResetChallengeResponse response; 93 94 Avb service(*client); 95 uint32_t ret = service.GetResetChallenge(request, &response); 96 if (ret != APP_SUCCESS) { 97 return ret; 98 } 99 *selector = response.selector(); 100 *nonce = response.nonce(); 101 // Only copy what there is space for. 102 *len = (*len < response.device_data().size() ? *len : response.device_data().size()); 103 memcpy(device_data, response.device_data().data(), *len); 104 // Let the caller assert if the requested size was too large. 105 *len = response.device_data().size(); 106 return ret; 107 } 108 109 int SetProduction(nos::NuggetClientInterface *client, bool production, 110 const uint8_t *data, size_t size) { 111 SetProductionRequest request; 112 113 request.set_production(production); 114 if (size != 0 && data != NULL) { 115 request.set_device_data(data, size); 116 } 117 // Substitute an empty hash 118 uint8_t empty[AVB_DEVICE_DATA_SIZE]; 119 memset(empty, 0, sizeof(empty)); 120 if (production && data == NULL) { 121 request.set_device_data(empty, sizeof(empty)); 122 } 123 124 Avb service(*client); 125 return service.SetProduction(request, nullptr); 126 } 127 128 void ResetProduction(nos::NuggetClientInterface *client) 129 { 130 struct ResetMessage message; 131 int code; 132 uint32_t selector; 133 size_t len = sizeof(message.data); 134 uint8_t signature[AVB_SIGNATURE_SIZE]; 135 size_t siglen = sizeof(signature); 136 memset(signature, 0, siglen); 137 138 // We need the nonce to be set before we get fallthrough. 139 memset(message.data, 0, sizeof(message.data)); 140 code = GetResetChallenge(client, &selector, &message.nonce, message.data, &len); 141 ASSERT_NO_ERROR(code, ""); 142 // No signature is needed for TEST_IMAGE. 143 //EXPECT_EQ(0, SignChallenge(&message, signature, &siglen)); 144 Reset(client, ResetRequest::PRODUCTION, signature, siglen); 145 bool bootloader; 146 bool production; 147 uint8_t locks[4]; 148 GetState(client, &bootloader, &production, locks); 149 ASSERT_EQ(production, false); 150 } 151 152 } // namespace nugget_tools 153