Skip to content

Commit 83d11ed

Browse files
author
unknownconstant
authored
Merge pull request #16 from unknownconstant/secure-random
Secure random & reject unknown LTK
2 parents 283038f + fb2b817 commit 83d11ed

File tree

4 files changed

+136
-64
lines changed

4 files changed

+136
-64
lines changed

src/local/BLELocalDevice.h

+13-5
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,19 @@ class BLELocalDevice {
9191
virtual bool pairable();
9292
virtual bool paired();
9393

94-
/// TODO: Put in actual variable names
95-
virtual void setStoreIRK(int (*storeIRK)(uint8_t*, uint8_t*));
96-
virtual void setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs));
97-
virtual void setStoreLTK(int (*storeLTK)(uint8_t*, uint8_t*));
98-
virtual void setGetLTK(int (*getLTK)(uint8_t*, uint8_t*));
94+
// address - The mac to store
95+
// IRK - The IRK to store with this mac
96+
virtual void setStoreIRK(int (*storeIRK)(uint8_t* address, uint8_t* IRK));
97+
// nIRKs - the number of IRKs being provided.
98+
// BDAddrType - an array containing the type of each address (0 public, 1 static random)
99+
// BDAddrs - an array containing the list of addresses
100+
virtual void setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BDAddrType, uint8_t*** BDAddrs, uint8_t*** IRKs));
101+
// address - the address to store [6 bytes]
102+
// LTK - the LTK to store with this mac [16 bytes]
103+
virtual void setStoreLTK(int (*storeLTK)(uint8_t* address, uint8_t* LTK));
104+
// address - The mac address needing its LTK
105+
// LTK - 16 octet LTK for the mac address
106+
virtual void setGetLTK(int (*getLTK)(uint8_t* address, uint8_t* LTK));
99107
uint8_t BDaddress[6];
100108

101109
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 _BLE_TRACE_
2830

@@ -1141,50 +1143,63 @@ void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[])
11411143
// Load our LTK for this connection.
11421144
uint8_t peerAddr[7];
11431145
uint8_t resolvableAddr[6];
1146+
uint8_t foundLTK;
11441147
ATT.getPeerAddrWithType(ltkRequest->connectionHandle, peerAddr);
11451148

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

12591274

12601275
uint8_t Z = 0;
1261-
for(int i=0; i<16; i++){
1262-
/// TODO: Implement secure random
1263-
Nb[i] = rand(); //// Should use ESP or ECCx08
1264-
}
1276+
1277+
HCI.leRand(Nb);
1278+
HCI.leRand(&Nb[8]);
1279+
12651280
#ifdef _BLE_TRACE_
12661281
Serial.print("nb: ");
12671282
btct.printBytes(Nb, 16);
@@ -1413,6 +1428,47 @@ int HCIClass::leEncrypt(uint8_t* key, uint8_t* plaintext, uint8_t* status, uint8
14131428
#endif
14141429
return res;
14151430
}
1431+
int HCIClass::leRand(uint8_t rand[]){
1432+
int res = sendCommand(OGF_LE_CTL << 10 | LE_COMMAND::RANDOM);
1433+
if(res == 0){
1434+
memcpy(rand,_cmdResponse, 8); /// backwards but it's a random number
1435+
}
1436+
return res;
1437+
}
1438+
int HCIClass::getLTK(uint8_t* address, uint8_t* LTK){
1439+
if(_getLTK!=0){
1440+
return _getLTK(address, LTK);
1441+
}else{
1442+
return 0;
1443+
}
1444+
}
1445+
int HCIClass::storeIRK(uint8_t* address, uint8_t* IRK){
1446+
if(_storeIRK!=0){
1447+
return _storeIRK(address, IRK);
1448+
}else{
1449+
return 0;
1450+
}
1451+
}
1452+
int HCIClass::storeLTK(uint8_t* address, uint8_t* LTK){
1453+
if(_storeLTK!=0){
1454+
return _storeLTK(address, LTK);
1455+
}else{
1456+
return 0;
1457+
}
1458+
}
1459+
1460+
/// Stub function to generate parameters for local authreq
1461+
AuthReq HCIClass::localAuthreq(){
1462+
// If get, set, IRK, LTK all set then we can bond.
1463+
AuthReq local = AuthReq();
1464+
if(_storeIRK!=0 && _storeLTK!=0 && _getLTK!=0 && _getIRKs!=0){
1465+
local.setBonding(true);
1466+
}
1467+
local.setSC(true);
1468+
local.setMITM(true);
1469+
local.setCT2(true);
1470+
return LOCAL_AUTHREQ;
1471+
}
14161472

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

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
#include "L2CAPSignaling.h"
2627

@@ -31,11 +32,13 @@
3132
#define OGF_LE_CTL 0x08
3233

