Add-on Spec:
 Add intermediate SHA256 in seeded key derivation
 Beautify spec

Pytool:
  Remove some log

 App:
  Fix GET_CHALLENGE commande to support addon mode
  Add '01F2' '01F1' access control
  Replace ugly temporary cx_sha_t address definition by clean union
  Rewrite dynamic menu management in ui
  Add 'About' menu

 Build:
  Rename application from GNUPG3 to OpenPGP and version to 1.0
  Lock path & curve
  Compile in optimization mode
This commit is contained in:
Cédric Mesnil 2017-03-27 15:14:51 +02:00
parent f188805766
commit 278d85a821
13 changed files with 419 additions and 256 deletions

View File

@ -14,15 +14,15 @@
# #
#extract TARGET_ID from the SDK to allow for makefile choices #extract TARGET_ID from the SDK to allow for makefile choices
APPNAME = "GNUPG3" APPNAME = "OpenPGP"
APPVERSION = "0.9" APPVERSION = "1.0RC1"
TARGET_ID = 0x31100002 TARGET_ID = 0x31100002
$(info TARGET_ID=$(TARGET_ID)) $(info TARGET_ID=$(TARGET_ID))
APP_LOAD_PARAMS=--appFlags 0 APP_LOAD_PARAMS=--appFlags 0 --path "2152157255" --curve secp256k1
LOADFLAGS = --params --appVersion $(APPVERSION) LOADFLAGS = --params --appVersion $(APPVERSION)
ICONNAME=icon.gif ICONNAME=icon_pgp.gif
################ ################
@ -60,10 +60,8 @@ DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=128
DEFINES += HAVE_BAGL HAVE_PRINTF HAVE_SPRINTF 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_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
DEFINES += HAVE_USB_CLASS_CCID DEFINES += HAVE_USB_CLASS_CCID
#DEFINES += PRINTF=screen_printf
DEFINES += PRINTF\(...\)=
DEFINES += $(GPG_CONFIG) DEFINES += $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME)
############## ##############
# Compiler # # Compiler #
@ -75,8 +73,8 @@ CC := $(CLANGPATH)/clang
CFLAGS := CFLAGS :=
CFLAGS += -gdwarf-2 -gstrict-dwarf CFLAGS += -gdwarf-2 -gstrict-dwarf
#CFLAGS += -O0 #CFLAGS += -O0
CFLAGS += -O0 -g3 #CFLAGS += -O0 -g3
#CFLAGS += -O3 -Os CFLAGS += -O3 -Os
CFLAGS += -mcpu=cortex-m0 -mthumb CFLAGS += -mcpu=cortex-m0 -mthumb
CFLAGS += -fno-common -mtune=cortex-m0 -mlittle-endian CFLAGS += -fno-common -mtune=cortex-m0 -mlittle-endian
CFLAGS += -std=gnu99 -Werror=int-to-pointer-cast -Wall -Wextra -Wno-unused-variable #-save-temps CFLAGS += -std=gnu99 -Werror=int-to-pointer-cast -Wall -Wextra -Wno-unused-variable #-save-temps

View File

@ -2,8 +2,7 @@
GnuPG application for Ledger Blue and Nano S GnuPG application for Ledger Blue and Nano S
This application implements "The OpenPGP card" specification revision 3.0. This specification is available in *doc* directory and at: This application implements "The OpenPGP card" specification revision 3.0. This specification is available in *doc* directory and at https://g10code.com/p-card.html .
ttps://g10code.com/p-card.html
The application supports: The application supports:
- RSA with key up to 4096 bits - RSA with key up to 4096 bits
@ -46,6 +45,8 @@ When installed the default slot is "1". You can change it in settings.
A seeded mode is implemented in order to restore private keys on a new token. A seeded mode is implemented in order to restore private keys on a new token.
In this mode key material is generated from the global token seeded. In this mode key material is generated from the global token seeded.
Please consider SEED mode as experimental.
More details to come... More details to come...
### On screen reset ### On screen reset

View File

