diff options
| author | 2024-10-14 10:45:11 -0700 | |
|---|---|---|
| committer | 2024-10-14 23:54:16 +0000 | |
| commit | b10bac90572f5d7996728fd78c33857db065f56f (patch) | |
| tree | 1157d52741cf60ec90235c63453a490c8ea277a3 | |
| parent | bb69ca6c84044f5b94f8dc736cfb16f51d352d64 (diff) | |
RootCanal: Implement the command LE Read Local P-256 Public Key
Bug: 354107188
Test: atest --host rootcanal_ll_test
Flag: EXEMPT, tool change
Change-Id: Ic7342ecd7d1de46dadf88c7d2d71c925f97f3904
| -rw-r--r-- | tools/rootcanal/Android.bp | 1 | ||||
| -rw-r--r-- | tools/rootcanal/model/controller/controller_properties.cc | 2 | ||||
| -rw-r--r-- | tools/rootcanal/model/controller/dual_mode_controller.cc | 63 | ||||
| -rw-r--r-- | tools/rootcanal/model/controller/dual_mode_controller.h | 3 | ||||
| -rw-r--r-- | tools/rootcanal/packets/hci_packets.pdl | 15 | ||||
| -rw-r--r-- | tools/rootcanal/py/controller.py | 2 | ||||
| -rw-r--r-- | tools/rootcanal/test/HCI/AEN/BV_06_C.py | 51 | ||||
| -rw-r--r-- | tools/rootcanal/test/main.py | 1 |
8 files changed, 127 insertions, 11 deletions
diff --git a/tools/rootcanal/Android.bp b/tools/rootcanal/Android.bp index c28ad576fc..69fc4bc456 100644 --- a/tools/rootcanal/Android.bp +++ b/tools/rootcanal/Android.bp @@ -305,6 +305,7 @@ python_test_host { ":llcp_packets_python3_gen", "py/bluetooth.py", "py/controller.py", + "test/HCI/AEN/*.py", "test/LL/*.py", "test/LL/CIS/CEN/*.py", "test/LL/CIS/PER/*.py", diff --git a/tools/rootcanal/model/controller/controller_properties.cc b/tools/rootcanal/model/controller/controller_properties.cc index b1ad2e8082..4ee868b159 100644 --- a/tools/rootcanal/model/controller/controller_properties.cc +++ b/tools/rootcanal/model/controller/controller_properties.cc @@ -285,7 +285,7 @@ static std::array<uint8_t, 64> SupportedCommands() { // OpCodeIndex::LE_SET_DATA_LENGTH, OpCodeIndex::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH, OpCodeIndex::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH, - // OpCodeIndex::LE_READ_LOCAL_P_256_PUBLIC_KEY, + OpCodeIndex::LE_READ_LOCAL_P_256_PUBLIC_KEY, // OpCodeIndex::LE_GENERATE_DHKEY_V1, OpCodeIndex::LE_ADD_DEVICE_TO_RESOLVING_LIST, OpCodeIndex::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST, OpCodeIndex::LE_CLEAR_RESOLVING_LIST, diff --git a/tools/rootcanal/model/controller/dual_mode_controller.cc b/tools/rootcanal/model/controller/dual_mode_controller.cc index 7480496a6e..5563d8319d 100644 --- a/tools/rootcanal/model/controller/dual_mode_controller.cc +++ b/tools/rootcanal/model/controller/dual_mode_controller.cc @@ -16,6 +16,10 @@ #include "model/controller/dual_mode_controller.h" +#include <openssl/ec.h> +#include <openssl/ec_key.h> +#include <openssl/mem.h> +#include <openssl/nid.h> #include <packet_runtime.h> #include <algorithm> @@ -2210,6 +2214,61 @@ void DualModeController::LeWriteSuggestedDefaultDataLength(CommandView command) kNumCommandPackets, status)); } +static ErrorCode generateP256Key(std::array<uint8_t, 32>& key_x_coordinate, + std::array<uint8_t, 32>& key_y_coordinate) { + auto ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!ec_key) { + WARNING("EC_KEY_new_by_curve_name(NID_X9_62_prime256v1) failed"); + return ErrorCode::UNSPECIFIED_ERROR; + } + + if (!EC_KEY_generate_key(ec_key)) { + WARNING("EC_KEY_generate_key failed"); + EC_KEY_free(ec_key); + return ErrorCode::UNSPECIFIED_ERROR; + } + + uint8_t* out_buf = nullptr; + auto size = EC_KEY_key2buf(ec_key, POINT_CONVERSION_UNCOMPRESSED, &out_buf, nullptr); + if (!out_buf) { + WARNING("EC_KEY_key2buf failed"); + EC_KEY_free(ec_key); + return ErrorCode::UNSPECIFIED_ERROR; + } + + const size_t expected_size = key_x_coordinate.size() + key_y_coordinate.size() + 1; + if (size != expected_size) { + WARNING("unexpected size {}", size); + OPENSSL_free(out_buf); + EC_KEY_free(ec_key); + return ErrorCode::UNSPECIFIED_ERROR; + } + + memcpy(key_x_coordinate.data(), out_buf + 1, key_x_coordinate.size()); + memcpy(key_y_coordinate.data(), out_buf + 1 + key_x_coordinate.size(), key_y_coordinate.size()); + + // OPENSSL_free(out_buf); // <-- this call fails with error invalid pointer + EC_KEY_free(ec_key); + return ErrorCode::SUCCESS; +} + +void DualModeController::LeReadLocalP256PublicKey(CommandView command) { + auto command_view = bluetooth::hci::LeReadLocalP256PublicKeyView::Create(command); + CHECK_PACKET_VIEW(command_view); + + DEBUG(id_, "<< LE Read Local P-256 Public Key"); + + send_event_(bluetooth::hci::LeReadLocalP256PublicKeyStatusBuilder::Create(ErrorCode::SUCCESS, + kNumCommandPackets)); + + std::array<uint8_t, 32> key_x_coordinate = {}; + std::array<uint8_t, 32> key_y_coordinate = {}; + ErrorCode status = generateP256Key(key_x_coordinate, key_y_coordinate); + + send_event_(bluetooth::hci::LeReadLocalP256PublicKeyCompleteBuilder::Create( + status, key_x_coordinate, key_y_coordinate)); +} + void DualModeController::LeAddDeviceToResolvingList(CommandView command) { auto command_view = bluetooth::hci::LeAddDeviceToResolvingListView::Create(command); CHECK_PACKET_VIEW(command_view); @@ -3959,8 +4018,8 @@ const std::unordered_map<OpCode, DualModeController::CommandHandler> &DualModeController::LeReadSuggestedDefaultDataLength}, {OpCode::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH, &DualModeController::LeWriteSuggestedDefaultDataLength}, - //{OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY, - //&DualModeController::LeReadLocalP256PublicKey}, + {OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY, + &DualModeController::LeReadLocalP256PublicKey}, //{OpCode::LE_GENERATE_DHKEY_V1, //&DualModeController::LeGenerateDhkeyV1}, {OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST, diff --git a/tools/rootcanal/model/controller/dual_mode_controller.h b/tools/rootcanal/model/controller/dual_mode_controller.h index bf95c8a95f..901d13d802 100644 --- a/tools/rootcanal/model/controller/dual_mode_controller.h +++ b/tools/rootcanal/model/controller/dual_mode_controller.h @@ -450,6 +450,9 @@ public: void LeReadSuggestedDefaultDataLength(CommandView command); void LeWriteSuggestedDefaultDataLength(CommandView command); + // 7.8.36 + void LeReadLocalP256PublicKey(CommandView command); + // 7.8.38 - 7.8.41 void LeAddDeviceToResolvingList(CommandView command); void LeRemoveDeviceFromResolvingList(CommandView command); diff --git a/tools/rootcanal/packets/hci_packets.pdl b/tools/rootcanal/packets/hci_packets.pdl index 6cb90fea7f..ec34b4da0f 100644 --- a/tools/rootcanal/packets/hci_packets.pdl +++ b/tools/rootcanal/packets/hci_packets.pdl @@ -3536,17 +3536,17 @@ packet LeWriteSuggestedDefaultDataLengthComplete : CommandComplete (command_op_c status : ErrorCode, } -packet LeReadLocalP256PublicKeyCommand : Command (op_code = LE_READ_LOCAL_P_256_PUBLIC_KEY) { +packet LeReadLocalP256PublicKey : Command (op_code = LE_READ_LOCAL_P_256_PUBLIC_KEY) { } -packet LeReadLocalP256PublicKeyCommandStatus : CommandStatus (command_op_code = LE_READ_LOCAL_P_256_PUBLIC_KEY) { +packet LeReadLocalP256PublicKeyStatus : CommandStatus (command_op_code = LE_READ_LOCAL_P_256_PUBLIC_KEY) { } -packet LeGenerateDhkeyV1Command : Command (op_code = LE_GENERATE_DHKEY_V1) { +packet LeGenerateDhkeyV1 : Command (op_code = LE_GENERATE_DHKEY_V1) { remote_p_256_public_key : 8[64], } -packet LeGenerateDhkeyV1CommandStatus : CommandStatus (command_op_code = LE_GENERATE_DHKEY_V1) { +packet LeGenerateDhkeyV1Status : CommandStatus (command_op_code = LE_GENERATE_DHKEY_V1) { } packet LeAddDeviceToResolvingList : Command (op_code = LE_ADD_DEVICE_TO_RESOLVING_LIST) { @@ -5211,12 +5211,13 @@ packet LeDataLengthChange : LeMetaEvent (subevent_code = DATA_LENGTH_CHANGE) { max_rx_time : 16, // 0x0148 - 0x4290 } -packet ReadLocalP256PublicKeyComplete : LeMetaEvent (subevent_code = READ_LOCAL_P256_PUBLIC_KEY_COMPLETE) { +packet LeReadLocalP256PublicKeyComplete : LeMetaEvent (subevent_code = READ_LOCAL_P256_PUBLIC_KEY_COMPLETE) { status : ErrorCode, - local_p_256_public_key : 8[64], + key_x_coordinate : 8[32], + key_y_coordinate : 8[32], } -packet GenerateDhKeyComplete : LeMetaEvent (subevent_code = GENERATE_DHKEY_COMPLETE) { +packet LeGenerateDhKeyComplete : LeMetaEvent (subevent_code = GENERATE_DHKEY_COMPLETE) { status : ErrorCode, dh_key : 8[32], } diff --git a/tools/rootcanal/py/controller.py b/tools/rootcanal/py/controller.py index be3488cbcb..80e83072b4 100644 --- a/tools/rootcanal/py/controller.py +++ b/tools/rootcanal/py/controller.py @@ -315,7 +315,7 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): async with asyncio.timeout(timeout): while True: - packet = await asyncio.wait_for(self.controller.receive_ll()) + packet = await self.controller.receive_ll() pdu = ll.LinkLayerPacket.parse_all(packet) for ignored_pdu in ignored_pdus: diff --git a/tools/rootcanal/test/HCI/AEN/BV_06_C.py b/tools/rootcanal/test/HCI/AEN/BV_06_C.py new file mode 100644 index 0000000000..7a04979bcd --- /dev/null +++ b/tools/rootcanal/test/HCI/AEN/BV_06_C.py @@ -0,0 +1,51 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # HCI/AEN/BV-06-C [Public Keys] + # + # Verify that the IUT can generate a P-256 Public-Private key pair and + # return the P-256 Public Key + async def test(self): + controller = self.controller + + controller.send_cmd(hci.LeReadLocalP256PublicKey()) + + await self.expect_evt(hci.LeReadLocalP256PublicKeyStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + first = await self.expect_evt( + hci.LeReadLocalP256PublicKeyComplete(status=ErrorCode.SUCCESS, + key_x_coordinate=self.Any, + key_y_coordinate=self.Any)) + + controller.send_cmd(hci.LeReadLocalP256PublicKey()) + + await self.expect_evt(hci.LeReadLocalP256PublicKeyStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + second = await self.expect_evt( + hci.LeReadLocalP256PublicKeyComplete(status=ErrorCode.SUCCESS, + key_x_coordinate=self.Any, + key_y_coordinate=self.Any)) + + self.assertTrue( + (first.key_x_coordinate, first.key_y_coordinate) != (second.key_x_coordinate, second.key_y_coordinate)) diff --git a/tools/rootcanal/test/main.py b/tools/rootcanal/test/main.py index b61a5b87a7..fba8d2aba3 100644 --- a/tools/rootcanal/test/main.py +++ b/tools/rootcanal/test/main.py @@ -20,6 +20,7 @@ import tempfile import unittest tests = [ + 'HCI.AEN.BV_06_C', 'LL.CIS.CEN.BV_01_C', 'LL.CIS.CEN.BV_03_C', 'LL.CIS.CEN.BV_10_C', |