From d2d764240dd2166dedd1bc9caa6111339c0f291c Mon Sep 17 00:00:00 2001
From: "matthias.ringwald@gmail.com"
 <matthias.ringwald@gmail.com@1a0a8af8-31b5-11de-8e0c-53a27eea117e>
Date: Mon, 2 Mar 2015 21:12:29 +0000
Subject: [PATCH] add encryption info to central db

---
 ble/att_server.c               |  6 ++--
 ble/central_device_db.h        | 50 +++++++++++++++++++++++++++++----
 ble/central_device_db_dummy.c  | 34 ++++++++++++++++++++---
 ble/central_device_db_memory.c | 51 +++++++++++++++++++++++++++++-----
 ble/sm.c                       | 35 +++++++++++++++++------
 5 files changed, 149 insertions(+), 27 deletions(-)

diff --git a/ble/att_server.c b/ble/att_server.c
index 2bb3319d6..f98c668ed 100644
--- a/ble/att_server.c
+++ b/ble/att_server.c
@@ -203,7 +203,7 @@ static void att_signed_write_handle_cmac_result(uint8_t hash[8]){
 
     // update sequence number
     uint32_t counter_packet = READ_BT_32(att_request_buffer, att_request_size-12);
-    central_device_db_counter_set(att_ir_central_device_db_index, counter_packet+1);
+    central_device_db_remote_counter_set(att_ir_central_device_db_index, counter_packet+1);
     att_server_state = ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED;
     att_run();
 }
@@ -237,7 +237,7 @@ static void att_run(void){
 
                 // check counter
                 uint32_t counter_packet = READ_BT_32(att_request_buffer, att_request_size-12);
-                uint32_t counter_db     = central_device_db_counter_get(att_ir_central_device_db_index);
+                uint32_t counter_db     = central_device_db_remote_counter_get(att_ir_central_device_db_index);
                 log_info("ATT Signed Write, DB counter %u, packet counter %u", counter_db, counter_packet);
                 if (counter_packet < counter_db){
                     log_info("ATT Signed Write, db reports higher counter, abort");
@@ -247,7 +247,7 @@ static void att_run(void){
 
                 // signature is { sequence counter, secure hash }
                 sm_key_t csrk;
-                central_device_db_csrk(att_ir_central_device_db_index, csrk);
+                central_device_db_csrk_get(att_ir_central_device_db_index, csrk);
                 att_server_state = ATT_SERVER_W4_SIGNED_WRITE_VALIDATION;
                 log_info("Orig Signature: ");
                 hexdump( &att_request_buffer[att_request_size-8], 8);
diff --git a/ble/central_device_db.h b/ble/central_device_db.h
index 8b7a57bbb..621deca4c 100644
--- a/ble/central_device_db.h
+++ b/ble/central_device_db.h
@@ -69,10 +69,10 @@ void central_device_db_init();
 /**
  * @brief add device to db
  * @param addr_type, address of the device
- * @param irk and csrk of the device
+ * @param irk of the device
  * @returns index if successful, -1 otherwise
  */
-int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk, sm_key_t csrk);
+int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk);
 
 /**
  * @brief get number of devices in db for enumeration
@@ -88,26 +88,66 @@ int central_device_db_count(void);
  */
 void central_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t irk);
 
+
+/**
+ * @brief set remote encryption info
+ * @brief index
+ * @brief ediv 
+ * @brief rand
+ * @brief ltk
+ */
+void central_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_key_t ltk);
+
+/**
+ * @brief get remote encryption info
+ * @brief index
+ * @brief ediv 
+ * @brief rand
+ * @brief ltk
+ */
+void central_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk);
+
+/**
+ * @brief set signing key for this device
+ * @param index
+ * @param signing key as input
+ */
+void central_device_db_csrk_set(int index, sm_key_t csrk);
+
 /**
  * @brief get signing key for this device
  * @param index
  * @param signing key as output
  */
-void central_device_db_csrk(int index, sm_key_t csrk);
+void central_device_db_csrk_get(int index, sm_key_t csrk);
 
 /**
  * @brief query last used/seen signing counter
  * @param index
  * @returns next expected counter, 0 after devices was added
  */
-uint32_t central_device_db_counter_get(int index);
+uint32_t central_device_db_remote_counter_get(int index);
 
 /**
  * @brief update signing counter
  * @param index
  * @param counter to store
  */