@ -94,7 +94,7 @@ Sn = BIP32_derive (/0x80475047/n)
Then specific seeds are derived with the SHA3-XOF function for each of the four key : Then specific seeds are derived with the SHA3-XOF function for each of the four key :
Sk[i] = SHA3-XOF(Sn \| <key_name> \| int16(i), length) Sk[i] = SHA3-XOF(SHA256(Sn \| <key_name> \| int16(i)), length)
Sn is the dedicated slot seed from step 1. Sn is the dedicated slot seed from step 1.
key_name is one of 'sig ','dec ', 'aut ', 'sym0', each four characters. key_name is one of 'sig ','dec ', 'aut ', 'sym0', each four characters.
@ -142,7 +142,7 @@ Deterministic random number
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
The deterministic random number generation relies on the BIP32 scheme. The deterministic random number generation relies on the BIP32 scheme.
The master install path of GPG-ledger is set to /0x80/'G'/'P'/'G', aka /0x80/0x47/0x50/0x47 The master install path of GPG-ledger is set to /0x80'GPG', aka /80475047
**Random prime number generation** : **Random prime number generation** :
@ -156,8 +156,8 @@ The master install path of GPG-ledger is set to /0x80/'G'/'P'/'G', aka /0x80/0x4
For a given length *L* and seed *S*: For a given length *L* and seed *S*:
- generate Sr = BIP32_derive (/0x80/'G'/'P'/'G'/0) - generate Sr = BIP32_derive(/0x80475047/0x0F0F0F0F)
- generate r = SHA3-XOF(Sr \| 'rnd' \| S, L) - generate r = SHA3-XOF(SHA256(Sr \| 'rnd' \| S), L)
- return r - return r
**Seeded prime number generation** : **Seeded prime number generation** :
@ -178,10 +178,10 @@ Key Slot management
Key slots are managed by data object 01F1 and 01F2 witch are Key slots are managed by data object 01F1 and 01F2 witch are
manageable by PUT/GET DATA command as for others DO and organized as follow. manageable by PUT/GET DATA command as for others DO and organized as follow.
On application reset the *01F2* content is set to *Default Slot* value On application reset, the *01F2* content is set to *Default Slot* value
of *01F1*. of *01F1*.
*01F1* *01F1:*
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
|bytes | description | R/W | |bytes | description | R/W |
@ -190,15 +190,23 @@ of *01F1*.
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
| 2 | Default slot | R/W | | 2 | Default slot | R/W |
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
| 3 | Allowed slot selection method: | R/W | | 3 | Allowed slot selection method | R/W |
| | 0: selection not allowed (locked to default) | |
| | 1: selection by APDU | |
| | 2: selection by screen | |
| | 3: selection by APDU and screen | |
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
Byte 3 is endoced as follow:
*01F2* +----+----+----+----+----+----+----+----+-------------------------+
| b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning |
+----+----+----+----+----+----+----+----+-------------------------+
| \- | \- | \- | \- | \- | \- | \- | x | selection by APDU |
+----+----+----+----+----+----+----+----+-------------------------+
| \- | \- | \- | \- | \- | \- | x | \- | selection by screen |
+----+----+----+----+----+----+----+----+-------------------------+
*01F2:*
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
|bytes | Description | R/W | |bytes | Description | R/W |
@ -206,7 +214,7 @@ of *01F1*.
| 1 | Current slot | R/W | | 1 | Current slot | R/W |
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
*01F0* *01F0:*
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
|bytes | Description | R/W | |bytes | Description | R/W |
@ -217,17 +225,17 @@ of *01F1*.
+------+--------------------------------------------------+--------+ +------+--------------------------------------------------+--------+
*Access Conditions* *Access Conditions:*
+------+--------------+-------------+ +-------+------------+-------------+
| DO | Read | Write | | DO | Read | Write |
+======+=============+=============+ +=======+============+=============+
| 01F0 | Always | Never | | 01F0 | Always | Never |
+------+-------------+-------------+ +-------+------------+-------------+
| 01F1 | Always | Verify PW3 | | 01F1 | Always | Verify PW3 |
+------+-------------+-------------+ +-------+------------+-------------+
| 01F2 | Always | Verify PW1 | | 01F2 | Always | Verify PW1 |
+------+-------------+-------------+ +-------+------------+-------------+
@ -242,13 +250,19 @@ P2 parameter of GENERATE ASYMMETRIC KEY PAIR is set to (hex value):
Deterministic random number Deterministic random number
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
P1 parameter of GET CHALLENGE is set to (hex value): P1 parameter of GET CHALLENGE is a bits field encoded as follow:
- 00 for true random
- 81 for prime true random
- 82 for seeded random
- 83 for prime seeded random
When P1 is set to 82 or 83, Data field contains the seed +----+-----+----+----+----+----+----+----+-------------------------+
| b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning |
+----+-----+----+----+----+----+----+----+-------------------------+
| \- | \- | \- | \- | \- | \- | \- | x | prime random |
+----+-----+----+----+----+----+----+----+-------------------------+
| \- | \- | \- | \- | \- | \- | x | \- | seeded random |
+----+-----+----+----+----+----+----+----+-------------------------+
When bit b2 is set, data field contains the seed and P2 contains
the length of random bytes to generate.
Other minor add-on Other minor add-on

View File

Before

Width:  |  Height:  |  Size: 90 B

After

Width:  |  Height:  |  Size: 90 B

View File

@ -113,7 +113,7 @@ class GPGCard() :
allreaders = readers() allreaders = readers()
for r in allreaders: for r in allreaders:
rname = str(r) rname = str(r)
print('try: %s : %s'%(rname,device[5:])) #print('try: %s : %s'%(rname,device[5:]))
if rname.startswith(device[5:]): if rname.startswith(device[5:]):
r.createConnection() r.createConnection()
self.token = r self.token = r
@ -121,7 +121,8 @@ class GPGCard() :
self.connection.connect() self.connection.connect()
self.exchange = self._exchange_pcsc self.exchange = self._exchange_pcsc
else: else:
print("No") #print("No")
pass
if not self.token: if not self.token:
print("No token") print("No token")
@ -146,7 +147,7 @@ class GPGCard() :
return resp,sw return resp,sw
def _exchange_pcsc(self,apdu,sw=0x9000): def _exchange_pcsc(self,apdu,sw=0x9000):
print("xch S cmd : %s"%(binascii.hexlify(apdu))) #print("xch S cmd : %s"%(binascii.hexlify(apdu)))
apdu = [x for x in apdu] apdu = [x for x in apdu]
resp, sw1, sw2 = self.connection.transmit(apdu) resp, sw1, sw2 = self.connection.transmit(apdu)
while sw1==0x61: while sw1==0x61:
@ -156,7 +157,7 @@ class GPGCard() :
resp = resp + resp2 resp = resp + resp2
resp = bytes(resp) resp = bytes(resp)
sw = (sw1<<8)|sw2 sw = (sw1<<8)|sw2
print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw)) #print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw))
return resp,sw return resp,sw
def select(self): def select(self):
@ -730,5 +731,3 @@ class GPGCard() :
'd': tags[0x98], 'd': tags[0x98],
} }
def dump():
pass

