Skip to content

Commit d9fb4bc

Browse files
author
unknownconstant
committed
Secure random & reject unknown LTK
1 parent 6ef59a5 commit d9fb4bc

File tree

4 files changed

+137
-61
lines changed

4 files changed

+137
-61
lines changed

src/local/BLELocalDevice.h

+13-5
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,19 @@ class BLELocalDevice {
8181
virtual void debug(Stream& stream);
8282
virtual void noDebug();
8383

84-
/// TODO: Put in actual variable names
85-
virtual void setStoreIRK(int (*storeIRK)(uint8_t*, uint8_t*));
86-
virtual void setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs));
87-
virtual void setStoreLTK(int (*storeLTK)(uint8_t*, uint8_t*));
88-
virtual void setGetLTK(int (*getLTK)(uint8_t*, uint8_t*));
84+
// address - The mac to store
85+
// IRK - The IRK to store with this mac
86+
virtual void setStoreIRK(int (*storeIRK)(uint8_t* address, uint8_t* IRK));
87+
// nIRKs - the number of IRKs being provided.
88+
// BDAddrType - an array containing the type of each address (0 public, 1 static random)
89+
// BDAddrs - an array containing the list of addresses
90+
virtual void setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BDAddrType, uint8_t*** BDAddrs, uint8_t*** IRKs));
91+
// address - the address to store [6 bytes]
92+
// LTK - the LTK to store with this mac [16 bytes]
93+
virtual void setStoreLTK(int (*storeLTK)(uint8_t* address, uint8_t* LTK));
94+
// address - The mac address needing its LTK
95+
// LTK - 16 octet LTK for the mac address
96+
virtual void setGetLTK(int (*getLTK)(uint8_t* address, uint8_t* LTK));
8997
uint8_t BDaddress[6];
9098

9199
protected:

src/utility/HCI.cpp

+94-38
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "L2CAPSignaling.h"
2424
#include "btct.h"
2525
#include "HCI.h"
26+
#include "bitDescriptions.h"
27+
// #define _BLE_TRACE_
2628

2729
#define HCI_COMMAND_PKT 0x01
2830
#define HCI_ACLDATA_PKT 0x02
@@ -1139,50 +1141,63 @@ void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[])
11391141
// Load our LTK for this connection.
11401142
uint8_t peerAddr[7];
11411143
uint8_t resolvableAddr[6];
1144+
uint8_t foundLTK;
11421145
ATT.getPeerAddrWithType(ltkRequest->connectionHandle, peerAddr);
11431146

