first commit

This commit is contained in:
valeh
2020-12-22 14:30:09 +02:00
commit 26b0ba5954
1832 changed files with 17777948 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
/**
* @file AuthorizationController.cpp
* @brief AuthorizationController implementation file
* */
#include "cJSON.h"
#include "controller.h"
#include "module.h"
AuthorizationController::AuthorizationController(BaseModel *model, const char* sni){
this->model = static_cast<UserModel *>(model);
this->sni = sni;
this->vw = new IndexView();
}
char* AuthorizationController::generateAuthenticateRequestJSON(){
cJSON *root, *params, *param;
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "id", 0.0);
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.Authenticate"));
params = cJSON_CreateArray();
cJSON_AddItemToObject(root, "params", params);
cJSON_AddItemToArray(params, param = cJSON_CreateObject());
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
cJSON_AddStringToObject(param, "PhoneNo", this->model->phone);
cJSON_AddStringToObject(param, "IDCode", this->model->ID);
char* pretty = cJSON_Print(root);
cJSON_Delete(root);
return pretty;
}
char* AuthorizationController::generateAuthenticateStatusRequestJSON(){
cJSON *root, *params, *param;
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "id", 0.0);
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.AuthenticateStatus"));
params = cJSON_CreateArray();
cJSON_AddItemToObject(root, "params", params);
cJSON_AddItemToArray(params, param = cJSON_CreateObject());
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
cJSON_AddStringToObject(param, "SessionCode", this->model->sscode);
char* pretty = cJSON_Print(root);
cJSON_Delete(root);
return pretty;
}
void AuthorizationController::index(){
this->vw->render((char *) "Authorization");
}
void AuthorizationController::auth(){
try{
// Start mobilID Authentication
ESP_LOGI(TAG, "authorization request sent");
cJSON *authJson = RPC::Instance().send_json_rpc(sni, generateAuthenticateRequestJSON());
if(authJson == NULL){
throw "Empty response";
}
if( cJSON_GetObjectItem(authJson, "error")->valuestring != NULL){
throw cJSON_GetObjectItem(authJson, "error")->valuestring;
}
cJSON* params = cJSON_GetObjectItem(authJson, "result");
int len = strlen(cJSON_GetObjectItem(params, "SessionID")->valuestring);
this->model->ssid = (char *) malloc(len +1);
memset(this->model->ssid, 0, len + 1);
memcpy(this->model->ssid, cJSON_GetObjectItem(params, "SessionID")->valuestring, len);
len = strlen(cJSON_GetObjectItem(params, "SessionCode")->valuestring);
this->model->sscode = (char *) malloc(len +1);
memset(this->model->sscode, 0, len + 1);
memcpy(this->model->sscode, cJSON_GetObjectItem(params, "SessionCode")->valuestring, len);
char pin[25];
bzero(pin, 25);
strncat(pin, "Verification code: ", 20);
strncat(pin, cJSON_GetObjectItem(params, "ChallengeID")->valuestring, 5);
cJSON_Delete(authJson);
this->vw->render(pin);
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}
void AuthorizationController::authStatus(){
try{
char* authStatusReq = generateAuthenticateStatusRequestJSON();
cJSON * result, * authJson;
do{
ESP_LOGI(TAG, "waiting to confirm verification code");
for(int i=10; i>0; i--){
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
// Check authentication status
ESP_LOGI(TAG, "authorization status request sent");
authJson = RPC::Instance().send_json_rpc(sni, authStatusReq );
if(authJson == NULL){
throw "Empty response";
}
result = cJSON_GetObjectItem(authJson, "result");
if( cJSON_GetObjectItem(authJson, "error")->valuestring != NULL){
throw cJSON_GetObjectItem(authJson, "error")->valuestring;
}
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "POLL") == 0){
continue;
}
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "OK") == 0){
int len = strlen(cJSON_GetObjectItem(result, "AuthToken")->valuestring);
this->model->authToken = (char *)malloc(len + 1);
memset(this->model->authToken, 0, len + 1);
memcpy(this->model->authToken, cJSON_GetObjectItem(result, "AuthToken")->valuestring, len);
this->vw->render((char *) "PIN CONFIRMED!");
break;
}
cJSON_free(authJson);
}
while(1);
cJSON_Delete(authJson);
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}

View File

