From e6026d5809f193c45b9a1ef387e77baf81a35fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric?= Date: Mon, 5 Mar 2018 21:51:57 +0100 Subject: [PATCH] intermediate commit --- Makefile | 61 ++++++++++------ doc/user/blue-app-openpgp-card.rst | 1 + src/gpg_api.h | 2 +- src/gpg_data.c | 2 +- src/gpg_dispatch.c | 9 ++- src/gpg_init.c | 5 +- src/gpg_io.c | 5 +- src/gpg_main.c | 2 +- src/gpg_pso.c | 40 +++++++++-- src/gpg_select.c | 15 +++- src/gpg_types.h | 4 +- src/gpg_ux_nanos.c | 112 ++++++++++++++++++++++++++++- src/usbd_ccid_impl.c | 5 +- 13 files changed, 219 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index d329bd0..360acd9 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,19 @@ -# Copyright 2017 Cedric Mesnil , Ledger SAS -# +#******************************************************************************* +# Ledger App +# (c) 2017 Ledger +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# +#******************************************************************************* ifeq ($(BOLOS_SDK),) $(error Environment variable BOLOS_SDK is not set) @@ -19,57 +21,74 @@ endif include $(BOLOS_SDK)/Makefile.defines APPNAME = "OpenPGP" -APP_LOAD_PARAMS=--appFlags 0x40 --path "2152157255" --curve secp256k1 $(COMMON_LOAD_PARAMS) +APP_LOAD_PARAMS=--appFlags 0x50 --path "" --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=1 -APPVERSION_N=1 +APPVERSION_N=2 APPVERSION_P=0 - APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) -SPECVERSION="3.3.1" -ICONNAME=images/icon_pgp.gif +ifeq ($(TARGET_NAME),TARGET_BLUE) +ICONNAME=blue_app_cxt.gif +else +ICONNAME=nanos_app_cxt.gif +endif + + +DEFINES += $(CXT_CONFIG) CXT_VERSION=$(APPVERSION) CXT_NAME=$(APPNAME) SPEC_VERSION=$(SPECVERSION) +DEFINES += DEBUGLEDGER ################ # Default rule # ################ + all: default ############ # Platform # ############ -DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=128 -DEFINES += HAVE_BAGL HAVE_PRINTF HAVE_SPRINTF -DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU -DEFINES += HAVE_USB_CLASS_CCID +DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300 +DEFINES += HAVE_BAGL HAVE_SPRINTF +#DEFINES += HAVE_PRINTF PRINTF=screen_printf +DEFINES += PRINTF\(...\)= +DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU + +DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) TCS_LOADER_PATCH_VERSION=0 + +DEFINES += UNUSED\(x\)=\(void\)x +DEFINES += APPVERSION=\"$(APPVERSION)\" -DEFINES += $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME) SPEC_VERSION=$(SPECVERSION) ############## -# Compiler # +# Compiler # ############## #GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/ #CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/ CC := $(CLANGPATH)clang -#CFLAGS += -O0 -gdwarf-2 -gstrict-dwarf +#CFLAGS += -O0 CFLAGS += -O3 -Os AS := $(GCCPATH)arm-none-eabi-gcc LD := $(GCCPATH)arm-none-eabi-gcc -#LDFLAGS += -O0 -gdwarf-2 -gstrict-dwarf LDFLAGS += -O3 -Os LDLIBS += -lm -lgcc -lc # import rules to compile glyphs(/pone) include $(BOLOS_SDK)/Makefile.glyphs -### computed variables +### variables processed by the common makefile.rules of the SDK to grab source files and include dirs APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl +SDK_SOURCE_PATH += lib_stusb qrcode +#use the SDK U2F+HIDGEN USB profile +SDK_SOURCE_PATH += lib_u2f lib_stusb_impl +DEFINES += U2F_PROXY_MAGIC=\"BTC\" +DEFINES += HAVE_IO_U2F HAVE_U2F USB_SEGMENT_SIZE=64 +DEFINES += BLE_SEGMENT_SIZE=20 +DEFINES += HAVE_USB_CLASS_CCID load: all python -m ledgerblue.loadApp $(APP_LOAD_PARAMS) @@ -81,5 +100,5 @@ delete: include $(BOLOS_SDK)/Makefile.rules #add dependency on custom makefile filename -dep/%.d: %.c Makefile.genericwallet +dep/%.d: %.c Makefile diff --git a/doc/user/blue-app-openpgp-card.rst b/doc/user/blue-app-openpgp-card.rst index 6709545..291068a 100644 --- a/doc/user/blue-app-openpgp-card.rst +++ b/doc/user/blue-app-openpgp-card.rst @@ -370,6 +370,7 @@ the reader and the delegated PIN support. Edit the file ~/.gnupg/scdaemon.conf and add the following lines: | ``reader-port "Ledger Token [Nano S] (0001) 01 00"`` + | ``allow-admin`` | ``enable-pinpad-varlen`` diff --git a/src/gpg_api.h b/src/gpg_api.h index fa9f854..da0b912 100644 --- a/src/gpg_api.h +++ b/src/gpg_api.h @@ -28,7 +28,7 @@ int gpg_apdu_get_data(unsigned int ref) ; int gpg_apdu_get_next_data(unsigned int ref) ; int gpg_apdu_put_data(unsigned int ref) ; -int gpg_apdu_pso(unsigned int ref); +int gpg_apdu_pso(void); int gpg_apdu_internal_authenticate(void); int gpg_apdu_gen(void ); int gpg_apdu_get_challenge(void) ; diff --git a/src/gpg_data.c b/src/gpg_data.c index 2c1ac08..4ca86d1 100644 --- a/src/gpg_data.c +++ b/src/gpg_data.c @@ -282,7 +282,7 @@ int gpg_apdu_put_data(unsigned int ref) { if (G_gpg_vstate.io_length != 4) { THROW(SW_WRONG_LENGTH); } - G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] &= ~0x07; + G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+3] &= ~0x07; nvm_write(&N_gpg_pstate->AID[10], &G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset], 4); break; diff --git a/src/gpg_dispatch.c b/src/gpg_dispatch.c index 6e907b3..9640a36 100644 --- a/src/gpg_dispatch.c +++ b/src/gpg_dispatch.c @@ -62,7 +62,7 @@ void gpg_check_access_ins() { case INS_PSO: if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) { - //pso:sign + //pso:sign if (N_gpg_pstate->PW_status[0] == 0) { gpg_pin_set_verified(PIN_ID_PW1, 0); } @@ -236,7 +236,9 @@ int gpg_dispatch() { unsigned int tag,t,l; int sw; - if ((G_gpg_vstate.io_cla != 0x00) && (G_gpg_vstate.io_cla != 0x10) && (G_gpg_vstate.io_cla != 0xEF)) { + if ((G_gpg_vstate.io_cla != 0x00) && + (G_gpg_vstate.io_cla != 0x10) && + (G_gpg_vstate.io_cla != 0xEF)) { THROW(SW_CLA_NOT_SUPPORTED); return SW_CLA_NOT_SUPPORTED; } @@ -378,8 +380,9 @@ int gpg_dispatch() { /* --- PSO --- */ case INS_PSO: - sw = gpg_apdu_pso(tag); + sw = gpg_apdu_pso(); break; + case INS_INTERNAL_AUTHENTICATE: sw = gpg_apdu_internal_authenticate(); break; diff --git a/src/gpg_init.c b/src/gpg_init.c index 03207b1..8b89a56 100644 --- a/src/gpg_init.c +++ b/src/gpg_init.c @@ -122,7 +122,7 @@ const unsigned char C_ext_length[8] = { const unsigned char C_default_AID[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01, //version - 0x03, 0x00, + 0x02, 0x00, //manufacturer 0x2C, 0x97, //serial @@ -289,7 +289,8 @@ int gpg_install(unsigned char app_state) { #if 1 G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM; gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1); - USBD_CCID_activate_pinpad(3); + #warning USBD_CCID_activate_pinpad commented + //USBD_CCID_activate_pinpad(3); #else G_gpg_vstate.work.io_buffer[0] = PIN_MODE_HOST; gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1); diff --git a/src/gpg_io.c b/src/gpg_io.c index 4fa85b1..9a36db2 100644 --- a/src/gpg_io.c +++ b/src/gpg_io.c @@ -149,10 +149,7 @@ void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) { /* ----------------------------------------------------------------------- */ /* FECTH data from received buffer */ /* ----------------------------------------------------------------------- */ -void gpg_io_fetch_buffer(unsigned char* buffer, unsigned int len) { - os_memmove(buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, len); - G_gpg_vstate.io_offset += len; -} + unsigned int gpg_io_fetch_u32() { unsigned int v32; diff --git a/src/gpg_main.c b/src/gpg_main.c index 9390543..78bb5e2 100644 --- a/src/gpg_main.c +++ b/src/gpg_main.c @@ -165,7 +165,7 @@ __attribute__((section(".boot"))) int main(void) { //start communication with MCU io_seproxyhal_init(); - USB_CCID_power(1); + USB_power(1); io_usb_ccid_set_card_inserted(1); diff --git a/src/gpg_pso.c b/src/gpg_pso.c index d98b0e1..07a2b9d 100644 --- a/src/gpg_pso.c +++ b/src/gpg_pso.c @@ -83,7 +83,7 @@ static int gpg_sign(gpg_key_t *sigkey) { if ((sigkey->attributes.value[0] == 19) || (sigkey->attributes.value[0] == 22)) { cx_ecfp_private_key_t *key; - unsigned int sz,i,rs_len; + unsigned int sz,i,rs_len,info; unsigned char *rs; key = &sigkey->key.ecfp256; @@ -97,7 +97,8 @@ static int gpg_sign(gpg_key_t *sigkey) { CX_RND_TRNG, CX_NONE, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, - G_gpg_vstate.work.io_buffer); + G_gpg_vstate.work.io_buffer, + &info); //reencode r,s in MPI format gpg_io_discard(0); @@ -116,11 +117,12 @@ static int gpg_sign(gpg_key_t *sigkey) { rs += 2; } } else{ - sz = cx_eddsa_sign(key, NULL, + sz = cx_eddsa_sign(key, CX_NONE, CX_SHA512, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, - G_gpg_vstate.work.io_buffer+128); + NULL, 0, + G_gpg_vstate.work.io_buffer+128, &info); gpg_io_discard(0); gpg_io_insert(G_gpg_vstate.work.io_buffer+128, sz); } @@ -134,8 +136,30 @@ static int gpg_sign(gpg_key_t *sigkey) { return SW_REFERENCED_DATA_NOT_FOUND; } -int gpg_apdu_pso(unsigned int pso) { +int gpg_apdu_pso() { unsigned int t,l,ksz; + + unsigned int pso; + + pso = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ; + + //UIF HANDLE + switch(pso) { + // --- PSO:CDS --- + case 0x9e9a: + if ((G_gpg_vstate.kslot->sig.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) { + ui_menu_uifconfirm_display(0); + return 0; + } + + case 0x8680: + if ((G_gpg_vstate.kslot->dec.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) { + ui_menu_uifconfirm_display(0); + return 0; + } + } + + switch(pso) { // --- PSO:CDS --- case 0x9e9a: { @@ -296,7 +320,6 @@ int gpg_apdu_pso(unsigned int pso) { THROW(SW_REFERENCED_DATA_NOT_FOUND); return SW_REFERENCED_DATA_NOT_FOUND; } - } //--- PSO:yy NOT SUPPPORTED --- @@ -310,6 +333,11 @@ int gpg_apdu_pso(unsigned int pso) { int gpg_apdu_internal_authenticate() { + if ((G_gpg_vstate.kslot->aut.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) { + ui_menu_uifconfirm_display(0); + return 0; + } + if (G_gpg_vstate.mse_aut->attributes.value[0] == 1) { if ( G_gpg_vstate.io_length > ((G_gpg_vstate.mse_aut->attributes.value[1]<<8)|G_gpg_vstate.mse_aut->attributes.value[2])*40/100) { THROW(SW_WRONG_LENGTH); diff --git a/src/gpg_select.c b/src/gpg_select.c index 908f874..6c36ac5 100644 --- a/src/gpg_select.c +++ b/src/gpg_select.c @@ -19,10 +19,19 @@ #include "gpg_types.h" #include "gpg_api.h" #include "gpg_vars.h" +const unsigned char C_MF[] = {0x3F, 0x00}; int gpg_apdu_select() { int sw; - if ( (G_gpg_vstate.io_length == 6) && + + //MF + if ( (G_gpg_vstate.io_length == 2) && + (os_memcmp(G_gpg_vstate.work.io_buffer, C_MF, G_gpg_vstate.io_length) == 0) ) { + gpg_io_discard(0); + sw = SW_OK; + } + //AID APP + else if ( (G_gpg_vstate.io_length == 6) && (os_memcmp(G_gpg_vstate.work.io_buffer, N_gpg_pstate->AID, G_gpg_vstate.io_length) == 0) ) { G_gpg_vstate.DO_current = 0; G_gpg_vstate.DO_reccord = 0; @@ -40,7 +49,9 @@ int gpg_apdu_select() { THROW(SW_STATE_TERMINATED); } sw = SW_OK; - } else { + } + //NOT FOUND + else { THROW(SW_FILE_NOT_FOUND); return SW_FILE_NOT_FOUND; } diff --git a/src/gpg_types.h b/src/gpg_types.h index 9b89fc8..0268b9d 100644 --- a/src/gpg_types.h +++ b/src/gpg_types.h @@ -178,6 +178,8 @@ struct gpg_v_state_s { gpg_key_t *mse_dec; unsigned char seed_mode; + unsigned char UIF_flags; + /* io state*/ unsigned char io_cla; @@ -230,7 +232,7 @@ struct gpg_v_state_s { unsigned char pinmode; /* ux menus */ - char menu[64]; + char menu[112]; unsigned char ux_pinentry[12]; unsigned int ux_key; unsigned int ux_type; diff --git a/src/gpg_ux_nanos.c b/src/gpg_ux_nanos.c index 25721e7..d3e4a8c 100644 --- a/src/gpg_ux_nanos.c +++ b/src/gpg_ux_nanos.c @@ -91,6 +91,115 @@ void ui_info(const char* msg1, const char* msg2, const void *menu_display, unsig UX_MENU_DISPLAY(0, G_gpg_vstate.ui_dogsays, NULL); }; + +/* ------------------------------ UIF CONFIRM UX ----------------------------- */ +unsigned int ui_uifconfirm_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); +unsigned int ui_uifconfirm_prepro(const bagl_element_t* element); + +const bagl_element_t ui_uifconfirm_nanos[] = { + // type userid x y w h str rad fill fg bg font_id icon_id + { {BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, 0, 0}, + NULL, + 0, + 0, 0, + NULL, NULL, NULL}, + + { {BAGL_ICON, 0x00, 3, 12, 7, 7, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CROSS }, + NULL, + 0, + 0, 0, + NULL, NULL, NULL }, + + { {BAGL_ICON, 0x00, 117, 13, 8, 6, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CHECK }, + NULL, + 0, + 0, 0, + NULL, NULL, NULL }, + + { {BAGL_LABELINE, 0x01, 0, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, + G_gpg_vstate.menu, + 0, + 0, 0, + NULL, NULL, NULL }, + { {BAGL_LABELINE, 0x02, 0, 26, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, + G_gpg_vstate.menu, + 0, + 0, 0, + NULL, NULL, NULL }, +}; + +void ui_menu_uifconfirm_display(unsigned int value) { + UX_DISPLAY(ui_uifconfirm_nanos, (void*)ui_uifconfirm_prepro); +} + +unsigned int ui_uifconfirm_prepro(const bagl_element_t* element) { + if (element->component.userid == 1) { + snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Confirm Operation:"); + return 1; + } + if (element->component.userid == 2) { + unsigned int uif_case = (G_gpg_vstate.io_ins<<16)|(G_gpg_vstate.io_p1<<8)|(G_gpg_vstate.io_p2); + switch (uif_case) { + case 0x002A9E9A: + snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Signature"); + return 1; + case 0x002A8680: + snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Encryption"); + return 1; + case 0x002A8086: + snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Decryption"); + return 1; + case 0x0088000: + snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Authentication"); + return 1; + } + } + snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Please Cancel"); + return 1; +} + +unsigned int ui_uifconfirm_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { + unsigned int sw; + + sw = 0x6985; + switch(button_mask) { + case BUTTON_EVT_RELEASED|BUTTON_LEFT: // CANCEL + gpg_io_discard(1); + gpg_io_insert_u16(sw); + gpg_io_do(IO_RETURN_AFTER_TX); + ui_menu_main_display(0); + sw = 0x6985; + break; + + case BUTTON_EVT_RELEASED|BUTTON_RIGHT: // OK + BEGIN_TRY { + TRY { + G_gpg_vstate.UIF_flags = 1; + sw = gpg_apdu_pso(); + } + CATCH_OTHER(e) { + gpg_io_discard(1); + if ( (e & 0xFFFF0000) || + ( ((e&0xF000)!=0x6000) && ((e&0xF000)!=0x9000) ) ) { + gpg_io_insert_u32(e); + sw = 0x6f42; + } else { + sw = e; + } + } + FINALLY { + G_gpg_vstate.UIF_flags = 0; + gpg_io_insert_u16(sw); + gpg_io_do(IO_RETURN_AFTER_TX); + ui_menu_main_display(0); + } + break; + + } END_TRY; + } + return 0; +} + /* ------------------------------ PIN CONFIRM UX ----------------------------- */ const bagl_element_t ui_pinconfirm_nanos[] = { @@ -663,7 +772,8 @@ void ui_menu_pinmode_action(unsigned int value) { } else { s = 3; } - USBD_CCID_activate_pinpad(s); + #warning USBD_CCID_activate_pinpad commented + //USBD_CCID_activate_pinpad(s); } } else { diff --git a/src/usbd_ccid_impl.c b/src/usbd_ccid_impl.c index 2a54750..178a614 100644 --- a/src/usbd_ccid_impl.c +++ b/src/usbd_ccid_impl.c @@ -40,6 +40,9 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_ccid_core.h" +#include "usbd_ccid_impl.h" +#define CCID_INTR_IN_EP 0x81 +#define CCID_INTR_EPIN_SIZE 16 #ifdef HAVE_USB_CLASS_CCID @@ -57,7 +60,7 @@ static const uint8_t const USBD_PRODUCT_FS_STRING[] = { 'e', 0, }; -#elif TARGET_ID == 0x31100002 // nano s +#elif TARGET_ID == 0x31100003 // nano s #define USBD_PID 0x0001 static const uint8_t const USBD_PRODUCT_FS_STRING[] = { 6*2+2,