1144-
if(ATT.getPeerResolvedAddress(ltkRequest->connectionHandle, resolvableAddr)
1145-
&& !((ATT.getPeerEncryption(ltkRequest->connectionHandle) & PEER_ENCRYPTION::PAIRING_REQUEST)>0)){
1146-
_getLTK(resolvableAddr, HCI.LTK);
1147+
if((ATT.getPeerEncryption(ltkRequest->connectionHandle) & PEER_ENCRYPTION::PAIRING_REQUEST)>0){
1148+
// Pairing request - LTK is one in buffer already
1149+
foundLTK = 1;
11471150
}else{
1148-
_getLTK(&peerAddr[1], HCI.LTK);
1151+
if(ATT.getPeerResolvedAddress(ltkRequest->connectionHandle, resolvableAddr)){
1152+
foundLTK = getLTK(resolvableAddr, HCI.LTK);
1153+
}else{
1154+
foundLTK = getLTK(&peerAddr[1], HCI.LTK);
1155+
}
11491156
}
1150-
// }
1157+
// } //2d
11511158
// Send our LTK back
1152-
struct __attribute__ ((packed)) LTKReply
1153-
{
1154-
uint16_t connectionHandle;
1155-
uint8_t LTK[16];
1156-
} ltkReply = {0,0};
1157-
ltkReply.connectionHandle = ltkRequest->connectionHandle;
1158-
for(int i=0; i<16; i++) ltkReply.LTK[15-i] = HCI.LTK[i];
1159-
int result = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_REPLY,sizeof(ltkReply), &ltkReply);
1160-
1161-
#ifdef _BLE_TRACE_
1162-
Serial.println("Sending LTK as: ");
1163-
btct.printBytes(ltkReply.LTK,16);
1164-
#endif
1165-
1166-
if(result == 0){
1167-
struct __attribute__ ((packed)) LTKReplyResult
1159+
if(foundLTK){
1160+
struct __attribute__ ((packed)) LTKReply
11681161
{
1169-
uint8_t status;
11701162
uint16_t connectionHandle;
1171-
} ltkReplyResult = {0,0};
1172-
memcpy(&ltkReplyResult, _cmdResponse, 3);
1173-
1174-
#ifdef _BLE_TRACE_
1175-
Serial.println("LTK send success");
1176-
Serial.print("status : ");
1177-
btct.printBytes(&ltkReplyResult.status,1);
1178-
Serial.print("Conn Handle: ");
1179-
btct.printBytes((uint8_t*)&ltkReplyResult.connectionHandle,2);
1180-
#endif
1163+
uint8_t LTK[16];
1164+
} ltkReply = {0,0};
1165+
ltkReply.connectionHandle = ltkRequest->connectionHandle;
1166+
for(int i=0; i<16; i++) ltkReply.LTK[15-i] = HCI.LTK[i];
1167+
int result = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_REPLY,sizeof(ltkReply), &ltkReply);
1168+
1169+
#ifdef _BLE_TRACE_
1170+
Serial.println("Sending LTK as: ");
1171+
btct.printBytes(ltkReply.LTK,16);
1172+
#endif
1173+
1174+
if(result == 0){
1175+
struct __attribute__ ((packed)) LTKReplyResult
1176+
{
1177+
uint8_t status;
1178+
uint16_t connectionHandle;
1179+
} ltkReplyResult = {0,0};
1180+
memcpy(&ltkReplyResult, _cmdResponse, 3);
1181+
1182+
#ifdef _BLE_TRACE_
1183+
Serial.println("LTK send success");
1184+
Serial.print("status : ");
1185+
btct.printBytes(&ltkReplyResult.status,1);
1186+
Serial.print("Conn Handle: ");
1187+
btct.printBytes((uint8_t*)&ltkReplyResult.connectionHandle,2);
1188+
#endif
1189+
}else{
1190+
#ifdef _BLE_TRACE_
1191+
Serial.print("Failed to send LTK...: ");
1192+
btct.printBytes((uint8_t*)&result,2);
1193+
#endif
1194+
}
11811195
}else{
1196+
/// do LTK rejection
11821197
#ifdef _BLE_TRACE_
1183-
Serial.print("Failed to send LTK...: ");
1184-
btct.printBytes((uint8_t*)&result,2);
1198+
Serial.println("LTK not found, rejecting");
11851199
#endif
1200+
sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::LONG_TERM_KEY_NEGATIVE_REPLY,2, &ltkRequest->connectionHandle);
11861201
}
11871202
break;
11881203
}
@@ -1256,10 +1271,10 @@ void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[])
12561271

12571272

