Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secure random & reject unknown LTK #16

Merged
merged 2 commits into from
Jan 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/local/BLELocalDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
132 changes: 94 additions & 38 deletions src/utility/HCI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "L2CAPSignaling.h"
#include "btct.h"
#include "HCI.h"
#include "bitDescriptions.h"
// #define _BLE_TRACE_

//#define _BLE_TRACE_

Expand Down Expand Up @@ -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), &ltkReply);

#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(&ltkReplyResult, _cmdResponse, 3);

#ifdef _BLE_TRACE_
Serial.println("LTK send success");
Serial.print("status : ");
btct.printBytes(&ltkReplyResult.status,1);
Serial.print("Conn Handle: ");
btct.printBytes((uint8_t*)&ltkReplyResult.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), &ltkReply);

#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(&ltkReplyResult, _cmdResponse, 3);

#ifdef _BLE_TRACE_
Serial.println("LTK send success");
Serial.print("status : ");
btct.printBytes(&ltkReplyResult.status,1);
Serial.print("Conn Handle: ");
btct.printBytes((uint8_t*)&ltkReplyResult.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, &ltkRequest->connectionHandle);
}
break;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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[])
{
Expand Down
30 changes: 19 additions & 11 deletions src/utility/HCI.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define _HCI_H_

#include <Arduino.h>
#include "bitDescriptions.h"

#include "L2CAPSignaling.h"

Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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];
Expand All @@ -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:

Expand Down
20 changes: 10 additions & 10 deletions src/utility/L2CAPSignaling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
L2CAPSignalingClass::L2CAPSignalingClass() :
_minInterval(0),
_maxInterval(0),
_supervisionTimeout(0)
,_pairing_enabled(1)
_supervisionTimeout(0),
_pairing_enabled(1)
{
}

Expand Down Expand Up @@ -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, ");
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down