/*! \fn approveMemoryManagementMode(uint8_t* pluginAnswer) * \brief Approve the memory management mode * \param pluginAnswer Pointer to the plugin answer byte */ void approveMemoryManagementMode(uint8_t* pluginAnswer) { // Ask permission to the user if (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_MEMORYMGMTQ)) == RETURN_OK) { guiSetCurrentScreen(SCREEN_MEMORY_MGMT); memoryManagementModeApproved = TRUE; *pluginAnswer = PLUGIN_BYTE_OK; } else { *pluginAnswer = PLUGIN_BYTE_ERROR; } guiGetBackToCurrentScreen(); }
/*! \fn approveImportExportMemoryOperation(uint8_t opUID, uint8_t* pluginAnswer) * \brief Approve a Flash/Eeprom import/export operation * \param opUID Unique memory operation identifier * \param pluginAnswer Pointer to the plugin answer byte */ void approveImportExportMemoryOperation(uint8_t opUID, uint8_t* pluginAnswer) { // Set all global vars to 0 flashOpCurAddr1 = 0; flashOpCurAddr2 = 0; currentFlashOpUid = 0; *pluginAnswer = PLUGIN_BYTE_ERROR; // Ask permission to the user if (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_APPROVEMEMOP)) == RETURN_OK) { currentFlashOpUid = opUID; *pluginAnswer = PLUGIN_BYTE_OK; } }
/*! \fn guiAskForLoginSelect(pNode* p, cNode* c, uint16_t parentNodeAddress) * \brief Ask for user login selection / approval * \param p Pointer to a parent node * \param c Pointer to a child node * \param parentNodeAddress Address of the parent node * \param bypass_confirmation Bool to bypass authorisation request * \return Valid child node address or 0 otherwise */ uint16_t guiAskForLoginSelect(pNode* p, cNode* c, uint16_t parentNodeAddress, uint8_t bypass_confirmation) { uint16_t first_child_address, temp_child_address; uint16_t picked_child = NODE_ADDR_NULL; uint16_t addresses[4]; uint8_t led_mask; int8_t i, j; // Check parent node address if (parentNodeAddress == NODE_ADDR_NULL) { return NODE_ADDR_NULL; } // Read the parent node readParentNode(p, parentNodeAddress); // Read its first child address first_child_address = p->nextChildAddress; // Check if there are stored credentials if (first_child_address == NODE_ADDR_NULL) { guiDisplayInformationOnScreenAndWait(ID_STRING_NO_CREDS); return NODE_ADDR_NULL; } // Read child node readChildNode(c, first_child_address); // Check if there's only one child, that's a confirmation screen if (c->nextChildAddress == NODE_ADDR_NULL) { confirmationText_t temp_conf_text; // Prepare asking confirmation screen temp_conf_text.lines[0] = readStoredStringToBuffer(ID_STRING_CONFACCESSTO); temp_conf_text.lines[1] = (char*)p->service; temp_conf_text.lines[2] = readStoredStringToBuffer(ID_STRING_WITHTHISLOGIN); temp_conf_text.lines[3] = (char*)c->login; // Prompt user for confirmation, flash the screen if ((bypass_confirmation == TRUE) || (guiAskForConfirmation(0xF0 | 4, &temp_conf_text) == RETURN_OK)) { picked_child = first_child_address; } } else { temp_child_address = first_child_address; uint8_t action_chosen = FALSE; while (action_chosen == FALSE) { // Draw asking bitmap oledBitmapDrawFlash(0, 0, BITMAP_LOGIN, 0); // Write domain name on screen char temp_string[INDEX_TRUNCATE_SERVICE_CENTER+1]; memcpy(temp_string, (char*)p->service, sizeof(temp_string)); temp_string[INDEX_TRUNCATE_SERVICE_CENTER] = 0; oledPutstrXY(0, 24, OLED_CENTRE, temp_string); // Clear led_mask led_mask = 0; i = 0; // List logins on screen while ((temp_child_address != NODE_ADDR_NULL) && (i != 4)) { // Read child node to get login readChildNode(c, temp_child_address); // Print Login at the correct slot displayCredentialAtSlot(i, (char*)c->login, INDEX_TRUNCATE_LOGIN_FAV); // Store address in array, fetch next address addresses[i] = temp_child_address; temp_child_address = c->nextChildAddress; i++; } // If nothing after, hide right arrow if ((i != 4) || (c->nextChildAddress == NODE_ADDR_NULL)) { oledFillXY(177, 25, 16, 14, 0x00); led_mask |= LED_MASK_RIGHT; } // Light only the available choices for (j = i; j < 4; j++) { led_mask |= (1 << j); } // Display picture oledDisplayOtherBuffer(); // Get touched quarter j = getTouchedPositionAnswer(led_mask); // Check its validity, knowing that by default we will return NODE_ADDR_NULL if (j == -1) { // Time out action_chosen = TRUE; } else if (j < i) { picked_child = addresses[j]; action_chosen = TRUE; } else if (j == TOUCHPOS_LEFT) { // If there is a previous children, go back 4 indexes if (addresses[0] != first_child_address) { c->prevChildAddress = addresses[0]; for (i = 0; i < 5; i++) { temp_child_address = c->prevChildAddress; readChildNode(c, temp_child_address); } } else { // otherwise, return action_chosen = TRUE; } } else if ((j == TOUCHPOS_RIGHT) && (i == 4) && (c->nextChildAddress != NODE_ADDR_NULL)) { // If there are more nodes to display, let it loop // temp_child_address = c->nextChildAddress; } else { // Wrong position temp_child_address = addresses[0]; } } } return picked_child; }
/*! \fn guiScreenLoop(uint8_t input_interface_result) * \brief Function called to handle screen changes * \param input_interface_result Touch detection result */ void guiScreenLoop(uint8_t input_interface_result) { // If no press, you can return! if ((input_interface_result == WHEEL_ACTION_NONE) || (currentScreen == SCREEN_DEFAULT_INSERTED_INVALID) || (currentScreen == SCREEN_DEFAULT_INSERTED_UNKNOWN)) { return; } if (currentScreen == SCREEN_DEFAULT_NINSERTED) { // No smart card inserted, ask the user to insert one guiDisplayInsertSmartCardScreenAndWait(); } else if (currentScreen == SCREEN_MEMORY_MGMT) { // Currently in memory management mode, tell the user to finish it via the plugin/app guiDisplayInformationOnScreenAndWait(ID_STRING_CLOSEMEMMGMT); guiGetBackToCurrentScreen(); miniWheelClearDetections(); } else if (currentScreen == SCREEN_DEFAULT_INSERTED_LCK) { // Locked screen and a detection happened, check that the user hasn't removed his card, launch unlocking process if ((cardDetectedRoutine() == RETURN_MOOLTIPASS_USER) && (validCardDetectedFunction(0, TRUE) == RETURN_VCARD_OK)) { // User approved his pin unlockFeatureCheck(); currentScreen = SCREEN_DEFAULT_INSERTED_NLCK; } // Go to the new screen guiGetBackToCurrentScreen(); } else { if (input_interface_result == WHEEL_ACTION_UP) { // We can do that because of defines and bitmap order (see logic_fw_flash_storage and gui.h) if (currentScreen == SCREEN_LOCK) { currentScreen = SCREEN_SETTINGS; } else if (currentScreen == SCREEN_SETTINGS_CHANGE_PIN) { currentScreen = SCREEN_SETTINGS_ERASE; } else { currentScreen--; } // We can do that because of defines and bitmap order (see logic_fw_flash_storage and gui.h) for (uint8_t i = 0; i < NB_BMPS_PER_TRANSITION; i++) { miniOledBitmapDrawFlash(0, 0, (currentScreen-SCREEN_LOCK)*NB_BMPS_PER_TRANSITION+BITMAP_MAIN_LOCK+NB_BMPS_PER_TRANSITION-1-i, OLED_SCROLL_FLIP); timerBasedDelayMs(12); } } else if (input_interface_result == WHEEL_ACTION_DOWN) { // We can do that because of defines and bitmap order (see logic_fw_flash_storage and gui.h) for (uint8_t i = 0; i < NB_BMPS_PER_TRANSITION-1; i++) { miniOledBitmapDrawFlash(0, 0, (currentScreen-SCREEN_LOCK)*NB_BMPS_PER_TRANSITION+BITMAP_MAIN_LOCK+1+i, OLED_SCROLL_FLIP); timerBasedDelayMs(12); } if (currentScreen == SCREEN_SETTINGS) { currentScreen = SCREEN_LOCK; } else if (currentScreen == SCREEN_SETTINGS_ERASE) { currentScreen = SCREEN_SETTINGS_CHANGE_PIN; } else { currentScreen++; } miniOledBitmapDrawFlash(0, 0, (currentScreen-SCREEN_LOCK)*NB_BMPS_PER_TRANSITION+BITMAP_MAIN_LOCK, OLED_SCROLL_FLIP); } else if (input_interface_result == WHEEL_ACTION_LONG_CLICK) { // Long press in main menu : lock, long press in settings menu: go back to login screen if ((currentScreen >= SCREEN_SETTINGS_CHANGE_PIN) && (currentScreen <= SCREEN_SETTINGS_ERASE)) { currentScreen = SCREEN_LOGIN; miniOledBitmapDrawFlash(0, 0, (currentScreen-SCREEN_LOCK)*NB_BMPS_PER_TRANSITION+BITMAP_MAIN_LOCK, OLED_SCROLL_UP); } } else if (input_interface_result == WHEEL_ACTION_SHORT_CLICK) { switch(currentScreen) { case SCREEN_LOCK: { // User wants to lock his mooltipass currentScreen = SCREEN_DEFAULT_INSERTED_LCK; handleSmartcardRemoved(); guiGetBackToCurrentScreen(); break; } case SCREEN_LOGIN: { // User wants to go to the login menu if (getStartingParentAddress() != NODE_ADDR_NULL) { loginSelectLogic(); } else { guiDisplayInformationOnScreenAndWait(ID_STRING_NO_CREDS); } guiGetBackToCurrentScreen(); break; } case SCREEN_FAVORITES: { // User wants to go to the favorite menu #if defined(ENABLE_CREDENTIAL_MANAGEMENT) && defined(REPLACE_FAVORITES_WITH_CREDENTIAL_MANAGEMENT) managementActionPickingLogic(); #else favoritePickingLogic(); #endif guiGetBackToCurrentScreen(); break; } case SCREEN_SETTINGS: { currentScreen = SCREEN_SETTINGS_CHANGE_PIN; miniOledBitmapDrawFlash(0, 0, (currentScreen-SCREEN_LOCK)*NB_BMPS_PER_TRANSITION+BITMAP_MAIN_LOCK, OLED_SCROLL_UP); break; } case SCREEN_SETTINGS_HOME: { currentScreen = SCREEN_LOGIN; miniOledBitmapDrawFlash(0, 0, (currentScreen-SCREEN_LOCK)*NB_BMPS_PER_TRANSITION+BITMAP_MAIN_LOCK, OLED_SCROLL_UP); break; } case SCREEN_SETTINGS_CHANGE_PIN: { // User wants to change his PIN code // Reauth user if (removeCardAndReAuthUser() == RETURN_OK) { // User approved his pin, ask his new one volatile uint16_t pin_code; if (guiAskForNewPin(&pin_code, ID_STRING_NEW_PINQ) == RETURN_NEW_PIN_OK) { // User successfully entered a new pin writeSecurityCode(&pin_code); // Inform of success guiDisplayInformationOnScreenAndWait(ID_STRING_PIN_CHANGED); } else { // Inform of fail guiDisplayInformationOnScreenAndWait(ID_STRING_PIN_NCGHANGED); } pin_code = 0x0000; } else { currentScreen = SCREEN_DEFAULT_INSERTED_LCK; } guiGetBackToCurrentScreen(); break; } case SCREEN_SETTINGS_BACKUP: { // User wants to clone his smartcard volatile uint16_t pin_code; RET_TYPE temp_rettype; // Reauth user if (removeCardAndReAuthUser() == RETURN_OK) { // Ask for new pin temp_rettype = guiAskForNewPin(&pin_code, ID_STRING_PIN_NEW_CARD); if (temp_rettype == RETURN_NEW_PIN_OK) { // Start the cloning process if (cloneSmartCardProcess(&pin_code) == RETURN_OK) { // Well it worked.... } else { currentScreen = SCREEN_DEFAULT_INSERTED_LCK; guiDisplayInformationOnScreen(ID_STRING_TGT_CARD_NBL); } pin_code = 0x0000; } else if (temp_rettype == RETURN_NEW_PIN_DIFF) { currentScreen = SCREEN_DEFAULT_INSERTED_LCK; guiDisplayInformationOnScreen(ID_STRING_PIN_DIFF); } else { guiGetBackToCurrentScreen(); return; } } else { currentScreen = SCREEN_DEFAULT_INSERTED_LCK; guiDisplayInformationOnScreen(ID_STRING_FAILED); } userViewDelay(); guiGetBackToCurrentScreen(); break; } case SCREEN_SETTINGS_ERASE: { // User wants to delete his profile in flash / eeprom.... if ((guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_AREYOUSURE)) == RETURN_OK) && (removeCardAndReAuthUser() == RETURN_OK) && (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_AREYOURLSURE)) == RETURN_OK)) { uint8_t currentuserid = getCurrentUserID(); guiDisplayProcessingScreen(); deleteCurrentUserFromFlash(); if (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_ERASE_TCARD)) == RETURN_OK) { guiDisplayProcessingScreen(); eraseSmartCard(); // Erase other smartcards while (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_OTHECARDFUSER)) == RETURN_OK) { // Ask the user to insert other smartcards guiDisplayInformationOnScreen(ID_STRING_INSERT_OTHER); // Wait for the user to remove and enter another smartcard while (isCardPlugged() != RETURN_JRELEASED); // Wait for the user to insert a new smart card while (isCardPlugged() != RETURN_JDETECT); guiDisplayProcessingScreen(); // Check the card type & ask user to enter his pin, check that the new user id loaded by validCardDetectedFunction is still the same if ((cardDetectedRoutine() == RETURN_MOOLTIPASS_USER) && (validCardDetectedFunction(0, FALSE) == RETURN_VCARD_OK) && (currentuserid == getCurrentUserID())) { eraseSmartCard(); } } } // Delete LUT entries guiDisplayProcessingScreen(); deleteUserIdFromSMCUIDLUT(currentuserid); // Go to invalid screen currentScreen = SCREEN_DEFAULT_INSERTED_INVALID; } else { currentScreen = SCREEN_DEFAULT_INSERTED_LCK; } userViewDelay(); handleSmartcardRemoved(); guiGetBackToCurrentScreen(); break; } default: break; } } } }
/*! \fn usbProcessIncoming(uint8_t* incomingData) * \brief Process the incoming USB packet * \param incomingData Pointer to the packet (can be overwritten!) */ void usbProcessIncoming(uint8_t* incomingData) { // Temp plugin return value, error by default uint8_t plugin_return_value = PLUGIN_BYTE_ERROR; // Use message structure usbMsg_t* msg = (usbMsg_t*)incomingData; // Get data len uint8_t datalen = msg->len; // Get data cmd uint8_t datacmd = msg->cmd; #ifdef USB_FEATURE_PLUGIN_COMMS // Temp ret_type RET_TYPE temp_rettype; #endif #ifdef DEV_PLUGIN_COMMS char stack_str[10]; #endif // Debug comms // USBDEBUGPRINTF_P(PSTR("usb: rx cmd 0x%02x len %u\n"), datacmd, datalen); switch(datacmd) { // ping command case CMD_PING : { usbSendMessage(0, 6, msg); return; } // version command case CMD_VERSION : { msg->len = 3; // len + cmd + FLASH_CHIP msg->cmd = CMD_VERSION; msg->body.data[0] = FLASH_CHIP; msg->len += getVersion((char*)&msg->body.data[1], sizeof(msg->body.data) - 1); usbSendMessage(0, msg->len, msg); return; } #ifdef USB_FEATURE_PLUGIN_COMMS // context command case CMD_CONTEXT : { if (checkTextField(msg->body.data, datalen, NODE_PARENT_SIZE_OF_SERVICE) == RETURN_NOK) { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("setCtx: len %d too big\n"), datalen); } else if (getSmartCardInsertedUnlocked() != TRUE) { plugin_return_value = PLUGIN_BYTE_NOCARD; USBPARSERDEBUGPRINTF_P(PSTR("set context: no card\n")); } else if (setCurrentContext(msg->body.data, datalen) == RETURN_OK) { plugin_return_value = PLUGIN_BYTE_OK; USBPARSERDEBUGPRINTF_P(PSTR("set context: \"%s\" ok\n"), msg->body.data); } else { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("set context: \"%s\" failed\n"), msg->body.data); } break; } // get login case CMD_GET_LOGIN : { if (getLoginForContext((char*)incomingData) == RETURN_OK) { // Use the buffer to store the login... usbSendMessage(CMD_GET_LOGIN, strlen((char*)incomingData)+1, incomingData); USBPARSERDEBUGPRINTF_P(PSTR("get login: \"%s\"\n"),(char *)incomingData); return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("get login: failed\n")); } break; } // get password case CMD_GET_PASSWORD : { if (getPasswordForContext((char*)incomingData) == RETURN_OK) { usbSendMessage(CMD_GET_PASSWORD, strlen((char*)incomingData)+1, incomingData); USBPARSERDEBUGPRINTF_P(PSTR("get pass: \"%s\"\n"),(char *)incomingData); return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("get pass: failed\n")); } break; } // set login case CMD_SET_LOGIN : { if (checkTextField(msg->body.data, datalen, NODE_CHILD_SIZE_OF_LOGIN) == RETURN_NOK) { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("set login: \"%s\" checkTextField failed\n"),msg->body.data); } else if (setLoginForContext(msg->body.data, datalen) == RETURN_OK) { plugin_return_value = PLUGIN_BYTE_OK; USBPARSERDEBUGPRINTF_P(PSTR("set login: \"%s\" ok\n"),msg->body.data); } else { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("set login: \"%s\" failed\n"),msg->body.data); } break; } // set password case CMD_SET_PASSWORD : { if (checkTextField(msg->body.data, datalen, NODE_CHILD_SIZE_OF_PASSWORD) == RETURN_NOK) { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("set pass: len %d invalid\n"), datalen); } else if (setPasswordForContext(msg->body.data, datalen) == RETURN_OK) { plugin_return_value = PLUGIN_BYTE_OK; USBPARSERDEBUGPRINTF_P(PSTR("set pass: \"%s\" ok\n"),msg->body.data); } else { plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("set pass: failed\n")); } break; } // check password case CMD_CHECK_PASSWORD : { if (checkTextField(msg->body.data, datalen, NODE_CHILD_SIZE_OF_PASSWORD) == RETURN_NOK) { plugin_return_value = PLUGIN_BYTE_ERROR; break; } temp_rettype = checkPasswordForContext(msg->body.data, datalen); if (temp_rettype == RETURN_PASS_CHECK_NOK) { plugin_return_value = PLUGIN_BYTE_ERROR; } else if(temp_rettype == RETURN_PASS_CHECK_OK) { plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_NA; } break; } // set password case CMD_ADD_CONTEXT : { if (checkTextField(msg->body.data, datalen, NODE_PARENT_SIZE_OF_SERVICE) == RETURN_NOK) { // Check field plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("set context: len %d invalid\n"), datalen); } else if (addNewContext(msg->body.data, datalen) == RETURN_OK) { // We managed to add a new context plugin_return_value = PLUGIN_BYTE_OK; USBPARSERDEBUGPRINTF_P(PSTR("add context: \"%s\" ok\n"),msg->body.data); } else { // Couldn't add a new context plugin_return_value = PLUGIN_BYTE_ERROR; USBPARSERDEBUGPRINTF_P(PSTR("add context: \"%s\" failed\n"),msg->body.data); } break; } #endif #ifdef FLASH_BLOCK_IMPORT_EXPORT // flash export start case CMD_EXPORT_FLASH_START : { approveImportExportMemoryOperation(CMD_EXPORT_FLASH_START, &plugin_return_value); guiGetBackToCurrentScreen(); break; } // export flash contents case CMD_EXPORT_FLASH : { uint8_t size = PACKET_EXPORT_SIZE; // Check that the user approved if (currentFlashOpUid != CMD_EXPORT_FLASH_START) { return; } //flashOpCurAddr1 is the page //flashOpCurAddr2 is the offset // Check if the export address is correct if (flashOpCurAddr1 >= PAGE_COUNT) { usbSendMessage(CMD_EXPORT_FLASH_END, 0, NULL); USBPARSERDEBUGPRINTF_P(PSTR("export: end\n")); currentFlashOpUid = 0; return; } // Check how much data we need in case we're close to the page end if ((BYTES_PER_PAGE - flashOpCurAddr2) < PACKET_EXPORT_SIZE) { size = (uint8_t)(BYTES_PER_PAGE - flashOpCurAddr2); } // Get a block of data and send it, increment counter readDataFromFlash(flashOpCurAddr1, flashOpCurAddr2, size, (void*)incomingData); usbSendMessage(CMD_EXPORT_FLASH, size, incomingData); //usbSendMessageWithRetries(CMD_EXPORT_FLASH, size, (char*)incomingData, 255); flashOpCurAddr2 += size; if (flashOpCurAddr2 == BYTES_PER_PAGE) { flashOpCurAddr2 = 0; flashOpCurAddr1++; } // Skip over the graphics address if we're in that case if (flashOpCurAddr1 == GRAPHIC_ZONE_PAGE_START) { flashOpCurAddr1 = GRAPHIC_ZONE_PAGE_END; } return; } // flash export end case CMD_EXPORT_FLASH_END : { currentFlashOpUid = 0; return; } // flash export start case CMD_EXPORT_EEPROM_START : { approveImportExportMemoryOperation(CMD_EXPORT_EEPROM_START, &plugin_return_value); guiGetBackToCurrentScreen(); break; } // export eeprom contents case CMD_EXPORT_EEPROM : { uint8_t size = PACKET_EXPORT_SIZE; // Check that the user approved if (currentFlashOpUid != CMD_EXPORT_EEPROM_START) { return; } //flashOpCurAddr1 is the current eeprom address // Check if the export address is correct if (flashOpCurAddr1 >= EEPROM_SIZE) { usbSendMessage(CMD_EXPORT_EEPROM_END, 0, NULL); USBPARSERDEBUGPRINTF_P(PSTR("export: end\n")); currentFlashOpUid = 0; return; } // Check how much data we need if ((EEPROM_SIZE - flashOpCurAddr1) < PACKET_EXPORT_SIZE) { size = (uint8_t)(EEPROM_SIZE - flashOpCurAddr1); } // Get a block of data and send it, increment counter eeprom_read_block(incomingData, (void*)flashOpCurAddr1, size); usbSendMessage(CMD_EXPORT_EEPROM, size, (char*)incomingData); //usbSendMessageWithRetries(CMD_EXPORT_EEPROM, size, (char*)incomingData, 255); flashOpCurAddr1 += size; return; } // end eeprom export case CMD_EXPORT_EEPROM_END : { currentFlashOpUid = 0; return; } // import flash contents case CMD_IMPORT_FLASH_BEGIN : { // Check datalen for arg if (datalen != 1) { USBPARSERDEBUGPRINTF_P(PSTR("import: no param\n")); return; } // Ask user approval approveImportExportMemoryOperation(CMD_IMPORT_FLASH_BEGIN, &plugin_return_value); //flashOpCurAddr1 is the page //flashOpCurAddr2 is the offset // Check what we want to write if (msg->body.data[0] == 0x00) { flashOpCurAddr1 = 0x0000; flash_import_user_space = TRUE; } else { flash_import_user_space = FALSE; flashOpCurAddr1 = GRAPHIC_ZONE_PAGE_START; } // Get back to normal screen guiGetBackToCurrentScreen(); break; } // import flash contents case CMD_IMPORT_FLASH : { // Check if we actually approved the import, haven't gone over the flash boundaries, if we're correctly aligned page size wise if ((currentFlashOpUid != CMD_IMPORT_FLASH_BEGIN) || (flashOpCurAddr1 >= PAGE_COUNT) || (flashOpCurAddr2 + datalen > BYTES_PER_PAGE) || ((flash_import_user_space == FALSE) && (flashOpCurAddr1 >= GRAPHIC_ZONE_PAGE_END))) { plugin_return_value = PLUGIN_BYTE_ERROR; currentFlashOpUid = 0; } else { flashWriteBuffer(msg->body.data, flashOpCurAddr2, datalen); flashOpCurAddr2+= datalen; // If we just filled a page, flush it to the page if (flashOpCurAddr2 == BYTES_PER_PAGE) { flashWriteBufferToPage(flashOpCurAddr1); flashOpCurAddr2 = 0; flashOpCurAddr1++; // If we are importing user contents, skip the graphics zone if ((flash_import_user_space == TRUE) && (flashOpCurAddr1 == GRAPHIC_ZONE_PAGE_START)) { flashOpCurAddr1 = GRAPHIC_ZONE_PAGE_END; } } plugin_return_value = PLUGIN_BYTE_OK; } break; } // end flash import case CMD_IMPORT_FLASH_END : { if ((currentFlashOpUid == CMD_IMPORT_FLASH_BEGIN) && (flashOpCurAddr2 != 0)) { flashWriteBufferToPage(flashOpCurAddr1); } plugin_return_value = PLUGIN_BYTE_OK; currentFlashOpUid = 0; break; } // import flash contents case CMD_IMPORT_EEPROM_BEGIN : { // Ask for user confirmation approveImportExportMemoryOperation(CMD_IMPORT_EEPROM_BEGIN, &plugin_return_value); guiGetBackToCurrentScreen(); break; } // import flash contents case CMD_IMPORT_EEPROM : { // flashOpCurAddr1 is the current eeprom address if ((currentFlashOpUid != CMD_IMPORT_EEPROM_BEGIN) || ((flashOpCurAddr1 + datalen) >= EEPROM_SIZE)) { plugin_return_value = PLUGIN_BYTE_ERROR; currentFlashOpUid = 0; } else { eeprom_write_block((void*)msg->body.data, (void*)flashOpCurAddr1, datalen); flashOpCurAddr1+= datalen; plugin_return_value = PLUGIN_BYTE_OK; } break; } // end eeprom import case CMD_IMPORT_EEPROM_END : { plugin_return_value = PLUGIN_BYTE_OK; currentFlashOpUid = 0; break; } #endif #ifdef NODE_BLOCK_IMPORT_EXPORT // Read user profile in flash case CMD_START_MEMORYMGMT : { // Check that the smartcard is unlocked if (getSmartCardInsertedUnlocked() == TRUE) { // If so, ask the user to approve memory management mode approveMemoryManagementMode(&plugin_return_value); } break; } // Read starting parent case CMD_GET_STARTING_PARENT : { // Check that we're actually in memory management mode if (memoryManagementModeApproved == TRUE) { // Read starting parent uint16_t temp_address = getStartingParentAddress(); // Send address usbSendMessage(CMD_GET_STARTING_PARENT, 2, (uint8_t*)&temp_address); // Return return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Get a free node address case CMD_GET_FREE_SLOT_ADDR : { // Check that we're actually in memory management mode if (memoryManagementModeApproved == TRUE) { uint16_t temp_address; // Scan for next free node address scanNodeUsage(); // Store next free node address temp_address = getFreeNodeAddress(); // Send address usbSendMessage(CMD_GET_FREE_SLOT_ADDR, 2, (uint8_t*)&temp_address); return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // End memory management mode case CMD_END_MEMORYMGMT : { // Check that we're actually in memory management mode if (memoryManagementModeApproved == TRUE) { // memoryManagementModeApproved is cleared when user removes his card guiSetCurrentScreen(SCREEN_DEFAULT_INSERTED_NLCK); plugin_return_value = PLUGIN_BYTE_OK; leaveMemoryManagementMode(); guiGetBackToCurrentScreen(); populateServicesLut(); scanNodeUsage(); } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Read node from Flash case CMD_READ_FLASH_NODE : { // Check that the mode is approved & that args are supplied if ((memoryManagementModeApproved == TRUE) && (datalen == 2)) { uint16_t* temp_uint_ptr = (uint16_t*)msg->body.data; uint8_t temp_buffer[NODE_SIZE]; // Read node in flash & send it, ownership check is done in the function readNode((gNode*)temp_buffer, *temp_uint_ptr); usbSendMessage(CMD_READ_FLASH_NODE, NODE_SIZE, temp_buffer); return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Set favorite case CMD_SET_FAVORITE : { // Check that the mode is approved & that args are supplied if ((memoryManagementModeApproved == TRUE) && (datalen == 5)) { uint16_t* temp_par_addr = (uint16_t*)&msg->body.data[1]; uint16_t* temp_child_addr = (uint16_t*)&msg->body.data[3]; setFav(msg->body.data[0], *temp_par_addr, *temp_child_addr); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Get favorite case CMD_GET_FAVORITE : { // Check that the mode is approved & that args are supplied if ((memoryManagementModeApproved == TRUE) && (datalen == 1)) { uint16_t data[2]; readFav(msg->body.data[0], &data[0], &data[1]); usbSendMessage(CMD_GET_FAVORITE, 4, (void*)data); return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Set starting parent case CMD_SET_STARTINGPARENT : { // Check that the mode is approved & that args are supplied if ((memoryManagementModeApproved == TRUE) && (datalen == 2)) { uint16_t* temp_par_addr = (uint16_t*)&msg->body.data[0]; setStartingParent(*temp_par_addr); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Set new CTR value case CMD_SET_CTRVALUE : { // Check that the mode is approved & that args are supplied if ((memoryManagementModeApproved == TRUE) && (datalen == USER_CTR_SIZE)) { setProfileCtr(msg->body.data); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Get CTR value case CMD_GET_CTRVALUE : { // Check that the mode is approved & that args are supplied if (memoryManagementModeApproved == TRUE) { // Temp buffer to store CTR uint8_t tempCtrVal[USER_CTR_SIZE]; // Read CTR value readProfileCtr(tempCtrVal); // Send it usbSendMessage(CMD_GET_CTRVALUE, USER_CTR_SIZE, tempCtrVal); return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Add a known card to the MP, 8 first bytes is the CPZ, next 16 is the CTR nonce case CMD_ADD_CARD_CPZ_CTR : { // Check that the mode is approved & that args are supplied if ((memoryManagementModeApproved == TRUE) && (datalen == SMARTCARD_CPZ_LENGTH + AES256_CTR_LENGTH)) { writeSmartCardCPZForUserId(msg->body.data, &msg->body.data[SMARTCARD_CPZ_LENGTH], getCurrentUserID()); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Get all the cpz ctr values for current user case CMD_GET_CARD_CPZ_CTR : { // Check that the mode is approved if (memoryManagementModeApproved == TRUE) { outputLUTEntriesForGivenUser(getCurrentUserID()); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Write node in Flash case CMD_WRITE_FLASH_NODE : { // First two bytes are the node address uint16_t* temp_node_addr_ptr = (uint16_t*)msg->body.data; uint16_t temp_flags; // Check that the plugin provided the address and packet # if ((memoryManagementModeApproved != TRUE) || (datalen != 3)) { plugin_return_value = PLUGIN_BYTE_ERROR; } else { // If it is the first packet, store the address and load the page in the internal buffer if (msg->body.data[2] == 0) { // Read the flags and check we're not overwriting someone else's data readDataFromFlash(pageNumberFromAddress(*temp_node_addr_ptr), NODE_SIZE * nodeNumberFromAddress(*temp_node_addr_ptr), 2, (void*)&temp_flags); // Either the node belongs to us or it is invalid if((getCurrentUserID() == userIdFromFlags(temp_flags)) || (validBitFromFlags(temp_flags) == NODE_VBIT_INVALID)) { currentNodeWritten = *temp_node_addr_ptr; loadPageToInternalBuffer(pageNumberFromAddress(currentNodeWritten)); } } // Check that the address the plugin wants to write is the one stored and that we're not writing more than we're supposed to if ((currentNodeWritten == *temp_node_addr_ptr) && (currentNodeWritten != NODE_ADDR_NULL) && (msg->body.data[2] * (PACKET_EXPORT_SIZE-3) + datalen < NODE_SIZE)) { // If it's the first packet, set correct user ID if (msg->body.data[2] == 0) { userIdToFlags((uint16_t*)&(msg->body.data[3]), getCurrentUserID()); } // Fill the data at the right place flashWriteBuffer(msg->body.data + 3, (NODE_SIZE * nodeNumberFromAddress(currentNodeWritten)) + (msg->body.data[2] * (PACKET_EXPORT_SIZE-3)), datalen - 3); // If we finished writing, flush buffer if (msg->body.data[2] == (NODE_SIZE/(PACKET_EXPORT_SIZE-3))) { flashWriteBufferToPage(pageNumberFromAddress(currentNodeWritten)); } plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } } break; } #endif // import media flash contents case CMD_IMPORT_MEDIA_START : { #ifndef DEV_PLUGIN_COMMS uint8_t temp_buffer[PACKET_EXPORT_SIZE]; #endif // Set default addresses mediaFlashImportPage = GRAPHIC_ZONE_PAGE_START; mediaFlashImportOffset = 0; // No check if dev comms #ifdef DEV_PLUGIN_COMMS plugin_return_value = PLUGIN_BYTE_OK; mediaFlashImportApproved = TRUE; #else // Mandatory wait for bruteforce userViewDelay(); // Compare with our password, can be 0xFF... if not initialized if (datalen == PACKET_EXPORT_SIZE) { eeprom_read_block((void*)temp_buffer, (void*)EEP_BOOT_PWD, PACKET_EXPORT_SIZE); if (memcmp((void*)temp_buffer, (void*)msg->body.data, PACKET_EXPORT_SIZE) == 0) { plugin_return_value = PLUGIN_BYTE_OK; mediaFlashImportApproved = TRUE; } } #endif break; } // import media flash contents case CMD_IMPORT_MEDIA : { // Check if we actually approved the import, haven't gone over the flash boundaries, if we're correctly aligned page size wise if ((mediaFlashImportApproved == FALSE) || (mediaFlashImportPage >= GRAPHIC_ZONE_PAGE_END) || (mediaFlashImportOffset + datalen > BYTES_PER_PAGE)) { plugin_return_value = PLUGIN_BYTE_ERROR; mediaFlashImportApproved = FALSE; } else { flashWriteBuffer(msg->body.data, mediaFlashImportOffset, datalen); mediaFlashImportOffset+= datalen; // If we just filled a page, flush it to the page if (mediaFlashImportOffset == BYTES_PER_PAGE) { flashWriteBufferToPage(mediaFlashImportPage); mediaFlashImportOffset = 0; mediaFlashImportPage++; } plugin_return_value = PLUGIN_BYTE_OK; } break; } // end media flash import case CMD_IMPORT_MEDIA_END : { if ((mediaFlashImportApproved == TRUE) && (mediaFlashImportOffset != 0)) { flashWriteBufferToPage(mediaFlashImportPage); } plugin_return_value = PLUGIN_BYTE_OK; mediaFlashImportApproved = FALSE; break; } // Set Mooltipass param case CMD_SET_MOOLTIPASS_PARM : { // Check that args are supplied if (datalen == 2) { setMooltipassParameterInEeprom(msg->body.data[0], msg->body.data[1]); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Get Mooltipass param case CMD_GET_MOOLTIPASS_PARM : { plugin_return_value = getMooltipassParameterInEeprom(msg->body.data[0]); break; } // Reset smartcard case CMD_RESET_CARD : { uint16_t* temp_uint_pt = (uint16_t*)msg->body.data; // Check the args, check we're not authenticated, check that the card detection returns a user card, try unlocking the card with provided PIN if ((datalen == 2) && (getCurrentScreen() == SCREEN_DEFAULT_INSERTED_UNKNOWN) && (mooltipassDetectedRoutine(swap16(*temp_uint_pt)) == RETURN_MOOLTIPASS_4_TRIES_LEFT)) { eraseSmartCard(); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Add current unknown smartcard case CMD_ADD_UNKNOWN_CARD : { uint16_t* temp_uint_pt = (uint16_t*)msg->body.data; // Check the args, check we're not authenticated, check that the card detection returns a user card, try unlocking the card with provided PIN if ((datalen == (2 + AES256_CTR_LENGTH)) && (getCurrentScreen() == SCREEN_DEFAULT_INSERTED_UNKNOWN) && (mooltipassDetectedRoutine(swap16(*temp_uint_pt)) == RETURN_MOOLTIPASS_4_TRIES_LEFT)) { addNewUserForExistingCard(msg->body.data + 2); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Read card login case CMD_READ_CARD_LOGIN : { if (getSmartCardInsertedUnlocked() == TRUE) { uint8_t temp_data[SMARTCARD_MTP_LOGIN_LENGTH/8]; readMooltipassWebsiteLogin(temp_data); usbSendMessage(CMD_READ_CARD_LOGIN, sizeof(temp_data), (void*)temp_data); return; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Read card stored password case CMD_READ_CARD_PASS : { if (getSmartCardInsertedUnlocked() == TRUE) { if (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_SEND_SMC_PASS)) == RETURN_OK) { uint8_t temp_data[SMARTCARD_MTP_PASS_LENGTH/8]; readMooltipassWebsitePassword(temp_data); usbSendMessage(CMD_READ_CARD_PASS, sizeof(temp_data), (void*)temp_data); guiGetBackToCurrentScreen(); return; } else { guiGetBackToCurrentScreen(); plugin_return_value = PLUGIN_BYTE_ERROR; } } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Set card login case CMD_SET_CARD_LOGIN : { if ((checkTextField(msg->body.data, datalen, SMARTCARD_MTP_LOGIN_LENGTH/8) == RETURN_OK) && (getSmartCardInsertedUnlocked() == TRUE)) { if (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_SET_SMC_LOGIN)) == RETURN_OK) { // Temp buffer for application zone 2 uint8_t temp_az2[SMARTCARD_AZ_BIT_LENGTH/8]; // Read Application Zone 2 readApplicationZone2(temp_az2); // Erase Application Zone 2 eraseApplicationZone1NZone2SMC(FALSE); // Write our data in the buffer at the right spot memcpy(temp_az2 + (SMARTCARD_MTP_LOGIN_OFFSET/8), msg->body.data, datalen); // Write the new data in the card writeApplicationZone2(temp_az2); // Return OK plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } guiGetBackToCurrentScreen(); } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Set card stored password case CMD_SET_CARD_PASS : { if ((checkTextField(msg->body.data, datalen, SMARTCARD_MTP_PASS_LENGTH/8) == RETURN_OK) && (getSmartCardInsertedUnlocked() == TRUE)) { if (guiAskForConfirmation(1, (confirmationText_t*)readStoredStringToBuffer(ID_STRING_SET_SMC_PASS)) == RETURN_OK) { // Temp buffer for application zone 1 uint8_t temp_az1[SMARTCARD_AZ_BIT_LENGTH/8]; // Read Application Zone 1 readApplicationZone1(temp_az1); // Erase Application Zone 1 eraseApplicationZone1NZone2SMC(TRUE); // Write our data in buffer memcpy(temp_az1 + (SMARTCARD_MTP_PASS_OFFSET/8), msg->body.data, datalen); // Write the new data in the card writeApplicationZone1(temp_az1); // Return OK plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } guiGetBackToCurrentScreen(); } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Get 32 random bytes case CMD_GET_RANDOM_NUMBER : { uint8_t randomBytes[32]; fillArrayWithRandomBytes(randomBytes, 32); usbSendMessage(CMD_GET_RANDOM_NUMBER, 32, randomBytes); return; } // set password bootkey case CMD_SET_BOOTLOADER_PWD : { if ((eeprom_read_byte((uint8_t*)EEP_BOOT_PWD_SET) != BOOTLOADER_PWDOK_KEY) && (datalen == PACKET_EXPORT_SIZE)) { eeprom_write_block((void*)msg->body.data, (void*)EEP_BOOT_PWD, PACKET_EXPORT_SIZE); eeprom_write_byte((uint8_t*)EEP_BOOT_PWD_SET, BOOTLOADER_PWDOK_KEY); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } // Jump to bootloader case CMD_JUMP_TO_BOOTLOADER : { #ifndef DEV_PLUGIN_COMMS uint8_t temp_buffer[PACKET_EXPORT_SIZE]; #endif // Mandatory wait for bruteforce userViewDelay(); #ifdef DEV_PLUGIN_COMMS // Write "jump to bootloader" key in eeprom eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, BOOTLOADER_BOOTKEY); // Use WDT to reset the device cli(); wdt_reset(); wdt_clear_flag(); wdt_change_enable(); wdt_enable_2s(); sei(); while(1); #else if ((eeprom_read_byte((uint8_t*)EEP_BOOT_PWD_SET) == BOOTLOADER_PWDOK_KEY) && (datalen == PACKET_EXPORT_SIZE)) { eeprom_read_block((void*)temp_buffer, (void*)EEP_BOOT_PWD, PACKET_EXPORT_SIZE); if (memcmp((void*)temp_buffer, (void*)msg->body.data, PACKET_EXPORT_SIZE) == 0) { // Write "jump to bootloader" key in eeprom eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, BOOTLOADER_BOOTKEY); // Set bootloader password bool to FALSE eeprom_write_byte((uint8_t*)EEP_BOOT_PWD_SET, FALSE); // Use WDT to reset the device cli(); wdt_reset(); wdt_clear_flag(); wdt_change_enable(); wdt_enable_2s(); sei(); while(1); } } #endif } // Development commands #ifdef DEV_PLUGIN_COMMS // erase eeprom case CMD_ERASE_EEPROM : { eraseFlashUsersContents(); firstTimeUserHandlingInit(); plugin_return_value = PLUGIN_BYTE_OK; break; } // erase flash case CMD_ERASE_FLASH : { eraseFlashUsersContents(); plugin_return_value = PLUGIN_BYTE_OK; break; } // erase eeprom case CMD_ERASE_SMC : { if (getSmartCardInsertedUnlocked() == TRUE) { eraseSmartCard(); plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } case CMD_DRAW_BITMAP : { usbPrintf_P(PSTR("draw bitmap file %d\n"), msg->body.data[0]); if (msg->body.data[3] != 0) // clear { oledWriteActiveBuffer(); oledClear(); oledBitmapDrawFlash(msg->body.data[1], msg->body.data[2], msg->body.data[0], 0); } else { // don't clear, overlay active screen oledWriteActiveBuffer(); oledBitmapDrawFlash(msg->body.data[1], msg->body.data[2], msg->body.data[0], 0); } return; } case CMD_CLONE_SMARTCARD : { if (cloneSmartCardProcess(SMARTCARD_DEFAULT_PIN) == RETURN_OK) { plugin_return_value = PLUGIN_BYTE_OK; } else { plugin_return_value = PLUGIN_BYTE_ERROR; } break; } case CMD_SET_FONT : { usbPrintf_P(PSTR("set font file %d\n"), msg->body.data[0]); oledSetFont(msg->body.data[0]); if (datalen > 1) { usbPrintf_P(PSTR("testing string \"%s\"\n"), (char *)&msg->body.data[1]); oledFlipBuffers(0,0); oledWriteActiveBuffer(); oledClear(); oledPutstr((char *)&msg->body.data[1]); } return; } case CMD_STACK_FREE: usbPutstr("Stack Free "); int_to_string(stackFree(),stack_str); usbPutstr(stack_str); usbPutstr(" bytes\n"); return; #endif default : return; } usbSendMessage(datacmd, 1, &plugin_return_value); }