1.0 RC1
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:
parent
f188805766
commit
278d85a821
16
Makefile
16
Makefile
@ -14,15 +14,15 @@
|
||||
#
|
||||
|
||||
#extract TARGET_ID from the SDK to allow for makefile choices
|
||||
APPNAME = "GNUPG3"
|
||||
APPVERSION = "0.9"
|
||||
APPNAME = "OpenPGP"
|
||||
APPVERSION = "1.0RC1"
|
||||
TARGET_ID = 0x31100002
|
||||
$(info TARGET_ID=$(TARGET_ID))
|
||||
|
||||
APP_LOAD_PARAMS=--appFlags 0
|
||||
APP_LOAD_PARAMS=--appFlags 0 --path "2152157255" --curve secp256k1
|
||||
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_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
||||
DEFINES += HAVE_USB_CLASS_CCID
|
||||
#DEFINES += PRINTF=screen_printf
|
||||
DEFINES += PRINTF\(...\)=
|
||||
|
||||
DEFINES += $(GPG_CONFIG)
|
||||
DEFINES += $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME)
|
||||
|
||||
##############
|
||||
# Compiler #
|
||||
@ -75,8 +73,8 @@ CC := $(CLANGPATH)/clang
|
||||
CFLAGS :=
|
||||
CFLAGS += -gdwarf-2 -gstrict-dwarf
|
||||
#CFLAGS += -O0
|
||||
CFLAGS += -O0 -g3
|
||||
#CFLAGS += -O3 -Os
|
||||
#CFLAGS += -O0 -g3
|
||||
CFLAGS += -O3 -Os
|
||||
CFLAGS += -mcpu=cortex-m0 -mthumb
|
||||
CFLAGS += -fno-common -mtune=cortex-m0 -mlittle-endian
|
||||
CFLAGS += -std=gnu99 -Werror=int-to-pointer-cast -Wall -Wextra -Wno-unused-variable #-save-temps
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
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:
|
||||
ttps://g10code.com/p-card.html
|
||||
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 .
|
||||
|
||||
The application supports:
|
||||
- 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.
|
||||
In this mode key material is generated from the global token seeded.
|
||||
|
||||
Please consider SEED mode as experimental.
|
||||
|
||||
More details to come...
|
||||
|
||||
### On screen reset
|
||||
|
@ -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 :
|
||||
|
||||
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.
|
||||
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 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** :
|
||||
|
||||
@ -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*:
|
||||
|
||||
- generate Sr = BIP32_derive (/0x80/'G'/'P'/'G'/0)
|
||||
- generate r = SHA3-XOF(Sr \| 'rnd' \| S, L)
|
||||
- generate Sr = BIP32_derive(/0x80475047/0x0F0F0F0F)
|
||||
- generate r = SHA3-XOF(SHA256(Sr \| 'rnd' \| S), L)
|
||||
- return r
|
||||
|
||||
**Seeded prime number generation** :
|
||||
@ -178,10 +178,10 @@ Key Slot management
|
||||
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.
|
||||
|
||||
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*.
|
||||
|
||||
*01F1*
|
||||
*01F1:*
|
||||
|
||||
+------+--------------------------------------------------+--------+
|
||||
|bytes | description | R/W |
|
||||
@ -190,15 +190,23 @@ of *01F1*.
|
||||
+------+--------------------------------------------------+--------+
|
||||
| 2 | Default slot | 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 | |
|
||||
| 3 | Allowed slot selection method | R/W |
|
||||
+------+--------------------------------------------------+--------+
|
||||
|
||||
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 |
|
||||
@ -206,7 +214,7 @@ of *01F1*.
|
||||
| 1 | Current slot | R/W |
|
||||
+------+--------------------------------------------------+--------+
|
||||
|
||||
*01F0*
|
||||
*01F0:*
|
||||
|
||||
+------+--------------------------------------------------+--------+
|
||||
|bytes | Description | R/W |
|
||||
@ -217,17 +225,17 @@ of *01F1*.
|
||||
+------+--------------------------------------------------+--------+
|
||||
|
||||
|
||||
*Access Conditions*
|
||||
*Access Conditions:*
|
||||
|
||||
+------+--------------+-------------+
|
||||
+-------+------------+-------------+
|
||||
| DO | Read | Write |
|
||||
+======+=============+=============+
|
||||
+=======+============+=============+
|
||||
| 01F0 | Always | Never |
|
||||
+------+-------------+-------------+
|
||||
+-------+------------+-------------+
|
||||
| 01F1 | Always | Verify PW3 |
|
||||
+------+-------------+-------------+
|
||||
+-------+------------+-------------+
|
||||
| 01F2 | Always | Verify PW1 |
|
||||
+------+-------------+-------------+
|
||||
+-------+------------+-------------+
|
||||
|
||||
|
||||
|
||||
@ -242,13 +250,19 @@ P2 parameter of GENERATE ASYMMETRIC KEY PAIR is set to (hex value):
|
||||
Deterministic random number
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
P1 parameter of GET CHALLENGE is set to (hex value):
|
||||
- 00 for true random
|
||||
- 81 for prime true random
|
||||
- 82 for seeded random
|
||||
- 83 for prime seeded random
|
||||
P1 parameter of GET CHALLENGE is a bits field encoded as follow:
|
||||
|
||||
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
|
||||
|
Before Width: | Height: | Size: 90 B After Width: | Height: | Size: 90 B |
@ -113,7 +113,7 @@ class GPGCard() :
|
||||
allreaders = readers()
|
||||
for r in allreaders:
|
||||
rname = str(r)
|
||||
print('try: %s : %s'%(rname,device[5:]))
|
||||
#print('try: %s : %s'%(rname,device[5:]))
|
||||
if rname.startswith(device[5:]):
|
||||
r.createConnection()
|
||||
self.token = r
|
||||
@ -121,7 +121,8 @@ class GPGCard() :
|
||||
self.connection.connect()
|
||||
self.exchange = self._exchange_pcsc
|
||||
else:
|
||||
print("No")
|
||||
#print("No")
|
||||
pass
|
||||
if not self.token:
|
||||
print("No token")
|
||||
|
||||
@ -146,7 +147,7 @@ class GPGCard() :
|
||||
return resp,sw
|
||||
|
||||
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]
|
||||
resp, sw1, sw2 = self.connection.transmit(apdu)
|
||||
while sw1==0x61:
|
||||
@ -156,7 +157,7 @@ class GPGCard() :
|
||||
resp = resp + resp2
|
||||
resp = bytes(resp)
|
||||
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
|
||||
|
||||
def select(self):
|
||||
@ -730,5 +731,3 @@ class GPGCard() :
|
||||
'd': tags[0x98],
|
||||
}
|
||||
|
||||
def dump():
|
||||
pass
|
||||
|
@ -20,20 +20,47 @@
|
||||
#include "gpg_vars.h"
|
||||
|
||||
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);
|
||||
}
|
||||
gpg_io_discard(1);
|
||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
||||
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) {
|
||||
unsigned int path[2];
|
||||
unsigned char chain[32];
|
||||
unsigned char Sr[32];
|
||||
|
||||
if (G_gpg_vstate.io_p1 & 0x80) {
|
||||
cx_math_next_prime(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,G_gpg_vstate.io_le);
|
||||
os_memset(chain, 0, 32);
|
||||
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;
|
||||
}
|
||||
|
@ -244,10 +244,11 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||
break;
|
||||
|
||||
case 0x01F2:
|
||||
if (G_gpg_vstate.io_length != 1) {
|
||||
THROW(SW_WRONG_LENGTH);
|
||||
}
|
||||
if (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS) {
|
||||
if ((N_gpg_pstate->config_slot[2] & 2) == 0) {
|
||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
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);
|
||||
}
|
||||
G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
|
||||
|
@ -156,7 +156,8 @@ void gpg_check_access_write_DO() {
|
||||
switch(ref) {
|
||||
//PW1
|
||||
case 0x0101:
|
||||
case 0x0103:
|
||||
case 0x0103:
|
||||
case 0x01F2:
|
||||
if (gpg_is_verified(ID_PW1)) {
|
||||
return;
|
||||
}
|
||||
@ -167,6 +168,7 @@ void gpg_check_access_write_DO() {
|
||||
case 0x4f:
|
||||
case 0x0102:
|
||||
case 0x0104:
|
||||
case 0x01F1:
|
||||
case 0x005E:
|
||||
case 0x005B:
|
||||
case 0x5F2D:
|
||||
@ -265,7 +267,6 @@ int gpg_dispatch() {
|
||||
#endif
|
||||
/* --- CHALLENGE --- */
|
||||
case INS_GET_CHALLENGE:
|
||||
|
||||
sw = gpg_apdu_get_challenge();
|
||||
break;
|
||||
|
||||
|
@ -39,17 +39,19 @@ static void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
|
||||
* @in Ski_len sub-seed length
|
||||
*/
|
||||
static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx,
|
||||
unsigned char *Ski, unsigned int Ski_len,
|
||||
cx_sha3_t *xof) {
|
||||
unsigned char *Ski, unsigned int Ski_len) {
|
||||
|
||||
unsigned char idx16[2];
|
||||
idx16[0] = idx >>8;
|
||||
idx16[1] = idx;
|
||||
|
||||
cx_sha3_xof_init(xof, 256, Ski_len);
|
||||
cx_hash((cx_hash_t *)xof, 0, Sn, 32, NULL);
|
||||
cx_hash((cx_hash_t *)xof, 0, (unsigned char *)key_name, 4, NULL);
|
||||
cx_hash((cx_hash_t *)xof, CX_LAST, idx16 , 2, Ski);
|
||||
unsigned char h[32];
|
||||
h[0] = idx >>8;
|
||||
h[1] = idx;
|
||||
|
||||
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
||||
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL);
|
||||
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, (unsigned char *)key_name, 4, NULL);
|
||||
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;
|
||||
size = ksz>>1;
|
||||
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, 2, pq+size, 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);
|
||||
*pq |= 0x80;
|
||||
*(pq+size) |= 0x80;
|
||||
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);
|
||||
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_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);
|
||||
keepprivate = 1;
|
||||
}
|
||||
|
@ -219,12 +219,8 @@ void gpg_init() {
|
||||
}
|
||||
|
||||
void gpg_init_ux() {
|
||||
snprintf(G_gpg_vstate.menu_cur_slot, 16, ">>SLOT: %d<<", G_gpg_vstate.slot+1);
|
||||
snprintf(G_gpg_vstate.menu_seed_mode, 16, ">>%s<<", G_gpg_vstate.seed_mode?"ON":"OFF");
|
||||
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;
|
||||
G_gpg_vstate.ux_type = -1;
|
||||
G_gpg_vstate.ux_key = -1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
@ -283,11 +283,15 @@ int gpg_io_do() {
|
||||
switch (G_gpg_vstate.io_ins) {
|
||||
case INS_GET_DATA:
|
||||
case INS_GET_RESPONSE:
|
||||
case INS_GET_CHALLENGE:
|
||||
case INS_TERMINATE_DF:
|
||||
case INS_ACTIVATE_FILE:
|
||||
G_gpg_vstate.io_le = G_io_apdu_buffer[4];
|
||||
break;
|
||||
|
||||
case INS_GET_CHALLENGE:
|
||||
if (G_gpg_vstate.io_p1 == 0) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
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);
|
||||
|
458
src/gpg_main.c
458
src/gpg_main.c
@ -29,7 +29,7 @@
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* --- UI layout --- */
|
||||
/* --- Blue UI layout --- */
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* screeen size:
|
||||
blue; 320x480
|
||||
@ -153,50 +153,53 @@ unsigned int ui_idle_blue_button(unsigned int button_mask,
|
||||
}
|
||||
|
||||
#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[];
|
||||
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) {
|
||||
ux_menu_entry_t ui_invalid[2] = {
|
||||
{back, NULL, 0, NULL, msg1, msg2, 0, 0},
|
||||
|
||||
/* ------------------------------- Helpers UX ------------------------------- */
|
||||
|
||||
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_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) {
|
||||
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);
|
||||
}
|
||||
/* ------------------------------- template UX ------------------------------- */
|
||||
|
||||
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_AUT "Authentication"
|
||||
#define LABEL_DEC "Decryption"
|
||||
@ -208,84 +211,66 @@ const ux_menu_entry_t ui_idle_sub_slot[] = {
|
||||
#define LABEL_BPOOLR1 "Brainpool R1"
|
||||
#define LABEL_Ed25519 "Ed25519"
|
||||
|
||||
const ux_menu_entry_t ui_idle_sub_template[];
|
||||
const ux_menu_entry_t ui_idle_sub_tmpl_key[];
|
||||
const ux_menu_entry_t ui_idle_sub_tmpl_type[];
|
||||
const ux_menu_entry_t ui_idle_sub_template[] = {
|
||||
{ui_idle_sub_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0},
|
||||
{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
|
||||
};
|
||||
|
||||
/*
|
||||
const bagl_element_t* ui_idle_sub_tmpl_key_prepocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
||||
if (entry == &ui_idle_sub_tmpl_key[2]) {
|
||||
if(element->component.userid==0x20) {
|
||||
element->component.stroke = 10; // 1 second stop in each way
|
||||
element->component.icon_id = 26; // roundtrip speed in pixel/s
|
||||
UX_CALLBACK_SET_INTERVAL(MAX(3000, 2*(1000+bagl_label_roundtrip_duration_ms(element, 7))));
|
||||
void ui_idle_sub_template_display(unsigned int value) {
|
||||
UX_MENU_DISPLAY(value, ui_idle_sub_template, ui_idle_sub_template_preprocessor);
|
||||
}
|
||||
|
||||
const bagl_element_t* ui_idle_sub_template_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
||||
if(element->component.userid==0x20) {
|
||||
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) {
|
||||
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
||||
@ -293,15 +278,7 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
||||
char* err;
|
||||
|
||||
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));
|
||||
switch (G_gpg_vstate.ux_type) {
|
||||
case 2048:
|
||||
@ -349,7 +326,7 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
||||
break;
|
||||
|
||||
default:
|
||||
err = "not supported";
|
||||
err = "type";
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
@ -365,97 +342,236 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
||||
dest = &G_gpg_vstate.kslot->aut;
|
||||
break;
|
||||
default:
|
||||
err = "key not found";
|
||||
err = "key";
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
gpg_nvm_write(dest, NULL, sizeof(gpg_key_t));
|
||||
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;
|
||||
|
||||
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_template[] = {
|
||||
{ui_idle_sub_tmpl_key, NULL, 0, NULL, G_gpg_vstate.menu_template_key, NULL, 0, 0},
|
||||
{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},
|
||||
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
/* ----- SEED UX ----- */
|
||||
const ux_menu_entry_t ui_idle_sub_seed[];
|
||||
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);
|
||||
void ui_idle_sub_tmpl_key_action(unsigned int value) {
|
||||
G_gpg_vstate.ux_key = value;
|
||||
ui_idle_sub_template_display(0);
|
||||
}
|
||||
|
||||
|
||||
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[] = {
|
||||
#if GPG_KEYS_SLOTS != 3
|
||||
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
||||
#endif
|
||||
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_seed_mode, 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},
|
||||
{ui_idle_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40},
|
||||
{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, 0, NULL, "Set off", NULL, 0, 0},
|
||||
{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
|
||||
};
|
||||
|
||||
/* ----- RESET UX ----- */
|
||||
void ui_idle_sub_reset_action(unsigned int value) {
|
||||
unsigned char magic[4];
|
||||
magic[0] = 0; magic[1] = 0; magic[2] = 0; magic[3] = 0;
|
||||
gpg_nvm_write(N_gpg_pstate->magic, magic, 4);
|
||||
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[] = {
|
||||
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_cur_slot, NULL, 0, 0},
|
||||
{ui_idle_sub_template, NULL, 0, NULL, "Key template", 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_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40},
|
||||
{NULL, ui_idle_sub_template_display, 0, NULL, "Key template", NULL, 0, 0},
|
||||
{NULL, ui_idle_sub_seed_display, 0, NULL, "Seed mode", 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},
|
||||
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
|
||||
};
|
||||
|
||||
/* ----- MAIN UX ----- */
|
||||
#undef STR
|
||||
#undef XSTR
|
||||
|
||||
/* --------------------------------- MAIN UX --------------------------------- */
|
||||
|
||||
const ux_menu_entry_t ui_idle_mainmenu[] = {
|
||||
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_cur_slot, NULL, 0, 0},
|
||||
{ui_idle_sub_slot, NULL, 0, NULL, "Select slot", 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},
|
||||
{NULL, NULL, 0, NULL, "", 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_info, NULL, 0, NULL, "About", NULL, 0, 0},
|
||||
{NULL, os_sched_exit, 0, &C_icon_dashboard, "Quit app" , NULL, 50, 29},
|
||||
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) {
|
||||
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 --- */
|
||||
|
@ -23,13 +23,13 @@
|
||||
|
||||
|
||||
/* big private DO */
|
||||
#define GPG_EXT_PRIVATE_DO_LENGTH 1024
|
||||
#define GPG_EXT_PRIVATE_DO_LENGTH 512
|
||||
/* 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 */
|
||||
#define GPG_EXT_CHALLENGE_LENTH 254
|
||||
/* 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
|
||||
|
||||
@ -201,6 +201,13 @@ struct gpg_v_state_s {
|
||||
cx_ecfp_public_key_t public;
|
||||
cx_ecfp_private_key_t private;
|
||||
}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;
|
||||
|
||||
/* data state */
|
||||
@ -213,10 +220,7 @@ struct gpg_v_state_s {
|
||||
|
||||
|
||||
/* ux menus */
|
||||
char menu_cur_slot[16];
|
||||
char menu_seed_mode[16];
|
||||
char menu_template_key[16];
|
||||
char menu_template_type[16];
|
||||
char menu[64];
|
||||
unsigned int ux_key;
|
||||
unsigned int ux_type;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user