diff --git a/src/local/BLELocalDevice.h b/src/local/BLELocalDevice.h index 0c471938..75e7dc31 100644 --- a/src/local/BLELocalDevice.h +++ b/src/local/BLELocalDevice.h @@ -91,11 +91,19 @@ class BLELocalDevice { virtual bool pairable(); virtual bool paired(); -/// TODO: Put in actual variable names - virtual void setStoreIRK(int (*storeIRK)(uint8_t*, uint8_t*)); - virtual void setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs)); - virtual void setStoreLTK(int (*storeLTK)(uint8_t*, uint8_t*)); - virtual void setGetLTK(int (*getLTK)(uint8_t*, uint8_t*)); + // address - The mac to store + // IRK - The IRK to store with this mac + virtual void setStoreIRK(int (*storeIRK)(uint8_t* address, uint8_t* IRK)); + // nIRKs - the number of IRKs being provided. + // BDAddrType - an array containing the type of each address (0 public, 1 static random) + // BDAddrs - an array containing the list of addresses + virtual void setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BDAddrType, uint8_t*** BDAddrs, uint8_t*** IRKs)); + // address - the address to store [6 bytes] + // LTK - the LTK to store with this mac [16 bytes] + virtual void setStoreLTK(int (*storeLTK)(uint8_t* address, uint8_t* LTK)); + // address - The mac address needing its LTK + // LTK - 16 octet LTK for the mac address + virtual void setGetLTK(int (*getLTK)(uint8_t* address, uint8_t* LTK)); uint8_t BDaddress[6]; protected: diff --git a/src/utility/HCI.cpp b/src/utility/HCI.cpp index 4c97f79d..9bcec4e1 100644 --- a/src/utility/HCI.cpp +++ b/src/utility/HCI.cpp @@ -23,6 +23,8 @@ #include "L2CAPSignaling.h" #include "btct.h" #include "HCI.h" +#include "bitDescriptions.h" +// #define _BLE_TRACE_ //#define _BLE_TRACE_ @@ -1141,50 +1143,63 @@ void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[]) // Load our LTK for this connection. uint8_t peerAddr[7]; uint8_t resolvableAddr[6]; + uint8_t foundLTK; ATT.getPeerAddrWithType(ltkRequest->connectionHandle, peerAddr); - if(ATT.getPeerResolvedAddress(ltkRequest->connectionHandle, resolvableAddr) - && !((ATT.getPeerEncryption(ltkRequest->connectionHandle) & PEER_ENCRYPTION::PAIRING_REQUEST)>0)){ - _getLTK(resolvableAddr, HCI.LTK); + if((ATT.getPeerEncryption(ltkRequest->connectionHandle) & PEER_ENCRYPTION::PAIRING_REQUEST)>0){ + // Pairing request - LTK is one in buffer already + foundLTK = 1; }else{ - _getLTK(&peerAddr[1], HCI.LTK); + if(ATT.getPeerResolvedAddress(ltkRequest->connectionHandle, resolvableAddr)){ + foundLTK = getLTK(resolvableAddr, HCI.LTK); + }else{ + foundLTK = getLTK(&peerAddr[1], HCI.LTK); + } } - // } + // } //2d // Send our LTK back - struct __attribute__ ((packed)) LTKReply - { - uint16_t connectionHandle; - uint8_t LTK[16]; - } ltkReply = {0,0}; - ltkReply.connectionHandle = ltkRequest->connectionHandle; - for(int i=0; i<16; i++) ltkReply.LTK[15-i] = HCI.LTK[i]; - int result = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_REPLY,sizeof(ltkReply), <kReply); - -#ifdef _BLE_TRACE_ - Serial.println("Sending LTK as: "); - btct.printBytes(ltkReply.LTK,16); -#endif - - if(result == 0){ - struct __attribute__ ((packed)) LTKReplyResult + if(foundLTK){ + struct __attribute__ ((packed)) LTKReply { - uint8_t status; uint16_t connectionHandle; - } ltkReplyResult = {0,0}; - memcpy(<kReplyResult, _cmdResponse, 3); - -#ifdef _BLE_TRACE_ - Serial.println("LTK send success"); - Serial.print("status : "); - btct.printBytes(<kReplyResult.status,1); - Serial.print("Conn Handle: "); - btct.printBytes((uint8_t*)<kReplyResult.connectionHandle,2); -#endif + uint8_t LTK[16]; + } ltkReply = {0,0}; + ltkReply.connectionHandle = ltkRequest->connectionHandle; + for(int i=0; i<16; i++) ltkReply.LTK[15-i] = HCI.LTK[i]; + int result = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_REPLY,sizeof(ltkReply), <kReply); + + #ifdef _BLE_TRACE_ + Serial.println("Sending LTK as: "); + btct.printBytes(ltkReply.LTK,16); + #endif + + if(result == 0){ + struct __attribute__ ((packed)) LTKReplyResult + { + uint8_t status; + uint16_t connectionHandle; + } ltkReplyResult = {0,0}; + memcpy(<kReplyResult, _cmdResponse, 3); + + #ifdef _BLE_TRACE_ + Serial.println("LTK send success"); + Serial.print("status : "); + btct.printBytes(<kReplyResult.status,1); + Serial.print("Conn Handle: "); + btct.printBytes((uint8_t*)<kReplyResult.connectionHandle,2); + #endif + }else{ + #ifdef _BLE_TRACE_ + Serial.print("Failed to send LTK...: "); + btct.printBytes((uint8_t*)&result,2); + #endif + } }else{ + /// do LTK rejection #ifdef _BLE_TRACE_ - Serial.print("Failed to send LTK...: "); - btct.printBytes((uint8_t*)&result,2); + Serial.println("LTK not found, rejecting"); #endif + sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_NEGATIVE_REPLY,2, <kRequest->connectionHandle); } break; } @@ -1258,10 +1273,10 @@ void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[]) uint8_t Z = 0; - for(int i=0; i<16; i++){ - /// TODO: Implement secure random - Nb[i] = rand(); //// Should use ESP or ECCx08 - } + + HCI.leRand(Nb); + HCI.leRand(&Nb[8]); + #ifdef _BLE_TRACE_ Serial.print("nb: "); btct.printBytes(Nb, 16); @@ -1413,6 +1428,47 @@ int HCIClass::leEncrypt(uint8_t* key, uint8_t* plaintext, uint8_t* status, uint8 #endif return res; } +int HCIClass::leRand(uint8_t rand[]){ + int res = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::RANDOM); + if(res == 0){ + memcpy(rand,_cmdResponse, 8); /// backwards but it's a random number + } + return res; +} +int HCIClass::getLTK(uint8_t* address, uint8_t* LTK){ + if(_getLTK!=0){ + return _getLTK(address, LTK); + }else{ + return 0; + } +} +int HCIClass::storeIRK(uint8_t* address, uint8_t* IRK){ + if(_storeIRK!=0){ + return _storeIRK(address, IRK); + }else{ + return 0; + } +} +int HCIClass::storeLTK(uint8_t* address, uint8_t* LTK){ + if(_storeLTK!=0){ + return _storeLTK(address, LTK); + }else{ + return 0; + } +} + +/// Stub function to generate parameters for local authreq +AuthReq HCIClass::localAuthreq(){ + // If get, set, IRK, LTK all set then we can bond. + AuthReq local = AuthReq(); + if(_storeIRK!=0 && _storeLTK!=0 && _getLTK!=0 && _getIRKs!=0){ + local.setBonding(true); + } + local.setSC(true); + local.setMITM(true); + local.setCT2(true); + return LOCAL_AUTHREQ; +} void HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]) { diff --git a/src/utility/HCI.h b/src/utility/HCI.h index 522570d3..f2bc535e 100644 --- a/src/utility/HCI.h +++ b/src/utility/HCI.h @@ -21,6 +21,7 @@ #define _HCI_H_ #include +#include "bitDescriptions.h" #include "L2CAPSignaling.h" @@ -31,11 +32,13 @@ #define OGF_LE_CTL 0x08 enum LE_COMMAND { - ENCRYPT = 0x0017, - LONG_TERM_KEY_REPLY = 0x001A, - READ_LOCAL_P256 = 0x0025, - GENERATE_DH_KEY_V1 = 0x0026, - GENERATE_DH_KEY_V2 = 0x005E + ENCRYPT = 0x0017, + RANDOM = 0x0018, + LONG_TERM_KEY_REPLY = 0x001A, + LONG_TERM_KEY_NEGATIVE_REPLY = 0x1B, + READ_LOCAL_P256 = 0x0025, + GENERATE_DH_KEY_V1 = 0x0026, + GENERATE_DH_KEY_V2 = 0x005E }; enum LE_META_EVENT { CONN_COMPLETE = 0x01, @@ -91,6 +94,9 @@ class HCIClass { uint16_t latency, uint16_t supervisionTimeout); virtual int leCancelConn(); virtual int leEncrypt(uint8_t* Key, uint8_t* plaintext, uint8_t* status, uint8_t* ciphertext); + // Generate a 64 bit random number + virtual int leRand(uint8_t rand[]); + virtual AuthReq localAuthreq(); virtual int saveNewAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk); virtual int leAddResolvingAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk); @@ -110,7 +116,7 @@ class HCIClass { virtual void debug(Stream& stream); virtual void noDebug(); - // TODO: Send command be private again & use ATT implementation within ATT. + // TODO: Send command be private again & use ATT implementation of send command within ATT. virtual int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL); uint8_t remotePublicKeyBuffer[64]; uint8_t remoteDHKeyCheckBuffer[16]; @@ -119,11 +125,13 @@ class HCIClass { uint8_t DHKey[32]; uint8_t localAddr[6]; uint8_t LTK[16]; - - int (*_storeIRK)(uint8_t* address, uint8_t* peerIrk); - int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs); - int (*_storeLTK)(uint8_t*, uint8_t*); - int (*_getLTK)(uint8_t*, uint8_t*); + virtual int getLTK(uint8_t* address, uint8_t* LTK); + virtual int storeLTK(uint8_t* address, uint8_t* LTK); + virtual int storeIRK(uint8_t* address, uint8_t* IRK); + int (*_storeIRK)(uint8_t* address, uint8_t* peerIrk) = 0; + int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs) = 0; + int (*_storeLTK)(uint8_t*, uint8_t*) = 0; + int (*_getLTK)(uint8_t*, uint8_t*) = 0; private: diff --git a/src/utility/L2CAPSignaling.cpp b/src/utility/L2CAPSignaling.cpp index 622f2178..f7712051 100644 --- a/src/utility/L2CAPSignaling.cpp +++ b/src/utility/L2CAPSignaling.cpp @@ -31,8 +31,8 @@ L2CAPSignalingClass::L2CAPSignalingClass() : _minInterval(0), _maxInterval(0), - _supervisionTimeout(0) - ,_pairing_enabled(1) + _supervisionTimeout(0), + _pairing_enabled(1) { } @@ -145,14 +145,14 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t uint8_t initiatorKeyDistribution; uint8_t responderKeyDistribution; } *pairingRequest = (PairingRequest*)l2capSignalingHdr->data; - - - ATT.remoteKeyDistribution = KeyDistribution(pairingRequest->initiatorKeyDistribution); - ATT.localKeyDistribution = KeyDistribution(pairingRequest->responderKeyDistribution); - KeyDistribution rkd(pairingRequest->responderKeyDistribution); - AuthReq req(pairingRequest->authReq); + KeyDistribution responseKD = KeyDistribution(); responseKD.setIdKey(true); + + ATT.remoteKeyDistribution = responseKD;// KeyDistribution(pairingRequest->initiatorKeyDistribution); + ATT.localKeyDistribution = responseKD; //KeyDistribution(pairingRequest->responderKeyDistribution); + // KeyDistribution rkd(pairingRequest->responderKeyDistribution); + AuthReq req(pairingRequest->authReq); #ifdef _BLE_TRACE_ Serial.print("Req has properties: "); Serial.print(req.Bonding()?"bonding, ":"no bonding, "); @@ -180,7 +180,7 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t uint8_t maxEncSize; uint8_t initiatorKeyDistribution; uint8_t responderKeyDistribution; - } response = { CONNECTION_PAIRING_RESPONSE, LOCAL_IOCAP, 0, LOCAL_AUTHREQ, 0x10, responseKD.getOctet(), responseKD.getOctet()}; + } response = { CONNECTION_PAIRING_RESPONSE, LOCAL_IOCAP, 0, HCI.localAuthreq().getOctet(), 0x10, responseKD.getOctet(), responseKD.getOctet()}; HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(response), &response); @@ -338,7 +338,7 @@ void L2CAPSignalingClass::smCalculateLTKandConfirm(uint16_t handle, uint8_t expe uint8_t Eb[16]; uint8_t R[16]; uint8_t MasterIOCap[3]; - uint8_t SlaveIOCap[3] = {LOCAL_AUTHREQ, 0x0, LOCAL_IOCAP}; + uint8_t SlaveIOCap[3] = {HCI.localAuthreq().getOctet(), 0x0, LOCAL_IOCAP}; ATT.getPeerIOCap(handle, MasterIOCap); for(int i=0; i<16; i++) R[i] = 0;