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

@ -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;
}

View file

@ -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];

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}
/* ----------------------------------------------------------------------- */

View file

@ -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);

View file

@ -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 --- */

View file

@ -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;