-void central_device_db_counter_set(int index, uint32_t counter);
+void central_device_db_remote_counter_set(int index, uint32_t counter);
+
+/**
+ * @brief query last used/seen signing counter
+ * @param index
+ * @returns next expected counter, 0 after devices was added
+ */
+uint32_t central_device_db_local_counter_get(int index);
+
+/**
+ * @brief update signing counter
+ * @param index
+ * @param counter to store
+ */
+void central_device_db_local_counter_set(int index, uint32_t counter);
 
 /**
  * @brief free device
diff --git a/ble/central_device_db_dummy.c b/ble/central_device_db_dummy.c
index ae1dcbe59..6af63bb14 100644
--- a/ble/central_device_db_dummy.c
+++ b/ble/central_device_db_dummy.c
@@ -40,7 +40,7 @@
 void central_device_db_init(){}
 
 // @returns index if successful, -1 otherwise
-int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk, sm_key_t csrk){
+int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk){
 	return -1;
 }
 
@@ -49,19 +49,45 @@ int central_device_db_count(void){
 	return 0;
 }
 
+/**
+ * @brief set remote encryption info
+ * @brief index
+ * @brief ediv 
+ * @brief rand
+ * @brief ltk
+ */
+void central_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_key_t ltk){}
+
+/**
+ * @brief get remote encryption info
+ * @brief index
+ * @brief ediv 
+ * @brief rand
+ * @brief ltk
+ */
+void central_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk){}
+
 // get device information: addr type and address
 void central_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t csrk){}
 
 // get signature key
-void central_device_db_csrk(int index, sm_key_t csrk){}
+void central_device_db_csrk_get(int index, sm_key_t csrk){}
 
 // query last used/seen signing counter
-uint32_t central_device_db_counter_get(int index){ 
+uint32_t central_device_db_remote_counter_get(int index){ 
 	return 0xffffffff;
 }
 
 // update signing counter
-void central_device_db_counter_set(int index, uint32_t counter){}
+void central_device_db_local_counter_set(int index, uint32_t counter){}
+
+// query last used/seen signing counter
+uint32_t central_device_db_local_counter_get(int index){ 
+	return 0xffffffff;
+}
+
+// update signing counter
+void central_device_db_remote_counter_set(int index, uint32_t counter){}
 
 // free device
 void central_device_db_remove(int index){}
diff --git a/ble/central_device_db_memory.c b/ble/central_device_db_memory.c
index a8904e4be..d4e756adf 100644
--- a/ble/central_device_db_memory.c
+++ b/ble/central_device_db_memory.c
@@ -86,12 +86,12 @@ int central_device_db_count(void){
     return counter;
 }
 
-// free device - TODO not implemented
+// free device
 void central_device_db_remove(int index){
     central_devices[index].addr_type = INVALID_ENTRY_ADDR_TYPE;
 }
 
-int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk, sm_key_t csrk){
+int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk){
     int i;
     int index = -1;
     for (i=0;i<CENTRAL_DEVICE_MEMORY_SIZE;i++){
@@ -105,11 +105,9 @@ int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk, sm_key_t
 
     log_info("Central Device DB adding type %u - %s", addr_type, bd_addr_to_str(addr));
     log_key("irk", irk);
-    log_key("csrk", csrk);
 
     central_devices[index].addr_type = addr_type;
     memcpy(central_devices[index].addr, addr, 6);
-    memcpy(central_devices[index].csrk, csrk, 16);
     memcpy(central_devices[index].irk, irk, 16);
     central_devices[index].remote_counter = 0; 
 
@@ -124,22 +122,61 @@ void central_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t
     if (irk) memcpy(irk, central_devices[index].irk, 16);
 }
 
+/**
+ * @brief set remote encryption info
+ * @brief index
+ * @brief ediv 
+ * @brief rand
+ * @brief ltk
+ */
+void central_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_key_t ltk){
+    central_devices[index].ediv = ediv;
+    if (rand) memcpy(central_devices[index].rand, rand, 8);
+    if (ltk) memcpy(central_devices[index].ltk, ltk, 16);
+}
+
+/**
+ * @brief get remote encryption info
+ * @brief index
+ * @brief ediv 
+ * @brief rand
+ * @brief ltk
+ */
+void central_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk){
+    if (ediv) *ediv = central_devices[index].ediv;
+    if (rand) memcpy(rand, central_devices[index].rand, 8);
+    if (ltk)  memcpy(ltk, central_devices[index].ltk, 16);    
+}
+
 // get signature key