3334
enum LE_COMMAND {
34-
ENCRYPT = 0x0017,
35-
LONG_TERM_KEY_REPLY = 0x001A,
36-
READ_LOCAL_P256 = 0x0025,
37-
GENERATE_DH_KEY_V1 = 0x0026,
38-
GENERATE_DH_KEY_V2 = 0x005E
35+
ENCRYPT = 0x0017,
36+
RANDOM = 0x0018,
37+
LONG_TERM_KEY_REPLY = 0x001A,
38+
LONG_TERM_KEY_NEGATIVE_REPLY = 0x1B,
39+
READ_LOCAL_P256 = 0x0025,
40+
GENERATE_DH_KEY_V1 = 0x0026,
41+
GENERATE_DH_KEY_V2 = 0x005E
3942
};
4043
enum LE_META_EVENT {
4144
CONN_COMPLETE = 0x01,
@@ -91,6 +94,9 @@ class HCIClass {
9194
uint16_t latency, uint16_t supervisionTimeout);
9295
virtual int leCancelConn();
9396
virtual int leEncrypt(uint8_t* Key, uint8_t* plaintext, uint8_t* status, uint8_t* ciphertext);
97+
// Generate a 64 bit random number
98+
virtual int leRand(uint8_t rand[]);
99+
virtual AuthReq localAuthreq();
94100

95101
virtual int saveNewAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);
96102
virtual int leAddResolvingAddress(uint8_t addressType, uint8_t* address, uint8_t* peerIrk, uint8_t* remoteIrk);
@@ -110,7 +116,7 @@ class HCIClass {
110116
virtual void debug(Stream& stream);
111117
virtual void noDebug();
112118

113-
// TODO: Send command be private again & use ATT implementation within ATT.
119+
// TODO: Send command be private again & use ATT implementation of send command within ATT.
114120
virtual int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL);
115121
uint8_t remotePublicKeyBuffer[64];
116122
uint8_t remoteDHKeyCheckBuffer[16];
@@ -119,11 +125,13 @@ class HCIClass {
119125
uint8_t DHKey[32];
120126
uint8_t localAddr[6];
121127
uint8_t LTK[16];
122-
123-
int (*_storeIRK)(uint8_t* address, uint8_t* peerIrk);
124-
int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs);
125-
int (*_storeLTK)(uint8_t*, uint8_t*);
126-
int (*_getLTK)(uint8_t*, uint8_t*);
128+
virtual int getLTK(uint8_t* address, uint8_t* LTK);
129+
virtual int storeLTK(uint8_t* address, uint8_t* LTK);
130+
virtual int storeIRK(uint8_t* address, uint8_t* IRK);
131+
int (*_storeIRK)(uint8_t* address, uint8_t* peerIrk) = 0;
132+
int (*_getIRKs)(uint8_t* nIRKs,uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs) = 0;
133+
int (*_storeLTK)(uint8_t*, uint8_t*) = 0;
134+
int (*_getLTK)(uint8_t*, uint8_t*) = 0;
127135

128136
private:
129137

src/utility/L2CAPSignaling.cpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
L2CAPSignalingClass::L2CAPSignalingClass() :
3232
_minInterval(0),
3333
_maxInterval(0),
34-
_supervisionTimeout(0)
35-
,_pairing_enabled(1)
34+
_supervisionTimeout(0),
35+
_pairing_enabled(1)
3636
{
3737
}
3838

@@ -145,14 +145,14 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
145145
uint8_t initiatorKeyDistribution;
146146
uint8_t responderKeyDistribution;
147147
} *pairingRequest = (PairingRequest*)l2capSignalingHdr->data;
148-
149-
150-
ATT.remoteKeyDistribution = KeyDistribution(pairingRequest->initiatorKeyDistribution);
151-
ATT.localKeyDistribution = KeyDistribution(pairingRequest->responderKeyDistribution);
152-
KeyDistribution rkd(pairingRequest->responderKeyDistribution);
153-
AuthReq req(pairingRequest->authReq);
148+
154149
KeyDistribution responseKD = KeyDistribution();
155150
responseKD.setIdKey(true);
151+
152+
ATT.remoteKeyDistribution = responseKD;// KeyDistribution(pairingRequest->initiatorKeyDistribution);
153+
ATT.localKeyDistribution = responseKD; //KeyDistribution(pairingRequest->responderKeyDistribution);
154+
// KeyDistribution rkd(pairingRequest->responderKeyDistribution);
155+
AuthReq req(pairingRequest->authReq);
156156
#ifdef _BLE_TRACE_
157157
Serial.print("Req has properties: ");
158158
Serial.print(req.Bonding()?"bonding, ":"no bonding, ");
@@ -180,7 +180,7 @@ void L2CAPSignalingClass::handleSecurityData(uint16_t connectionHandle, uint8_t
180180
uint8_t maxEncSize;
181181
uint8_t initiatorKeyDistribution;
182182
uint8_t responderKeyDistribution;
183-
} response = { CONNECTION_PAIRING_RESPONSE, LOCAL_IOCAP, 0, LOCAL_AUTHREQ, 0x10, responseKD.getOctet(), responseKD.getOctet()};
183+
} response = { CONNECTION_PAIRING_RESPONSE, LOCAL_IOCAP, 0, HCI.localAuthreq().getOctet(), 0x10, responseKD.getOctet(), responseKD.getOctet()};
184184

185185
HCI.sendAclPkt(connectionHandle, SECURITY_CID, sizeof(response), &response);
186186

@@ -338,7 +338,7 @@ void L2CAPSignalingClass::smCalculateLTKandConfirm(uint16_t handle, uint8_t expe
338338
uint8_t Eb[16];
339339
uint8_t R[16];
340340
uint8_t MasterIOCap[3];
341-
uint8_t SlaveIOCap[3] = {LOCAL_AUTHREQ, 0x0, LOCAL_IOCAP};
341+
uint8_t SlaveIOCap[3] = {HCI.localAuthreq().getOctet(), 0x0, LOCAL_IOCAP};
342342

343343
ATT.getPeerIOCap(handle, MasterIOCap);
344344
for(int i=0; i<16; i++) R[i] = 0;

0 commit comments

Comments
 (0)