Demonstration of possible usage of the Security Manager. Security Manager deals with pairing, authentication and encryption.
main.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include <events/mbed_events.h> 00018 #include <mbed.h> 00019 #include "ble/BLE.h" 00020 #include "SecurityManager.h" 00021 #include "pretty_printer.h" 00022 00023 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00024 #include "LittleFileSystem.h" 00025 #include "HeapBlockDevice.h" 00026 #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT 00027 00028 /** This example demonstrates all the basic setup required 00029 * for pairing and setting up link security both as a central and peripheral 00030 * 00031 * The example is implemented as two classes, one for the peripheral and one 00032 * for central inheriting from a common base. They are run in sequence and 00033 * require a peer device to connect to. During the peripheral device demonstration 00034 * a peer device is required to connect. In the central device demonstration 00035 * this peer device will be scanned for and connected to - therefore it should 00036 * be advertising with the same address as when it connected. 00037 * 00038 * During the test output is written on the serial connection to monitor its 00039 * progress. 00040 */ 00041 00042 static const char DEVICE_NAME[] = "SM_device"; 00043 00044 /* we have to specify the disconnect call because of ambiguous overloads */ 00045 typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); 00046 const static disconnect_call_t disconnect_call = &Gap::disconnect; 00047 00048 /* for demonstration purposes we will store the peer device address 00049 * of the device that connects to us in the first demonstration 00050 * so we can use its address to reconnect to it later */ 00051 static BLEProtocol::AddressBytes_t peer_address; 00052 00053 /** Base class for both peripheral and central. The same class that provides 00054 * the logic for the application also implements the SecurityManagerEventHandler 00055 * which is the interface used by the Security Manager to communicate events 00056 * back to the applications. You can provide overrides for a selection of events 00057 * your application is interested in. 00058 */ 00059 class SMDevice : private mbed::NonCopyable<SMDevice>, 00060 public SecurityManager::EventHandler, 00061 public ble::Gap::EventHandler 00062 { 00063 public: 00064 SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) : 00065 _led1(LED1, 0), 00066 _ble(ble), 00067 _event_queue(event_queue), 00068 _peer_address(peer_address), 00069 _handle(0), 00070 _is_connecting(false) { }; 00071 00072 virtual ~SMDevice() 00073 { 00074 if (_ble.hasInitialized()) { 00075 _ble.shutdown(); 00076 } 00077 }; 00078 00079 /** Start BLE interface initialisation */ 00080 void run() 00081 { 00082 ble_error_t error; 00083 00084 /* to show we're running we'll blink every 500ms */ 00085 _event_queue.call_every(500, this, &SMDevice::blink); 00086 00087 if (_ble.hasInitialized()) { 00088 printf("Ble instance already initialised.\r\n"); 00089 return; 00090 } 00091 00092 /* this will inform us off all events so we can schedule their handling 00093 * using our event queue */ 00094 _ble.onEventsToProcess( 00095 makeFunctionPointer(this, &SMDevice::schedule_ble_events) 00096 ); 00097 00098 /* handle gap events */ 00099 _ble.gap().setEventHandler(this); 00100 00101 error = _ble.init(this, &SMDevice::on_init_complete); 00102 00103 if (error) { 00104 printf("Error returned by BLE::init.\r\n"); 00105 return; 00106 } 00107 00108 /* this will not return until shutdown */ 00109 _event_queue.dispatch_forever(); 00110 }; 00111 00112 private: 00113 /** Override to start chosen activity when initialisation completes */ 00114 virtual void start() = 0; 00115 00116 /** This is called when BLE interface is initialised and starts the demonstration */ 00117 void on_init_complete(BLE::InitializationCompleteCallbackContext *event) 00118 { 00119 ble_error_t error; 00120 00121 if (event->error) { 00122 printf("Error during the initialisation\r\n"); 00123 return; 00124 } 00125 00126 /* This path will be used to store bonding information but will fallback 00127 * to storing in memory if file access fails (for example due to lack of a filesystem) */ 00128 const char* db_path = "/fs/bt_sec_db"; 00129 /* If the security manager is required this needs to be called before any 00130 * calls to the Security manager happen. */ 00131 error = _ble.securityManager().init( 00132 true, 00133 false, 00134 SecurityManager::IO_CAPS_NONE, 00135 NULL, 00136 false, 00137 db_path 00138 ); 00139 00140 if (error) { 00141 printf("Error during init %d\r\n", error); 00142 return; 00143 } 00144 00145 error = _ble.securityManager().preserveBondingStateOnReset(true); 00146 00147 if (error) { 00148 printf("Error during preserveBondingStateOnReset %d\r\n", error); 00149 } 00150 00151 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00152 /* Enable privacy so we can find the keys */ 00153 error = _ble.gap().enablePrivacy(true); 00154 00155 if (error) { 00156 printf("Error enabling privacy\r\n"); 00157 } 00158 00159 Gap::PeripheralPrivacyConfiguration_t configuration_p = { 00160 /* use_non_resolvable_random_address */ false, 00161 Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS 00162 }; 00163 _ble.gap().setPeripheralPrivacyConfiguration(&configuration_p); 00164 00165 Gap::CentralPrivacyConfiguration_t configuration_c = { 00166 /* use_non_resolvable_random_address */ false, 00167 Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD 00168 }; 00169 _ble.gap().setCentralPrivacyConfiguration(&configuration_c); 00170 00171 /* this demo switches between being master and slave */ 00172 _ble.securityManager().setHintFutureRoleReversal(true); 00173 #endif 00174 00175 /* Tell the security manager to use methods in this class to inform us 00176 * of any events. Class needs to implement SecurityManagerEventHandler. */ 00177 _ble.securityManager().setSecurityManagerEventHandler(this); 00178 00179 /* gap events also handled by this class */ 00180 _ble.gap().setEventHandler(this); 00181 00182 /* print device address */ 00183 Gap::AddressType_t addr_type; 00184 Gap::Address_t addr; 00185 _ble.gap().getAddress(&addr_type, addr); 00186 print_address(addr); 00187 00188 /* start test in 500 ms */ 00189 _event_queue.call_in(500, this, &SMDevice::start); 00190 }; 00191 00192 /** Schedule processing of events from the BLE in the event queue. */ 00193 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 00194 { 00195 _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents)); 00196 }; 00197 00198 /** Blink LED to show we're running */ 00199 void blink(void) 00200 { 00201 _led1 = !_led1; 00202 }; 00203 00204 private: 00205 /* Event handler */ 00206 00207 /** Respond to a pairing request. This will be called by the stack 00208 * when a pairing request arrives and expects the application to 00209 * call acceptPairingRequest or cancelPairingRequest */ 00210 virtual void pairingRequest( 00211 ble::connection_handle_t connectionHandle 00212 ) { 00213 printf("Pairing requested - authorising\r\n"); 00214 _ble.securityManager().acceptPairingRequest(connectionHandle); 00215 } 00216 00217 /** Inform the application of a successful pairing. Terminate the demonstration. */ 00218 virtual void pairingResult( 00219 ble::connection_handle_t connectionHandle, 00220 SecurityManager::SecurityCompletionStatus_t result 00221 ) { 00222 if (result == SecurityManager::SEC_STATUS_SUCCESS) { 00223 printf("Pairing successful\r\n"); 00224 } else { 00225 printf("Pairing failed\r\n"); 00226 } 00227 } 00228 00229 /** Inform the application of change in encryption status. This will be 00230 * communicated through the serial port */ 00231 virtual void linkEncryptionResult( 00232 ble::connection_handle_t connectionHandle, 00233 ble::link_encryption_t result 00234 ) { 00235 if (result == ble::link_encryption_t::ENCRYPTED) { 00236 printf("Link ENCRYPTED\r\n"); 00237 } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { 00238 printf("Link ENCRYPTED_WITH_MITM\r\n"); 00239 } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) { 00240 printf("Link NOT_ENCRYPTED\r\n"); 00241 } 00242 00243 /* disconnect in 2 s */ 00244 _event_queue.call_in( 00245 2000, 00246 &_ble.gap(), 00247 disconnect_call, 00248 _handle, 00249 ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) 00250 ); 00251 } 00252 00253 /** This is called by Gap to notify the application we disconnected, 00254 * in our case it ends the demonstration. */ 00255 virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &) 00256 { 00257 printf("Diconnected\r\n"); 00258 _event_queue.break_dispatch(); 00259 }; 00260 00261 virtual void onAdvertisingEnd(const ble::AdvertisingEndEvent &) 00262 { 00263 printf("Advertising timed out - aborting\r\n"); 00264 _event_queue.break_dispatch(); 00265 } 00266 00267 virtual void onScanTimeout(const ble::ScanTimeoutEvent &) 00268 { 00269 printf("Scan timed out - aborting\r\n"); 00270 _event_queue.break_dispatch(); 00271 } 00272 00273 private: 00274 DigitalOut _led1; 00275 00276 protected: 00277 BLE &_ble; 00278 events::EventQueue &_event_queue; 00279 BLEProtocol::AddressBytes_t &_peer_address; 00280 ble::connection_handle_t _handle; 00281 bool _is_connecting; 00282 }; 00283 00284 /** A peripheral device will advertise, accept the connection and request 00285 * a change in link security. */ 00286 class SMDevicePeripheral : public SMDevice { 00287 public: 00288 SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) 00289 : SMDevice(ble, event_queue, peer_address) { } 00290 00291 virtual void start() 00292 { 00293 /* Set up and start advertising */ 00294 uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 00295 /* use the helper to build the payload */ 00296 ble::AdvertisingDataBuilder adv_data_builder( 00297 adv_buffer 00298 ); 00299 00300 adv_data_builder.setFlags(); 00301 adv_data_builder.setName(DEVICE_NAME); 00302 00303 /* Set payload for the set */ 00304 ble_error_t error = _ble.gap().setAdvertisingPayload( 00305 ble::LEGACY_ADVERTISING_HANDLE, 00306 adv_data_builder.getAdvertisingData() 00307 ); 00308 00309 if (error) { 00310 print_error(error, "Gap::setAdvertisingPayload() failed"); 00311 _event_queue.break_dispatch(); 00312 return; 00313 } 00314 00315 ble::AdvertisingParameters adv_parameters( 00316 ble::advertising_type_t::CONNECTABLE_UNDIRECTED 00317 ); 00318 00319 error = _ble.gap().setAdvertisingParameters( 00320 ble::LEGACY_ADVERTISING_HANDLE, 00321 adv_parameters 00322 ); 00323 00324 if (error) { 00325 print_error(error, "Gap::setAdvertisingParameters() failed"); 00326 return; 00327 } 00328 00329 error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 00330 00331 if (error) { 00332 print_error(error, "Gap::startAdvertising() failed"); 00333 return; 00334 } 00335 00336 printf("Please connect to device\r\n"); 00337 00338 /** This tells the stack to generate a pairingRequest event 00339 * which will require this application to respond before pairing 00340 * can proceed. Setting it to false will automatically accept 00341 * pairing. */ 00342 _ble.securityManager().setPairingRequestAuthorisation(true); 00343 }; 00344 00345 /** This is called by Gap to notify the application we connected, 00346 * in our case it immediately requests a change in link security */ 00347 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) 00348 { 00349 ble_error_t error; 00350 00351 /* remember the device that connects to us now so we can connect to it 00352 * during the next demonstration */ 00353 memcpy(_peer_address, event.getPeerAddress().data(), sizeof(_peer_address)); 00354 00355 printf("Connected to peer: "); 00356 print_address(event.getPeerAddress().data()); 00357 00358 _handle = event.getConnectionHandle(); 00359 00360 /* Request a change in link security. This will be done 00361 * indirectly by asking the master of the connection to 00362 * change it. Depending on circumstances different actions 00363 * may be taken by the master which will trigger events 00364 * which the applications should deal with. */ 00365 error = _ble.securityManager().setLinkSecurity( 00366 _handle, 00367 SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM 00368 ); 00369 00370 if (error) { 00371 printf("Error during SM::setLinkSecurity %d\r\n", error); 00372 return; 00373 } 00374 }; 00375 }; 00376 00377 /** A central device will scan, connect to a peer and request pairing. */ 00378 class SMDeviceCentral : public SMDevice { 00379 public: 00380 SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) 00381 : SMDevice(ble, event_queue, peer_address) { } 00382 00383 virtual void start() 00384 { 00385 ble::ScanParameters params; 00386 ble_error_t error = _ble.gap().setScanParameters(params); 00387 00388 if (error) { 00389 print_error(error, "Error in Gap::startScan %d\r\n"); 00390 return; 00391 } 00392 00393 /* start scanning, results will be handled by onAdvertisingReport */ 00394 error = _ble.gap().startScan(); 00395 00396 if (error) { 00397 print_error(error, "Error in Gap::startScan %d\r\n"); 00398 return; 00399 } 00400 00401 printf("Please advertise\r\n"); 00402 00403 printf("Scanning for: "); 00404 print_address(_peer_address); 00405 } 00406 00407 private: 00408 /* Gap::EventHandler */ 00409 00410 /** Look at scan payload to find a peer device and connect to it */ 00411 virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event) 00412 { 00413 /* don't bother with analysing scan result if we're already connecting */ 00414 if (_is_connecting) { 00415 return; 00416 } 00417 00418 /* parse the advertising payload, looking for a discoverable device */ 00419 if (memcmp(event.getPeerAddress().data(), _peer_address, sizeof(_peer_address)) == 0) { 00420 ble_error_t error = _ble.gap().stopScan(); 00421 00422 if (error) { 00423 print_error(error, "Error caused by Gap::stopScan"); 00424 return; 00425 } 00426 00427 ble::ConnectionParameters connection_params( 00428 ble::phy_t::LE_1M, 00429 ble::scan_interval_t(50), 00430 ble::scan_window_t(50), 00431 ble::conn_interval_t(50), 00432 ble::conn_interval_t(100), 00433 ble::slave_latency_t(0), 00434 ble::supervision_timeout_t(100) 00435 ); 00436 connection_params.setOwnAddressType(ble::own_address_type_t::RANDOM); 00437 00438 error = _ble.gap().connect( 00439 event.getPeerAddressType(), 00440 event.getPeerAddress(), 00441 connection_params 00442 ); 00443 00444 if (error) { 00445 print_error(error, "Error caused by Gap::connect"); 00446 return; 00447 } 00448 00449 /* we may have already scan events waiting 00450 * to be processed so we need to remember 00451 * that we are already connecting and ignore them */ 00452 _is_connecting = true; 00453 00454 return; 00455 } 00456 } 00457 00458 /** This is called by Gap to notify the application we connected, 00459 * in our case it immediately request pairing */ 00460 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) 00461 { 00462 if (event.getStatus() == BLE_ERROR_NONE) { 00463 /* store the handle for future Security Manager requests */ 00464 _handle = event.getConnectionHandle(); 00465 00466 printf("Connected\r\n"); 00467 00468 /* in this example the local device is the master so we request pairing */ 00469 ble_error_t error = _ble.securityManager().requestPairing(_handle); 00470 00471 if (error) { 00472 printf("Error during SM::requestPairing %d\r\n", error); 00473 return; 00474 } 00475 00476 /* upon pairing success the application will disconnect */ 00477 } 00478 00479 /* failed to connect - restart scan */ 00480 ble_error_t error = _ble.gap().startScan(); 00481 00482 if (error) { 00483 print_error(error, "Error in Gap::startScan %d\r\n"); 00484 return; 00485 } 00486 }; 00487 }; 00488 00489 00490 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00491 bool create_filesystem() 00492 { 00493 static LittleFileSystem fs("fs"); 00494 00495 /* replace this with any physical block device your board supports (like an SD card) */ 00496 static HeapBlockDevice bd(4096, 256); 00497 00498 int err = bd.init(); 00499 00500 if (err) { 00501 return false; 00502 } 00503 00504 err = bd.erase(0, bd.size()); 00505 00506 if (err) { 00507 return false; 00508 } 00509 00510 err = fs.mount(&bd); 00511 00512 if (err) { 00513 /* Reformat if we can't mount the filesystem */ 00514 printf("No filesystem found, formatting...\r\n"); 00515 00516 err = fs.reformat(&bd); 00517 00518 if (err) { 00519 return false; 00520 } 00521 } 00522 00523 return true; 00524 } 00525 #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT 00526 00527 int main() 00528 { 00529 BLE& ble = BLE::Instance(); 00530 events::EventQueue queue; 00531 00532 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00533 /* if filesystem creation fails or there is no filesystem the security manager 00534 * will fallback to storing the security database in memory */ 00535 if (!create_filesystem()) { 00536 printf("Filesystem creation failed, will use memory storage\r\n"); 00537 } 00538 #endif 00539 00540 while(1) { 00541 { 00542 printf("\r\n PERIPHERAL \r\n\r\n"); 00543 SMDevicePeripheral peripheral(ble, queue, peer_address); 00544 peripheral.run(); 00545 } 00546 00547 { 00548 printf("\r\n CENTRAL \r\n\r\n"); 00549 SMDeviceCentral central(ble, queue, peer_address); 00550 central.run(); 00551 } 00552 } 00553 00554 return 0; 00555 }
Generated on Sat Jul 16 2022 20:53:44 by 1.7.2