-void central_device_db_csrk(int index, sm_key_t csrk){
+void central_device_db_csrk_get(int index, sm_key_t csrk){
     if (csrk) memcpy(csrk, central_devices[index].csrk, 16);
 }
 
+void central_device_db_csrk_set(int index, sm_key_t csrk){
+    if (csrk) memcpy(central_devices[index].csrk, csrk, 16);
+}
 
 // query last used/seen signing counter
-uint32_t central_device_db_counter_get(int index){
+uint32_t central_device_db_remote_counter_get(int index){
     return central_devices[index].remote_counter;
 }
 
 // update signing counter
-void central_device_db_counter_set(int index, uint32_t counter){
+void central_device_db_remote_counter_set(int index, uint32_t counter){
     central_devices[index].remote_counter = counter;
 }
 
+// query last used/seen signing counter
+uint32_t central_device_db_local_counter_get(int index){
+    return central_devices[index].local_counter;
+}
+
+// update signing counter
+void central_device_db_local_counter_set(int index, uint32_t counter){
+    central_devices[index].local_counter = counter;
+}
+
 void central_device_db_dump(){
     log_info("Central Device DB dump, devices: %u", central_device_db_count);
     int i;
diff --git a/ble/sm.c b/ble/sm.c
index 563a0ab19..1fe807632 100644
--- a/ble/sm.c
+++ b/ble/sm.c
@@ -215,8 +215,10 @@ typedef struct sm_setup_context {
     uint8_t   sm_peer_rand[8];
     sm_key_t  sm_peer_ltk;
     sm_key_t  sm_peer_irk;
+    sm_key_t  sm_peer_csrk;
     uint8_t   sm_peer_addr_type;
     bd_addr_t sm_peer_address;
+
 } sm_setup_context_t;
 
 // 
@@ -1579,6 +1581,7 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
                             sm_conn->sm_connection_encrypted = 0;
                             sm_conn->sm_connection_authenticated = 0;
                             sm_conn->sm_connection_authorization_state = AUTHORIZATION_UNKNOWN;
+                            sm_conn->sm_central_db_index = -1;
 
                             // prepare CSRK lookup (does not involve setup)
                             sm_conn->sm_csrk_lookup_state = CSRK_LOOKUP_W4_READY;
@@ -1733,7 +1736,6 @@ static void sm_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *pac
 
     log_debug("sm_packet_handler: state %u, pdu 0x%02x", sm_conn->sm_engine_state, packet[0]);
 
-    sm_key_t csrk;
     int err;
 
     switch (sm_conn->sm_engine_state){
@@ -1869,13 +1871,7 @@ static void sm_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *pac
 
                 case SM_CODE_SIGNING_INFORMATION:
                     setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
-                    swap128(&packet[1], csrk);
-
-                    // store, if: it's a public address, or, we got an IRK
-                    if (setup->sm_peer_addr_type == 0 || (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION)) {
-                        sm_central_device_matched =  central_device_db_add(setup->sm_peer_addr_type, setup->sm_peer_address, setup->sm_peer_irk, csrk);
-                        break;
-                    } 
+                    swap128(&packet[1], setup->sm_peer_csrk);
                     break;
                 default:
                     // Unexpected PDU
@@ -1884,6 +1880,29 @@ static void sm_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *pac
             }     
             // done with key distribution?         
             if (sm_key_distribution_all_received()){
+
+                // store, if: it's a public address, or, we got an IRK
+                if (setup->sm_peer_addr_type == 0 || (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION)) {
+                    sm_conn->sm_central_db_index = central_device_db_add(setup->sm_peer_addr_type, setup->sm_peer_address, setup->sm_peer_irk);
+                } 
+
+                if (sm_conn->sm_central_db_index >= 0){
+                    central_device_db_local_counter_set(sm_conn->sm_central_db_index, 0);
+                    
+                    // store CSRK
+                    if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
+                        central_device_db_csrk_set(sm_conn->sm_central_db_index, setup->sm_peer_csrk);
+                        central_device_db_remote_counter_set(sm_conn->sm_central_db_index, 0);
+                    }
+
+                    // store encryption information as Central
+                    if (sm_conn->sm_role == 0
+                        && setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION   
+                        && setup->sm_key_distribution_received_set &  SM_KEYDIST_FLAG_MASTER_IDENTIFICATION){
+                        central_device_db_encryption_set(sm_conn->sm_central_db_index, setup->sm_peer_ediv, setup->sm_peer_rand, setup->sm_peer_ltk);
+                    }                
+                }
+
                 if (sm_conn->sm_role){
                     sm_conn->sm_engine_state = SM_GENERAL_IDLE; 
                     sm_done_for_handle(sm_conn->sm_handle);