12581273
uint8_t Z = 0;
1259-
for(int i=0; i<16; i++){
1260-
/// TODO: Implement secure random
1261-
Nb[i] = rand(); //// Should use ESP or ECCx08
1262-
}
1274+
1275+
HCI.leRand(Nb);
1276+
HCI.leRand(&Nb[8]);
1277+
12631278
#ifdef _BLE_TRACE_
12641279
Serial.print("nb: ");
12651280
btct.printBytes(Nb, 16);
@@ -1405,6 +1420,47 @@ int HCIClass::leEncrypt(uint8_t* key, uint8_t* plaintext, uint8_t* status, uint8
14051420
#endif
14061421
return res;
14071422
}
1423+
int HCIClass::leRand(uint8_t rand[]){
1424+
int res = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::RANDOM);
1425+
if(res == 0){
1426+
memcpy(rand,_cmdResponse, 8); /// backwards but it's a random number
1427+
}
1428+
return res;
1429+
}
1430+
int HCIClass::getLTK(uint8_t* address, uint8_t* LTK){
1431+
if(_getLTK!=0){
1432+
return _getLTK(address, LTK);
1433+
}else{
1434+
return 0;
1435+
}
1436+
}
1437+
int HCIClass::storeIRK(uint8_t* address, uint8_t* IRK){
1438+
if(_storeIRK!=0){
1439+
return _storeIRK(address, IRK);
1440+
}else{
1441+
return 0;
1442+
}
1443+
}
1444+
int HCIClass::storeLTK(uint8_t* address, uint8_t* LTK){
1445+
if(_storeLTK!=0){
1446+
return _storeLTK(address, LTK);
1447+
}else{
1448+
return 0;
1449+
}
1450+
}
1451+
1452+
/// Stub function to generate parameters for local authreq
1453+
AuthReq HCIClass::localAuthreq(){
1454+
// If get, set, IRK, LTK all set then we can bond.
1455+
AuthReq local = AuthReq();
1456+
if(_storeIRK!=0 && _storeLTK!=0 && _getLTK!=0 && _getIRKs!=0){
1457+
local.setBonding(true);
1458+
}
1459+
local.setSC(true);
1460+
local.setMITM(true);
1461+
local.setCT2(true);
1462+
return LOCAL_AUTHREQ;
1463+
}
14081464

14091465
void HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[])
14101466
{

src/utility/HCI.h

+19-11
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#define _HCI_H_
2222

2323
#include <Arduino.h>
24+
#include "bitDescriptions.h"
2425

2526
#define OGF_LINK_CTL 0x01
2627
#define OGF_HOST_CTL 0x03
@@ -29,11 +30,13 @@
2930
#define OGF_LE_CTL 0x08
3031

3132
enum LE_COMMAND {
32-
ENCRYPT = 0x0017,
33-
LONG_TERM_KEY_REPLY = 0x001A,
34-
READ_LOCAL_P256 = 0x0025,
35-
GENERATE_DH_KEY_V1 = 0x0026,
36-
GENERATE_DH_KEY_V2 = 0x005E
33+
ENCRYPT = 0x0017,
34+
RANDOM = 0x0018,
35+
LONG_TERM_KEY_REPLY = 0x001A,
36+
LONG_TERM_KEY_NEGATIVE_REPLY = 0x1B,
37+
READ_LOCAL_P256 = 0x0025,
38+
GENERATE_DH_KEY_V1 = 0x0026,
39+
GENERATE_DH_KEY_V2 = 0x005E
3740
};
3841
enum LE_META_EVENT {
3942
CONN_COMPLETE = 0x01,
@@ -89,6 +92,9 @@ class HCIClass {
8992
uint16_t latency, uint16_t supervisionTimeout);
9093
virtual int leCancelConn();
9194
virtual int leEncrypt(uint8_t* Key, uint8_t* plaintext, uint8_t* status, uint8_t* ciphertext);
95+
// Generate a 64 bit random number
96+
virtual int leRand(uint8_t rand[]);
97+
virtual AuthReq localAuthreq();
9298

9399
virtual int saveNewAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);
94100
virtual int leAddResolvingAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);
@@ -108,19 +114,21 @@ class HCIClass {
108114
virtual void debug(Stream& stream);
109115
virtual void noDebug();
110116

111-
// TODO: Send command be private again & use ATT implementation within ATT.
117+
// TODO: Send command be private again & use ATT implementation of send command within ATT.
112118
virtual int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL);
113119
uint8_t remotePublicKeyBuffer[64];
114120
uint8_t Na[16];
115121
uint8_t Nb[16];
116122
uint8_t DHKey[32];
117123
uint8_t localAddr[6];
118124
uint8_t LTK[16];
119-
120-
int (*_storeIRK)(uint8_t* address, uint8_t* peerIrk);
121-
int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs);
122-
int (*_storeLTK)(uint8_t*, uint8_t*);
123-
int (*_getLTK)(uint8_t*, uint8_t*);
125+
virtual int getLTK(uint8_t* address, uint8_t* LTK);
126+
virtual int storeLTK(uint8_t* address, uint8_t* LTK);
127+
virtual int storeIRK(uint8_t* address, uint8_t* IRK);
128+
int (*_storeIRK)(uint8_t* address, uint8_t* peerIrk) = 0;
129+
int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs) = 0;
130+
int (*_storeLTK)(uint8_t*, uint8_t*) = 0;
131+
int (*_getLTK)(uint8_t*, uint8_t*) = 0;
124132

