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
13 changed files with 419 additions and 256 deletions
|
@ -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…
Add table
Add a link
Reference in a new issue