/*! \fn guiDisplaySmartcardUnlockedScreen(uint8_t* username) * \brief Display the smartcard unlocked screen * \param username The username (if there's one) */ void guiDisplaySmartcardUnlockedScreen(uint8_t* username) { #if defined(MINI_VERSION) uint8_t temp_Y = THREE_LINE_TEXT_SECOND_POS; // Clear screen, check that the username is valid oledClear(); if ((username[0] != 0) && (username[0] != 0xFF)) { temp_Y = THREE_LINE_TEXT_FIRST_POS; miniOledPutCenteredString(THREE_LINE_TEXT_SECOND_POS, readStoredStringToBuffer(ID_STRING_YOUR_USERNAME)); miniOledPutCenteredString(THREE_LINE_TEXT_THIRD_POS, (char*)username); } miniOledPutCenteredString(temp_Y, readStoredStringToBuffer(ID_STRING_CARD_UNLOCKED)); //oledBitmapDrawFlash(2, 17, BITMAP_INFO, 0); miniOledFlushEntireBufferToDisplay(); #elif defined(HARDWARE_OLIVIER_V1) uint8_t temp_Y = 24; // Clear screen, check that the username is valid oledClear(); if ((username[0] != 0) && (username[0] != 0xFF)) { temp_Y -= 16; oledPutstrXY(10, 24, OLED_CENTRE, readStoredStringToBuffer(ID_STRING_YOUR_USERNAME)); oledPutstrXY(10, 40, OLED_CENTRE, (const char*)username); } oledPutstrXY(10, temp_Y, OLED_CENTRE, readStoredStringToBuffer(ID_STRING_CARD_UNLOCKED)); oledBitmapDrawFlash(2, 17, BITMAP_INFO, 0); oledDisplayOtherBuffer(); #endif }
void oledInit(void) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); exit(1); } atexit(SDL_Quit); int scale = emulatorScale(); SDL_Window *window = SDL_CreateWindow("TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, OLED_WIDTH * scale, OLED_HEIGHT * scale, 0); if (window == NULL) { fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); exit(1); } renderer = SDL_CreateRenderer(window, -1, 0); if (!renderer) { fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); exit(1); } /* Use unscaled coordinate system */ SDL_RenderSetLogicalSize(renderer, OLED_WIDTH, OLED_HEIGHT); texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); oledClear(); oledRefresh(); }
void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { int left = 0; oledClear(); if (icon) { oledDrawBitmap(0, 0, icon); left = icon->width + 4; } if (line1) oledDrawString(left, 0 * 9, line1, FONT_STANDARD); if (line2) oledDrawString(left, 1 * 9, line2, FONT_STANDARD); if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD); if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD); if (desc) { oledDrawStringCenter(OLED_HEIGHT - 2 * 9 - 1, desc, FONT_STANDARD); if (btnYes || btnNo) { oledHLine(OLED_HEIGHT - 21); } } else { if (line5) oledDrawString(left, 4 * 9, line5, FONT_STANDARD); if (line6) oledDrawString(left, 5 * 9, line6, FONT_STANDARD); if (btnYes || btnNo) { oledHLine(OLED_HEIGHT - 13); } } if (btnNo) { layoutButtonNo(btnNo); } if (btnYes) { layoutButtonYes(btnYes); } oledRefresh(); }
int main(void) { __stack_chk_guard = random32(); setup(); memory_protect(); oledInit(); // at least one button is unpressed uint16_t state = gpio_port_read(BTN_PORT); if ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO) { check_firmware_sanity(); oledClear(); oledDrawBitmap(40, 0, &bmp_logo64_empty); oledRefresh(); uint8_t hash[32]; if (!signatures_ok(hash)) { show_unofficial_warning(hash); } load_app(); } bootloader_loop(); return 0; }
__fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { const BITMAP *icon = &bmp_icon_error; char line[128] = {0}; int y = icon->height + 3; oledClear(); oledDrawBitmap(0, 0, icon); oledDrawStringCenter(OLED_WIDTH / 2, (icon->height - FONT_HEIGHT) / 2 + 1, "FATAL ERROR", FONT_STANDARD); snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); oledDrawString(0, y, line, FONT_STANDARD); y += FONT_HEIGHT + 1; snprintf(line, sizeof(line), "Msg: %s", msg ? msg : "(null)"); oledDrawString(0, y, line, FONT_STANDARD); y += FONT_HEIGHT + 1; const char *label = "File: "; snprintf(line, sizeof(line), "%s:%d", file ? file : "(null)", line_num); oledDrawStringRight(OLED_WIDTH - 1, y, line, FONT_STANDARD); oledBox(0, y, oledStringWidth(label, FONT_STANDARD), y + FONT_HEIGHT, false); oledDrawString(0, y, label, FONT_STANDARD); y += FONT_HEIGHT + 1; snprintf(line, sizeof(line), "Func: %s", func ? func : "(null)"); oledDrawString(0, y, line, FONT_STANDARD); y += FONT_HEIGHT + 1; oledDrawString(0, y, "Contact TREZOR support.", FONT_STANDARD); oledRefresh(); shutdown(); }
/*! \fn guiDisplayGoingToSleep(void) * \brief Going to sleep code */ void guiDisplayGoingToSleep(void) { oledClear(); oledPutstrXY(10, 24, OLED_CENTRE, readStoredStringToBuffer(ID_STRING_GOINGTOSLEEP)); oledBitmapDrawFlash(2, 17, BITMAP_ZZZ, 0); oledDisplayOtherBuffer(); }
void layoutProgressSwipe(const char *desc, int permil) { if (layoutLast == layoutProgressSwipe) { oledClear(); } else { layoutLast = layoutProgressSwipe; layoutSwipe(); } layoutProgress(desc, permil); }
void afterHadLogoDisplayTests(void) { //#define TEST_PWM #ifdef TEST_PWM uint8_t toto = 0; switchOnLeftButonLed(); switchOnRightButonLed(); switchOnTopLeftWheelLed(); switchOnTopRightWheelLed(); switchOnBotLeftWheelLed(); switchOnBotRightWheelLed(); oledWriteActiveBuffer(); while(1) { oledSetXY(2,0); printf("%02X", MAX_PWM_VAL >> toto); setPwmDc(MAX_PWM_VAL >> toto); _delay_ms(1000); if(toto++ == 11) toto = 0; } #endif //#define TEST_HID #ifdef TEST_HID uint8_t i; while(1) { if (getKeyboardLeds() & HID_CAPS_MASK) { usbPutstr("NOPE!\r\n"); while(getKeyboardLeds() & HID_CAPS_MASK) { usbKeyboardPress(KEY_CAPS_LOCK, 0); _delay_ms(30); } for(i = ' '; i < 0x7F; i++) { usbKeybPutChar(i); } usbKeybPutStr("\rBonjour oh grand dieu!\n"); } } #endif //#define TEST_PLUGIN #ifdef TEST_PLUGIN printf_P(PSTR("Plugin test\n")); oledFlipBuffers(OLED_SCROLL_UP,5); oledClear(); // clear inactive buffer oledWriteActiveBuffer(); #endif }
void layoutResetWord(const char *word, int pass, int word_pos, bool last) { layoutLast = layoutResetWord; layoutSwipe(); const char *btnYes; if (last) { if (pass == 1) { btnYes = _("Finish"); } else { btnYes = _("Again"); } } else { btnYes = _("Next"); } const char *action; if (pass == 1) { action = _("Please check the seed"); } else { action = _("Write down the seed"); } char index_str[] = "##th word is:"; if (word_pos < 10) { index_str[0] = ' '; } else { index_str[0] = '0' + word_pos / 10; } index_str[1] = '0' + word_pos % 10; if (word_pos == 1 || word_pos == 21) { index_str[2] = 's'; index_str[3] = 't'; } else if (word_pos == 2 || word_pos == 22) { index_str[2] = 'n'; index_str[3] = 'd'; } else if (word_pos == 3 || word_pos == 23) { index_str[2] = 'r'; index_str[3] = 'd'; } int left = 0; oledClear(); oledDrawBitmap(0, 0, &bmp_icon_info); left = bmp_icon_info.width + 4; oledDrawString(left, 0 * 9, action, FONT_STANDARD); oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str, FONT_STANDARD); oledDrawString(left, 3 * 9, word, FONT_STANDARD | FONT_DOUBLE); oledHLine(OLED_HEIGHT - 13); layoutButtonYes(btnYes); oledRefresh(); }
/*! \fn displayInitForTest() * \brief Init OLED SCREEN per test */ void displayInitForTest(void) { #ifdef FLASH_TEST_DEBUG_OUTPUT_OLED oledClear(); oledSetXY(0,0); printf_P(PSTR("Flash Test")); oledSetXY(0,8); #endif #ifdef FLASH_TEST_DEBUG_OUTPUT_USB usbPrintf_P(PSTR("\n----Flash Test----\n")); #endif }
/* * oledClear() Python Analogue */ static PyObject* pyOledClear(PyObject* self, PyObject* args) { int status; // make the oled-exp call status = oledClear (); if (status != EXIT_SUCCESS) { PyErr_SetString(PyExc_IOError, wrmsg_i2c); return NULL; } return Py_BuildValue("i", status); }
void oledInit() { static uint8_t s[25] = { OLED_DISPLAYOFF, OLED_SETDISPLAYCLOCKDIV, 0x80, OLED_SETMULTIPLEX, 0x3F, // 128x64 OLED_SETDISPLAYOFFSET, 0x00, OLED_SETSTARTLINE | 0x00, OLED_CHARGEPUMP, 0x14, OLED_MEMORYMODE, 0x00, OLED_SEGREMAP | 0x01, OLED_COMSCANDEC, OLED_SETCOMPINS, 0x12, // 128x64 OLED_SETCONTRAST, 0xCF, OLED_SETPRECHARGE, 0xF1, OLED_SETVCOMDETECT, 0x40, OLED_DISPLAYALLON_RESUME, OLED_NORMALDISPLAY, OLED_DISPLAYON }; gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect // Reset the LCD gpio_set(OLED_RST_PORT, OLED_RST_PIN); delay(40); gpio_clear(OLED_RST_PORT, OLED_RST_PIN); delay(400); gpio_set(OLED_RST_PORT, OLED_RST_PIN); // init gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select SPISend(SPI_BASE, s, 25); gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect oledClear(); oledRefresh(); }
/*! \fn guiDisplayTextInformationOnScreen(char* text) * \brief Display text information on screen * \param text Text to display */ void guiDisplayTextInformationOnScreen(char* text) { oledClear(); #if defined(HARDWARE_OLIVIER_V1) // No LEDs touchDetectionRoutine(0xFF); oledPutstrXY(10, 24, OLED_CENTRE, text); oledBitmapDrawFlash(2, 17, BITMAP_INFO, 0); oledDisplayOtherBuffer(); #elif defined(MINI_VERSION) miniOledPutCenteredString(THREE_LINE_TEXT_SECOND_POS, text); //oledPutstrXY(0, 10, OLED_CENTRE, text); //oledBitmapDrawFlash(2, 17, BITMAP_INFO, 0); miniOledFlushEntireBufferToDisplay(); #endif }
/*! \fn guiDisplayInsertSmartCardScreenAndWait(void) * \brief Ask for the user to insert his smart card * \return RETURN_OK if the user inserted and unlocked his smartcard */ RET_TYPE guiDisplayInsertSmartCardScreenAndWait(void) { RET_TYPE card_detect_ret = RETURN_JRELEASED; //#define KEYBOARD_LAYOUT_TEST #ifdef KEYBOARD_LAYOUT_TEST for (uint8_t i = ' '; i <= '~'; i++) { usbKeybPutChar(i); usbKeybPutChar(i); } //setMooltipassParameterInEeprom(KEYBOARD_LAYOUT_PARAM, getMooltipassParameterInEeprom(KEYBOARD_LAYOUT_PARAM)+1); //if (getMooltipassParameterInEeprom(KEYBOARD_LAYOUT_PARAM) > LAST_KEYB_LUT) //{ // setMooltipassParameterInEeprom(KEYBOARD_LAYOUT_PARAM, FIRST_KEYB_LUT); //} #endif // Switch on lights activityDetectedRoutine(); // Draw insert bitmap oledClear(); oledBitmapDrawFlash(0, 0, BITMAP_INSERT, 0); oledFlipBuffers(0,0); // Wait for either timeout or for the user to insert his smartcard while ((hasTimerExpired(TIMER_USERINT, TRUE) == TIMER_RUNNING) && (card_detect_ret != RETURN_JDETECT)) { card_detect_ret = isCardPlugged(); touchDetectionRoutine(0); } // If the user didn't insert his smart card if (card_detect_ret != RETURN_JDETECT) { // Get back to other screen guiGetBackToCurrentScreen(); return RETURN_NOK; } else { return handleSmartcardInserted(); } }
void oledDebug(const char *line) { int i; static const char *lines[8] = {0, 0, 0, 0, 0, 0, 0, 0}; static char id = 3; for (i = 0; i < 7; i++) { lines[i] = lines[i + 1]; } lines[7] = line; oledClear(); for (i = 0; i < 8; i++) { if (lines[i]) { oledDrawChar(0, i * 8, '0' + (id + i) % 10, 1); oledDrawString(8, i * 8, lines[i]); } } oledRefresh(); id = (id + 1) % 10; }
/**************************************************************************** * 函数名:oledInit 输 入:void 输 出:void 功 能:OLED初始化函数 备 注:无 * 日 期:2015.02.01 ****************************************************************************/ void oledInit(void) { oledGpioInit(); OLED_RST_Set(); delayMs(100); OLED_RST_Clr(); delayMs(100); OLED_RST_Set(); oledWriteCmd(0xAE);//--turn off oled panel oledWriteCmd(0x02);//---set low column address oledWriteCmd(0x10);//---set high column address oledWriteCmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F) oledWriteCmd(0x81);//--set contrast control register oledWriteCmd(0xCF); // Set SEG Output Current Brightness oledWriteCmd(0xA1);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常 oledWriteCmd(0xC8);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常 oledWriteCmd(0xA6);//--set normal display oledWriteCmd(0xA8);//--set multiplex ratio(1 to 64) oledWriteCmd(0x3f);//--1/64 duty oledWriteCmd(0xD3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F) oledWriteCmd(0x00);//-not offset oledWriteCmd(0xd5);//--set display clock divide ratio/oscillator frequency oledWriteCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec oledWriteCmd(0xD9);//--set pre-charge period oledWriteCmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock oledWriteCmd(0xDA);//--set com pins hardware configuration oledWriteCmd(0x12); oledWriteCmd(0xDB);//--set vcomh oledWriteCmd(0x40);//Set VCOM Deselect Level oledWriteCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02) oledWriteCmd(0x02);// oledWriteCmd(0x8D);//--set Charge Pump enable/disable oledWriteCmd(0x14);//--set(0x10) disable oledWriteCmd(0xA4);// Disable Entire Display On (0xa4/0xa5) oledWriteCmd(0xA6);// Disable Inverse Display On (0xa6/a7) oledWriteCmd(0xAF);//--turn on oled panel oledWriteCmd(0xAF); /*display ON*/ oledClear(); oledSetPosition(0,0); }
static void render_address_dialog(const CoinInfo *coin, const char *address, const char *line1, const char *line2, const char *extra_line) { if (coin && coin->cashaddr_prefix) { /* If this is a cashaddr address, remove the prefix from the * string presented to the user */ int prefix_len = strlen(coin->cashaddr_prefix); if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0 && address[prefix_len] == ':') { address += prefix_len + 1; } } int addrlen = strlen(address); int numlines = addrlen <= 42 ? 2 : 3; int linelen = (addrlen - 1) / numlines + 1; if (linelen > 21) { linelen = 21; } const char **str = split_message((const uint8_t *)address, addrlen, linelen); layoutLast = layoutDialogSwipe; layoutSwipe(); oledClear(); oledDrawBitmap(0, 0, &bmp_icon_question); oledDrawString(20, 0 * 9, line1, FONT_STANDARD); oledDrawString(20, 1 * 9, line2, FONT_STANDARD); int left = linelen > 18 ? 0 : 20; oledDrawString(left, 2 * 9, str[0], FONT_FIXED); oledDrawString(left, 3 * 9, str[1], FONT_FIXED); oledDrawString(left, 4 * 9, str[2], FONT_FIXED); oledDrawString(left, 5 * 9, str[3], FONT_FIXED); if (!str[3][0]) { if (extra_line) { oledDrawString(0, 5 * 9, extra_line, FONT_STANDARD); } else { oledHLine(OLED_HEIGHT - 13); } } layoutButtonNo(_("Cancel")); layoutButtonYes(_("Confirm")); oledRefresh(); }
void layoutHome(void) { if (layoutLast == layoutHome || layoutLast == layoutScreensaver) { oledClear(); } else { layoutSwipe(); } layoutLast = layoutHome; const char *label = storage_isInitialized() ? storage_getLabel() : _("Go to trezor.io/start"); const uint8_t *homescreen = storage_getHomescreen(); if (homescreen) { BITMAP b; b.width = 128; b.height = 64; b.data = homescreen; oledDrawBitmap(0, 0, &b); } else { if (label && strlen(label) > 0) { oledDrawBitmap(44, 4, &bmp_logo48); oledDrawStringCenter(OLED_HEIGHT - 8, label, FONT_STANDARD); } else { oledDrawBitmap(40, 0, &bmp_logo64); } } if (storage_noBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "SEEDLESS", FONT_STANDARD); } else if (storage_unfinishedBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "BACKUP FAILED!", FONT_STANDARD); } else if (storage_needsBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "NEEDS BACKUP!", FONT_STANDARD); } oledRefresh(); // Reset lock screen timeout system_millis_lock_start = timer_ms(); }
void layoutProgress(const char *desc, int permil) { oledClear(); layoutProgressUpdate(false); // progressbar oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); permil = permil * (OLED_WIDTH - 4) / 1000; if (permil < 0) { permil = 0; } if (permil > OLED_WIDTH - 4) { permil = OLED_WIDTH - 4; } oledBox(2, OLED_HEIGHT - 6, 1 + permil, OLED_HEIGHT - 3, 1); // text oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); if (desc) { oledDrawStringCenter(OLED_HEIGHT - 16, desc); } oledRefresh(); }
void bootloader_loop(void) { oledClear(); oledDrawBitmap(0, 0, &bmp_logo64); if (firmware_present()) { oledDrawString(52, 0, "TREZOR", FONT_STANDARD); static char serial[25]; fill_serialno_fixed(serial); oledDrawString(52, 20, "Serial No.", FONT_STANDARD); oledDrawString(52, 40, serial + 12, FONT_STANDARD); // second part of serial serial[12] = 0; oledDrawString(52, 30, serial, FONT_STANDARD); // first part of serial oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "Loader " VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); } else { oledDrawString(52, 10, "Welcome!", FONT_STANDARD); oledDrawString(52, 30, "Please visit", FONT_STANDARD); oledDrawString(52, 50, "trezor.io/start", FONT_STANDARD); } oledRefresh(); usbLoop(firmware_present()); }
int main(void) { #ifndef APPVER setup(); #endif __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #ifndef APPVER memory_protect(); oledInit(); #endif #ifndef APPVER // at least one button is unpressed uint16_t state = gpio_port_read(BTN_PORT); int unpressed = ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO); if (firmware_present() && unpressed) { oledClear(); oledDrawBitmap(40, 0, &bmp_logo64_empty); oledRefresh(); uint8_t hash[32]; int signed_firmware = signatures_ok(hash); if (SIG_OK != signed_firmware) { show_unofficial_warning(hash); timer_init(); } load_app(signed_firmware); } #endif bootloader_loop(); return 0; }
void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { int left = 0; oledClear(); if (icon) { oledDrawBitmap(0, 0, icon); left = icon->width + 4; } if (line1) oledDrawString(left, 0 * 9, line1); if (line2) oledDrawString(left, 1 * 9, line2); if (line3) oledDrawString(left, 2 * 9, line3); if (line4) oledDrawString(left, 3 * 9, line4); if (desc) { oledDrawStringCenter(OLED_HEIGHT - 2 * 9 - 1, desc); if (btnYes || btnNo) { oledHLine(OLED_HEIGHT - 21); } } else { if (line5) oledDrawString(left, 4 * 9, line5); if (line6) oledDrawString(left, 5 * 9, line6); if (btnYes || btnNo) { oledHLine(OLED_HEIGHT - 13); } } if (btnNo) { oledDrawString(1, OLED_HEIGHT - 8, "\x15"); oledDrawString(fontCharWidth('\x15') + 3, OLED_HEIGHT - 8, btnNo); oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('\x15') + oledStringWidth(btnNo) + 2, OLED_HEIGHT - 1); } if (btnYes) { oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); } oledRefresh(); }
/*! \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 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 // 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); // 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); }
/*! \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); }
/*! \fn guiGetPinFromUser(volatile uint16_t* pin_code, uint8_t stringID) * \brief Ask the user to enter a PIN * \param pin_code Pointer to where to store the pin code * \param stringID String ID * \return If the user approved the request */ RET_TYPE guiGetPinFromUser(volatile uint16_t* pin_code, uint8_t stringID) { // If we don't need a pin code, send default one #if defined(NO_PIN_CODE_REQUIRED) || defined(HARDWARE_V1) || defined(V2_DEVELOPERS_BOTPCB_BOOTLOADER_SETUP) *pin_code = SMARTCARD_DEFAULT_PIN; return RETURN_OK; #endif RET_TYPE ret_val = RETURN_NOK; uint8_t selected_digit = 0; uint8_t finished = FALSE; uint8_t current_pin[4]; RET_TYPE temp_rettype; int8_t temp_int8; // Set current pin to 0000 memset((void*)current_pin, 0, 4); // Draw pin entering bitmap oledClear(); oledBitmapDrawFlash(0, 0, BITMAP_YES_NO, 0); oledBitmapDrawFlash(83, 51, BITMAP_PIN_LINES, 0); oledBitmapDrawFlash(238, 23, BITMAP_RIGHT_ARROW, 0); oledPutstrXY(0, 0, OLED_CENTRE, readStoredStringToBuffer(stringID)); oledDisplayOtherBuffer(); oledSetFont(FONT_PROFONT_24); oledWriteActiveBuffer(); // Display current pin on screen guiDisplayPinOnPinEnteringScreen(current_pin, selected_digit); // While the user hasn't entered his pin while(!finished) { // Still process the USB commands usbProcessIncoming(USB_CALLER_PIN); // Detect key touches temp_rettype = touchDetectionRoutine(0); // Send it to the touch wheel interface logic temp_int8 = touchWheelIntefaceLogic(temp_rettype); // Position increment / decrement if (temp_int8 != 0) { if ((current_pin[selected_digit] == 0x0F) && (temp_int8 == 1)) { current_pin[selected_digit] = 0xFF; } else if ((current_pin[selected_digit] == 0) && (temp_int8 == -1)) { current_pin[selected_digit] = 0x10; } current_pin[selected_digit] += temp_int8; guiDisplayPinOnPinEnteringScreen(current_pin, selected_digit); } if ((isSmartCardAbsent() == RETURN_OK) || (hasTimerExpired(TIMER_USERINT, TRUE) == TIMER_EXPIRED)) { // Smartcard removed, no reason to continue ret_val = RETURN_NOK; finished = TRUE; } if (temp_rettype & RETURN_LEFT_PRESSED) { if (selected_digit == 1) { oledFillXY(0, 23, 18, 18, 0x00); oledBitmapDrawFlash(0, 24, BITMAP_CROSS, 0); } if (selected_digit > 0) { // When going back set pin digit to 0 current_pin[selected_digit] = 0; current_pin[--selected_digit] = 0; } else { ret_val = RETURN_NOK; finished = TRUE; } guiDisplayPinOnPinEnteringScreen(current_pin, selected_digit); oledBitmapDrawFlash(238, 23, BITMAP_RIGHT_ARROW, 0); } else if (temp_rettype & RETURN_RIGHT_PRESSED) { if (selected_digit == 2) { oledFillXY(238, 23, 18, 18, 0x00); oledBitmapDrawFlash(240, 24, BITMAP_TICK, 0); } if (selected_digit < 3) { selected_digit++; } else { ret_val = RETURN_OK; finished = TRUE; } guiDisplayPinOnPinEnteringScreen(current_pin, selected_digit); oledBitmapDrawFlash(0, 23, BITMAP_LEFT_ARROW, 0); } } // Reset default font oledSetFont(FONT_DEFAULT); oledWriteInactiveBuffer(); // Store the pin *pin_code = (uint16_t)(((uint16_t)(current_pin[0]) << 12) | (((uint16_t)current_pin[1]) << 8) | (current_pin[2] << 4) | current_pin[3]); // Set current pin to 0000 memset((void*)current_pin, 0, 4); // Prevent touches until the user lifts his finger touchInhibitUntilRelease(); // Return success status return ret_val; }
/*! \fn guiMainLoop(void) * \brief Main user interface loop */ void guiMainLoop(void) { RET_TYPE input_interface_result; uint8_t screenSaverOnCopy; uint8_t isScreenOnCopy; #if defined(HARDWARE_OLIVIER_V1) // Set led mask depending on our current screen switch(getCurrentScreen()) { case SCREEN_DEFAULT_NINSERTED : currentLedMask = LED_MASK_LEFT|LED_MASK_RIGHT|LED_MASK_WHEEL; break; case SCREEN_DEFAULT_INSERTED_LCK : currentLedMask = LED_MASK_LEFT|LED_MASK_RIGHT|LED_MASK_WHEEL; break; case SCREEN_DEFAULT_INSERTED_NLCK : currentLedMask = LED_MASK_LEFT|LED_MASK_RIGHT; break; case SCREEN_DEFAULT_INSERTED_INVALID : currentLedMask = LED_MASK_LEFT|LED_MASK_RIGHT|LED_MASK_WHEEL; break; case SCREEN_SETTINGS : currentLedMask = LED_MASK_LEFT|LED_MASK_RIGHT; break; case SCREEN_MEMORY_MGMT : currentLedMask = LED_MASK_LEFT|LED_MASK_RIGHT|LED_MASK_WHEEL; break; default: break; } #endif // Make a copy of the screen on & screensaver on bools screenSaverOnCopy = screenSaverOn; isScreenOnCopy = oledIsOn(); #if defined(HARDWARE_OLIVIER_V1) // Launch touch detection routine to check for interactions input_interface_result = touchDetectionRoutine(currentLedMask); #elif defined(MINI_VERSION) input_interface_result = miniGetWheelAction(FALSE, FALSE); #endif #if defined(HARDWARE_OLIVIER_V1) // No activity, switch off LEDs and activate prox detection if (hasTimerExpired(TIMER_LIGHT, TRUE) == TIMER_EXPIRED) { setPwmDc(0x0000); areLightsOn = FALSE; activateProxDetection(); } #endif // No activity, switch off screen if (hasTimerExpired(TIMER_SCREEN, TRUE) == TIMER_EXPIRED) { guiDisplayGoingToSleep(); userViewDelay(); if (getMooltipassParameterInEeprom(SCREENSAVER_PARAM) != FALSE) { screenSaverOn = TRUE; oledWriteInactiveBuffer(); oledClear(); oledDisplayOtherBuffer(); oledClear(); } else { oledDisplayOtherBuffer(); oledOff(); } } #if defined(HARDWARE_OLIVIER_V1) // If there was some activity and we are showing the screen saver if ((input_interface_result & TOUCH_PRESS_MASK) && (screenSaverOnCopy == TRUE)) { guiGetBackToCurrentScreen(); } // If the screen just got turned on, don't call the guiScreenLoop() function if ((input_interface_result & TOUCH_PRESS_MASK) && (((isScreenOnCopy != FALSE) && (screenSaverOnCopy == FALSE)) || (getCurrentScreen() == SCREEN_DEFAULT_INSERTED_LCK))) { guiScreenLoop(input_interface_result); } #elif defined(MINI_VERSION) // If there was some activity and we are showing the screen saver if ((input_interface_result != WHEEL_ACTION_NONE) && (screenSaverOnCopy == TRUE)) { guiGetBackToCurrentScreen(); } if ((input_interface_result != WHEEL_ACTION_NONE) && (((isScreenOnCopy != FALSE) && (screenSaverOnCopy == FALSE)) || (getCurrentScreen() == SCREEN_DEFAULT_INSERTED_LCK))) { guiScreenLoop(input_interface_result); } #endif }
/*! \fn guiAskForConfirmation(const char* string) * \brief Ask for user confirmation for different things * \param nb_args Number of text lines (must be either 1 2 or 3/4 (depending on the MP version)) * \param text_object Pointer to the text object if more than 1 line, pointer to the string if not * \return User confirmation or not */ RET_TYPE guiAskForConfirmation(uint8_t nb_args, confirmationText_t* text_object) { uint8_t flash_flag = FALSE; // Check if we want to flash the screen if ((nb_args & 0xF0) != 0) { nb_args = nb_args & 0x0F; // Check that the user didn't disable it if (getMooltipassParameterInEeprom(FLASH_SCREEN_PARAM) != FALSE) { flash_flag = TRUE; } } #if defined(HARDWARE_OLIVIER_V1) // Temp string for truncating char string_tbd[31]; string_tbd[30] = 0; // Draw asking bitmap oledClear(); oledBitmapDrawFlash(0, 0, BITMAP_YES_NO_INT_L, 0); oledBitmapDrawFlash(222, 0, BITMAP_YES_NO_INT_R, 0); // If more than one line if (nb_args == 1) { // Yeah, that's a bit dirty oledPutstrXY(0, 24, OLED_CENTRE, (char*)text_object); } else { while (nb_args--) { // Truncate and then display string memcpy(string_tbd, text_object->lines[nb_args], 30); oledPutstrXY(0, 2 + (nb_args << 4), OLED_CENTRE, string_tbd); } } // Display result oledDisplayOtherBuffer(); #elif defined(MINI_VERSION) // Variables for scrolling uint8_t string_y_indexes[3]; uint8_t string_extra_chars[3]; uint8_t string_offset_cntrs[3] = {0,0,0}; // Display variables uint8_t approve_selected = TRUE; // Draw asking bitmap oledClear(); miniOledSetMaxTextY(SSD1305_OLED_WIDTH-15); oledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_APPROVE, 0); // Display lines. // Note: line are truncated at the oled driver level when miniOledTextWritingYIncrement is set to FALSE if (nb_args == 1) { miniOledPutCenteredString(THREE_LINE_TEXT_SECOND_POS, (char*)text_object); } else if (nb_args == 2) { string_y_indexes[0] = TWO_LINE_TEXT_FIRST_POS; string_y_indexes[1] = TWO_LINE_TEXT_SECOND_POS; } else { string_y_indexes[0] = THREE_LINE_TEXT_FIRST_POS; string_y_indexes[1] = THREE_LINE_TEXT_SECOND_POS; string_y_indexes[2] = THREE_LINE_TEXT_THIRD_POS; } // For loop to display lines when there is more than one arg if (nb_args > 1) { for (uint8_t i = 0; i < nb_args; i++) { string_extra_chars[i] = strlen(text_object->lines[i]) - miniOledPutCenteredString(string_y_indexes[i], text_object->lines[i]); } } miniOledFlushEntireBufferToDisplay(); miniOledResetMaxTextY(); #endif // In case the display inverted, set it correctly if (flash_flag == TRUE) { activityDetectedRoutine(); oledInvertedDisplay(); timerBased500MsDelay(); oledNormalDisplay(); timerBased500MsDelay(); oledInvertedDisplay(); timerBased500MsDelay(); oledNormalDisplay(); } // Wait for user input #if defined(HARDWARE_OLIVIER_V1) if(getTouchedPositionAnswer(LED_MASK_WHEEL) == TOUCHPOS_RIGHT) { return RETURN_OK; } else { return RETURN_NOK; } #elif defined(MINI_VERSION) RET_TYPE input_answer = MINI_INPUT_RET_NONE; // Switch on lights activityDetectedRoutine(); // Clear possible remaining detection miniWheelClearDetections(); // Arm timer for scrolling (caps timer that isn't relevant here) activateTimer(TIMER_CAPS, SCROLLING_DEL); // Loop while no timeout occurs or no button is pressed while (input_answer == MINI_INPUT_RET_NONE) { input_answer = getYesNoAnswerInput(FALSE); // Text scrolling if ((hasTimerExpired(TIMER_CAPS, TRUE) == TIMER_EXPIRED) && (nb_args > 1)) { miniOledDrawRectangle(0, 0, SSD1305_OLED_WIDTH-15, SSD1305_OLED_HEIGHT, FALSE); activateTimer(TIMER_CAPS, SCROLLING_DEL); miniOledSetMaxTextY(SSD1305_OLED_WIDTH-15); for (uint8_t i = 0; i < nb_args; i++) { if (string_extra_chars[i] > 0) { miniOledPutCenteredString(string_y_indexes[i], (text_object->lines[i]) + string_offset_cntrs[i]); if (string_offset_cntrs[i]++ == string_extra_chars[i]) { string_offset_cntrs[i] = 0; } } else { miniOledPutCenteredString(string_y_indexes[i], text_object->lines[i]); } } miniOledFlushEntireBufferToDisplay(); miniOledResetMaxTextY(); } // Approve / deny display change if (getWheelCurrentIncrement() != 0) { if(approve_selected == FALSE) { oledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_APPROVE, 0); } else { oledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_DENY, 0); } approve_selected = !approve_selected; miniOledFlushEntireBufferToDisplay(); } } if ((input_answer == MINI_INPUT_RET_YES) && (approve_selected != FALSE)) { return RETURN_OK; } else { return RETURN_NOK; } #endif }
/*! \fn favoriteSelectionScreen(pNode* p, cNode* c) * \brief Screen displayed to let the user choose a favorite * \param p Pointer to a parent node * \param c Pointer to a child node * \return Valid child node address or 0 otherwise */ uint16_t favoriteSelectionScreen(pNode* p, cNode* c) { uint16_t picked_child = NODE_ADDR_NULL; uint16_t parentAddresses[USER_MAX_FAV]; uint16_t childAddresses[USER_MAX_FAV]; uint16_t tempparaddr, tempchildaddr; uint8_t action_chosen = FALSE; uint8_t nbFavorites = 0; uint8_t offset = 0; uint8_t led_mask; int8_t i, j; // Browse through the favorites for (i = 0; i < USER_MAX_FAV; i++) { // Read favorite, check that it is valid readFav(i, &tempparaddr, &tempchildaddr); // If so, store it in our know addresses if (tempparaddr != NODE_ADDR_NULL) { parentAddresses[nbFavorites] = tempparaddr; childAddresses[nbFavorites++] = tempchildaddr; } } // If no favorite, return if (nbFavorites == 0) { guiDisplayInformationOnScreen(ID_STRING_NOSTOREDFAV); userViewDelay(); return NODE_ADDR_NULL; } // Loop until the user chooses smth while (action_chosen != TRUE) { // Draw asking bitmap oledClear(); oledBitmapDrawFlash(0, 0, BITMAP_LOGIN, 0); // Clear led_mask led_mask = 0; i = 0; // List logins on screen while (((offset + i) < nbFavorites) && (i != 4)) { // Read child node to get login readChildNode(c, childAddresses[offset+i]); readParentNode(p, parentAddresses[offset+i]); // Print service / login on screen displayCredentialAtSlot(i+((i&0x02)<<2), (char*)c->login); displayCredentialAtSlot(i+((~i&0x02)<<2), (char*)p->service); // Increment i i++; } // If nothing after, hide right arrow if ((i != 4) || ((offset+i) == nbFavorites)) { 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 oledFlipBuffers(0,0); // Get touched quarter j = getTouchedPositionAnswer(led_mask); // Check its validity, knowing that by default we will return NODE_ADDR_NULL if (j == -1) { action_chosen = TRUE; // Time out } else if (j < i) { // Valid choice, load parent node as it will be used later readParentNode(p, parentAddresses[offset+j]); picked_child = childAddresses[offset+j]; action_chosen = TRUE; } else if (j == TOUCHPOS_LEFT) { if (offset > 0) { offset -= 4; } else { // User wants to go back action_chosen = TRUE; } } else if ((j == TOUCHPOS_RIGHT) && (i == 4) && ((offset+i) != nbFavorites)) { // If there are more nodes to display offset += 4; } } // Return selected child return picked_child; }
/*! \fn loginSelectionScreen(void) * \brief Screen displayed to let the user choose/find a login * \return Valid child node address or 0 otherwise */ uint16_t loginSelectionScreen(void) { char currentText[SEARCHTEXT_MAX_LENGTH+1]; uint8_t displayRefreshNeeded = TRUE; uint16_t ret_val = NODE_ADDR_NULL; uint8_t wasWheelReleased = TRUE; uint16_t tempParentAddresses[4]; uint8_t currentStringIndex = 0; uint8_t nbMatchedParents= 0; uint8_t finished = FALSE; RET_TYPE temp_rettype; uint8_t led_mask = 0; int8_t temp_int8; // Set current text to a last_matching_parent_addr = NODE_ADDR_NULL; last_matching_parent_number = 0; strcpy(currentText, "a"); // Draw bitmap, display it and write active buffer oledClear(); oledBitmapDrawFlash(0, 0, BITMAP_LOGIN_FIND, 0); oledFlipBuffers(0,0); oledWriteActiveBuffer(); // Arm interaction timer activateTimer(TIMER_USERINT, SELECT_TIMER_DEL); // While the user hasn't chosen a credential while(!finished) { if (displayRefreshNeeded == TRUE) { nbMatchedParents = displayCurrentSearchLoginTexts(currentText, tempParentAddresses); displayRefreshNeeded = FALSE; // Light only the available choices led_mask = 0; for (temp_int8 = nbMatchedParents; temp_int8 < 4; temp_int8++) { led_mask |= (1 << temp_int8); } } // Detect key touches temp_rettype = touchDetectionRoutine(led_mask); // If something happened, rearm timer if (temp_rettype != RETURN_NO_CHANGE) { activateTimer(TIMER_USERINT, SELECT_TIMER_DEL); } // Algo to differentiate a tap from a scroll if ((temp_rettype & RETURN_WHEEL_PRESSED) && (wasWheelReleased == TRUE)) { // We use the timer dedicated to wait functions for min activateTimer(TIMER_WAIT_FUNCTS, TAP_MIN_DEL); // We use the timer dedicated to caps detect for max activateTimer(TIMER_CAPS, TAP_MAX_DEL); // This works because we use the same clearing flags wasWheelReleased = FALSE; } else if (temp_rettype & RETURN_WHEEL_RELEASED) { // Check if it's a tap and that the selected domain is valid if ((hasTimerExpired(TIMER_CAPS, FALSE) == TIMER_RUNNING) && (hasTimerExpired(TIMER_WAIT_FUNCTS, TRUE) == TIMER_EXPIRED) && (getWheelTouchDetectionQuarter() < nbMatchedParents)) { ret_val = tempParentAddresses[getWheelTouchDetectionQuarter()]; finished = TRUE; } wasWheelReleased = TRUE; } // Send it to the touch wheel interface logic temp_int8 = touchWheelIntefaceLogic(temp_rettype); // Position increment / decrement if (temp_int8 != 0) { if ((currentText[currentStringIndex] == 0x7A) && (temp_int8 == 1)) { // z->0 wrap currentText[currentStringIndex] = 0x2F; } if ((currentText[currentStringIndex] == 0x39) && (temp_int8 == 1)) { // 9->a wrap currentText[currentStringIndex] = 0x60; } else if ((currentText[currentStringIndex] == 0x30) && (temp_int8 == -1)) { // 0->z wrap currentText[currentStringIndex] = 0x7B; } else if ((currentText[currentStringIndex] == 0x61) && (temp_int8 == -1)) { // a->9 wrap currentText[currentStringIndex] = 0x3A; } currentText[currentStringIndex] += temp_int8; displayRefreshNeeded = TRUE; } if ((isSmartCardAbsent() == RETURN_OK) || (hasTimerExpired(TIMER_USERINT, TRUE) == TIMER_EXPIRED)) { // Smartcard removed or no interaction for a while finished = TRUE; } else if (temp_rettype & RETURN_LEFT_PRESSED) { // Change search index if (currentStringIndex > 0) { currentText[currentStringIndex--] = 0; displayRefreshNeeded = TRUE; } else { finished = TRUE; } } else if (temp_rettype & RETURN_RIGHT_PRESSED) { // Change search index if (currentStringIndex < SEARCHTEXT_MAX_LENGTH-1) { currentText[++currentStringIndex] = 'a'; currentText[currentStringIndex + 1] = 0; displayRefreshNeeded = TRUE; } } } // Set inactive buffer write by default oledWriteInactiveBuffer(); return ret_val; }
/*! \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) { 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 if ((bypass_confirmation == TRUE) || (guiAskForConfirmation(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 oledClear(); oledBitmapDrawFlash(0, 0, BITMAP_LOGIN, 0); // Write domain name on screen oledPutstrXY(0, 24, OLED_CENTRE, (char*)p->service); // 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); // 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 oledFlipBuffers(0,0); // 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]; } } } // Prevent touches until the user lifts his finger touchInhibitUntilRelease(); return picked_child; }