1 /* packet-btsm.c 2 * Routines for Bluetooth Low Energy Security Manager dissection 3 * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartners /dot/ com 4 * 5 * Wireshark - Network traffic analyzer 6 * By Gerald Combs <[email protected]> 7 * Copyright 1998 Gerald Combs 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2 12 * of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 # include "config.h" 26 #endif 27 28 #include <wireshark/config.h> /* needed for epan/gcc-4.x */ 29 #include <epan/packet.h> 30 #include <epan/prefs.h> 31 32 #define BTL2CAP_FIXED_CID_BTSM 0x0006 33 34 /* initialize the protocol and registered fields */ 35 static int proto_btsm = -1; 36 static int hf_btsm_command = -1; 37 static int hf_btsm_pairing_request_io_capability = -1; 38 static int hf_btsm_pairing_request_oob_data = -1; 39 static int hf_btsm_pairing_request_auth_req = -1; 40 static int hf_btsm_pairing_request_reserved = -1; 41 static int hf_btsm_pairing_request_mitm = -1; 42 static int hf_btsm_pairing_request_bonding_flags = -1; 43 static int hf_btsm_pairing_request_max_key_size = -1; 44 static int hf_btsm_pairing_request_initiator_key_distribution = -1; 45 static int hf_btsm_pairing_request_responder_key_distribution = -1; 46 static int hf_btsm_pairing_response_io_capability = -1; 47 static int hf_btsm_pairing_response_oob_data = -1; 48 static int hf_btsm_pairing_response_auth_req = -1; 49 static int hf_btsm_pairing_response_reserved = -1; 50 static int hf_btsm_pairing_response_mitm = -1; 51 static int hf_btsm_pairing_response_bonding_flags = -1; 52 static int hf_btsm_pairing_response_max_key_size = -1; 53 static int hf_btsm_pairing_response_initiator_key_distribution = -1; 54 static int hf_btsm_pairing_response_responder_key_distribution = -1; 55 static int hf_btsm_pairing_confirm_confirm = -1; 56 static int hf_btsm_pairing_random_random = -1; 57 static int hf_btsm_encryption_info_ltk = -1; 58 59 static const value_string commands[] = { 60 { 0x00, "Reserved" }, 61 { 0x01, "Pairing Request" }, 62 { 0x02, "Pairing Response" }, 63 { 0x03, "Pairing Confirm" }, 64 { 0x04, "Pairing Random" }, 65 { 0x05, "Pairing Failed" }, 66 { 0x06, "Encryption Information" }, 67 { 0x07, "Master Identification" }, 68 { 0x08, "Identity Information" }, 69 { 0x09, "Identity Address Information" }, 70 { 0x0A, "Signing Information" }, 71 { 0x0B, "Security Request" }, 72 { 0, NULL } 73 }; 74 75 static const value_string io_capability[] = { 76 { 0x00, "DisplayOnly" }, 77 { 0x01, "DisplayYesNo" }, 78 { 0x02, "KeyboardOnly" }, 79 { 0x03, "NoInputOutput" }, 80 { 0x04, "KeyboardDisplay" }, 81 { 0, NULL } 82 }; 83 84 static const value_string oob_data[] = { 85 { 0x00, "OOB Authentication data not present" }, 86 { 0x01, "OOB Authentication data from remote device present" }, 87 { 0, NULL } 88 }; 89 90 static const value_string bonding_flags[] = { 91 { 0x0, "No Bonding" }, 92 { 0x1, "Bonding" }, 93 { 0, NULL }, 94 }; 95 96 /* initialize the subtree pointers */ 97 static gint ett_btsm = -1; 98 static gint ett_auth_req = -1; 99 100 static void 101 dissect_pairing_request(tvbuff_t *tvb, proto_tree *tree) 102 { 103 proto_item *auth_req_item; 104 proto_tree *auth_req_tree; 105 106 proto_tree_add_item(tree, hf_btsm_pairing_request_io_capability, tvb, 1, 1, TRUE); 107 proto_tree_add_item(tree, hf_btsm_pairing_request_oob_data, tvb, 2, 1, TRUE); 108 109 auth_req_item = proto_tree_add_item(tree, hf_btsm_pairing_request_auth_req, tvb, 3, 1, TRUE); 110 auth_req_tree = proto_item_add_subtree(auth_req_item, ett_auth_req); 111 proto_tree_add_item(auth_req_tree, hf_btsm_pairing_request_reserved, tvb, 3, 1, TRUE); 112 proto_tree_add_bits_item(auth_req_tree, hf_btsm_pairing_request_mitm, tvb, 3 * 8 + 5, 1, TRUE); 113 proto_tree_add_item(auth_req_tree, hf_btsm_pairing_request_bonding_flags, tvb, 3, 1, TRUE); 114 115 // TODO: check that max key size iswithin [7,16] 116 proto_tree_add_item(tree, hf_btsm_pairing_request_max_key_size, tvb, 4, 1, TRUE); 117 proto_tree_add_item(tree, hf_btsm_pairing_request_initiator_key_distribution, tvb, 5, 1, TRUE); 118 proto_tree_add_item(tree, hf_btsm_pairing_request_responder_key_distribution, tvb, 6, 1, TRUE); 119 } 120 121 static void 122 dissect_pairing_response(tvbuff_t *tvb, proto_tree *tree) 123 { 124 proto_item *auth_req_item; 125 proto_tree *auth_req_tree; 126 127 proto_tree_add_item(tree, hf_btsm_pairing_response_io_capability, tvb, 1, 1, TRUE); 128 proto_tree_add_item(tree, hf_btsm_pairing_response_oob_data, tvb, 2, 1, TRUE); 129 130 auth_req_item = proto_tree_add_item(tree, hf_btsm_pairing_response_auth_req, tvb, 3, 1, TRUE); 131 auth_req_tree = proto_item_add_subtree(auth_req_item, ett_auth_req); 132 proto_tree_add_item(auth_req_tree, hf_btsm_pairing_response_reserved, tvb, 3, 1, TRUE); 133 proto_tree_add_bits_item(auth_req_tree, hf_btsm_pairing_response_mitm, tvb, 3 * 8 + 5, 1, TRUE); 134 proto_tree_add_item(auth_req_tree, hf_btsm_pairing_response_bonding_flags, tvb, 3, 1, TRUE); 135 136 // TODO: check that max key size iswithin [7,16] 137 proto_tree_add_item(tree, hf_btsm_pairing_response_max_key_size, tvb, 4, 1, TRUE); 138 proto_tree_add_item(tree, hf_btsm_pairing_response_initiator_key_distribution, tvb, 5, 1, TRUE); 139 proto_tree_add_item(tree, hf_btsm_pairing_response_responder_key_distribution, tvb, 6, 1, TRUE); 140 } 141 142 static void 143 dissect_pairing_confirm(tvbuff_t *tvb, proto_tree *tree) 144 { 145 proto_tree_add_item(tree, hf_btsm_pairing_confirm_confirm, tvb, 1, 16, TRUE); 146 } 147 148 static void 149 dissect_pairing_random(tvbuff_t *tvb, proto_tree *tree) 150 { 151 proto_tree_add_item(tree, hf_btsm_pairing_random_random, tvb, 1, 16, TRUE); 152 } 153 154 static void 155 dissect_encryption_info(tvbuff_t *tvb, proto_tree *tree) 156 { 157 proto_tree_add_item(tree, hf_btsm_encryption_info_ltk, tvb, 1, 16, TRUE); 158 } 159 160 /* dissect a packet */ 161 static void 162 dissect_btsm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 163 { 164 proto_item *btsm_item; 165 proto_tree *btsm_tree; 166 guint8 command; 167 168 #if 0 169 /* sanity check: length */ 170 if (tvb_length(tvb) > 0 && tvb_length(tvb) < 9) 171 /* bad length: look for a different dissector */ 172 return 0; 173 #endif 174 175 /* make entries in protocol column and info column on summary display */ 176 if (check_col(pinfo->cinfo, COL_PROTOCOL)) 177 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BTLE Security Manager"); 178 179 command = tvb_get_guint8(tvb, 0); 180 181 /* see if we are being asked for details */ 182 if (tree) { 183 184 /* create display subtree for the protocol */ 185 btsm_item = proto_tree_add_item(tree, proto_btsm, tvb, 0, tvb_length(tvb), TRUE); 186 btsm_tree = proto_item_add_subtree(btsm_item, ett_btsm); 187 188 proto_tree_add_item(btsm_tree, hf_btsm_command, tvb, 0, 1, TRUE); 189 190 if (check_col(pinfo->cinfo, COL_INFO)) { 191 if (command <= 0xb) { 192 col_set_str(pinfo->cinfo, COL_INFO, commands[command].strptr); 193 } else { 194 col_set_str(pinfo->cinfo, COL_INFO, "Unknown"); 195 } 196 } 197 198 switch (command) { 199 // pairing request 200 case (0x1): 201 dissect_pairing_request(tvb, btsm_tree); 202 break; 203 case (0x2): 204 dissect_pairing_response(tvb, btsm_tree); 205 break; 206 case (0x3): 207 dissect_pairing_confirm(tvb, btsm_tree); 208 break; 209 case (0x4): 210 dissect_pairing_random(tvb, btsm_tree); 211 break; 212 case (0x6): 213 dissect_encryption_info(tvb, btsm_tree); 214 break; 215 default: 216 break; 217 } 218 } 219 220 return; 221 } 222 223 void 224 proto_reg_handoff_btsm(void) 225 { 226 dissector_handle_t btsm_handle; 227 228 btsm_handle = find_dissector("btsm"); 229 dissector_add_uint("btl2cap.cid", BTL2CAP_FIXED_CID_BTSM, btsm_handle); 230 } 231 232 /* register the protocol with Wireshark */ 233 void 234 proto_register_btsm(void) 235 { 236 237 /* list of fields */ 238 static hf_register_info hf[] = { 239 { &hf_btsm_command, 240 { "Command", "btsm.command", 241 FT_UINT8, BASE_HEX, VALS(commands), 0x0, 242 NULL, HFILL } 243 }, 244 245 // pairing request 246 { &hf_btsm_pairing_request_io_capability, 247 { "IO Capability", "btsm.pairing_request.io_capability", 248 FT_UINT8, BASE_HEX, VALS(io_capability), 0x0, 249 NULL, HFILL } 250 }, 251 { &hf_btsm_pairing_request_oob_data, 252 { "OOB Data", "btsm.pairing_request.oob_data", 253 FT_UINT8, BASE_HEX, VALS(oob_data), 0x0, 254 NULL, HFILL } 255 }, 256 { &hf_btsm_pairing_request_auth_req, 257 { "AuthReq", "btsm.pairing_request.auth_req", 258 FT_UINT8, BASE_HEX, NULL, 0x0, 259 NULL, HFILL } 260 }, 261 { &hf_btsm_pairing_request_reserved, 262 { "Reserved", "btsm.pairing_request.auth_req.reserved", 263 FT_UINT8, BASE_HEX, NULL, 0xf8, 264 NULL, HFILL } 265 }, 266 { &hf_btsm_pairing_request_mitm, 267 { "MITM Protection", "btsm.pairing_request.auth_req.mitm", 268 FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, 269 NULL, HFILL } 270 }, 271 { &hf_btsm_pairing_request_bonding_flags, 272 { "Bonding Flags", "btsm.pairing_request.auth_req.bonding_flags", 273 FT_UINT8, BASE_HEX, VALS(bonding_flags), 0x3, 274 NULL, HFILL } 275 }, 276 { &hf_btsm_pairing_request_max_key_size, 277 { "Max Key Size", "btsm.pairing_request.max_key_size", 278 FT_UINT8, BASE_DEC, NULL, 0x0, 279 NULL, HFILL } 280 }, 281 { &hf_btsm_pairing_request_initiator_key_distribution, 282 { "Initiator Key Distribution", "btsm.pairing_request.initiator_key_distribution", 283 FT_UINT8, BASE_DEC, NULL, 0x0, 284 NULL, HFILL } 285 }, 286 { &hf_btsm_pairing_request_responder_key_distribution, 287 { "Responder Key Distribution", "btsm.pairing_request.responder_key_distribution", 288 FT_UINT8, BASE_DEC, NULL, 0x0, 289 NULL, HFILL } 290 }, 291 292 // pairing response 293 { &hf_btsm_pairing_response_io_capability, 294 { "IO Capability", "btsm.pairing_response.io_capability", 295 FT_UINT8, BASE_HEX, VALS(io_capability), 0x0, 296 NULL, HFILL } 297 }, 298 { &hf_btsm_pairing_response_oob_data, 299 { "OOB Data", "btsm.pairing_response.oob_data", 300 FT_UINT8, BASE_HEX, VALS(oob_data), 0x0, 301 NULL, HFILL } 302 }, 303 { &hf_btsm_pairing_response_auth_req, 304 { "AuthReq", "btsm.pairing_response.auth_req", 305 FT_UINT8, BASE_HEX, NULL, 0x0, 306 NULL, HFILL } 307 }, 308 { &hf_btsm_pairing_response_reserved, 309 { "Reserved", "btsm.pairing_response.auth_req.reserved", 310 FT_UINT8, BASE_HEX, NULL, 0xf8, 311 NULL, HFILL } 312 }, 313 { &hf_btsm_pairing_response_mitm, 314 { "MITM Protection", "btsm.pairing_response.auth_req.mitm", 315 FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, 316 NULL, HFILL } 317 }, 318 { &hf_btsm_pairing_response_bonding_flags, 319 { "Bonding Flags", "btsm.pairing_response.auth_req.bonding_flags", 320 FT_UINT8, BASE_HEX, VALS(bonding_flags), 0x3, 321 NULL, HFILL } 322 }, 323 { &hf_btsm_pairing_response_max_key_size, 324 { "Max Key Size", "btsm.pairing_response.max_key_size", 325 FT_UINT8, BASE_DEC, NULL, 0x0, 326 NULL, HFILL } 327 }, 328 { &hf_btsm_pairing_response_initiator_key_distribution, 329 { "Initiator Key Distribution", "btsm.pairing_response.initiator_key_distribution", 330 FT_UINT8, BASE_DEC, NULL, 0x0, 331 NULL, HFILL } 332 }, 333 { &hf_btsm_pairing_response_responder_key_distribution, 334 { "Responder Key Distribution", "btsm.pairing_response.responder_key_distribution", 335 FT_UINT8, BASE_DEC, NULL, 0x0, 336 NULL, HFILL } 337 }, 338 339 340 // pairing confirm 341 { &hf_btsm_pairing_confirm_confirm, 342 { "Confirm", "btsm.pairing_confirm.confirm", 343 FT_BYTES, BASE_NONE, NULL, 0x0, 344 NULL, HFILL } 345 }, 346 347 // pairing random 348 { &hf_btsm_pairing_random_random, 349 { "Random", "btsm.pairing_random.random", 350 FT_BYTES, BASE_NONE, NULL, 0x0, 351 NULL, HFILL } 352 }, 353 354 // encryption info LTK 355 { &hf_btsm_encryption_info_ltk, 356 { "LTK", "btsm.encryption_info.ltk", 357 FT_BYTES, BASE_NONE, NULL, 0x0, 358 NULL, HFILL } 359 }, 360 361 }; 362 363 /* protocol subtree arrays */ 364 static gint *ett[] = { 365 &ett_btsm, 366 &ett_auth_req, 367 }; 368 369 /* register the protocol name and description */ 370 proto_btsm = proto_register_protocol( 371 "Bluetooth Low Energy Security Manager", /* full name */ 372 "BTSM", /* short name */ 373 "btsm" /* abbreviation (e.g. for filters) */ 374 ); 375 376 register_dissector("btsm", dissect_btsm, proto_btsm); 377 378 /* register the header fields and subtrees used */ 379 proto_register_field_array(proto_btsm, hf, array_length(hf)); 380 proto_register_subtree_array(ett, array_length(ett)); 381 } 382