125133
private:
126134

src/utility/L2CAPSignaling.cpp

+11-7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#define CONNECTION_PARAMETER_UPDATE_REQUEST 0x12
2727
#define CONNECTION_PARAMETER_UPDATE_RESPONSE 0x13
2828

29+
30+
// #define _BLE_TRACE_
31+
2932
L2CAPSignalingClass::L2CAPSignalingClass() :
3033
_minInterval(0),
3134
_maxInterval(0),
@@ -139,13 +142,14 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
139142
uint8_t responderKeyDistribution;
140143
} *pairingRequest = (PairingRequest*)l2capSignalingHdr->data;
141144

142-
143-
ATT.remoteKeyDistribution = KeyDistribution(pairingRequest->initiatorKeyDistribution);
144-
ATT.localKeyDistribution = KeyDistribution(pairingRequest->responderKeyDistribution);
145-
KeyDistribution rkd(pairingRequest->responderKeyDistribution);
146-
AuthReq req(pairingRequest->authReq);
147145
KeyDistribution responseKD = KeyDistribution();
148146
responseKD.setIdKey(true);
147+
148+
ATT.remoteKeyDistribution = responseKD;// KeyDistribution(pairingRequest->initiatorKeyDistribution);
149+
ATT.localKeyDistribution = responseKD; //KeyDistribution(pairingRequest->responderKeyDistribution);
150+
// KeyDistribution rkd(pairingRequest->responderKeyDistribution);
151+
AuthReq req(pairingRequest->authReq);
152+
149153
#ifdef _BLE_TRACE_
150154
Serial.print("Req has properties: ");
151155
Serial.print(req.Bonding()?"bonding, ":"no bonding, ");
@@ -173,7 +177,7 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
173177
uint8_t maxEncSize;
174178
uint8_t initiatorKeyDistribution;
175179
uint8_t responderKeyDistribution;
176-
} response = { CONNECTION_PAIRING_RESPONSE, LOCAL_IOCAP, 0, LOCAL_AUTHREQ, 0x10, responseKD.getOctet(), responseKD.getOctet()};
180+
} response = { CONNECTION_PAIRING_RESPONSE, LOCAL_IOCAP, 0, HCI.localAuthreq().getOctet(), 0x10, responseKD.getOctet(), responseKD.getOctet()};
177181

178182
HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(response), &response);
179183
}
@@ -305,7 +309,7 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
305309
uint8_t Eb[16];
306310
uint8_t R[16];
307311
uint8_t MasterIOCap[3];
308-
uint8_t SlaveIOCap[3] = {LOCAL_AUTHREQ, 0x0, LOCAL_IOCAP};
312+
uint8_t SlaveIOCap[3] = {HCI.localAuthreq().getOctet(), 0x0, LOCAL_IOCAP};
309313

310314
ATT.getPeerIOCap(connectionHandle, MasterIOCap);
311315
for(int i=0; i<16; i++) R[i] = 0;

0 commit comments

Comments
 (0)