View File

@ -20,20 +20,47 @@
#include "gpg_vars.h" #include "gpg_vars.h"
int gpg_apdu_get_challenge() { int gpg_apdu_get_challenge() {
unsigned int olen,hlen;
if (G_gpg_vstate.io_le > GPG_EXT_CHALLENGE_LENTH) { if ((G_gpg_vstate.io_p1&0x80) == 0x80) {
olen = G_gpg_vstate.io_p2;
} else {
olen = G_gpg_vstate.io_le;
}
if (olen > GPG_EXT_CHALLENGE_LENTH) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
} }
gpg_io_discard(1);
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le); if ((G_gpg_vstate.io_p1&0x82) == 0x82) {
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le); unsigned int path[2];
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le); unsigned char chain[32];
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le); unsigned char Sr[32];
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
if (G_gpg_vstate.io_p1 & 0x80) { os_memset(chain, 0, 32);
cx_math_next_prime(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,G_gpg_vstate.io_le); path[0] = 0x80475047;
path[1] = 0x0F0F0F0F;
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2 , Sr, chain);
chain[0] = 'r'; chain[1]='n'; chain[2] = 'd';
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL);
hlen=cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256,
CX_LAST, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
G_gpg_vstate.work.io_buffer);
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3,
CX_LAST, G_gpg_vstate.work.io_buffer, hlen,
G_gpg_vstate.work.io_buffer);
} else {
cx_rng(G_gpg_vstate.work.io_buffer, olen);
} }
gpg_io_inserted(G_gpg_vstate.io_le);
if ((G_gpg_vstate.io_p1&0x81) == 0x81) {
cx_math_next_prime(G_gpg_vstate.work.io_buffer,olen);
}
gpg_io_discard(0);
gpg_io_inserted(olen);
return SW_OK; return SW_OK;
} }

View File

@ -244,10 +244,11 @@ int gpg_apdu_put_data(unsigned int ref) {
break; break;
case 0x01F2: case 0x01F2:
if (G_gpg_vstate.io_length != 1) { if ((N_gpg_pstate->config_slot[2] & 2) == 0) {
THROW(SW_WRONG_LENGTH); THROW(SW_CONDITIONS_NOT_SATISFIED);
} }
if (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS) { if ((G_gpg_vstate.io_length != 1) ||
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
} }
G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset]; G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];

View File

@ -156,7 +156,8 @@ void gpg_check_access_write_DO() {
switch(ref) { switch(ref) {
//PW1 //PW1
case 0x0101: case 0x0101:
case 0x0103: case 0x0103:
case 0x01F2:
if (gpg_is_verified(ID_PW1)) { if (gpg_is_verified(ID_PW1)) {
return; return;
} }
@ -167,6 +168,7 @@ void gpg_check_access_write_DO() {
case 0x4f: case 0x4f:
case 0x0102: case 0x0102:
case 0x0104: case 0x0104:
case 0x01F1:
case 0x005E: case 0x005E:
case 0x005B: case 0x005B:
case 0x5F2D: case 0x5F2D:
@ -265,7 +267,6 @@ int gpg_dispatch() {
#endif #endif
/* --- CHALLENGE --- */ /* --- CHALLENGE --- */
case INS_GET_CHALLENGE: case INS_GET_CHALLENGE:
sw = gpg_apdu_get_challenge(); sw = gpg_apdu_get_challenge();
break; break;

View File

@ -39,17 +39,19 @@ static void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
* @in Ski_len sub-seed length * @in Ski_len sub-seed length
*/ */
static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx, static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx,
unsigned char *Ski, unsigned int Ski_len, unsigned char *Ski, unsigned int Ski_len) {
cx_sha3_t *xof) {
unsigned char idx16[2]; unsigned char h[32];
idx16[0] = idx >>8; h[0] = idx >>8;
idx16[1] = idx; h[1] = idx;
cx_sha3_xof_init(xof, 256, Ski_len); cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *)xof, 0, Sn, 32, NULL); cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL);
cx_hash((cx_hash_t *)xof, 0, (unsigned char *)key_name, 4, NULL); cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, (unsigned char *)key_name, 4, NULL);
cx_hash((cx_hash_t *)xof, CX_LAST, idx16 , 2, Ski); cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, CX_LAST, h , 2, h);
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len);
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski);
} }
@ -140,8 +142,8 @@ int gpg_apdu_gen() {
unsigned int size; unsigned int size;
size = ksz>>1; size = ksz>>1;
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed); gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, pq, size, (cx_sha3_t*)((unsigned int)&G_gpg_vstate.work.io_buffer[1024] & (~3))); gpg_pso_derive_key_seed(seed, name, 1, pq, size);
gpg_pso_derive_key_seed(seed, name, 2, pq+size, size, (cx_sha3_t*)((unsigned int)&G_gpg_vstate.work.io_buffer[1024] & (~3))); gpg_pso_derive_key_seed(seed, name, 2, pq+size, size);
*pq |= 0x80; *pq |= 0x80;
*(pq+size) |= 0x80; *(pq+size) |= 0x80;
cx_math_next_prime(pq,size); cx_math_next_prime(pq,size);
@ -172,7 +174,7 @@ int gpg_apdu_gen() {
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1); curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
if ((G_gpg_vstate.io_p2 == 0x01) | (G_gpg_vstate.seed_mode)) { if ((G_gpg_vstate.io_p2 == 0x01) | (G_gpg_vstate.seed_mode)) {
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed); gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, seed, 32, (cx_sha3_t*)&G_gpg_vstate.work.io_buffer[1024]); gpg_pso_derive_key_seed(seed, name, 1, seed, 32);
cx_ecfp_init_private_key(curve,seed, 32, &G_gpg_vstate.work.ecfp256.private); cx_ecfp_init_private_key(curve,seed, 32, &G_gpg_vstate.work.ecfp256.private);
keepprivate = 1; keepprivate = 1;
} }