@@ -0,0 +1,430 @@
#include "controller.h"
#include "view.h"
#include "module.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
/**
* @file BluetoothController.cpp
* @brief BluetoothController implementation file
* */
#define GATTS_SERVICE_UUID_TEST_A 0x00FF
#define GATTS_CHAR_UUID_TEST_A 0xFF01
#define GATTS_DESCR_UUID_TEST_A 0x3333
#define GATTS_NUM_HANDLE_TEST_A 4
#define DEVICE_NAME "ESP_BOARD"
#define TEST_MANUFACTURER_DATA_LEN 17
#define GATTS_TAG "GATTS"
#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40
#define PREPARE_BUF_MAX_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)
static uint8_t char1_str[] = {0x11,0x22,0x33};
#ifdef CONFIG_SET_RAW_ADV_DATA
static uint8_t raw_adv_data[] = {
0x02, 0x01, 0x06,
0x02, 0x0a, 0xeb, 0x03, 0x03, 0xab, 0xcd
};
static uint8_t raw_scan_rsp_data[] = {
0x0f, 0x09, 0x45, 0x53, 0x50, 0x5f, 0x47, 0x41, 0x54, 0x54, 0x53, 0x5f, 0x44,
0x45, 0x4d, 0x4f
};
#else
static uint8_t adv_service_uuid128[16] = {
/* LSB <--------------------------------------------------------------------------------> MSB */
//first uuid, 16bit, [12],[13] is the value
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00
};
// The length of adv data must be less than 31 bytes
//static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56};
//adv data
static esp_ble_adv_data_t adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = true,
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
.appearance = 0x00,
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
.p_manufacturer_data = NULL, //&test_manufacturer[0],
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = sizeof(adv_service_uuid128),
.p_service_uuid = adv_service_uuid128,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
// scan response data
static esp_ble_adv_data_t scan_rsp_data = {
.set_scan_rsp = true,
.include_name = true,
.include_txpower = true,
.min_interval = 0x0006,
.max_interval = 0x0010,
.appearance = 0x00,
.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
.p_manufacturer_data = NULL, //&test_manufacturer[0],
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = sizeof(adv_service_uuid128),
.p_service_uuid = adv_service_uuid128,
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
#endif /* CONFIG_SET_RAW_ADV_DATA */
#define adv_config_flag (1 << 0)
#define scan_rsp_config_flag (1 << 1)
#define PROFILE_A_APP_ID 0
struct gatts_profile_inst {
esp_gatts_cb_t gatts_cb;
uint16_t gatts_if;
uint16_t app_id;
uint16_t conn_id;
uint16_t service_handle;
esp_gatt_srvc_id_t service_id;
uint16_t char_handle;
esp_bt_uuid_t char_uuid;
esp_gatt_perm_t perm;
esp_gatt_char_prop_t property;
uint16_t descr_handle;
esp_bt_uuid_t descr_uuid;
char* data;
};
enum
{
OVC_IDX_SVC,
OVC_IDX_VVC_CHAR,
OVC_IDX_VVC_VAL,
OVC_IDX_VVC_USR_DESC,
OVC_IDX_VVC_NTF_CFG,
OVC_IDX_NB,
};
static const uint16_t ovc_svc = GATTS_SERVICE_UUID_TEST_A;
#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint16_t character_client_description_uuid = ESP_GATT_UUID_CHAR_DESCRIPTION;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
/// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify
static const uint16_t vote_verification_svc_uuid = GATTS_CHAR_UUID_TEST_A;
static const uint8_t vote_verification_ccc[2] ={ 0x01, 0x01};
static uint16_t ovc_handle_table[OVC_IDX_NB];
static esp_gatts_attr_db_t attr_db[OVC_IDX_NB] = {
// Heart Rate Service Declaration
[OVC_IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ_ENC_MITM,
sizeof(uint16_t), sizeof(ovc_svc), (uint8_t *)&ovc_svc}},
// Vote Verification Characteristic Declaration
[OVC_IDX_VVC_CHAR] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ_ENC_MITM,
CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
// Vote Verification Characteristic Value
[OVC_IDX_VVC_VAL] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&vote_verification_svc_uuid, ESP_GATT_PERM_READ_ENC_MITM,
32,3, char1_str}},
// Vote Verification Characteristic User Descriptor
[OVC_IDX_VVC_USR_DESC] =
{{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_description_uuid, ESP_GATT_PERM_READ_ENC_MITM,
600, 0, NULL}},
// Vote Verification Characteristic - Client Characteristic Configuration Descriptor
[OVC_IDX_VVC_NTF_CFG] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ_ENC_MITM|ESP_GATT_PERM_WRITE_ENC_MITM,
sizeof(uint16_t),sizeof(vote_verification_ccc), (uint8_t *)vote_verification_ccc}},
};
static BLEModule ble;
static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
static struct gatts_profile_inst PROFILE_A_APP;
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
/* If event is register event, store the gatts_if for each profile */
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK && param->reg.app_id == PROFILE_A_APP_ID) {
PROFILE_A_APP.gatts_if = gatts_if;
} else {
ESP_LOGI(GATTS_TAG, "Reg app failed, app_id %04x, status %d\n", param->reg.app_id, param->reg.status);
return;
}
}
/* If the gatts_if equal to profile A, call profile A cb handler,
* so here call each profile's callback */
do {
if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
gatts_if == PROFILE_A_APP.gatts_if) {
if (PROFILE_A_APP.gatts_cb) {
PROFILE_A_APP.gatts_cb(event, gatts_if, param);
}
}
} while (0);
}
static uint8_t BT_ON = 0;
static uint8_t data_sent = 0;
uint16_t mtuVal = 23;
static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
switch (event) {
case ESP_GATTS_REG_EVT:{
ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id);
esp_err_t set_dev_name_ret;
set_dev_name_ret = esp_ble_gap_set_device_name(DEVICE_NAME);
if (set_dev_name_ret){
ESP_LOGE(GATTS_TAG, "set device name failed, error code = %x", set_dev_name_ret);
}
esp_ble_gap_config_local_privacy(true);
attr_db[OVC_IDX_VVC_USR_DESC].att_desc.length = (uint16_t) strlen( PROFILE_A_APP.data);
attr_db[OVC_IDX_VVC_USR_DESC].att_desc.value = (uint8_t *) PROFILE_A_APP.data;
esp_ble_gatts_create_attr_tab(attr_db, gatts_if, OVC_IDX_NB, PROFILE_A_APP_ID);
break;
}
case ESP_GATTS_READ_EVT:{
ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle);
esp_gatt_rsp_t rsp;
memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
rsp.attr_value.handle = param->read.handle;
size_t len = MIN(mtuVal -1, strlen(PROFILE_A_APP.data) - param->read.offset);
rsp.attr_value.len = len ;
printf("%d %d %d %d %d\n", len, rsp.attr_value.len, rsp.attr_value.offset, param->read.offset, param->read.is_long);
memcpy(rsp.attr_value.value, PROFILE_A_APP.data + param->read.offset, len);
esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
break;
}
case ESP_GATTS_WRITE_EVT:{
ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d", param->write.conn_id, param->write.trans_id, param->write.handle);
if (!param->write.is_prep){
ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value :", param->write.len);
esp_log_buffer_hex(GATTS_TAG, param->write.value, param->write.len);
ESP_LOGI(GATTS_TAG, "%u %u", PROFILE_A_APP.descr_handle, param->write.handle);
if (param->write.len == 2){
uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
printf("%d %04x \n", *(param->write.value), descr_value);
if(descr_value == 0x0101){
ESP_LOGI(GATTS_TAG, "data received");
esp_err_t ret;
data_sent = 1;
ret = esp_ble_gap_disconnect(param->write.bda);
if(ret != ESP_OK){
ESP_LOGE(GATTS_TAG, "unable to disconnect the device");
}
}else{
ESP_LOGE(GATTS_TAG, "unallowed operations");
esp_log_buffer_hex(GATTS_TAG, param->write.value, param->write.len);
}
}
}
break;
}
case ESP_GATTS_EXEC_WRITE_EVT:
break;
case ESP_GATTS_MTU_EVT:
mtuVal = param->mtu.mtu;
ESP_LOGI(GATTS_TAG, "ESP_GATTS_MTU_EVT, MTU %d", mtuVal);
break;
case ESP_GATTS_UNREG_EVT:
break;
case ESP_GATTS_CREATE_EVT:{
ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle);
break;
}
case ESP_GATTS_ADD_INCL_SRVC_EVT:
break;
case ESP_GATTS_ADD_CHAR_EVT: {
uint16_t length = 0;
const uint8_t *prf_char;
ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n",
param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
break;
}
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n",
param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
break;
case ESP_GATTS_DELETE_EVT:
break;
case ESP_GATTS_START_EVT:
ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n",
param->start.status, param->start.service_handle);
break;
case ESP_GATTS_STOP_EVT:
break;
case ESP_GATTS_CONNECT_EVT: {
//start sent the update connection parameters to the peer device.
// esp_ble_gap_update_conn_params(&conn_params);
esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM);
break;
}
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(GATTS_TAG, "ESP_GATTS_DISCONNECT_EVT, disconnect reason 0x%x", param->disconnect.reason);
if(!data_sent)
esp_ble_gap_start_advertising(ble.adv);
else
BT_ON=1;
break;
case ESP_GATTS_CONF_EVT:
ESP_LOGI(GATTS_TAG, "ESP_GATTS_CONF_EVT, status %d attr_handle %d", param->conf.status, param->conf.handle);
if (param->conf.status != ESP_GATT_OK){
esp_log_buffer_hex(GATTS_TAG, param->conf.value, param->conf.len);
}
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT: {
ESP_LOGI(GATTS_TAG, "The number handle = %x",param->add_attr_tab.num_handle);
if (param->create.status == ESP_GATT_OK){
if(param->add_attr_tab.num_handle == OVC_IDX_NB) {
memcpy(ovc_handle_table, param->add_attr_tab.handles, sizeof(ovc_handle_table));
esp_ble_gatts_start_service(ovc_handle_table[OVC_IDX_SVC]);
}else{
ESP_LOGE(GATTS_TAG, "Create attribute table abnormally, num_handle (%d) doesn't equal to OVC_IDX_NB(%d)",
param->add_attr_tab.num_handle, OVC_IDX_NB);
}
}else{
ESP_LOGE(GATTS_TAG, " Create attribute table failed, error code = %x", param->create.status);
}
}
break;
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
case ESP_GATTS_SEND_SERVICE_CHANGE_EVT:
default:
break;
}
}
BluetoothController::BluetoothController(BaseModel *model){
this->vw = new IndexView();
this->model = static_cast<BluetoothModel *>(model);
}
void BluetoothController::index(){
try{
ble = BLEModule();
esp_err_t ret = ble.init(); //! * init bluetooth module, and start advertising
this->vw->render((void*) "bluetooth on");
BT_ON = 1;
PROFILE_A_APP.gatts_cb = gatts_profile_a_event_handler;
PROFILE_A_APP.gatts_if = ESP_GATT_IF_NONE; /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
ret = esp_ble_gatts_register_callback(gatts_event_handler); //! * register callback function for bletooth events
if (ret){
ESP_LOGE(TAG, "gatts register error, error code = %x", ret);
throw "TAG error";
}
size_t len = strlen(this->model->ssid) + strlen(this->model->voteID) + strlen((char *)this->model->rndBase64) + 3;
PROFILE_A_APP.data = (char *) malloc(len);
memset(PROFILE_A_APP.data, 0 , len);
snprintf(PROFILE_A_APP.data, len, "%s\n%s\n%s",this->model->ssid,this->model->rndBase64,this->model->voteID); //! * prepare data to send
ret = esp_ble_gatts_app_register(PROFILE_A_APP_ID); //! * register app profile
if (ret){
ESP_LOGE(TAG, "gatts app register error, error code = %x", ret);
throw "BLE error";
}
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
if (local_mtu_ret){
ESP_LOGE(TAG, "set local MTU failed, error code = %x", local_mtu_ret);
throw "BLE error";
}
/* set the security iocap & auth_req & key size & init key response key parameters to the stack*/
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM; //bonding with peer device after authentication
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to No output No input
uint8_t key_size = 16; //the key size should be 7~16 bytes
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
//set static passkey
uint32_t passkey = esp_random() % 999999;
char bt_pin[8];
snprintf(bt_pin, 7, "%06u", passkey);
this->vw->render((void *) bt_pin);
uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE;
uint8_t oob_support = ESP_BLE_OOB_DISABLE;
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
/* If your BLE device acts as a Slave, the init_key means you hope which types of key of the master should distribute to you,
and the response key means which key you can distribute to the master;
If your BLE device acts as a master, the response key means you hope which types of key of the slave should distribute to you,
and the init key means which key you can distribute to the slave. */
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
while(BT_ON && !data_sent){
vTaskDelay(500 / portTICK_PERIOD_MS); //! * wait while bluetooth task is running
}
ret = esp_ble_gatts_app_unregister(PROFILE_A_APP_ID);
if(ret != ESP_OK){
ESP_LOGE(GATTS_TAG, "unable to unregister the app profile");
}
ESP_LOGI(GATTS_TAG, "gatt server disconnected.");
ret = ble.deinit(); //! * turn off bluetooth
this->vw->render((void*) "bluetooth off");
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}

View File

@@ -0,0 +1,118 @@
/**
* @file ChoiceController.cpp
* @brief ChoiceController implementation file
* */
#include "cJSON.h"
#include "controller.h"
ChoiceController::ChoiceController(BaseModel *model, const char* sni){
this->vw = new ChoiceView();
this->model = static_cast<ChoiceModel*>(model);
this->sni = sni;
}
void ChoiceController::index(){
try{
char* choicesRequestJson = generateChoicesRequestJSON(this->model);
// Get choices from server
cJSON *choicesJson = RPC::Instance().send_json_rpc(sni, choicesRequestJson);
cJSON *result;
if(choicesJson == NULL){
throw "Empty response";
}
if( cJSON_GetObjectItem(choicesJson, "error")->valuestring != NULL){
throw cJSON_GetObjectItem(choicesJson, "error")->valuestring;
}
result = cJSON_GetObjectItem(choicesJson, "result");
unsigned char* list = (unsigned char *) cJSON_GetObjectItem(result, "List")->valuestring;
this->model->choices = (char *) malloc(21);
memset(this->model->choices, 0, 21);
strncpy(this->model->choices, cJSON_GetObjectItem(result, "Choices")->valuestring, 21);
size_t bufflen = strlen((char*) list);
bufflen = (bufflen/4) *3 +1; // base64 decoded length
unsigned char *decoded_list = (unsigned char *) malloc(bufflen);
if(decoded_list == NULL) throw "insufficient memory";
memset(decoded_list, 0, bufflen);
size_t len;
int error = mbedtls_base64_decode(decoded_list, bufflen, &len, list, strlen( (char*) list));
if(error) throw "Error decoding choice list";
cJSON *parsedList = cJSON_Parse((char *) decoded_list);
parse_object(parsedList, (char *)"" );
ESP_LOGI(TAG, "total candidates: %d", this->model->choice_list->size());
this->vw->render((void *) this->model);
cJSON_Delete(choicesJson);
cJSON_Delete(parsedList);
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}
char* ChoiceController::generateChoicesRequestJSON(ChoiceModel *cm){
cJSON *root, *params, *param;
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "id", 0.0);
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.VoterChoices"));
params = cJSON_CreateArray();
cJSON_AddItemToObject(root, "params", params);
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
cJSON_AddStringToObject(param, "AuthToken", cm->authToken);
cJSON_AddStringToObject(param, "OS", "Operating System,2,0");
cJSON_AddStringToObject(param, "SessionID", cm->ssid);
char* pretty = cJSON_Print(root);
cJSON_Delete(root);
return pretty;
}
void ChoiceController::parse_object(cJSON *item, char* par){
cJSON *subitem=item->child;
if ( !subitem ) { // leaf nodes are candidates
while(item){
choice_t *c = new choice_t(); // create new choice element
c->candidate = (char *) malloc(strlen(item->valuestring)+1); // allocate memory for candidate field
memset(c->candidate, 0, strlen(item->valuestring) +1); // set content 0
memcpy(c->candidate, item->valuestring, strlen(item->valuestring)); // copy from json to struct field
c->code = (char *) malloc(strlen(item->string)+1); // allocate memory for code field
memset(c->code, 0, strlen(item->string) +1); // set content 0
memcpy(c->code, item->string, strlen(item->string)); // copy from json to struct field
c->party = (char *) malloc(strlen(par)+1); // allocate memory for party field
memset(c->party, 0, strlen(par) +1); // set content 0
memcpy(c->party, par, strlen(par)); // copy from json to struct field
this->model->choice_list->push_back(*c); // push choice element to vector (list of choices)
item = item->next; // go to next candidate
}
}
while (subitem){
// handle subitem
if (subitem->child) {
parse_object(subitem->child, subitem->string);
}
subitem=subitem->next;
}
}

View File

@@ -0,0 +1,335 @@
/**
* @file EncryptionController.cpp
* @brief EncryptionController implementation file
* */
#include "esp_log.h"
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
extern "C" {
#include "mbedtls/bignum.h"
}
#include "controller.h"
#include "converter.h"
#ifndef modlength
#define modlength 96 /**< 3072 bits = 384 bytes = 96 words */
#endif
/**
* Struct to store ElGamal encryption results.
* g is group generator and pk is public key
* In general, ElGamal encyption cipher is a pair (c1, c2). But, we'll need randomness later for verification,
* so we also keep random number
* */
typedef struct{
mbedtls_mpi c1; /**< c1 = g^r mod p */
mbedtls_mpi c2; /**< c2 = c1*g^pk mod p */
mbedtls_mpi random; /**< r */
}elgamal_cipher_t;
typedef struct{
mbedtls_mpi* base;
mbedtls_mpi* exponent;
mbedtls_mpi* buff;
mbedtls_mpi* mod;
uint8_t flag;
int error;
}task_param_t;
void taskMont(void* data){
task_param_t* params = (task_param_t*) data;
params->error = mbedtls_mpi_exp_mod(params->buff, params->base, params->exponent, params->mod, NULL);
params->flag = 1;
for(;;){
}
}
/**
* @brief secure big random generator
*
* Multi-precision integer (mpi) is an array of 64bit unsigned integers in big endian representation. This method
* creates grows input parameter to the length of modlength, then fills the array with random unsigned integers using
* esp_random()
*
* @param mpi The destination MPI. This must point to an initialized MPI.
*
*/
void mpi_RandomNumber(mbedtls_mpi * mpi ){
srand ( time(NULL) );
mbedtls_mpi_grow(mpi, modlength);
for(int i = 0;i < modlength; i++){
mpi->p[i] = (mbedtls_mpi_uint) esp_random();
}
}
/**
* @brief fast multi-core ElGamal implementation
* ElGamal is a homomorphic encryption method used in ivxv protocol.
* 3072 bit long keys provide 128 bit security.
*
* @param pk public key
* @param m encoded plaintext
* @param res pointer to cipher struct
* @param mod pointer to modulus variable
*
* @returns 0 if successful, -1 otherwise
* */
int ElGamalEncrypt(mbedtls_mpi * pk, mbedtls_mpi* m, elgamal_cipher_t * res, mbedtls_mpi * mod){
esp_err_t error;
mbedtls_mpi rnd, g, c1, c2;
mbedtls_mpi_init(&c1);
mbedtls_mpi_init(&c2);
mbedtls_mpi_init(&rnd);
mbedtls_mpi_init(&g);
mpi_RandomNumber(&rnd);
error = mbedtls_mpi_read_string(&g, 10, "2");
if(error) return error;
task_param_t * c1Params = new task_param_t();
c1Params->base = &g;
c1Params->exponent = &rnd;
c1Params->buff = &c1;
c1Params->mod = mod;
TaskHandle_t c1Task;
xTaskCreatePinnedToCore(taskMont, "C1_Mont", 4192, (void *) c1Params, 0 , &c1Task, 1);
mbedtls_mpi c3;
mbedtls_mpi_init(&c3);
error = mbedtls_mpi_exp_mod(&c3, pk, &rnd, mod, NULL);
if(error) return error;
error = esp_mpi_mul_mpi_mod(&c2, &c3, m, mod);
if(error) return error;
while(!c1Params->flag){
}
vTaskDelete(c1Task);
if(c1Params->error) return c1Params->error;
error = mbedtls_mpi_copy(&res->c1, &c1); if(error) return error;
error = mbedtls_mpi_copy(&res->c2, &c2); if(error) return error;
error = mbedtls_mpi_copy(&res->random, &rnd); if(error) return error;
mbedtls_mpi_free(&c1);
mbedtls_mpi_free(&c2);
mbedtls_mpi_free(&c3);
mbedtls_mpi_free(&rnd);
mbedtls_mpi_free(&g);
return 0;
}
EncryptionController::EncryptionController(BaseModel *model){
this->model = static_cast<EncryptionModel *>(model);
this->vw = new IndexView();
}
void EncryptionController::index(){
try{
this->vw->render((void *)"Encrypting ballot...");
unsigned char * PK_DER = (unsigned char *) malloc(1024);
memset(PK_DER, 0, 1024);
size_t lenPK = 1024;
memset(PK_DER, 0 , lenPK);
int error = converter::convert_pem_to_der(this->model->keypem, this->model->keypem_length, PK_DER, &lenPK); //! * First, convert election public key file to DER format*/
if(error) throw "unable to parse pem file";
unsigned char *p = PK_DER;
const unsigned char *end = p + lenPK;
size_t len; int i;
mbedtls_asn1_buf oid, oid_params;
memset( &oid, 0, sizeof( mbedtls_asn1_buf ) );
memset( &oid_params, 0, sizeof( mbedtls_asn1_buf ) );
mbedtls_mpi mod;
mbedtls_mpi_init(&mod);
//! * Start decoding ASN1 DER encoded key contents using mbedtls_asn1 library /
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if(error) throw "ASN1 parse error";
error = mbedtls_asn1_get_alg(&p, end, &oid, &oid_params); if(error) throw "ASN1 parse error";
unsigned char * q = oid_params.p;
const unsigned char *q_end = q + oid_params.len;
error = mbedtls_asn1_get_mpi(&q, q_end, &mod); if(error) throw "ASN1 parse error"; //! * extract mod
error = mbedtls_asn1_get_tag(&q, q_end, &len, MBEDTLS_ASN1_INTEGER); if(error) throw "ASN1 parse error";
q += len;
error = mbedtls_asn1_get_tag(&q, q_end, &len, 0x1B ); if(error) throw "ASN1 parse error"; //! * extract electionID
this->model->election_id = (char *)malloc(len+1);
memset(this->model->election_id, 0, len+1);
memcpy(this->model->election_id, q, len);
mbedtls_asn1_bitstring bs = {0, 0 , NULL};
error = mbedtls_asn1_get_bitstring(&p, end, &bs); if(error) throw "ASN1 parse error";
p = bs.p;
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if(error) throw "ASN1 parse error";
mbedtls_mpi key;
mbedtls_mpi_init(&key);
error = mbedtls_asn1_get_mpi(&p, end, &key); if(error) throw "ASN1 parse error"; //! * extract 3072bit public key
if(error) throw "key error";
if(p != end){
printf("Error. Didn't parse until the end\n");
throw "Incomplete ASN";
}
/**
* * Then, pad the ballot using following scheme
*
* padded-ballot = '\x00' '\x01' *'\xff' '\x00' ballot
*
*/
len = mbedtls_mpi_bitlen(&key);
len /= 8;
unsigned char *padded_ballot = (unsigned char *) malloc(len + 1);
memset(padded_ballot, 0xFF, len);
padded_ballot[0] = 0x00;
padded_ballot[1] = 0x01;
padded_ballot[len] = 0x00; // end of string (null-terminated)
padded_ballot[len - strlen(this->model->ballot) - 1] = 0x00;
for(i=1;i<=strlen(this->model->ballot);i++){
padded_ballot[len - i] = this->model->ballot[strlen(this->model->ballot) - i];
}
mbedtls_mpi plaintext;
mbedtls_mpi_init(&plaintext);
error = mbedtls_mpi_read_binary(&plaintext, padded_ballot, len); //! * convert padded ballot to group element
if (error) throw "ballot mpi conversion error";
free(padded_ballot);
mbedtls_mpi pq; //pq = (modulus-1)/2
mbedtls_mpi_init(&pq);
error = mbedtls_mpi_sub_int(&pq, &mod, 1); if(error) throw "error at mod - 1";
error = mbedtls_mpi_div_int(&pq, NULL, &pq, 2); if(error) throw "error at pq // 2";
//! * encode plaintext as a quadratic residue in the set
mbedtls_mpi encoded_plaintext, res;
mbedtls_mpi_init(&encoded_plaintext);
mbedtls_mpi_init(&res);
error = mbedtls_mpi_exp_mod(&res, &plaintext, &pq, &mod, NULL); if(error) throw "quadratic residue check error";
if( mbedtls_mpi_cmp_int(&res, 1) == 0){
error = mbedtls_mpi_copy(&encoded_plaintext, &plaintext);
if(error) throw "mpi copy error";
ESP_LOGI(TAG, "quadratic residue");
}else{
error = mbedtls_mpi_sub_mpi(&encoded_plaintext, &mod, &plaintext);
if(error) throw "mpi substract error";
}
elgamal_cipher_t *cipher = new elgamal_cipher_t();
mbedtls_mpi_init(&cipher->c1);
mbedtls_mpi_init(&cipher->c2);
mbedtls_mpi_init(&cipher->random);
time_t before_enc, after_enc;
time(&before_enc);
error = ElGamalEncrypt(&key, &encoded_plaintext, cipher, &mod); //! * encrypt and store results in cipher
time(&after_enc);
ESP_LOGI(TAG, "encryption took %ld seconds", (long) after_enc - (long) before_enc);
if(error) throw "Encryption error";
ESP_LOGI(TAG, "plaintext encrypted");
unsigned char * rndASN = (unsigned char*) malloc( len );
memset(rndASN, 0, len);
error = mbedtls_mpi_write_binary(&cipher->random, rndASN, len ); //! * convert used random number into hex and base64 encode it.
if(error) throw "error in rnd binary export";
this->model->rndBase64 = (unsigned char *)malloc(2*len);
memset(this->model->rndBase64,0, 2*len);
error = mbedtls_base64_encode(this->model->rndBase64, 2*len, &len, rndASN, len);
if(error) throw "Random number hash error";
//! * start DER encoding of cipher
puts((char *) this->model->rndBase64);
unsigned char * asnder = (unsigned char *) malloc(1220);
memset(asnder, 0, 1220);
unsigned char *asn_end = asnder + 1220;
int succ, total_succ = 0;
succ = mbedtls_asn1_write_mpi(&asn_end, asnder, &cipher->c2); //! * convert second component of cipher into hex and encode as ASN1 Integer
total_succ+=succ;
succ = mbedtls_asn1_write_mpi(&asn_end, asnder, &cipher->c1); //! * convert first component of cipher into hex and encode as ASN1 Integer
total_succ+=succ;
succ = mbedtls_asn1_write_len(&asn_end, asnder, total_succ);
total_succ+=succ;
succ = mbedtls_asn1_write_tag(&asn_end, asnder, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
total_succ+=succ;
int params_total = 0;
succ = mbedtls_asn1_write_raw_buffer(&asn_end, asnder, oid_params.p, oid_params.len);
params_total+=succ;
succ = mbedtls_asn1_write_len(&asn_end, asnder, oid_params.len);
params_total+=succ;
succ = mbedtls_asn1_write_tag(&asn_end, asnder, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
params_total+=succ;
succ = mbedtls_asn1_write_algorithm_identifier(&asn_end, asnder, (char *) oid.p, oid.len, params_total); //! * append encryption algorithm identifier to DER
total_succ+=succ;
succ = mbedtls_asn1_write_len(&asn_end, asnder, total_succ);
total_succ+=succ;
succ = mbedtls_asn1_write_tag(&asn_end, asnder, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
total_succ+=succ;
this->model->ballotASN = (unsigned char *) malloc(total_succ+1);
memset(this->model->ballotASN, 0, total_succ + 1);
memcpy(this->model->ballotASN, asnder+1220-total_succ, total_succ);
this->model->ballotLength = total_succ;
free(asnder);
free(PK_DER);
free(rndASN);
mbedtls_mpi_free(&mod);
mbedtls_mpi_free(&pq);
mbedtls_mpi_free(&key);
mbedtls_mpi_free(&plaintext);
mbedtls_mpi_free(&encoded_plaintext);
mbedtls_mpi_free(&res);
mbedtls_mpi_free(&cipher->c1);
mbedtls_mpi_free(&cipher->c2);
mbedtls_mpi_free(&cipher->random);
// SHA256 hash + Base64 asnder
this->model->ballotFileName = (char *)malloc(65);
memset(this->model->ballotFileName, 0, 65);
snprintf(this->model->ballotFileName, 64, "%s.%s.ballot", this->model->election_id, "1"); //! * set filename for DER encoded encrypted ballot
this->model->ballotHash = converter::base64hash(this->model->ballotASN, this->model->ballotLength); //! * hash and base64 encode it for future references
ESP_LOGI(TAG, "ballot hash: %s\n",(char *)this->model->ballotHash);
this->vw->render((void*) "Encrypted");
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}

View File

@@ -0,0 +1,16 @@
/**
* @file IndexController.cpp
* @brief IndexController implementation file
* */
#include "controller.h"
IndexController::IndexController(){
this->vw = new IndexView();
}
void IndexController::index(){
this->vw->render((void *) "Index ctrl");
}

View File

@@ -0,0 +1,344 @@
/**
* @file SignatureController.cpp
* @brief SignatureController implementation file
* */
#include "cJSON.h"
#include "controller.h"
#include "converter.h"
SignatureController::SignatureController(BaseModel *model, const char * sni){
this->vw = new IndexView();
this->model = static_cast<SignatureModel *>(model);
this->sni = sni;
}
void SignatureController::index(){
try{
this->vw->render((void *) "Getting certificate");
// Get certificate
ESP_LOGI(TAG, "get certificate request sent");
cJSON *certificateJson = RPC::Instance().send_json_rpc(sni, generateGetCertificateRequestJSON()); //! * Get certificate from server
if(certificateJson == NULL){
throw "Empty response";
}
if( cJSON_GetObjectItem(certificateJson, "error")->valuestring != NULL){ //! * check for error message
throw cJSON_GetObjectItem(certificateJson, "error")->valuestring;
}
cJSON * result = cJSON_GetObjectItem(certificateJson, "result"); //! * if no error, parse JSON result
size_t len = strlen(cJSON_GetObjectItem(result, "Certificate")->valuestring);
char * signCertificate = (char *)malloc(len + 1); //! * allocate enough memory to store certificate
if(signCertificate == NULL){
ESP_LOGE("ivxv", "unable to allocate memory to store certificate");
throw "Insufficient memory";
}
memset(signCertificate, 0, len + 1);
memcpy(signCertificate, cJSON_GetObjectItem(result, "Certificate")->valuestring, len);
len = (len/64) *65 + len%64;
this->model->certificate = (char *)malloc(len+1);
memset(this->model->certificate,0, len+1); //! * base64 decode and add line breaks after 64th character
int i, j=0;
for(i=0;i<strlen(signCertificate);i++){
this->model->certificate[j++] = signCertificate[i];
if(i && (i+1)%64==0){
this->model->certificate[j++] = '\n';
}
}
cJSON_Delete(certificateJson);
// ASN1 Parse certificate
// decode certificate, parse it, hash it, base64 encode it.
unsigned char *certificateDER = (unsigned char *) malloc(1600);
if(certificateDER == NULL){
ESP_LOGE("ivxv", "unable to allocate memory to store certificate DER");
throw "Insufficient memory";
}
memset(certificateDER, 0, 1600);
int error = mbedtls_base64_decode(certificateDER, 1600, &len, (unsigned char *)signCertificate, strlen(signCertificate));
if(error) throw "Error";
int der_length = len;
unsigned char* p = certificateDER;
unsigned char* end = p + len;
int version;
mbedtls_mpi serial = {0,0,0};
char * serialBuf = (char *)malloc(128);
memset(serialBuf, 0 , 128);
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if(error) throw "Error";
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if(error) throw "Error";
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC);
if(error) throw "Error";
error = mbedtls_asn1_get_int(&p, end, &version);
if(error) throw "Error";
error = mbedtls_asn1_get_mpi(&p, end, &serial);
if(error) throw "Error";
error = mbedtls_mpi_write_string(&serial, 10, serialBuf, 128, &len); //! * parse certificate serial number
if(error) throw "Error";
mbedtls_asn1_buf oid, oid_params;
memset( &oid, 0, sizeof( mbedtls_asn1_buf ) );
memset( &oid_params, 0, sizeof( mbedtls_asn1_buf ) );
error = mbedtls_asn1_get_alg_null(&p, end, &oid);
if(error) throw "Error";
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if(error) throw "Error";
char *DN = (char *)malloc(256);
memset(DN,0, 256);
char* CN = (char *) malloc(32);
memset(CN,0, 32);
char* C = (char *) malloc(32);
memset(C,0, 32);
char* O = (char *) malloc(32);
memset(O,0, 32);
char* org = (char *) malloc(32);
memset(org,0, 32);
for(i=0;i<4;i++){
memset( &oid, 0, sizeof( mbedtls_asn1_buf ) );
memset( &oid_params, 0, sizeof( mbedtls_asn1_buf ) );
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET);
if(error) {
throw "Error";
}
error = mbedtls_asn1_get_alg(&p, end, &oid, &oid_params);
if(error) {
throw "Error";
}
if( *(oid.p + 2) == 0x03) strncat(CN, (char *) oid_params.p, oid_params.len);
if( *(oid.p + 2) == 0x06) strncat(C, (char *) oid_params.p, oid_params.len);
if( *(oid.p + 2) == 0x0A) strncat(O, (char *) oid_params.p, oid_params.len);
if( *(oid.p + 2) == 0x61) strncat(org, (char *) oid_params.p, oid_params.len);
}
if(error) throw "Error";
snprintf(DN, 256, "CN=%s,organizationIdentifier=%s,O=%s,C=%s", CN, org, O, C); // copy certificate DN field
unsigned char *certificateHashBase64 = converter::base64hash(certificateDER, der_length);
free(certificateDER);
free(signCertificate);
// Create signedProperties
char *signingTime = (char *) malloc(64);
memset(signingTime, 0, 64);
time_t now;
time(&now);
strftime(signingTime, 21,"%Y-%m-%dT%XZ", localtime(&now)); //! * get signing time
ESP_LOGI(TAG, "time: %s", signingTime);
this->model->SP_XML = (char *) malloc(2048);
memset(this->model->SP_XML, 0, 2048);
snprintf(this->model->SP_XML, 2048, SignedProperties, signingTime, (char *)certificateHashBase64, DN, serialBuf); //! * create SignedProperties XML element
converter::xmlc14n11(this->model->SP_XML, 2048); //! * canonicalize SignedProperties
unsigned char *spHashBase64 = converter::base64hash((unsigned char *)this->model->SP_XML, strlen(this->model->SP_XML)); //! * hash (sha256) + base64 encode canonicalize
// Create signedInfo
this->model->SI_XML = (char *) malloc(2048);
memset(this->model->SI_XML, 0, 2048);
snprintf(this->model->SI_XML, 2048, SignedInfo, this->model->ballotFileName ,(char *) this->model->ballotHash, spHashBase64); //! create DignedInfo XML element
converter::xmlc14n11(this->model->SI_XML, 2048);
this->model->SignedInfoHash = converter::base64hash((unsigned char *)this->model->SI_XML, strlen(this->model->SI_XML));//! * hash(sha268) andbase64 encode canonicalize
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}
char* SignatureController::generateGetCertificateRequestJSON(){
cJSON *root, *params, *param;
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "id", 0.0);
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.GetCertificate"));
params = cJSON_CreateArray();
cJSON_AddItemToObject(root, "params", params);
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
cJSON_AddStringToObject(param, "AuthToken", this->model->authToken);
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
cJSON_AddStringToObject(param, "PhoneNo", this->model->phone);
cJSON_AddStringToObject(param, "IDCode", this->model->ID);
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
char* pretty = cJSON_Print(root);
cJSON_Delete(root);
return pretty;
}
char* SignatureController::generateSignRequestJSON(){
cJSON *root, *params, *param;
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "id", 0.0);
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.Sign"));
params = cJSON_CreateArray();
cJSON_AddItemToObject(root, "params", params);
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
cJSON_AddStringToObject(param, "AuthToken", this->model->authToken);
cJSON_AddStringToObject(param, "Hash", (char *) this->model->SignedInfoHash);
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
cJSON_AddStringToObject(param, "PhoneNo", this->model->phone);
cJSON_AddStringToObject(param, "IDCode", this->model->ID);
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
char* pretty = cJSON_Print(root);
cJSON_Delete(root);
return pretty;
}
void SignatureController::sign(){
try{
ESP_LOGI(TAG, "signing request sent");
cJSON * signJson = RPC::Instance().send_json_rpc(sni, generateSignRequestJSON());
if(signJson == NULL){
throw "Empty response";
}
if(cJSON_GetObjectItem(signJson, "error")->valuestring != NULL){
throw cJSON_GetObjectItem(signJson, "error")->valuestring;
}
cJSON * params = cJSON_GetObjectItem(signJson, "result");
size_t len = strlen(cJSON_GetObjectItem(params, "SessionCode")->valuestring);
this->model->sscode = (char *) malloc(len +1);
memset(this->model->sscode, 0, len + 1);
memcpy(this->model->sscode, cJSON_GetObjectItem(params, "SessionCode")->valuestring, len);
char pin[25];
bzero(pin, 25);
strncat(pin, "Verification code: ", 20);
strncat(pin, cJSON_GetObjectItem(params, "ChallengeID")->valuestring, 5);
this->vw->render((void *) pin);
cJSON_Delete(signJson);
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}
char* SignatureController::generateSignStatusRequestJSON(){
cJSON *root, *params, *param;
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "id", 0.0);
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.SignStatus"));
params = cJSON_CreateArray();
cJSON_AddItemToObject(root, "params", params);
cJSON_AddItemToArray(params, param = cJSON_CreateObject());
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
cJSON_AddStringToObject(param, "SessionCode", this->model->sscode);
char* pretty = cJSON_Print(root);
cJSON_Delete(root);
return pretty;
}
void SignatureController::status(){
try{
// Poll RPC.SignStatus
cJSON *signJson, *result;
char* signStatusReq = generateSignStatusRequestJSON();
do{
ESP_LOGI(TAG, "waiting to confirm pin");
for(int i=10; i>0; i--){
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
// check status
ESP_LOGI(TAG, "signing status request sent");
signJson = RPC::Instance().send_json_rpc(sni, signStatusReq );
if(signJson == NULL){
throw "Empty response";
}
result = cJSON_GetObjectItem(signJson, "result");
if( cJSON_GetObjectItem(signJson, "error")->valuestring != NULL){
throw cJSON_GetObjectItem(signJson, "error")->valuestring;
}
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "POLL") == 0){
continue;
}
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "OK") == 0){
size_t len = strlen(cJSON_GetObjectItem(result, "Signature")->valuestring);
this->model->signature = (char *) malloc(len + 1);
memset(this->model->signature, 0, len + 1);
memcpy(this->model->signature, cJSON_GetObjectItem(result, "Signature")->valuestring, len);
this->vw->render((void *) "PIN CONFIRMED!");
break;
}
cJSON_free(signJson);
}
while(1);
this->vw->render((void *)"Successfully signed");
ESP_LOGI(TAG, "succesfully signed");
cJSON_Delete(signJson);
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}
void SignatureController::combine(){
try{
// Create SignatureValue
this->model->SV_XML = (char *) malloc(512);
memset(this->model->SV_XML, 0, 512);
snprintf(this->model->SV_XML, 511, SignatureValue, this->model->signature);
// merge above 3 and create signature0.xml
this->model->Signature = (char *) malloc(10240);
if(this->model->Signature == NULL){
throw "Insufficient memory";
}
memset(this->model->Signature, 0, 10240);
snprintf(this->model->Signature, 10240, Signature, this->model->SI_XML, this->model->SV_XML, this->model->certificate, this->model->SP_XML);
free(this->model->SI_XML);
free(this->model->SP_XML);
free(this->model->SV_XML);
free(this->model->certificate);
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}

View File

@@ -0,0 +1,69 @@
/**
* @file VoteController.cpp
* @brief VoteController implementation file
* */
#include "cJSON.h"
#include "controller.h"
VoteController::VoteController(BaseModel *model, const char * sni){
this->vw = new IndexView();
this->model = static_cast<VoteModel *>(model);
this->sni = sni;
}
void VoteController::index(){
try{
// send last hash to vote and get voteID
ESP_LOGI(TAG, "final voting request sent");
cJSON* voteJson = RPC::Instance().send_json_rpc(sni, generateVoteRequestJSON()); //! * send signed digital ballot to voting service
if(voteJson == NULL){
throw "Empty response";
}
if(cJSON_GetObjectItem(voteJson, "error")->valuestring != NULL){ //! * check error message
throw cJSON_GetObjectItem(voteJson, "error")->valuestring;
}
cJSON* result = cJSON_GetObjectItem(voteJson, "result"); //! * if no error, parse result
size_t len = strlen(cJSON_GetObjectItem(result, "VoteID")->valuestring);
this->model->voteID = (char *) malloc(len+1); //! * allocate memory and store voteID
memset(this->model->voteID, 0, len+1);
memcpy(this->model->voteID, cJSON_GetObjectItem(result, "VoteID")->valuestring,len);
cJSON_Delete(voteJson);
ESP_LOGI(TAG, "voteID: %s", this->model->voteID);
this->vw->render((void *) "Vote casted");
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}
char* VoteController::generateVoteRequestJSON(){
cJSON *root, *params, *param;
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "id", 0.0);
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.Vote"));
params = cJSON_CreateArray();
cJSON_AddItemToObject(root, "params", params);
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
cJSON_AddStringToObject(param, "AuthToken", this->model->authToken);
cJSON_AddStringToObject(param, "Choices", this->model->choices);
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
cJSON_AddStringToObject(param, "Type", "bdoc");
cJSON_AddStringToObject(param, "Vote", (char *) this->model->voteBase64);
char* pretty = cJSON_Print(root);
cJSON_Delete(root);
return pretty;
}

View File

@@ -0,0 +1,89 @@
/**
* @file ZipController.cpp
* @brief ZipController implementation file
* */
#include "miniz.h"
#include "controller.h"
ZipController::ZipController(BaseModel *model){
this->vw = new IndexView();
this->model = static_cast<ZipModel *>(model);
}
void ZipController::index(){
try{
// create a container with .ballot and .xml files
mz_bool status;
mz_zip_archive bdoc;
mz_zip_zero_struct(&bdoc);
size_t len;
status = mz_zip_writer_init_heap(&bdoc, 0,10240); //! * init zip heap
if(!status){
throw mz_zip_get_error_string(bdoc.m_last_error);
}
// Add mimefile
char *mimetype = (char *) "application/vnd.etsi.asic-e+zip"; //! * add mimetype file to zip
status = mz_zip_writer_add_mem(&bdoc, "mimetype", (void *) mimetype, strlen(mimetype), MZ_NO_COMPRESSION);
if (!status){
throw mz_zip_get_error_string(bdoc.m_last_error);
}
// Add manifest.xml
char* manifestXML = (char *) malloc(512);
memset(manifestXML,0,512);
snprintf(manifestXML, 512, manifest, "EP2065.1.ballot");
status = mz_zip_writer_add_mem(&bdoc, "META-INF/manifest.xml", (void *)manifestXML, strlen(manifestXML), MZ_NO_COMPRESSION); //! * add manifest.xml file to zip
if (!status){
throw mz_zip_get_error_string(bdoc.m_last_error);
}
// Add ballot file
status = mz_zip_writer_add_mem(&bdoc, this->model->ballotFileName, (void *) this->model->ballot, this->model->ballotLength, MZ_NO_COMPRESSION); //! * add ballot file to zip
if (!status){
throw mz_zip_get_error_string(bdoc.m_last_error);
}
// Add signature0.xml
status = mz_zip_writer_add_mem(&bdoc, "META-INF/signatures0.xml", (void *) this->model->Signature, strlen(this->model->Signature), MZ_NO_COMPRESSION); //! * add signature file to zip
if (!status){
throw mz_zip_get_error_string(bdoc.m_last_error);
}
// Close zip file
void *zipBuf;
status = mz_zip_writer_finalize_heap_archive(&bdoc, &zipBuf, &len);
if (!status){
throw mz_zip_get_error_string(bdoc.m_last_error);
}
status = mz_zip_writer_end(&bdoc);
if (!status){
throw "zip end failed";
}
// hash container
this->model->voteBase64 = (unsigned char *)malloc(2*len);
if(this->model->voteBase64 == NULL){
throw "Insufficient memory";
}
memset(this->model->voteBase64, 0, 2*len);
int error = mbedtls_base64_encode(this->model->voteBase64, 2*len - 1, &len, (unsigned char *) zipBuf, len); //! * base64 encode zip file
if(error) {
throw "Base64 encode error";
}
this->vw->render((void*) "Signature complete");
mz_free(zipBuf);
free(this->model->Signature);
}
catch (const char* msg){
this->vw->render((void *)msg);
throw msg;
}
}