@@ -156,7 +156,8 @@ void TeslaBLE::Vehicle::process_command_queue_() {
156156 break ;
157157 case CommandState::WAITING_FOR_RESPONSE: {
158158 auto tx_duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - command->last_tx_at );
159- if (tx_duration > CLOCK_SYNC_MAX_LATENCY) {
159+ const auto timeout = (command->name == " Whitelist Add Key" ) ? COMMAND_TIMEOUT : CLOCK_SYNC_MAX_LATENCY;
160+ if (tx_duration > timeout) {
160161 if (command->name == " Wake" && is_vehicle_awake_) {
161162 LOG_INFO (" Wake response timeout but vehicle is awake - proceeding" );
162163 mark_command_completed_ (command);
@@ -181,6 +182,15 @@ std::shared_ptr<TeslaBLE::Command> TeslaBLE::Vehicle::peek_command_() const {
181182
182183void TeslaBLE::Vehicle::process_idle_command_ (const std::shared_ptr<Command> &command) {
183184 command->started_at = std::chrono::steady_clock::now ();
185+
186+ // Pairing starts with an untrusted key, so VCSEC session auth will return
187+ // KEY_NOT_ON_WHITELIST. This command must be sent without prior session auth.
188+ if (command->name == " Whitelist Add Key" ) {
189+ LOG_INFO (" Bypassing session auth for Whitelist Add Key" );
190+ command->state = CommandState::READY;
191+ return ;
192+ }
193+
184194 switch (command->domain ) {
185195 case UniversalMessage_Domain_DOMAIN_BROADCAST:
186196 command->state = CommandState::READY;
@@ -1216,11 +1226,48 @@ void TeslaBLE::Vehicle::close_windows() {
12161226// Pairing and Key Management
12171227// =============================================================================
12181228
1229+ bool TeslaBLE::Vehicle::persist_private_key_ () {
1230+ if (!client_ || !storage_adapter_) {
1231+ LOG_ERROR (" Client or storage adapter unavailable" );
1232+ return false ;
1233+ }
1234+
1235+ std::array<uint8_t , 2048 > key_buf{};
1236+ size_t key_len = 0 ;
1237+ if (client_->get_private_key (key_buf.data (), key_buf.size (), &key_len) != 0 ) {
1238+ LOG_ERROR (" Failed to export private key" );
1239+ return false ;
1240+ }
1241+
1242+ if (key_len == 0 || key_len > key_buf.size ()) {
1243+ LOG_ERROR (" Invalid private key length: %zu" , key_len);
1244+ return false ;
1245+ }
1246+
1247+ std::vector<uint8_t > key_vec (key_buf.begin (), key_buf.begin () + key_len);
1248+ if (!storage_adapter_->save (" private_key" , key_vec)) {
1249+ LOG_ERROR (" Failed to save private key to storage" );
1250+ return false ;
1251+ }
1252+
1253+ return true ;
1254+ }
1255+
12191256void TeslaBLE::Vehicle::pair (Keys_Role role) {
12201257 LOG_INFO (" Initiating pairing sequence..." );
1221- if (client_->create_private_key () != 0 ) {
1222- LOG_WARNING (" Could not check/create private key, proceeding anyway" );
1258+ if (!client_->has_private_key ()) {
1259+ LOG_INFO (" No private key loaded, creating a new one" );
1260+ if (client_->create_private_key () != 0 ) {
1261+ LOG_ERROR (" Failed to create private key for pairing" );
1262+ return ;
1263+ }
12231264 }
1265+
1266+ if (!persist_private_key_ ()) {
1267+ LOG_ERROR (" Cannot start pairing without persisted private key" );
1268+ return ;
1269+ }
1270+
12241271 send_command (UniversalMessage_Domain_DOMAIN_VEHICLE_SECURITY, " Whitelist Add Key" ,
12251272 [role_copy = role](Client *client, uint8_t *buf, size_t *len) {
12261273 return client->build_white_list_message (role_copy, VCSEC_KeyFormFactor_KEY_FORM_FACTOR_NFC_CARD, buf,
@@ -1230,23 +1277,17 @@ void TeslaBLE::Vehicle::pair(Keys_Role role) {
12301277
12311278void TeslaBLE::Vehicle::regenerate_key () {
12321279 LOG_INFO (" Regenerating private key..." );
1233- if (client_->create_private_key () == 0 ) {
1234- // NOLINTNEXTLINE(readability-math-missing-parentheses) - macro from external library
1235- uint8_t key_buf[MBEDTLS_ECP_MAX_PT_LEN];
1236- size_t key_len = 0 ;
1237- size_t buf_len = sizeof (key_buf);
1238- if (client_->get_private_key (key_buf, buf_len, &key_len) == 0 ) {
1239- std::vector<uint8_t > key_vec (key_buf, key_buf + key_len);
1240- if (storage_adapter_->save (" private_key" , key_vec)) {
1241- LOG_INFO (" New private key saved to storage" );
1242- } else {
1243- LOG_ERROR (" Failed to save new private key" );
1244- }
1245- } else {
1246- LOG_ERROR (" Failed to create private key" );
1247- }
1280+ if (client_->create_private_key () != 0 ) {
1281+ LOG_ERROR (" Failed to create private key" );
1282+ return ;
12481283 }
1249- } // namespace TeslaBLE
1284+
1285+ if (persist_private_key_ ()) {
1286+ LOG_INFO (" New private key saved to storage" );
1287+ } else {
1288+ LOG_ERROR (" Failed to save new private key" );
1289+ }
1290+ }
12501291
12511292void TeslaBLE::Vehicle::handle_signed_message_error_ (const UniversalMessage_RoutableMessage &msg,
12521293 bool &has_session_error) {
0 commit comments