View File

@ -219,12 +219,8 @@ void gpg_init() {
} }
void gpg_init_ux() { void gpg_init_ux() {
snprintf(G_gpg_vstate.menu_cur_slot, 16, ">>SLOT: %d<<", G_gpg_vstate.slot+1); G_gpg_vstate.ux_type = -1;
snprintf(G_gpg_vstate.menu_seed_mode, 16, ">>%s<<", G_gpg_vstate.seed_mode?"ON":"OFF"); G_gpg_vstate.ux_key = -1;
snprintf(G_gpg_vstate.menu_template_key, 16, "choose key...");
snprintf(G_gpg_vstate.menu_template_type, 16, "choose type...");
G_gpg_vstate.ux_type = 0;
G_gpg_vstate.ux_key = 0;
} }
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */

View File

@ -283,11 +283,15 @@ int gpg_io_do() {
switch (G_gpg_vstate.io_ins) { switch (G_gpg_vstate.io_ins) {
case INS_GET_DATA: case INS_GET_DATA:
case INS_GET_RESPONSE: case INS_GET_RESPONSE:
case INS_GET_CHALLENGE:
case INS_TERMINATE_DF: case INS_TERMINATE_DF:
case INS_ACTIVATE_FILE: case INS_ACTIVATE_FILE:
G_gpg_vstate.io_le = G_io_apdu_buffer[4]; G_gpg_vstate.io_le = G_io_apdu_buffer[4];
break; break;
case INS_GET_CHALLENGE:
if (G_gpg_vstate.io_p1 == 0) {
break;
}
default: default:
G_gpg_vstate.io_lc = G_io_apdu_buffer[4]; G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
os_memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer+5, G_gpg_vstate.io_lc); os_memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer+5, G_gpg_vstate.io_lc);

View File

@ -29,7 +29,7 @@
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- UI layout --- */ /* --- Blue UI layout --- */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* screeen size: /* screeen size:
blue; 320x480 blue; 320x480
@ -153,50 +153,53 @@ unsigned int ui_idle_blue_button(unsigned int button_mask,
} }
#endif #endif
/* ----------------------------------------------------------------------- */
/* --- NanoS UI layout --- */
/* ----------------------------------------------------------------------- */
const ux_menu_entry_t ui_idle_sub_template[];
void ui_idle_sub_template_display(unsigned int value);
const bagl_element_t* ui_idle_sub_template_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
void ui_idle_sub_tmpl_set_action(unsigned int value) ;
const ux_menu_entry_t ui_idle_sub_tmpl_key[];
void ui_idle_sub_tmpl_key_action(unsigned int value);
const ux_menu_entry_t ui_idle_sub_tmpl_type[];
void ui_idle_sub_tmpl_type_action(unsigned int value);
const ux_menu_entry_t ui_idle_sub_seed[];
void ui_idle_sub_seed_display(unsigned int value);
const bagl_element_t* ui_idle_sub_seed_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) ;
void ui_idle_sub_seed_action(unsigned int value) ;
const ux_menu_entry_t ui_idle_sub_reset[] ;
void ui_idle_sub_reset_action(unsigned int value);
const ux_menu_entry_t ui_idle_sub_slot[];
void ui_idle_sub_slot_display(unsigned int value);
const bagl_element_t* ui_idle_sub_slot_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
void ui_idle_sub_slot_action(unsigned int value);
const ux_menu_entry_t ui_idle_settings[] ;
const ux_menu_entry_t ui_idle_mainmenu[]; const ux_menu_entry_t ui_idle_mainmenu[];
void ui_idle_main_display(unsigned int value) ;
const bagl_element_t* ui_idle_main_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
/* ----- Helpers UX ----- */
void ui_info(const ux_menu_entry_t *back, const char* msg1, const char* msg2) { /* ------------------------------- Helpers UX ------------------------------- */
ux_menu_entry_t ui_invalid[2] = {
{back, NULL, 0, NULL, msg1, msg2, 0, 0}, void ui_info(const char* msg1, const char* msg2, const void *menu_display, unsigned int entry) {
ux_menu_entry_t ui_dogsays[2] = {
{NULL, menu_display, 0, NULL, msg1, msg2, 0, 0},
UX_MENU_END UX_MENU_END
}; };
UX_MENU_DISPLAY(0, ui_invalid, NULL); UX_MENU_DISPLAY(entry, ui_dogsays, NULL);
}; };
/* ----- SLOT UX ----- */
void ui_idle_sub_slot_action(unsigned int value) {
unsigned char s;
if (value == 0) { /* ------------------------------- template UX ------------------------------- */
s = G_gpg_vstate.slot;
gpg_nvm_write(&N_gpg_pstate->config_slot[1], &s,1);
}
else {
s = (unsigned char)(value-1);
G_gpg_vstate.slot = s;
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
}
// redisplay first entry of the idle menu
gpg_init_ux();
UX_MENU_DISPLAY(0, ui_idle_mainmenu, NULL);
}
const ux_menu_entry_t ui_idle_sub_slot[] = {
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
{NULL, ui_idle_sub_slot_action, 1, NULL, "Select slot 1", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 2, NULL, "Select slot 2", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 3, NULL, "Select slot 3", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 0, NULL, "Set as default", NULL, 0, 0},
{ui_idle_mainmenu, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
/* ----- template UX ----- */
#define LABEL_SIG "Signature" #define LABEL_SIG "Signature"
#define LABEL_AUT "Authentication" #define LABEL_AUT "Authentication"
#define LABEL_DEC "Decryption" #define LABEL_DEC "Decryption"
@ -208,84 +211,66 @@ const ux_menu_entry_t ui_idle_sub_slot[] = {
#define LABEL_BPOOLR1 "Brainpool R1" #define LABEL_BPOOLR1 "Brainpool R1"
#define LABEL_Ed25519 "Ed25519" #define LABEL_Ed25519 "Ed25519"
const ux_menu_entry_t ui_idle_sub_template[]; const ux_menu_entry_t ui_idle_sub_template[] = {
const ux_menu_entry_t ui_idle_sub_tmpl_key[]; {ui_idle_sub_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0},
const ux_menu_entry_t ui_idle_sub_tmpl_type[]; {ui_idle_sub_tmpl_type, NULL, -1, NULL, "Choose type...", NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_set_action, -1, NULL, "Set template", NULL, 0, 0},
{ui_idle_settings, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
/* void ui_idle_sub_template_display(unsigned int value) {
const bagl_element_t* ui_idle_sub_tmpl_key_prepocessor(const ux_menu_entry_t* entry, bagl_element_t* element) { UX_MENU_DISPLAY(value, ui_idle_sub_template, ui_idle_sub_template_preprocessor);
if (entry == &ui_idle_sub_tmpl_key[2]) { }
if(element->component.userid==0x20) {
element->component.stroke = 10; // 1 second stop in each way const bagl_element_t* ui_idle_sub_template_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
element->component.icon_id = 26; // roundtrip speed in pixel/s if(element->component.userid==0x20) {
UX_CALLBACK_SET_INTERVAL(MAX(3000, 2*(1000+bagl_label_roundtrip_duration_ms(element, 7)))); if (entry == &ui_idle_sub_template[0]) {
switch(G_gpg_vstate.ux_key) {
case 1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_SIG);
break;
case 2:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_DEC);
break;
case 3:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_AUT);
break;
default:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Choose key...");
break;
}
element->text = G_gpg_vstate.menu;
}
if (entry == &ui_idle_sub_template[1]) {
switch(G_gpg_vstate.ux_type) {
case 2048:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA2048);
break;
case 3072:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA3072);
break;
case 4096:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA4096);
break;
case CX_CURVE_SECP256R1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP256);
break;
case CX_CURVE_BrainPoolP256R1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOLR1);
break;
case CX_CURVE_Ed25519:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_Ed25519);
break;
default:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Choose type...");
break;
}
element->text = G_gpg_vstate.menu;
} }
} }
return element; return element;
} }
*/
void ui_idle_sub_tmpl_key_action(unsigned int value) {
switch(value) {
case 1:
snprintf(G_gpg_vstate.menu_template_key, 16, "%s", LABEL_SIG);
G_gpg_vstate.ux_key = 1;
break;
case 2:
snprintf(G_gpg_vstate.menu_template_key, 16, "%s", LABEL_AUT);
G_gpg_vstate.ux_key = 2;
break;
case 3:
snprintf(G_gpg_vstate.menu_template_key, 16," %s", LABEL_DEC);
G_gpg_vstate.ux_key = 3;
break;
}
UX_MENU_DISPLAY(0, ui_idle_sub_template, NULL);
}
const ux_menu_entry_t ui_idle_sub_tmpl_key[] = {
{NULL, ui_idle_sub_tmpl_key_action, 1, NULL, LABEL_SIG, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_key_action, 2, NULL, LABEL_DEC, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_key_action, 3, NULL, LABEL_AUT, NULL, 0, 0},
{ui_idle_sub_template, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_tmpl_type_action(unsigned int value) {
switch(value) {
case 2048:
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_RSA2048);
break;
case 3072:
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_RSA3072);
break;
case 4096:
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_RSA4096);
break;
case CX_CURVE_SECP256R1:
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_NISTP256);
break;
case CX_CURVE_BrainPoolP256R1:
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_BPOOLR1);
break;
case CX_CURVE_Ed25519:
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_Ed25519);
break;
}
G_gpg_vstate.ux_type = value;
UX_MENU_DISPLAY(1, ui_idle_sub_template, NULL);
}
const ux_menu_entry_t ui_idle_sub_tmpl_type[] = {
{NULL, ui_idle_sub_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOLR1, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
{ui_idle_sub_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_tmpl_set_action(unsigned int value) { void ui_idle_sub_tmpl_set_action(unsigned int value) {
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH); LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
@ -293,15 +278,7 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
char* err; char* err;
err = NULL; err = NULL;
if (!G_gpg_vstate.ux_key) {
err = "key";
goto ERROR;
}
if (!G_gpg_vstate.ux_type){
err = "type ";
goto ERROR;
}
os_memset(&attributes, 0, sizeof(attributes)); os_memset(&attributes, 0, sizeof(attributes));
switch (G_gpg_vstate.ux_type) { switch (G_gpg_vstate.ux_type) {
case 2048: case 2048:
@ -349,7 +326,7 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
break; break;
default: default:
err = "not supported"; err = "type";
goto ERROR; goto ERROR;
} }
@ -365,97 +342,236 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
dest = &G_gpg_vstate.kslot->aut; dest = &G_gpg_vstate.kslot->aut;
break; break;
default: default:
err = "key not found"; err = "key";
goto ERROR; goto ERROR;
} }
gpg_nvm_write(dest, NULL, sizeof(gpg_key_t)); gpg_nvm_write(dest, NULL, sizeof(gpg_key_t));
gpg_nvm_write(&dest->attributes, &attributes, sizeof(attributes)); gpg_nvm_write(&dest->attributes, &attributes, sizeof(attributes));
ui_info(ui_idle_sub_template, "Template set!", NULL); ui_info("Template set!", NULL, ui_idle_sub_template_display, 0);
return; return;
ERROR: ERROR:
ui_info(ui_idle_sub_template, "Invalid selection:", err); ui_info("Invalid selection:", err, ui_idle_sub_template_display, 0);
} }
/*
void ui_idle_sub_tmpl_key_display(unsigned int value) {
UX_MENU_DISPLAY(0,ui_idle_sub_tmpl_key,ui_idle_sub_tmpl_key_prepocessor); const ux_menu_entry_t ui_idle_sub_tmpl_key[] = {
} {NULL, ui_idle_sub_tmpl_key_action, 1, NULL, LABEL_SIG, NULL, 0, 0},
*/ {NULL, ui_idle_sub_tmpl_key_action, 2, NULL, LABEL_DEC, NULL, 0, 0},
const ux_menu_entry_t ui_idle_sub_template[] = { {NULL, ui_idle_sub_tmpl_key_action, 3, NULL, LABEL_AUT, NULL, 0, 0},
{ui_idle_sub_tmpl_key, NULL, 0, NULL, G_gpg_vstate.menu_template_key, NULL, 0, 0}, {ui_idle_sub_template, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
{ui_idle_sub_tmpl_type, NULL, 0, NULL, G_gpg_vstate.menu_template_type, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_set_action, 0, NULL, "Set template", NULL, 0, 0},
{ui_idle_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END UX_MENU_END
}; };
void ui_idle_sub_tmpl_key_action(unsigned int value) {
/* ----- SEED UX ----- */ G_gpg_vstate.ux_key = value;
const ux_menu_entry_t ui_idle_sub_seed[]; ui_idle_sub_template_display(0);
void ui_idle_sub_seed_action(unsigned int value) {
G_gpg_vstate.seed_mode = value;
gpg_init_ux();
UX_MENU_DISPLAY(0, ui_idle_sub_seed, NULL);
} }
const ux_menu_entry_t ui_idle_sub_tmpl_type[] = {
{NULL, ui_idle_sub_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOLR1, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
{ui_idle_sub_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_tmpl_type_action(unsigned int value) {
G_gpg_vstate.ux_type = value;
ui_idle_sub_template_display(1);
}
/* --------------------------------- SEED UX --------------------------------- */
const ux_menu_entry_t ui_idle_sub_seed[] = { const ux_menu_entry_t ui_idle_sub_seed[] = {
#if GPG_KEYS_SLOTS != 3 #if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS #error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif #endif
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_seed_mode, NULL, 0, 0}, {NULL, NULL, 0, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_seed_action, 1, NULL, "Set on", NULL, 0, 0}, {NULL, ui_idle_sub_seed_action, 1, NULL, "Set on", NULL, 0, 0},
{NULL, ui_idle_sub_seed_action, 0, NULL, "Set off", NULL, 0, 0}, {NULL, ui_idle_sub_seed_action, 0, NULL, "Set off", NULL, 0, 0},
{ui_idle_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40}, {ui_idle_settings, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_seed_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_idle_sub_seed, ui_idle_sub_seed_preprocessor);
}
const bagl_element_t* ui_idle_sub_seed_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
if(element->component.userid==0x20) {
if (entry == &ui_idle_sub_seed[0]) {
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "< %s >", G_gpg_vstate.seed_mode?"ON":"OFF");
element->text = G_gpg_vstate.menu;
}
}
return element;
}
void ui_idle_sub_seed_action(unsigned int value) {
G_gpg_vstate.seed_mode = value;
ui_idle_sub_seed_display(0);
}
/* -------------------------------- RESET UX --------------------------------- */
const ux_menu_entry_t ui_idle_sub_reset[] = {
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
{NULL, NULL, 0, NULL, "Really Reset ?", NULL, 0, 0},
{NULL, ui_idle_main_display, 0, &C_badge_back, "Oh No!", NULL, 61, 40},
{NULL, ui_idle_sub_reset_action, 0, NULL, "Yes!", NULL, 0, 0},
UX_MENU_END UX_MENU_END
}; };
/* ----- RESET UX ----- */
void ui_idle_sub_reset_action(unsigned int value) { void ui_idle_sub_reset_action(unsigned int value) {
unsigned char magic[4]; unsigned char magic[4];
magic[0] = 0; magic[1] = 0; magic[2] = 0; magic[3] = 0; magic[0] = 0; magic[1] = 0; magic[2] = 0; magic[3] = 0;
gpg_nvm_write(N_gpg_pstate->magic, magic, 4); gpg_nvm_write(N_gpg_pstate->magic, magic, 4);
gpg_init(); gpg_init();
UX_MENU_DISPLAY(0, ui_idle_mainmenu, NULL); ui_idle_main_display(0);
} }
const ux_menu_entry_t ui_idle_sub_reset[] = {
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
{NULL, NULL, 0, NULL, "Really Reset ?", NULL, 0, 0},
{NULL, ui_idle_sub_reset_action, 0, NULL, "Yes!", NULL, 0, 0},
{ui_idle_mainmenu, NULL, 0, &C_badge_back, "Oh No!", NULL, 61, 40},
UX_MENU_END
};
/* ----- SETTINGS UX ----- */ /* ------------------------------- SETTINGS UX ------------------------------- */
const ux_menu_entry_t ui_idle_settings[] = { const ux_menu_entry_t ui_idle_settings[] = {
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_cur_slot, NULL, 0, 0}, {NULL, ui_idle_sub_template_display, 0, NULL, "Key template", NULL, 0, 0},
{ui_idle_sub_template, NULL, 0, NULL, "Key template", NULL, 0, 0}, {NULL, ui_idle_sub_seed_display, 0, NULL, "Seed mode", NULL, 0, 0},
{ui_idle_sub_seed, NULL, 0, NULL, "Seed mode", NULL, 0, 0}, {ui_idle_sub_reset, NULL, 0, NULL, "Reset", NULL, 0, 0},
{ui_idle_sub_reset, NULL, 0, NULL, "Reset", NULL, 0, 0}, {NULL, ui_idle_main_display, 2, &C_badge_back, "Back", NULL, 61, 40},
{ui_idle_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40}, UX_MENU_END
};
/* --------------------------------- SLOT UX --------------------------------- */
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
const ux_menu_entry_t ui_idle_sub_slot[] = {
{NULL, NULL, -1, NULL, "Choose:", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 1, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 2, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 3, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 128, NULL, "Set Default", NULL, 0, 0},
{NULL, ui_idle_main_display, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_slot_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_idle_sub_slot, ui_idle_sub_slot_preprocessor);
}
const bagl_element_t* ui_idle_sub_slot_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
unsigned int slot;
if(element->component.userid==0x20) {
for (slot = 1; slot <= 3; slot ++) {
if (entry == &ui_idle_sub_slot[slot]) {
break;
}
}
if (slot != 4) {
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Slot %d %s %s",
slot,
slot == N_gpg_pstate->config_slot[1]+1?"#":" ", /* default */
slot == G_gpg_vstate.slot+1?"+":" " /* selected*/);
element->text = G_gpg_vstate.menu;
}
}
return element;
}
void ui_idle_sub_slot_action(unsigned int value) {
unsigned char s;
if (value == 128) {
s = G_gpg_vstate.slot;
gpg_nvm_write(&N_gpg_pstate->config_slot[1], &s,1);
value = s+1;
}
else {
s = (unsigned char)(value-1);
G_gpg_vstate.slot = s;
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
}
// redisplay first entry of the idle menu
ui_idle_sub_slot_display(value);
}
/* --------------------------------- INFO UX --------------------------------- */
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
#define STR(x) #x
#define XSTR(x) STR(x)
const ux_menu_entry_t ui_idle_info[] = {
{NULL, NULL, -1, NULL, "OpenPGP Card", NULL, 0, 0},
{NULL, NULL, -1, NULL, "(c) Ledger SAS", NULL, 0, 0},
{NULL, NULL, -1, NULL, "Spec 3.0", NULL, 0, 0},
{NULL, NULL, -1, NULL, "App " XSTR(GPG_VERSION), NULL, 0, 0},
{NULL, ui_idle_main_display, 3, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END UX_MENU_END
}; };
/* ----- MAIN UX ----- */ #undef STR
#undef XSTR
/* --------------------------------- MAIN UX --------------------------------- */
const ux_menu_entry_t ui_idle_mainmenu[] = { const ux_menu_entry_t ui_idle_mainmenu[] = {
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_cur_slot, NULL, 0, 0}, {NULL, NULL, 0, NULL, "", NULL, 0, 0},
{ui_idle_sub_slot, NULL, 0, NULL, "Select slot", NULL, 0, 0}, {NULL, ui_idle_sub_slot_display, 0, NULL, "Select slot", NULL, 0, 0},
{ui_idle_settings, NULL, 0, NULL, "Settings", NULL, 0, 0}, {ui_idle_settings, NULL, 0, NULL, "Settings", NULL, 0, 0},
{NULL, os_sched_exit, 0, &C_icon_dashboard, "Quit app" , NULL, 50, 29}, {ui_idle_info, NULL, 0, NULL, "About", NULL, 0, 0},
{NULL, os_sched_exit, 0, &C_icon_dashboard, "Quit app" , NULL, 50, 29},
UX_MENU_END UX_MENU_END
}; };
const bagl_element_t* ui_idle_main_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
if (entry == &ui_idle_mainmenu[0]) {
if(element->component.userid==0x20) {
unsigned int serial;
char name[20];
serial = MIN(N_gpg_pstate->name.length,19);
os_memset(name, 0, 20);
os_memmove(name, N_gpg_pstate->name.value, serial);
serial = (N_gpg_pstate->AID[10] << 24) |
(N_gpg_pstate->AID[11] << 16) |
(N_gpg_pstate->AID[12] << 8) |
(N_gpg_pstate->AID[13]);
os_memset(G_gpg_vstate.menu, 0, sizeof(G_gpg_vstate.menu));
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "< User: %s / SLOT: %d / Serial: %x >",
name, G_gpg_vstate.slot+1, serial);
element->component.stroke = 10; // 1 second stop in each way
element->component.icon_id = 26; // roundtrip speed in pixel/s
element->text = G_gpg_vstate.menu;
UX_CALLBACK_SET_INTERVAL(bagl_label_roundtrip_duration_ms(element, 7));
}
}
return element;
}
void ui_idle_main_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_idle_mainmenu, ui_idle_main_preprocessor);
}
void ui_idle_init(void) {
ui_idle_main_display(0);
// setup the first screen changing
UX_CALLBACK_SET_INTERVAL(1000);
}
void io_seproxyhal_display(const bagl_element_t *element) { void io_seproxyhal_display(const bagl_element_t *element) {
io_seproxyhal_display_default((bagl_element_t *)element); io_seproxyhal_display_default((bagl_element_t *)element);
} }
void ui_idle_init(void) {
UX_MENU_DISPLAY(0, ui_idle_mainmenu, NULL);
// setup the first screen changing
UX_CALLBACK_SET_INTERVAL(1000);
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- Application Entry --- */ /* --- Application Entry --- */

View File

@ -23,13 +23,13 @@
/* big private DO */ /* big private DO */
#define GPG_EXT_PRIVATE_DO_LENGTH 1024 #define GPG_EXT_PRIVATE_DO_LENGTH 512
/* will be fixed..1024 is not enougth */ /* will be fixed..1024 is not enougth */
#define GPG_EXT_CARD_HOLDER_CERT_LENTH 4096 #define GPG_EXT_CARD_HOLDER_CERT_LENTH 2560
/* random choice */ /* random choice */
#define GPG_EXT_CHALLENGE_LENTH 254 #define GPG_EXT_CHALLENGE_LENTH 254
/* accpet long PW, but less than one sha256 block */ /* accpet long PW, but less than one sha256 block */
#define GPG_MAX_PW_LENGTH 48 #define GPG_MAX_PW_LENGTH 12
#define GPG_KEYS_SLOTS 3 #define GPG_KEYS_SLOTS 3
@ -201,6 +201,13 @@ struct gpg_v_state_s {
cx_ecfp_public_key_t public; cx_ecfp_public_key_t public;
cx_ecfp_private_key_t private; cx_ecfp_private_key_t private;
}ecfp256; }ecfp256;
struct {
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH-MAX(sizeof(cx_sha3_t),sizeof(cx_sha256_t))];
union {
cx_sha3_t sha3;
cx_sha256_t sha256;
};
} md ;
} work; } work;
/* data state */ /* data state */
@ -213,10 +220,7 @@ struct gpg_v_state_s {
/* ux menus */ /* ux menus */
char menu_cur_slot[16]; char menu[64];
char menu_seed_mode[16];
char menu_template_key[16];
char menu_template_type[16];
unsigned int ux_key; unsigned int ux_key;
unsigned int ux_type; unsigned int ux_type;