summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Henri Chataing <henrichataing@google.com> 2024-10-14 10:45:11 -0700
committer Henri Chataing <henrichataing@google.com> 2024-10-14 23:54:16 +0000
commitb10bac90572f5d7996728fd78c33857db065f56f (patch)
tree1157d52741cf60ec90235c63453a490c8ea277a3
parentbb69ca6c84044f5b94f8dc736cfb16f51d352d64 (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.bp1
-rw-r--r--tools/rootcanal/model/controller/controller_properties.cc2
-rw-r--r--tools/rootcanal/model/controller/dual_mode_controller.cc63
-rw-r--r--tools/rootcanal/model/controller/dual_mode_controller.h3
-rw-r--r--tools/rootcanal/packets/hci_packets.pdl15
-rw-r--r--tools/rootcanal/py/controller.py2
-rw-r--r--tools/rootcanal/test/HCI/AEN/BV_06_C.py51
-rw-r--r--tools/rootcanal/test/main.py1
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',