1 /******************************************************************************
2  *
3  *  Copyright 2016 The Android Open Source Project
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <stdarg.h>
21 
22 #include <string>
23 
24 #include "crypto_toolbox/crypto_toolbox.h"
25 #include "hci/include/packet_fragmenter.h"
26 #include "internal_include/stack_config.h"
27 #include "stack/btm/btm_int_types.h"
28 #include "stack/include/acl_api.h"
29 #include "stack/include/bt_octets.h"
30 #include "stack/include/btm_ble_api.h"
31 #include "stack/include/smp_status.h"
32 #include "stack/smp/p_256_ecc_pp.h"
33 #include "stack/smp/smp_int.h"
34 #include "test/mock/mock_stack_acl.h"
35 #include "types/hci_role.h"
36 #include "types/raw_address.h"
37 
38 // TODO(b/369381361) Enfore -Wmissing-prototypes
39 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
40 
41 using testing::StrEq;
42 
43 tBTM_CB btm_cb;
44 
45 const std::string kSmpOptions("mock smp options");
46 const std::string kBroadcastAudioConfigOptions("mock broadcast audio config options");
get_pts_avrcp_test(void)47 bool get_pts_avrcp_test(void) { return false; }
get_pts_secure_only_mode(void)48 bool get_pts_secure_only_mode(void) { return false; }
get_pts_conn_updates_disabled(void)49 bool get_pts_conn_updates_disabled(void) { return false; }
get_pts_crosskey_sdp_disable(void)50 bool get_pts_crosskey_sdp_disable(void) { return false; }
get_pts_smp_options(void)51 const std::string* get_pts_smp_options(void) { return &kSmpOptions; }
get_pts_smp_failure_case(void)52 int get_pts_smp_failure_case(void) { return 123; }
get_pts_force_eatt_for_notifications(void)53 bool get_pts_force_eatt_for_notifications(void) { return false; }
get_pts_connect_eatt_unconditionally(void)54 bool get_pts_connect_eatt_unconditionally(void) { return false; }
get_pts_connect_eatt_before_encryption(void)55 bool get_pts_connect_eatt_before_encryption(void) { return false; }
get_pts_unencrypt_broadcast(void)56 bool get_pts_unencrypt_broadcast(void) { return false; }
get_pts_eatt_peripheral_collision_support(void)57 bool get_pts_eatt_peripheral_collision_support(void) { return false; }
get_pts_use_eatt_for_all_services(void)58 bool get_pts_use_eatt_for_all_services(void) { return false; }
get_pts_force_le_audio_multiple_contexts_metadata(void)59 bool get_pts_force_le_audio_multiple_contexts_metadata(void) { return false; }
get_pts_l2cap_ecoc_upper_tester(void)60 bool get_pts_l2cap_ecoc_upper_tester(void) { return false; }
get_pts_l2cap_ecoc_min_key_size(void)61 int get_pts_l2cap_ecoc_min_key_size(void) { return -1; }
get_pts_l2cap_ecoc_initial_chan_cnt(void)62 int get_pts_l2cap_ecoc_initial_chan_cnt(void) { return -1; }
get_pts_l2cap_ecoc_connect_remaining(void)63 bool get_pts_l2cap_ecoc_connect_remaining(void) { return false; }
get_pts_l2cap_ecoc_send_num_of_sdu(void)64 int get_pts_l2cap_ecoc_send_num_of_sdu(void) { return -1; }
get_pts_l2cap_ecoc_reconfigure(void)65 bool get_pts_l2cap_ecoc_reconfigure(void) { return false; }
get_pts_broadcast_audio_config_options(void)66 const std::string* get_pts_broadcast_audio_config_options(void) {
67   return &kBroadcastAudioConfigOptions;
68 }
get_pts_le_audio_disable_ases_before_stopping(void)69 bool get_pts_le_audio_disable_ases_before_stopping(void) { return false; }
get_all(void)70 config_t* get_all(void) { return nullptr; }
packet_fragmenter_get_interface()71 const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; }
72 
73 stack_config_t mock_stack_config{
74         .get_pts_avrcp_test = get_pts_avrcp_test,
75         .get_pts_secure_only_mode = get_pts_secure_only_mode,
76         .get_pts_conn_updates_disabled = get_pts_conn_updates_disabled,
77         .get_pts_crosskey_sdp_disable = get_pts_crosskey_sdp_disable,
78         .get_pts_smp_options = get_pts_smp_options,
79         .get_pts_smp_failure_case = get_pts_smp_failure_case,
80         .get_pts_force_eatt_for_notifications = get_pts_force_eatt_for_notifications,
81         .get_pts_connect_eatt_unconditionally = get_pts_connect_eatt_unconditionally,
82         .get_pts_connect_eatt_before_encryption = get_pts_connect_eatt_before_encryption,
83         .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast,
84         .get_pts_eatt_peripheral_collision_support = get_pts_eatt_peripheral_collision_support,
85         .get_pts_use_eatt_for_all_services = get_pts_use_eatt_for_all_services,
86         .get_pts_force_le_audio_multiple_contexts_metadata =
87                 get_pts_force_le_audio_multiple_contexts_metadata,
88         .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester,
89         .get_pts_l2cap_ecoc_min_key_size = get_pts_l2cap_ecoc_min_key_size,
90         .get_pts_l2cap_ecoc_initial_chan_cnt = get_pts_l2cap_ecoc_initial_chan_cnt,
91         .get_pts_l2cap_ecoc_connect_remaining = get_pts_l2cap_ecoc_connect_remaining,
92         .get_pts_l2cap_ecoc_send_num_of_sdu = get_pts_l2cap_ecoc_send_num_of_sdu,
93         .get_pts_l2cap_ecoc_reconfigure = get_pts_l2cap_ecoc_reconfigure,
94         .get_pts_broadcast_audio_config_options = get_pts_broadcast_audio_config_options,
95         .get_pts_le_audio_disable_ases_before_stopping =
96                 get_pts_le_audio_disable_ases_before_stopping,
97         .get_all = get_all,
98 };
stack_config_get_interface(void)99 const stack_config_t* stack_config_get_interface(void) { return &mock_stack_config; }
100 
101 /*
102  * This test verifies various key distribution methods in SMP works using the
103  * following parameter set:
104  *
105  * When testing target as Central (Initiator is local, Responder is remote)
106  *
107  * Initiator's Pairing Request: 0x070710000001(01)
108  * Responder's Pairing Response: 0x050008000003(02)
109  * Initiator's Bluetooth Address: 0xA1A2A3A4A5A6
110  * Initiator's Bluetooth Address Type: 0x01
111  * Responder's Bluetooth Address: 0xB1B2B3B4B5B6
112  * Responder's Bluetooth Address Type: 0x00
113  * Initiator's Random Number: 0x5783D52156AD6F0E6388274EC6702EE0
114  * TK Encryption Key: 0x0
115  *
116  * Correct values:
117  *
118  * p1: 0x05000800000302070710000001010001
119  * p1 XOR r: 0x5283dd2156ae6d096498274ec7712ee1
120  * p1 prime: 0x02c7aa2a9857ac866ff91232df0e3c95
121  * p2: 0x00000000a1a2a3a4a5a6b1b2b3b4b5b6
122  * MConfirm (c1): 0x1e1e3fef878988ead2a74dc5bef13b86
123  *
124  * NOTE: All these values are presented in mathematical reasonable canonical
125  * form that has MSB on the left and LSB on the right. In Bluetooth packets,
126  * they are mostly reversed to be Little Endian which have LSB on the left and
127  * MSB on the right.
128  */
129 
130 Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb, tBLE_ADDR_TYPE remote_bd_addr_type);
131 
132 Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda);
133 
134 tSMP_STATUS smp_calculate_confirm(tSMP_CB* p_cb, const Octet16& rand, Octet16* output);
135 
dump_uint128(const Octet16 & a,char * buffer)136 void dump_uint128(const Octet16& a, char* buffer) {
137   for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
138     snprintf(buffer, 3, "%02x", a[i]);
139     buffer += 2;
140   }
141   *buffer = '\0';
142 }
143 
dump_uint128_reverse(const Octet16 & a,char * buffer)144 void dump_uint128_reverse(const Octet16& a, char* buffer) {
145   for (int i = (int)(OCTET16_LEN - 1); i >= 0; --i) {
146     snprintf(buffer, 3, "%02x", a[i]);
147     buffer += 2;
148   }
149   *buffer = '\0';
150 }
151 
print_uint128(const Octet16 & a)152 void print_uint128(const Octet16& a) {
153   for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
154     printf("%02x", a[i]);
155   }
156   printf("\n");
157 }
158 
parse_uint128(const char * input)159 Octet16 parse_uint128(const char* input) {
160   Octet16 output{0};
161   for (unsigned int count = 0; count < OCTET16_LEN; count++) {
162     sscanf(input, "%2hhx", &output[count]);
163     input += 2;
164   }
165   return output;
166 }
167 
168 class SmpCalculateConfirmTest : public testing::Test {
169 protected:
170   tSMP_CB p_cb_;
171   // Set random to 0x5783D52156AD6F0E6388274EC6702EE0
172   Octet16 rand_{0x57, 0x83, 0xD5, 0x21, 0x56, 0xAD, 0x6F, 0x0E,
173                 0x63, 0x88, 0x27, 0x4E, 0xC6, 0x70, 0x2E, 0xE0};
174 
SetUp()175   void SetUp() override {
176     p_cb_.tk = {0};
177     // Set pairing request packet to 0x070710000001(01)
178     p_cb_.local_io_capability = 0x01;
179     p_cb_.loc_oob_flag = 0x00;
180     p_cb_.loc_auth_req = 0x00;
181     p_cb_.loc_enc_size = 0x10;
182     p_cb_.local_i_key = 0x07;
183     p_cb_.local_r_key = 0x07;
184     // Set pairing response packet to 0x050008000003(02)
185     p_cb_.peer_io_caps = 0x03;
186     p_cb_.peer_oob_flag = 0x00;
187     p_cb_.peer_auth_req = 0x00;
188     p_cb_.peer_enc_size = 0x08;
189     p_cb_.peer_i_key = 0x00;
190     p_cb_.peer_r_key = 0x05;
191     // Set role to central
192     p_cb_.role = HCI_ROLE_CENTRAL;
193     std::reverse(rand_.begin(), rand_.end());
194   }
TearDown()195   void TearDown() override {}
196 
197 public:
198 };
199 
200 // Test smp_gen_p2_4_confirm function implementation
TEST_F(SmpCalculateConfirmTest,test_smp_gen_p2_4_confirm_as_central)201 TEST_F(SmpCalculateConfirmTest, test_smp_gen_p2_4_confirm_as_central) {
202   // Set local_bda to 0xA1A2A3A4A5A6
203   test::mock::stack_acl::BTM_ReadConnectionAddr.body =
204           [](const RawAddress& /*remote_bda*/, RawAddress& local_conn_addr,
205              tBLE_ADDR_TYPE* p_addr_type, bool /*ota_address*/) {
206             local_conn_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6});
207             *p_addr_type = BLE_ADDR_RANDOM;
208           };
209 
210   // Set remote bda to 0xB1B2B3B4B5B6
211   test::mock::stack_acl::BTM_ReadRemoteConnectionAddr.body =
212           [](const RawAddress& /*pseudo_addr*/, RawAddress& conn_addr, tBLE_ADDR_TYPE* p_addr_type,
213              bool /*ota_address*/) {
214             conn_addr = RawAddress({0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6});
215             *p_addr_type = BLE_ADDR_PUBLIC;
216             return true;
217           };
218 
219   RawAddress remote_bda;
220   tBLE_ADDR_TYPE remote_bd_addr_type = BLE_ADDR_PUBLIC;
221   BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda, &remote_bd_addr_type, true);
222   BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type, true);
223   Octet16 p2 = smp_gen_p2_4_confirm(&p_cb_, remote_bda);
224   // Correct p2 is 0x00000000a1a2a3a4a5a6b1b2b3b4b5b6
225   const char expected_p2_str[] = "00000000a1a2a3a4a5a6b1b2b3b4b5b6";
226   char p2_str[2 * OCTET16_LEN + 1];
227   dump_uint128_reverse(p2, p2_str);
228   ASSERT_THAT(p2_str, StrEq(expected_p2_str));
229 
230   test::mock::stack_acl::BTM_ReadConnectionAddr = {};
231   test::mock::stack_acl::BTM_ReadRemoteConnectionAddr = {};
232 }
233 
234 // Test smp_gen_p1_4_confirm and aes_128 function implementation
TEST_F(SmpCalculateConfirmTest,test_aes_128_as_central)235 TEST_F(SmpCalculateConfirmTest, test_aes_128_as_central) {
236   // Set local_bda to 0xA1A2A3A4A5A6
237   test::mock::stack_acl::BTM_ReadConnectionAddr.body =
238           [](const RawAddress& /*remote_bda*/, RawAddress& local_conn_addr,
239              tBLE_ADDR_TYPE* p_addr_type, bool /*ota_address*/) {
240             local_conn_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6});
241             *p_addr_type = BLE_ADDR_RANDOM;
242           };
243 
244   // Set remote bda to 0xB1B2B3B4B5B6
245   test::mock::stack_acl::BTM_ReadRemoteConnectionAddr.body =
246           [](const RawAddress& /*pseudo_addr*/, RawAddress& conn_addr, tBLE_ADDR_TYPE* p_addr_type,
247              bool /*ota_address*/) {
248             conn_addr = RawAddress({0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6});
249             *p_addr_type = BLE_ADDR_PUBLIC;
250             return true;
251           };
252 
253   RawAddress remote_bda;
254   tBLE_ADDR_TYPE remote_bd_addr_type = BLE_ADDR_PUBLIC;
255   BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda, &remote_bd_addr_type, true);
256   BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type, true);
257   Octet16 p1 = smp_gen_p1_4_confirm(&p_cb_, remote_bd_addr_type);
258   // Correct p1 is 0x05000800000302070710000001010001
259   const char expected_p1_str[] = "05000800000302070710000001010001";
260   char p1_str[2 * OCTET16_LEN + 1];
261   dump_uint128_reverse(p1, p1_str);
262   ASSERT_THAT(p1_str, StrEq(expected_p1_str));
263   smp_xor_128(&p1, rand_);
264   // Correct p1 xor r is 0x5283dd2156ae6d096498274ec7712ee1
265   const char expected_p1_xor_r_str[] = "5283dd2156ae6d096498274ec7712ee1";
266   char p1_xor_r_str[2 * OCTET16_LEN + 1];
267   dump_uint128_reverse(p1, p1_xor_r_str);
268   ASSERT_THAT(p1_xor_r_str, StrEq(expected_p1_xor_r_str));
269   Octet16 output = crypto_toolbox::aes_128(p_cb_.tk, p1);
270   const char expected_p1_prime_str[] = "02c7aa2a9857ac866ff91232df0e3c95";
271   char p1_prime_str[2 * OCTET16_LEN + 1];
272   dump_uint128_reverse(output, p1_prime_str);
273   ASSERT_THAT(p1_prime_str, StrEq(expected_p1_prime_str));
274 
275   test::mock::stack_acl::BTM_ReadConnectionAddr = {};
276   test::mock::stack_acl::BTM_ReadRemoteConnectionAddr = {};
277 }
278 
279 // Test smp_calculate_confirm function implementation
TEST_F(SmpCalculateConfirmTest,test_smp_calculate_confirm_as_central)280 TEST_F(SmpCalculateConfirmTest, test_smp_calculate_confirm_as_central) {
281   // Set local_bda to 0xA1A2A3A4A5A6
282   test::mock::stack_acl::BTM_ReadConnectionAddr.body =
283           [](const RawAddress& /*remote_bda*/, RawAddress& local_conn_addr,
284              tBLE_ADDR_TYPE* p_addr_type, bool /*ota_address*/) {
285             local_conn_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6});
286             *p_addr_type = BLE_ADDR_RANDOM;
287           };
288 
289   // Set remote bda to 0xB1B2B3B4B5B6
290   test::mock::stack_acl::BTM_ReadRemoteConnectionAddr.body =
291           [](const RawAddress& /*pseudo_addr*/, RawAddress& conn_addr, tBLE_ADDR_TYPE* p_addr_type,
292              bool /*ota_address*/) {
293             conn_addr = RawAddress({0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6});
294             *p_addr_type = BLE_ADDR_PUBLIC;
295             return true;
296           };
297 
298   Octet16 output;
299   tSMP_STATUS status = smp_calculate_confirm(&p_cb_, rand_, &output);
300   EXPECT_EQ(status, SMP_SUCCESS);
301   // Correct MConfirm is 0x1e1e3fef878988ead2a74dc5bef13b86
302   const char expected_confirm_str[] = "1e1e3fef878988ead2a74dc5bef13b86";
303   char confirm_str[2 * OCTET16_LEN + 1];
304   dump_uint128_reverse(output, confirm_str);
305   ASSERT_THAT(confirm_str, StrEq(expected_confirm_str));
306 
307   test::mock::stack_acl::BTM_ReadConnectionAddr = {};
308   test::mock::stack_acl::BTM_ReadRemoteConnectionAddr = {};
309 }
310 
311 // Test ECC point validation
TEST(SmpEccValidationTest,test_valid_points)312 TEST(SmpEccValidationTest, test_valid_points) {
313   Point p;
314 
315   // Test data from Bluetooth Core Specification
316   // Version 5.0 | Vol 2, Part G | 7.1.2
317 
318   // Sample 1
319   p.x[7] = 0x20b003d2;
320   p.x[6] = 0xf297be2c;
321   p.x[5] = 0x5e2c83a7;
322   p.x[4] = 0xe9f9a5b9;
323   p.x[3] = 0xeff49111;
324   p.x[2] = 0xacf4fddb;
325   p.x[1] = 0xcc030148;
326   p.x[0] = 0x0e359de6;
327 
328   p.y[7] = 0xdc809c49;
329   p.y[6] = 0x652aeb6d;
330   p.y[5] = 0x63329abf;
331   p.y[4] = 0x5a52155c;
332   p.y[3] = 0x766345c2;
333   p.y[2] = 0x8fed3024;
334   p.y[1] = 0x741c8ed0;
335   p.y[0] = 0x1589d28b;
336 
337   EXPECT_TRUE(ECC_ValidatePoint(p));
338 
339   // Sample 2
340   p.x[7] = 0x2c31a47b;
341   p.x[6] = 0x5779809e;
342   p.x[5] = 0xf44cb5ea;
343   p.x[4] = 0xaf5c3e43;
344   p.x[3] = 0xd5f8faad;
345   p.x[2] = 0x4a8794cb;
346   p.x[1] = 0x987e9b03;
347   p.x[0] = 0x745c78dd;
348 
349   p.y[7] = 0x91951218;
350   p.y[6] = 0x3898dfbe;
351   p.y[5] = 0xcd52e240;
352   p.y[4] = 0x8e43871f;
353   p.y[3] = 0xd0211091;
354   p.y[2] = 0x17bd3ed4;
355   p.y[1] = 0xeaf84377;
356   p.y[0] = 0x43715d4f;
357 
358   EXPECT_TRUE(ECC_ValidatePoint(p));
359 }
360 
TEST(SmpEccValidationTest,test_invalid_points)361 TEST(SmpEccValidationTest, test_invalid_points) {
362   Point p;
363   multiprecision_init(p.x);
364   multiprecision_init(p.y);
365 
366   EXPECT_FALSE(ECC_ValidatePoint(p));
367 
368   // Sample 1
369   p.x[7] = 0x20b003d2;
370   p.x[6] = 0xf297be2c;
371   p.x[5] = 0x5e2c83a7;
372   p.x[4] = 0xe9f9a5b9;
373   p.x[3] = 0xeff49111;
374   p.x[2] = 0xacf4fddb;
375   p.x[1] = 0xcc030148;
376   p.x[0] = 0x0e359de6;
377 
378   EXPECT_FALSE(ECC_ValidatePoint(p));
379 
380   p.y[7] = 0xdc809c49;
381   p.y[6] = 0x652aeb6d;
382   p.y[5] = 0x63329abf;
383   p.y[4] = 0x5a52155c;
384   p.y[3] = 0x766345c2;
385   p.y[2] = 0x8fed3024;
386   p.y[1] = 0x741c8ed0;
387   p.y[0] = 0x1589d28b;
388 
389   p.y[0]--;
390 
391   EXPECT_FALSE(ECC_ValidatePoint(p));
392 }
393 
TEST(SmpStatusText,smp_status_text)394 TEST(SmpStatusText, smp_status_text) {
395   std::vector<std::pair<tSMP_STATUS, std::string>> status = {
396           std::make_pair(SMP_SUCCESS, "SMP_SUCCESS"),
397           std::make_pair(SMP_PASSKEY_ENTRY_FAIL, "SMP_PASSKEY_ENTRY_FAIL"),
398           std::make_pair(SMP_OOB_FAIL, "SMP_OOB_FAIL"),
399           std::make_pair(SMP_PAIR_AUTH_FAIL, "SMP_PAIR_AUTH_FAIL"),
400           std::make_pair(SMP_CONFIRM_VALUE_ERR, "SMP_CONFIRM_VALUE_ERR"),
401           std::make_pair(SMP_PAIR_NOT_SUPPORT, "SMP_PAIR_NOT_SUPPORT"),
402           std::make_pair(SMP_ENC_KEY_SIZE, "SMP_ENC_KEY_SIZE"),
403           std::make_pair(SMP_INVALID_CMD, "SMP_INVALID_CMD"),
404           std::make_pair(SMP_PAIR_FAIL_UNKNOWN, "SMP_PAIR_FAIL_UNKNOWN"),
405           std::make_pair(SMP_REPEATED_ATTEMPTS, "SMP_REPEATED_ATTEMPTS"),
406           std::make_pair(SMP_INVALID_PARAMETERS, "SMP_INVALID_PARAMETERS"),
407           std::make_pair(SMP_DHKEY_CHK_FAIL, "SMP_DHKEY_CHK_FAIL"),
408           std::make_pair(SMP_NUMERIC_COMPAR_FAIL, "SMP_NUMERIC_COMPAR_FAIL"),
409           std::make_pair(SMP_BR_PARING_IN_PROGR, "SMP_BR_PARING_IN_PROGR"),
410           std::make_pair(SMP_XTRANS_DERIVE_NOT_ALLOW, "SMP_XTRANS_DERIVE_NOT_ALLOW"),
411           std::make_pair(SMP_MAX_FAIL_RSN_PER_SPEC,
412                          "SMP_XTRANS_DERIVE_NOT_ALLOW"),  // NOTE: Dup
413           std::make_pair(SMP_PAIR_INTERNAL_ERR, "SMP_PAIR_INTERNAL_ERR"),
414           std::make_pair(SMP_UNKNOWN_IO_CAP, "SMP_UNKNOWN_IO_CAP"),
415           std::make_pair(SMP_BUSY, "SMP_BUSY"),
416           std::make_pair(SMP_ENC_FAIL, "SMP_ENC_FAIL"),
417           std::make_pair(SMP_STARTED, "SMP_STARTED"),
418           std::make_pair(SMP_RSP_TIMEOUT, "SMP_RSP_TIMEOUT"),
419           std::make_pair(SMP_FAIL, "SMP_FAIL"),
420           std::make_pair(SMP_CONN_TOUT, "SMP_CONN_TOUT"),
421   };
422   for (const auto& stat : status) {
423     ASSERT_STREQ(stat.second.c_str(), smp_status_text(stat.first).c_str());
424   }
425   auto unknown = base::StringPrintf("UNKNOWN[%hhu]", std::numeric_limits<uint8_t>::max());
426   ASSERT_STREQ(
427           unknown.c_str(),
428           smp_status_text(static_cast<tSMP_STATUS>(std::numeric_limits<uint8_t>::max())).c_str());
429 }
430