Merge pull request #104 from LedgerHQ/cev/issue_101_doc

Issue 101: Improve doc readability
This commit is contained in:
Charles-Edouard de la Vergne 2024-03-21 13:51:03 +01:00 committed by GitHub
commit 4f84034d41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 1384 additions and 251 deletions

View File

@ -30,7 +30,7 @@ APPNAME = OpenPGP
# Application version
APPVERSION_M = 2
APPVERSION_N = 2
APPVERSION_P = 1
APPVERSION_P = 2
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"
SPECVERSION:="3.3.1"

View File

@ -926,9 +926,6 @@ class GPGCard() :
if not attributes or len(attributes) == 0:
return ""
if attributes[0] not in set(iter(PubkeyAlgo)):
return ""
if attributes[0] == PubkeyAlgo.RSA:
if attributes[5] == 0:
fmt = "standard (e, p, q)"
@ -944,14 +941,12 @@ class GPGCard() :
return ret
if attributes[0] == PubkeyAlgo.ECDSA:
ret = "ECDSA"
return "ECDSA"
if attributes[0] == PubkeyAlgo.ECDH:
ret = "ECDH"
return "ECDH"
if attributes[0] == PubkeyAlgo.EDDSA:
ret = "EDDSA"
else:
ret = ""
return ret
return "EDDSA"
return ""
def decode_key(self, key: str) -> dict:

View File

@ -18,18 +18,28 @@
#ifndef GPG_API_H
#define GPG_API_H
void gpg_activate_pinpad(uint8_t enabled);
/* ----------------------------------------------------------------------- */
/* --- INIT ---- */
/* ----------------------------------------------------------------------- */
void gpg_activate_pinpad(uint8_t enabled);
unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len);
unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len);
unsigned int gpg_curve2domainlen(unsigned int cv);
void gpg_init(void);
void gpg_init_ux(void);
void gpg_install(unsigned char app_state);
void gpg_install_slot(gpg_key_slot_t *slot);
/* ----------------------------------------------------------------------- */
/* --- DISPATCH ---- */
/* ----------------------------------------------------------------------- */
int gpg_dispatch(void);
/* ----------------------------------------------------------------------- */
/* --- DATA ---- */
/* ----------------------------------------------------------------------- */
void gpg_apdu_select_data(unsigned int ref, int record);
int gpg_apdu_get_data(unsigned int ref);
int gpg_apdu_get_next_data(unsigned int ref);
@ -37,6 +47,10 @@ int gpg_apdu_put_data(unsigned int ref);
int gpg_apdu_get_key_data(unsigned int ref);
int gpg_apdu_put_key_data(unsigned int ref);
/* ----------------------------------------------------------------------- */
/* --- PSO ---- */
/* ----------------------------------------------------------------------- */
int gpg_pso_derive_slot_seed(int slot, unsigned char *seed);
int gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned char *key_name,
@ -45,27 +59,48 @@ int gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned int Ski_len);
int gpg_apdu_pso(void);
int gpg_apdu_internal_authenticate(void);
/* ----------------------------------------------------------------------- */
/* --- GEN ---- */
/* ----------------------------------------------------------------------- */
int gpg_apdu_gen(void);
/* ----------------------------------------------------------------------- */
/* --- CHALLENGE ---- */
/* ----------------------------------------------------------------------- */
int gpg_apdu_get_challenge(void);
/* ----------------------------------------------------------------------- */
/* --- SELECT ---- */
/* ----------------------------------------------------------------------- */
int gpg_apdu_select(void);
/* ----------------------------------------------------------------------- */
/* --- PIN ---- */
/* ----------------------------------------------------------------------- */
int gpg_apdu_verify(void);
int gpg_apdu_change_ref_data(void);
int gpg_apdu_reset_retry_counter(void);
gpg_pin_t *gpg_pin_get_pin(int id);
int gpg_pin_is_blocked(gpg_pin_t *pin);
int gpg_pin_is_verified(int pinID);
void gpg_pin_set_verified(int pinID, int verified);
int gpg_pin_check(gpg_pin_t *pin, int pinID, const unsigned char *pin_val, unsigned int pin_len);
int gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
/* ----------------------------------------------------------------------- */
/* --- MSE ---- */
/* ----------------------------------------------------------------------- */
void gpg_mse_reset();
int gpg_apdu_mse();
/* ----------------------------------------------------------------------- */
/* --- IO ---- */
/* --- IO ---- */
/* ----------------------------------------------------------------------- */
void gpg_io_discard(int clear);
void gpg_io_clear(void);

View File

@ -18,6 +18,12 @@
#include "gpg_vars.h"
#include "cx_errors.h"
/**
* Generate a Random Number
*
* @return Status Word
*
*/
int gpg_apdu_get_challenge() {
unsigned int olen;
cx_err_t error = CX_INTERNAL_ERROR;

View File

@ -19,12 +19,27 @@
#include "gpg_ux.h"
#include "cx_errors.h"
/**
* Select a DO (Data Object) in the current template
*
* @param[in] ref DO tag
* @param[in] record Offset of the record
*
*/
void gpg_apdu_select_data(unsigned int ref, int record) {
G_gpg_vstate.DO_current = ref;
G_gpg_vstate.DO_reccord = record;
G_gpg_vstate.DO_offset = 0;
}
/**
* Read a DO (Data Object) from the card
*
* @param[in] ref DO tag
*
* @return Status Word
*
*/
int gpg_apdu_get_data(unsigned int ref) {
int sw = SW_UNKNOWN;
@ -211,6 +226,14 @@ int gpg_apdu_get_data(unsigned int ref) {
return sw;
}
/**
* Read the next instance of the same DO (Data Object) from the card
*
* @param[in] ref DO tag
*
* @return Status Word
*
*/
int gpg_apdu_get_next_data(unsigned int ref) {
int sw = SW_UNKNOWN;
@ -224,6 +247,14 @@ int gpg_apdu_get_next_data(unsigned int ref) {
return sw;
}
/**
* Write a DO (Data Object) to the card
*
* @param[in] ref DO tag
*
* @return Status Word
*
*/
int gpg_apdu_put_data(unsigned int ref) {
unsigned int t, l, sw;
unsigned int *ptr_l = NULL;
@ -799,6 +830,15 @@ end:
return error;
}
/**
* Init an encryption key to protect Private Key
* Used for Backup/Restore
*
* @param[out] keyenc aes encryption key
*
* @return Status Word
*
*/
static int gpg_init_keyenc(cx_aes_key_t *keyenc) {
int sw = SW_UNKNOWN;
unsigned char seed[32];
@ -821,8 +861,15 @@ end:
return SW_OK;
}
// cmd
// resp TID API COMPAT len_pub len_priv priv
/**
* Read a Key DO (Data Object) from the card
* for Backup
*
* @param[in] ref DO tag
*
* @return Status Word
*
*/
int gpg_apdu_get_key_data(unsigned int ref) {
cx_aes_key_t keyenc = {0};
gpg_key_t *keygpg = NULL;
@ -932,8 +979,15 @@ end:
return error;
}
// cmd TID API COMPAT len_pub len_priv priv
// resp -
/**
* Write a key DO (Data Object) to the card
* For Restore
*
* @param[in] ref DO tag
*
* @return Status Word
*
*/
int gpg_apdu_put_key_data(unsigned int ref) {
cx_aes_key_t keyenc = {0};
gpg_key_t *keygpg = NULL;

View File

@ -17,6 +17,13 @@
#include "gpg_vars.h"
/**
* Check INS access condition
* Verify if the corresponding PW is verified
*
* @return Status Word
*
*/
static int gpg_check_access_ins() {
int sw = SW_UNKNOWN;
@ -92,6 +99,13 @@ static int gpg_check_access_ins() {
return sw;
}
/**
* Check INS Read access condition
* Verify if the corresponding PW is verified
*
* @return Status Word
*
*/
static int gpg_check_access_read_DO() {
int sw = SW_UNKNOWN;
@ -163,6 +177,13 @@ static int gpg_check_access_read_DO() {
return sw;
}
/**
* Check INS Write access condition
* Verify if the corresponding PW is verified
*
* @return Status Word
*
*/
static int gpg_check_access_write_DO() {
int sw = SW_UNKNOWN;
@ -228,7 +249,12 @@ static int gpg_check_access_write_DO() {
return sw;
}
/* assume command is fully received */
/**
* APDU Handler: dispatch command
*
* @return Status Word
*
*/
int gpg_dispatch() {
unsigned int tag, t, l;
int sw = SW_UNKNOWN;

View File

@ -19,8 +19,14 @@
#include "cx_ram.h"
#include "cx_errors.h"
/* @in slot slot num [0 ; GPG_KEYS_SLOTS[
* @out seed 32 bytes master seed for given slot
/**
* Derivate the App Path from the Master Seed for a specific slot
*
* @param[in] slot Selected slot
* @param[out] seed 32 bytes seed for given slot
*
* @return Status Word
*
*/
int gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
unsigned int path[2];
@ -39,11 +45,17 @@ end:
return SW_OK;
}
/* @in Sn master seed slot number
* @in key_name key name: 'sig ', 'auth ', 'dec '
* @in idx sub-seed index
* @out Ski generated sub_seed
* @in Ski_len sub-seed length
/**
* Derivate the Key from the Generated Seed
*
* @param[in] Sn Seed for the selected slot
* @param[in] key_name key name: 'sig ', 'auth ', 'dec '
* @param[in] idx sub-seed index
* @param[out] Ski generated sub_seed
* @param[in] Ski_len sub-seed length
*
* @return Status Word
*
*/
int gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned char *key_name,
@ -74,6 +86,15 @@ end:
return SW_OK;
}
/**
* Generate a RSA key pair and writes it in NVRam
*
* @param[in] keygpg pointer on key structure
* @param[in] name key name: 'sig ', 'auth ', 'dec '
*
* @return Status Word
*
*/
static int gpg_gen_rsa_kyey(gpg_key_t *keygpg, uint8_t *name) {
cx_rsa_public_key_t *rsa_pub = NULL;
cx_rsa_private_key_t *rsa_priv = NULL;
@ -146,6 +167,14 @@ end:
return error;
}
/**
* Read a RSA key pair
*
* @param[in] keygpg pointer on key structure
*
* @return Status Word
*
*/
static int gpg_read_rsa_kyey(gpg_key_t *keygpg) {
uint32_t ksz = 0;
@ -182,6 +211,15 @@ static int gpg_read_rsa_kyey(gpg_key_t *keygpg) {
return SW_OK;
}
/**
* Generate an Elliptic Curve key pair and writes it in NVRam
*
* @param[in] keygpg pointer on key structure
* @param[in] name key name: 'sig ', 'auth ', 'dec '
*
* @return Status Word
*
*/
static int gpg_gen_ecc_kyey(gpg_key_t *keygpg, uint8_t *name) {
uint32_t curve = 0, keepprivate = 0;
uint32_t ksz = 0, reset_cnt = 0;
@ -225,6 +263,14 @@ end:
return error;
}
/**
* Read an Elliptic Curve key pair
*
* @param[in] keygpg pointer on key structure
*
* @return Status Word
*
*/
static int gpg_read_ecc_kyey(gpg_key_t *keygpg) {
uint32_t curve = 0;
uint32_t i, len;
@ -262,7 +308,12 @@ end:
return error;
}
/* assume command is fully received */
/**
* APDU handler to Generate/Read key pair
*
* @return Status Word
*
*/
int gpg_apdu_gen() {
uint32_t t, l;
gpg_key_t *keygpg = NULL;

View File

@ -24,7 +24,7 @@
/* -- A Kind of Magic -- */
/* ----------------------*/
const unsigned char C_MAGIC[8] = {'G', 'P', 'G', 'C', 'A', 'R', 'D', '3'};
const unsigned char C_MAGIC[MAGIC_LENGTH] = {'G', 'P', 'G', 'C', 'A', 'R', 'D', '3'};
/* ----------------------*/
/* --ECC OID -- */
/* ----------------------*/
@ -91,6 +91,15 @@ const unsigned char C_OID_cv25519[10] = {
0x01,
};
/**
* Retrieve Curve associated to a given OID
*
* @param[in] oid Selected OID as a reference
* @param[in] len OID length
*
* @return Found Curve, or CX_CURVE_NONE if not supported
*
*/
unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len) {
if ((len == sizeof(C_OID_SECP256R1)) && (memcmp(oid, C_OID_SECP256R1, len) == 0)) {
return CX_CURVE_SECP256R1;
@ -131,6 +140,15 @@ unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len) {
return CX_CURVE_NONE;
}
/**
* Retrieve OID of the selected Curve
*
* @param[in] cv Selected Curve as a reference
* @param[out] len OID length
*
* @return Found OID, or NULL if not supported
*
*/
unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len) {
switch (cv) {
case CX_CURVE_SECP256R1:
@ -175,6 +193,14 @@ unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len) {
return NULL;
}
/**
* Retrieve the selected Curve length
*
* @param[in] cv Selected Curve as a reference
*
* @return Length, or 0 if not supported
*
*/
unsigned int gpg_curve2domainlen(unsigned int cv) {
switch (cv) {
case CX_CURVE_SECP256K1:
@ -341,12 +367,16 @@ const unsigned char C_sha256_PW2[] = {
/* --- boot init --- */
/* ----------------------------------------------------------------------- */
/**
* App global config
*
*/
void gpg_init() {
explicit_bzero(&G_gpg_vstate, sizeof(gpg_v_state_t));
// first init ?
if (memcmp((void *) (N_gpg_pstate->magic), (void *) C_MAGIC, sizeof(C_MAGIC)) != 0) {
if (memcmp((void *) (N_gpg_pstate->magic), (void *) C_MAGIC, MAGIC_LENGTH) != 0) {
gpg_install(STATE_ACTIVATE);
nvm_write((void *) (N_gpg_pstate->magic), (void *) C_MAGIC, sizeof(C_MAGIC));
nvm_write((void *) (N_gpg_pstate->magic), (void *) C_MAGIC, MAGIC_LENGTH);
explicit_bzero(&G_gpg_vstate, sizeof(gpg_v_state_t));
}
@ -359,10 +389,6 @@ void gpg_init() {
// seed conf
G_gpg_vstate.seed_mode = 1;
// ux conf
gpg_init_ux();
}
void gpg_init_ux() {
G_gpg_vstate.ux_type = -1;
G_gpg_vstate.ux_key = -1;
}
@ -370,6 +396,13 @@ void gpg_init_ux() {
/* ----------------------------------------------------------------------- */
/* --- Install/ReInstall GPGapp --- */
/* ----------------------------------------------------------------------- */
/**
* App dedicated slot config
*
* @param[in] slot Selected slot to configure
*
*/
void gpg_install_slot(gpg_key_slot_t *slot) {
unsigned char tmp[4];
unsigned int l;
@ -396,6 +429,12 @@ void gpg_install_slot(gpg_key_slot_t *slot) {
nvm_write((void *) (&slot->aut.UIF), &tmp, 2);
}
/**
* App 1st installation or reinstallation
*
* @param[in] app_state Current App (card) state
*
*/
void gpg_install(unsigned char app_state) {
gpg_pin_t pin;
@ -459,6 +498,14 @@ void gpg_install(unsigned char app_state) {
}
}
/**
* Setup pinpad configuration
*
* @param[in] enabled pinpad configuration
*
* @return N/A
*
*/
void gpg_activate_pinpad(uint8_t enabled) {
uint8_t e = enabled ? 3 : 0;

View File

@ -30,6 +30,12 @@
/* MISC */
/* ----------------------------------------------------------------------- */
/**
* Set Offset in APDU buffer
*
* @param[in] offset value to set
*
*/
void gpg_io_set_offset(unsigned int offset) {
switch (offset) {
case IO_OFFSET_END:
@ -45,15 +51,32 @@ void gpg_io_set_offset(unsigned int offset) {
}
}
/**
* Mark current offset in APDU buffer
*
*/
void gpg_io_mark() {
G_gpg_vstate.io_mark = G_gpg_vstate.io_offset;
}
/**
* Shift empty space in APDU buffer
*
* @param[in] len space length
*
*/
void gpg_io_inserted(unsigned int len) {
G_gpg_vstate.io_offset += len;
G_gpg_vstate.io_length += len;
}
/**
* Discard APDU buffer values
* Set Length, Offset and Mark to 0
*
* @param[in] clear request to fully zeroed the buffer
*
*/
void gpg_io_discard(int clear) {
G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_offset = 0;
@ -63,6 +86,10 @@ void gpg_io_discard(int clear) {
}
}
/**
* Clear (zeroed) the APDU buffer
*
*/
void gpg_io_clear() {
explicit_bzero(G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
}
@ -71,6 +98,12 @@ void gpg_io_clear() {
/* INSERT data to be sent */
/* ----------------------------------------------------------------------- */
/**
* Move APDU buffer content after a hole
*
* @param[in] sz hole length
*
*/
static void gpg_io_hole(unsigned int sz) {
LEDGER_ASSERT((G_gpg_vstate.io_length + sz) <= GPG_IO_BUFFER_LENGTH, "Bad hole!");
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + sz,
@ -79,18 +112,37 @@ static void gpg_io_hole(unsigned int sz) {
G_gpg_vstate.io_length += sz;
}
/**
* Insert a data buffer into the APDU buffer
*
* @param[in] buff data buffer
* @param[in] len buffer length
*
*/
void gpg_io_insert(unsigned char const *buff, unsigned int len) {
gpg_io_hole(len);
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, buff, len);
G_gpg_vstate.io_offset += len;
}
/**
* Insert a u32 value into the APDU buffer
*
* @param[in] v32 value to insert
*
*/
void gpg_io_insert_u32(unsigned int v32) {
gpg_io_hole(4);
U4BE_ENCODE(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_offset, v32);
G_gpg_vstate.io_offset += 4;
}
/**
* Insert a u24 value into the APDU buffer
*
* @param[in] v24 value to insert
*
*/
void gpg_io_insert_u24(unsigned int v24) {
gpg_io_hole(3);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v24 >> 16;
@ -98,17 +150,38 @@ void gpg_io_insert_u24(unsigned int v24) {
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] = v24 >> 0;
G_gpg_vstate.io_offset += 3;
}
/**
* Insert a u16 value into the APDU buffer
*
* @param[in] v16 value to insert
*
*/
void gpg_io_insert_u16(unsigned int v16) {
gpg_io_hole(2);
U2BE_ENCODE(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_offset, v16);
G_gpg_vstate.io_offset += 2;
}
/**
* Insert a u8 value into the APDU buffer
*
* @param[in] v8 value to insert
*
*/
void gpg_io_insert_u8(unsigned int v8) {
gpg_io_hole(1);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v8;
G_gpg_vstate.io_offset += 1;
}
/**
* Insert a TAG into the APDU buffer
* (To handle TLV)
*
* @param[in] T tag to insert
*
*/
void gpg_io_insert_t(unsigned int T) {
if (T & 0xFF00) {
gpg_io_insert_u16(T);
@ -117,6 +190,14 @@ void gpg_io_insert_t(unsigned int T) {
}
}
/**
* Insert a TAG/LENGTH into the APDU buffer
* (To handle TLV)
*
* @param[in] T tag to insert
* @param[in] L length to insert
*
*/
void gpg_io_insert_tl(unsigned int T, unsigned int L) {
gpg_io_insert_t(T);
if (L < 128) {
@ -129,6 +210,15 @@ void gpg_io_insert_tl(unsigned int T, unsigned int L) {
}
}
/**
* Insert a TAG/LENGTH/VALUE into the APDU buffer
* (To handle TLV)
*
* @param[in] T tag to insert
* @param[in] L length to insert
* @param[in] V data to insert
*
*/
void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) {
gpg_io_insert_tl(T, L);
gpg_io_insert(V, L);
@ -138,6 +228,12 @@ void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) {
/* FECTH data from received buffer */
/* ----------------------------------------------------------------------- */
/**
* Read a u32 value from the APDU buffer
*
* @return value retrieved
*
*/
unsigned int gpg_io_fetch_u32() {
unsigned int v32;
v32 = U4BE(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_offset);
@ -145,6 +241,12 @@ unsigned int gpg_io_fetch_u32() {
return v32;
}
/**
* Read a u24 value from the APDU buffer
*
* @return value retrieved
*
*/
unsigned int gpg_io_fetch_u24() {
unsigned int v24;
v24 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 16) |
@ -154,6 +256,12 @@ unsigned int gpg_io_fetch_u24() {
return v24;
}
/**
* Read a u16 value from the APDU buffer
*
* @return value retrieved
*
*/
unsigned int gpg_io_fetch_u16() {
unsigned int v16;
v16 = U2BE(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_offset);
@ -161,6 +269,12 @@ unsigned int gpg_io_fetch_u16() {
return v16;
}
/**
* Read a u8 value from the APDU buffer
*
* @return value retrieved
*
*/
unsigned int gpg_io_fetch_u8() {
unsigned int v8;
v8 = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
@ -168,6 +282,13 @@ unsigned int gpg_io_fetch_u8() {
return v8;
}
/**
* Read a TAG from the APDU buffer
* (To handle TLV)
*
* @param[out] T read tag
*
*/
void gpg_io_fetch_t(unsigned int *T) {
*T = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset++;
@ -177,6 +298,13 @@ void gpg_io_fetch_t(unsigned int *T) {
}
}
/**
* Read a LENGTH from the APDU buffer
* (To handle TLV)
*
* @param[out] L read length
*
*/
void gpg_io_fetch_l(unsigned int *L) {
*L = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
@ -196,16 +324,40 @@ void gpg_io_fetch_l(unsigned int *L) {
}
}
/**
* Read a TAG/LENGTH from the APDU buffer
* (To handle TLV)
*
* @param[out] T read tag
* @param[out] L read length
*
*/
void gpg_io_fetch_tl(unsigned int *T, unsigned int *L) {
gpg_io_fetch_t(T);
gpg_io_fetch_l(L);
}
/**
* Read a buffer from the APDU buffer and write it in NVRam
* (To handle TLV)
*
* @param[in] buffer NVRAM address
* @param[in] len buffer length
*
*/
void gpg_io_fetch_nv(unsigned char *buffer, int len) {
nvm_write(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
G_gpg_vstate.io_offset += len;
}
/**
* Read a buffer from the APDU buffer
* (To handle TLV)
*
* @param[out] buffer data buffer
* @param[in] len buffer length
*
*/
int gpg_io_fetch(unsigned char *buffer, int len) {
if (buffer) {
memmove(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
@ -220,6 +372,12 @@ int gpg_io_fetch(unsigned char *buffer, int len) {
#define MAX_OUT GPG_APDU_LENGTH
/**
* APDU Receive/transmit
*
* @param[in] flag io buffer flag
*
*/
void gpg_io_do(unsigned int io_flags) {
unsigned int rx = 0;

View File

@ -17,6 +17,13 @@
#include "gpg_vars.h"
/**
* Set a new MSE configuration
*
* @param[in] crt selected key
* @param[in] ref new operation type
*
*/
static void gpg_mse_set(int crt, int ref) {
if (crt == KEY_AUT) {
if (ref == 0x02) {
@ -37,11 +44,21 @@ static void gpg_mse_set(int crt, int ref) {
}
}
/**
* Reset MSE config
*
*/
void gpg_mse_reset() {
gpg_mse_set(KEY_AUT, 0x03);
gpg_mse_set(KEY_DEC, 0x02);
}
/**
* APDU handler to Manage Security Environment
*
* @return Status Word
*
*/
int gpg_apdu_mse() {
int crt, ref;

View File

@ -18,6 +18,14 @@
#include "gpg_vars.h"
#include "gpg_ux.h"
/**
* Get Pin structure from reference ID value
*
* @param[in] pinref PinCode reference ID
*
* @return Pin structure, or NULL if invalid
*
*/
gpg_pin_t *gpg_pin_get_pin(int pinref) {
switch (pinref) {
case PIN_ID_PW1:
@ -31,6 +39,14 @@ gpg_pin_t *gpg_pin_get_pin(int pinref) {
return NULL;
}
/**
* Get Pin index from reference ID value
*
* @param[in] pinref PinCode reference ID
*
* @return Pin index
*
*/
static int gpg_pin_get_state_index(unsigned int pinref) {
switch (pinref) {
case PIN_ID_PW1:
@ -45,6 +61,16 @@ static int gpg_pin_get_state_index(unsigned int pinref) {
return -1;
}
/**
* Compare the PinCode hash and handle the associated counter
*
* @param[in] pin PinCode reference to check
* @param[in] pin_val PinCode value
* @param[in] pin_len PinCode length
*
* @return Status Word
*
*/
static int gpg_pin_check_internal(gpg_pin_t *pin, const unsigned char *pin_val, int pin_len) {
unsigned int counter;
cx_err_t error = CX_INTERNAL_ERROR;
@ -75,6 +101,16 @@ end:
return error;
}
/**
* Check the PinCode value and set verification status
*
* @param[in] pin PinCode reference to check
* @param[in] pin_val PinCode value
* @param[in] pin_len PinCode length
*
* @return Status Word
*
*/
int gpg_pin_check(gpg_pin_t *pin, int pinID, const unsigned char *pin_val, unsigned int pin_len) {
int sw = SW_UNKNOWN;
gpg_pin_set_verified(pinID, 0);
@ -85,6 +121,16 @@ int gpg_pin_check(gpg_pin_t *pin, int pinID, const unsigned char *pin_val, unsig
return sw;
}
/**
* Set the PinCode value in NVRam
*
* @param[in] pin PinCode reference to set
* @param[in] pin_val PinCode value
* @param[in] pin_len PinCode length
*
* @return Status Word
*
*/
int gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len) {
cx_sha256_t sha256;
cx_err_t error = CX_INTERNAL_ERROR;
@ -103,6 +149,13 @@ end:
return SW_OK;
}
/**
* Change the Pin verification status
*
* @param[in] pinID PinCode ID to change
* @param[in] verified new status
*
*/
void gpg_pin_set_verified(int pinID, int verified) {
int idx;
idx = gpg_pin_get_state_index(pinID);
@ -111,6 +164,14 @@ void gpg_pin_set_verified(int pinID, int verified) {
}
}
/**
* Check if the selected Pin is verified
*
* @param[in] pinID PinCode ID to check
*
* @return 0 or 1 (false or true)
*
*/
int gpg_pin_is_verified(int pinID) {
int idx;
idx = gpg_pin_get_state_index(pinID);
@ -120,10 +181,24 @@ int gpg_pin_is_verified(int pinID) {
return 0;
}
/**
* Check if the selected Pin is blocked
*
* @param[in] pin PinCode reference to check
*
* @return 0 or 1 (false or true)
*
*/
int gpg_pin_is_blocked(gpg_pin_t *pin) {
return pin->counter == 0;
}
/**
* APDU handler to Verify PinCode
*
* @return Status Word
*
*/
int gpg_apdu_verify() {
int sw = SW_UNKNOWN;
gpg_pin_t *pin;
@ -196,6 +271,12 @@ int gpg_apdu_verify() {
return SW_WRONG_DATA;
}
/**
* APDU handler to Change PinCode
*
* @return Status Word
*
*/
int gpg_apdu_change_ref_data() {
int sw = SW_UNKNOWN;
gpg_pin_t *pin;
@ -237,6 +318,12 @@ int gpg_apdu_change_ref_data() {
return sw;
}
/**
* APDU handler to Reste PinCode or Counter
*
* @return Status Word
*
*/
int gpg_apdu_reset_retry_counter() {
int sw = SW_UNKNOWN;
gpg_pin_t *pin_pw1;

View File

@ -58,80 +58,92 @@ const unsigned char gpg_oid_sha512[] = {0x30,
0x04,
0x40};
/**
* Reset PW1 verified status
*
*/
static void gpg_pso_reset_PW1() {
if (N_gpg_pstate->PW_status[0] == 0) {
gpg_pin_set_verified(PIN_ID_PW1, 0);
}
}
/**
* Perform a Digital Signature
*
* @param[in] sigKey signing key
*
* @return Status Word
*
*/
static int gpg_sign(gpg_key_t *sigkey) {
cx_err_t error = CX_INTERNAL_ERROR;
if (sigkey->attributes.value[0] == KEY_ID_RSA) {
cx_rsa_private_key_t *key = NULL;
unsigned int ksz, l;
ksz = U2BE(sigkey->attributes.value, 1) >> 3;
switch (ksz) {
case 2048 / 8:
key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa2048;
break;
case 3072 / 8:
key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa3072;
break;
cx_rsa_private_key_t *rsa_key = NULL;
unsigned int ksz, l;
cx_ecfp_private_key_t *ecfp_key = NULL;
unsigned int s_len, i, rs_len, info;
unsigned char *rs;
switch (sigkey->attributes.value[0]) {
case KEY_ID_RSA:
ksz = U2BE(sigkey->attributes.value, 1) >> 3;
switch (ksz) {
case 2048 / 8:
rsa_key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa2048;
break;
case 3072 / 8:
rsa_key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa3072;
break;
#ifdef WITH_SUPPORT_RSA4096
case 4096 / 8:
key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa4096;
break;
case 4096 / 8:
rsa_key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa4096;
break;
#endif
default:
default:
break;
}
if ((rsa_key == NULL) || (rsa_key->size != ksz)) {
error = SW_CONDITIONS_NOT_SATISFIED;
break;
}
if ((key == NULL) || (key->size != ksz)) {
return SW_CONDITIONS_NOT_SATISFIED;
}
}
// sign
if (ksz < G_gpg_vstate.io_length) {
return SW_WRONG_LENGTH;
}
l = ksz - G_gpg_vstate.io_length;
memmove(G_gpg_vstate.work.io_buffer + l,
G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length);
memset(G_gpg_vstate.work.io_buffer, 0xFF, l);
G_gpg_vstate.work.io_buffer[0] = 0;
G_gpg_vstate.work.io_buffer[1] = 1;
G_gpg_vstate.work.io_buffer[l - 1] = 0;
CX_CHECK(cx_rsa_decrypt_no_throw(key,
CX_PAD_NONE,
CX_NONE,
G_gpg_vstate.work.io_buffer,
ksz,
G_gpg_vstate.work.io_buffer,
&ksz));
// send
gpg_io_discard(0);
gpg_io_inserted(ksz);
gpg_pso_reset_PW1();
return SW_OK;
}
if ((sigkey->attributes.value[0] == KEY_ID_ECDSA) ||
(sigkey->attributes.value[0] == KEY_ID_EDDSA)) {
cx_ecfp_private_key_t *key;
size_t ksz;
unsigned int s_len, i, rs_len, info;
unsigned char *rs;
// sign
if (ksz < G_gpg_vstate.io_length) {
error = SW_WRONG_LENGTH;
break;
}
l = ksz - G_gpg_vstate.io_length;
memmove(G_gpg_vstate.work.io_buffer + l,
G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length);
memset(G_gpg_vstate.work.io_buffer, 0xFF, l);
G_gpg_vstate.work.io_buffer[0] = 0;
G_gpg_vstate.work.io_buffer[1] = 1;
G_gpg_vstate.work.io_buffer[l - 1] = 0;
CX_CHECK(cx_rsa_decrypt_no_throw(rsa_key,
CX_PAD_NONE,
CX_NONE,
G_gpg_vstate.work.io_buffer,
ksz,
G_gpg_vstate.work.io_buffer,
&ksz));
// send
gpg_io_discard(0);
gpg_io_inserted(ksz);
gpg_pso_reset_PW1();
error = SW_OK;
break;
key = &sigkey->priv_key.ecfp;
// sign
#define RS (G_gpg_vstate.work.io_buffer + (GPG_IO_BUFFER_LENGTH - 256))
if (sigkey->attributes.value[0] == KEY_ID_ECDSA) {
ksz = (unsigned int) gpg_curve2domainlen(key->curve);
if ((ksz == 0) || (key->d_len != ksz)) {
return SW_CONDITIONS_NOT_SATISFIED;
case KEY_ID_ECDSA:
ecfp_key = &sigkey->priv_key.ecfp;
ksz = (unsigned int) gpg_curve2domainlen(ecfp_key->curve);
if ((ksz == 0) || (ecfp_key->d_len != ksz)) {
error = SW_CONDITIONS_NOT_SATISFIED;
break;
}
s_len = 256;
CX_CHECK(cx_ecdsa_sign_no_throw(key,
CX_CHECK(cx_ecdsa_sign_no_throw(ecfp_key,
CX_RND_TRNG,
CX_NONE,
G_gpg_vstate.work.io_buffer,
@ -156,33 +168,51 @@ static int gpg_sign(gpg_key_t *sigkey) {
rs_len = rs[1];
rs += 2;
}
} else {
error = SW_OK;
break;
case KEY_ID_EDDSA:
ecfp_key = &sigkey->priv_key.ecfp;
ksz = 256;
CX_CHECK(cx_eddsa_sign_no_throw(key,
CX_CHECK(cx_eddsa_sign_no_throw(ecfp_key,
CX_SHA512,
G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length,
RS,
ksz));
CX_CHECK(cx_ecdomain_parameters_length(key->curve, &ksz));
CX_CHECK(cx_ecdomain_parameters_length(ecfp_key->curve, &ksz));
ksz *= 2;
gpg_io_discard(0);
gpg_io_insert(RS, ksz);
}
error = SW_OK;
break;
// send
gpg_pso_reset_PW1();
return SW_OK;
default:
// --- PSO:CDS NOT SUPPORTED
error = SW_REFERENCED_DATA_NOT_FOUND;
break;
}
// --- PSO:CDS NOT SUPPORTED
return SW_REFERENCED_DATA_NOT_FOUND;
end:
gpg_pso_reset_PW1();
return error;
}
/**
* APDU handler to Perform Security Operation
*
* @return Status Word
*
*/
int gpg_apdu_pso() {
unsigned int t, l, ksz;
cx_err_t error = CX_INTERNAL_ERROR;
unsigned int t, l, ksz;
unsigned int cnt, pad_byte;
unsigned int msg_len;
unsigned int curve;
cx_aes_key_t *aes_key = NULL;
cx_rsa_private_key_t *rsa_key = NULL;
cx_ecfp_private_key_t *ecfp_key = NULL;
// UIF HANDLE
switch (G_gpg_vstate.io_p1p2) {
@ -211,26 +241,20 @@ int gpg_apdu_pso() {
// --- PSO:ENC ---
switch (G_gpg_vstate.io_p1p2) {
// --- PSO:CDS ---
case PSO_CDS: {
unsigned int cnt;
int sw = SW_UNKNOWN;
sw = gpg_sign(&G_gpg_vstate.kslot->sig);
case PSO_CDS:
error = gpg_sign(&G_gpg_vstate.kslot->sig);
cnt = G_gpg_vstate.kslot->sig_count + 1;
nvm_write(&G_gpg_vstate.kslot->sig_count, &cnt, sizeof(unsigned int));
return sw;
}
// --- PSO:ENC ---
case PSO_ENC: {
unsigned int msg_len;
cx_aes_key_t *key = NULL;
key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != CX_AES_128_KEY_LEN)) {
break;
case PSO_ENC:
aes_key = &G_gpg_vstate.kslot->AES_dec;
if (!(aes_key->size != CX_AES_128_KEY_LEN)) {
return SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
ksz = GPG_IO_BUFFER_LENGTH - 1;
CX_CHECK(cx_aes_no_throw(key,
CX_CHECK(cx_aes_no_throw(aes_key,
CX_ENCRYPT | CX_CHAIN_CBC | CX_LAST,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
msg_len,
@ -240,44 +264,43 @@ int gpg_apdu_pso() {
gpg_io_discard(0);
G_gpg_vstate.work.io_buffer[0] = PAD_AES;
gpg_io_inserted(1 + ksz);
return SW_OK;
}
error = SW_OK;
break;
// --- PSO:DEC ---
case PSO_DEC: {
unsigned int msg_len;
unsigned int pad_byte;
case PSO_DEC:
pad_byte = gpg_io_fetch_u8();
switch (pad_byte) {
// --- PSO:DEC:RSA
case PAD_RSA: {
cx_rsa_private_key_t *key = NULL;
case PAD_RSA:
if (G_gpg_vstate.mse_dec->attributes.value[0] != KEY_ID_RSA) {
return SW_CONDITIONS_NOT_SATISFIED;
error = SW_CONDITIONS_NOT_SATISFIED;
break;
}
ksz = U2BE(G_gpg_vstate.mse_dec->attributes.value, 1) >> 3;
key = NULL;
switch (ksz) {
case 2048 / 8:
key = (cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa2048;
rsa_key =
(cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa2048;
break;
case 3072 / 8:
key = (cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa3072;
rsa_key =
(cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa3072;
break;
#ifdef WITH_SUPPORT_RSA4096
case 4096 / 8:
key = (cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa4096;
rsa_key =
(cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa4096;
break;
#endif
}
if ((key == NULL) || (key->size != ksz)) {
return SW_CONDITIONS_NOT_SATISFIED;
if ((rsa_key == NULL) || (rsa_key->size != ksz)) {
error = SW_CONDITIONS_NOT_SATISFIED;
break;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
CX_CHECK(cx_rsa_decrypt_no_throw(
key,
rsa_key,
CX_PAD_PKCS1_1o5,
CX_NONE,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
@ -287,19 +310,18 @@ int gpg_apdu_pso() {
// send
gpg_io_discard(0);
gpg_io_inserted(ksz);
return SW_OK;
}
error = SW_OK;
break;
// --- PSO:DEC:AES
case PAD_AES: {
cx_aes_key_t *key;
key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != CX_AES_128_KEY_LEN)) {
return SW_CONDITIONS_NOT_SATISFIED;
case PAD_AES:
aes_key = &G_gpg_vstate.kslot->AES_dec;
if (!(aes_key->size != CX_AES_128_KEY_LEN)) {
error = SW_CONDITIONS_NOT_SATISFIED;
break;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
ksz = GPG_IO_BUFFER_LENGTH;
CX_CHECK(cx_aes_no_throw(key,
CX_CHECK(cx_aes_no_throw(aes_key,
CX_DECRYPT | CX_CHAIN_CBC | CX_LAST,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
msg_len,
@ -308,85 +330,90 @@ int gpg_apdu_pso() {
// send
gpg_io_discard(0);
gpg_io_inserted(ksz);
return SW_OK;
}
// --- PSO:DEC:ECDH
case PAD_ECDH: {
cx_ecfp_private_key_t *key;
unsigned int curve;
error = SW_OK;
break;
case PAD_ECDH:
if (G_gpg_vstate.mse_dec->attributes.value[0] != KEY_ID_ECDH) {
return SW_CONDITIONS_NOT_SATISFIED;
error = SW_CONDITIONS_NOT_SATISFIED;
break;
}
key = &G_gpg_vstate.mse_dec->priv_key.ecfp;
ecfp_key = &G_gpg_vstate.mse_dec->priv_key.ecfp;
gpg_io_fetch_l(&l);
gpg_io_fetch_tl(&t, &l);
if (t != 0x7f49) {
return SW_WRONG_DATA;
error = SW_WRONG_DATA;
break;
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x86) {
return SW_WRONG_DATA;
error = SW_WRONG_DATA;
break;
}
curve = gpg_oid2curve(G_gpg_vstate.mse_dec->attributes.value + 1,
G_gpg_vstate.mse_dec->attributes.length - 1);
if (key->curve != curve) {
return SW_CONDITIONS_NOT_SATISFIED;
if (ecfp_key->curve != curve) {
error = SW_CONDITIONS_NOT_SATISFIED;
break;
}
if (curve == CX_CURVE_Curve25519) {
unsigned int i;
for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer[512 + i] =
(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset)[31 - i];
for (cnt = 0; cnt <= 31; cnt++) {
G_gpg_vstate.work.io_buffer[512 + cnt] =
(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset)[31 - cnt];
}
G_gpg_vstate.work.io_buffer[511] = 0x02;
CX_CHECK(cx_ecdh_no_throw(key,
CX_CHECK(cx_ecdh_no_throw(ecfp_key,
CX_ECDH_X,
G_gpg_vstate.work.io_buffer + 511,
65,
G_gpg_vstate.work.io_buffer + 256,
160));
CX_CHECK(cx_ecdomain_parameters_length(key->curve, &ksz));
CX_CHECK(cx_ecdomain_parameters_length(ecfp_key->curve, &ksz));
for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer[128 + i] =
G_gpg_vstate.work.io_buffer[287 - i];
for (cnt = 0; cnt <= 31; cnt++) {
G_gpg_vstate.work.io_buffer[128 + cnt] =
G_gpg_vstate.work.io_buffer[287 - cnt];
}
ksz = 32;
} else {
CX_CHECK(
cx_ecdh_no_throw(key,
cx_ecdh_no_throw(ecfp_key,
CX_ECDH_X,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
65,
G_gpg_vstate.work.io_buffer + 128,
160));
CX_CHECK(cx_ecdomain_parameters_length(key->curve, &ksz));
CX_CHECK(cx_ecdomain_parameters_length(ecfp_key->curve, &ksz));
}
// send
gpg_io_discard(0);
gpg_io_insert(G_gpg_vstate.work.io_buffer + 128, ksz);
return SW_OK;
}
error = SW_OK;
break;
// --- PSO:DEC:xx NOT SUPPORTED
default:
return SW_REFERENCED_DATA_NOT_FOUND;
error = SW_REFERENCED_DATA_NOT_FOUND;
break;
}
}
break;
//--- PSO:yy NOT SUPPORTED ---
default:
return SW_REFERENCED_DATA_NOT_FOUND;
error = SW_REFERENCED_DATA_NOT_FOUND;
break;
}
return SW_REFERENCED_DATA_NOT_FOUND;
end:
return error;
}
/**
* APDU handler to Internal Authentication
*
* @return Status Word
*
*/
int gpg_apdu_internal_authenticate() {
// --- PSO:AUTH ---
if (G_gpg_vstate.kslot->aut.UIF[0]) {

View File

@ -20,6 +20,12 @@
const unsigned char C_MF[] = {0x3F, 0x00};
const unsigned char C_ATR[] = {0x2F, 0x02};
/**
* APDU handler to Select the card
*
* @return Status Word
*
*/
int gpg_apdu_select() {
int sw = SW_UNKNOWN;

View File

@ -41,6 +41,7 @@
#define GPG_MIN_PW1_LENGTH 6
#define GPG_MIN_PW3_LENGTH 8
#define MAGIC_LENGTH 8
#define AID_LENGTH 16
#define HISTO_LENGTH 15
#define HISTO_OFFSET_STATE 12 // 3rd byte from last (buffer size is 15)
@ -136,7 +137,7 @@ typedef struct gpg_key_slot_s {
struct gpg_nv_state_s {
/* magic */
unsigned char magic[8];
unsigned char magic[MAGIC_LENGTH];
/* pin mode */
unsigned char config_pin[1];

View File

@ -16,9 +16,38 @@
* limitations under the License.
*****************************************************************************/
#include "gpg_vars.h"
#include "gpg_ux.h"
#include "usbd_ccid_if.h"
/**
* Reset CCID
*
*/
void ui_CCID_reset(void) {
io_usb_ccid_set_card_inserted(0);
io_usb_ccid_set_card_inserted(1);
}
/**
* Exit app
*
*/
void app_quit(void) {
// exit app here
os_sched_exit(0);
}
/**
* Reset app
*
*/
void app_reset(void) {
unsigned char magic[MAGIC_LENGTH];
explicit_bzero(magic, MAGIC_LENGTH);
nvm_write((void*) (N_gpg_pstate->magic), magic, MAGIC_LENGTH);
gpg_init();
ui_CCID_reset();
ui_init();
}

View File

@ -34,6 +34,8 @@
#define LABEL_Ed25519 "Ed25519"
void ui_CCID_reset(void);
void app_quit(void);
void app_reset(void);
void ui_init(void);
void ui_menu_pinconfirm_display(unsigned int value);
void ui_menu_pinentry_display(unsigned int value);

View File

@ -39,10 +39,18 @@ unsigned int ui_pinentry_action_button(unsigned int button_mask, unsigned int bu
/* ------------------------------- Helpers UX ------------------------------- */
void ui_info(const char *msg1, const char *msg2, const void *menu_display, unsigned int value) {
/**
* Display popup message on screen
*
* @param[in] msg1 1st part of the message
* @param[in] msg2 2nd part of the message
* @param[in] menu_display next page display callback
*
*/
void ui_info(const char *msg1, const char *msg2, const void *menu_display) {
explicit_bzero(&G_gpg_vstate.ui_dogsays[0], sizeof(ux_menu_entry_t));
G_gpg_vstate.ui_dogsays[0].callback = menu_display;
G_gpg_vstate.ui_dogsays[0].userid = value;
G_gpg_vstate.ui_dogsays[0].userid = 0;
G_gpg_vstate.ui_dogsays[0].line1 = msg1;
G_gpg_vstate.ui_dogsays[0].line2 = msg2;
@ -95,11 +103,25 @@ const bagl_element_t ui_uifconfirm_action[] = {
G_gpg_vstate.menu},
};
/**
* UIF page display
*
* @param[in] value unused
*
*/
void ui_menu_uifconfirm_display(unsigned int value) {
UNUSED(value);
UX_DISPLAY(ui_uifconfirm_action, (void *) ui_uifconfirm_predisplay);
}
/**
* UIF page display preparation callback
*
* @param[in] element selected element to display
*
* @return Error code
*
*/
unsigned int ui_uifconfirm_predisplay(const bagl_element_t *element) {
explicit_bzero(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu));
@ -140,6 +162,15 @@ unsigned int ui_uifconfirm_predisplay(const bagl_element_t *element) {
return 1;
}
/**
* UIF page Action callback
*
* @param[in] button_mask selected button
* @param[in] button_mask_counter unused
*
* @return Error code
*
*/
unsigned int ui_uifconfirm_action_button(unsigned int button_mask,
unsigned int button_mask_counter) {
UNUSED(button_mask_counter);
@ -216,6 +247,14 @@ const bagl_element_t ui_pinconfirm_action[] = {
G_gpg_vstate.menu},
};
/**
* Pin Confirm display preparation callback
*
* @param[in] element selected element to display
*
* @return Error code
*
*/
unsigned int ui_pinconfirm_predisplay(const bagl_element_t *element) {
if (element->component.userid == 1) {
if ((G_gpg_vstate.io_p2 == PIN_ID_PW1) || (G_gpg_vstate.io_p2 == PIN_ID_PW2) ||
@ -239,11 +278,26 @@ unsigned int ui_pinconfirm_predisplay(const bagl_element_t *element) {
return 1;
}
/**
* Pin Confirm page display
*
* @param[in] value unused
*
*/
void ui_menu_pinconfirm_display(unsigned int value) {
UNUSED(value);
UX_DISPLAY(ui_pinconfirm_action, (void *) ui_pinconfirm_predisplay);
}
/**
* Pin Confirm Action callback
*
* @param[in] button_mask selected button
* @param[in] button_mask_counter unused
*
* @return Error code
*
*/
unsigned int ui_pinconfirm_action_button(unsigned int button_mask,
unsigned int button_mask_counter) {
UNUSED(button_mask_counter);
@ -317,6 +371,14 @@ const bagl_element_t ui_pinentry_action[] = {
static const char C_pin_digit[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '<', 'A', 'V'};
/**
* Pin Entry display preparation callback
*
* @param[in] element selected element to display
*
* @return Error code
*
*/
unsigned int ui_pinentry_predisplay(const bagl_element_t *element) {
if (element->component.userid == 1) {
if (G_gpg_vstate.io_ins == INS_CHANGE_REFERENCE_DATA) {
@ -368,6 +430,12 @@ unsigned int ui_pinentry_predisplay(const bagl_element_t *element) {
return 1;
}
/**
* Pin Entry page display
*
* @param[in] value indicate if pin is reset
*
*/
void ui_menu_pinentry_display(unsigned int value) {
if (value == 0) {
explicit_bzero(G_gpg_vstate.ux_pinentry, sizeof(G_gpg_vstate.ux_pinentry));
@ -377,6 +445,10 @@ void ui_menu_pinentry_display(unsigned int value) {
UX_DISPLAY(ui_pinentry_action, (void *) ui_pinentry_predisplay);
}
/**
* Pin Entry Validation callback
*
*/
static void validate_pin() {
unsigned int offset, len, sw = SW_UNKNOWN;
gpg_pin_t *pin;
@ -399,7 +471,7 @@ static void validate_pin() {
sizeof(G_gpg_vstate.menu),
" %d tries remaining",
pin->counter);
ui_info(WRONG_PIN, G_gpg_vstate.menu, ui_menu_main_display, 0);
ui_info(WRONG_PIN, G_gpg_vstate.menu, ui_menu_main_display);
} else {
ui_menu_main_display(0);
}
@ -424,7 +496,7 @@ static void validate_pin() {
sizeof(G_gpg_vstate.menu),
" %d tries remaining",
pin->counter);
ui_info(WRONG_PIN, G_gpg_vstate.menu, ui_menu_main_display, 0);
ui_info(WRONG_PIN, G_gpg_vstate.menu, ui_menu_main_display);
return;
}
offset = 1 + G_gpg_vstate.work.io_buffer[0];
@ -436,7 +508,7 @@ static void validate_pin() {
gpg_io_discard(1);
gpg_io_insert_u16(SW_CONDITIONS_NOT_SATISFIED);
gpg_io_do(IO_RETURN_AFTER_TX);
ui_info(PIN_DIFFERS, EMPTY, ui_menu_main_display, 0);
ui_info(PIN_DIFFERS, EMPTY, ui_menu_main_display);
} else {
sw = gpg_pin_set(gpg_pin_get_pin(G_gpg_vstate.io_p2),
G_gpg_vstate.work.io_buffer + offset + 1,
@ -452,6 +524,15 @@ static void validate_pin() {
}
}
/**
* Pin Entry page Action callback
*
* @param[in] button_mask selected button
* @param[in] button_mask_counter unused
*
* @return Error code
*
*/
unsigned int ui_pinentry_action_button(unsigned int button_mask, unsigned int button_mask_counter) {
UNUSED(button_mask_counter);
unsigned int offset = G_gpg_vstate.ux_pinLen;
@ -541,6 +622,15 @@ const ux_menu_entry_t ui_menu_tmpl_type[] = {
{ui_menu_template, NULL, 0, &C_icon_back, "Back", NULL, 61, 40},
UX_MENU_END};
/**
* Template page display preparation callback
*
* @param[in] entry selected menu to display
* @param[in] element selected element to display
*
* @return Eelement to display
*
*/
const bagl_element_t *ui_menu_template_predisplay(const ux_menu_entry_t *entry,
bagl_element_t *element) {
if (element->component.userid == 0x20) {
@ -593,10 +683,22 @@ const bagl_element_t *ui_menu_template_predisplay(const ux_menu_entry_t *entry,
return element;
}
/**
* Template page display
*
* @param[in] value flow step
*
*/
void ui_menu_template_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_menu_template, ui_menu_template_predisplay);
}
/**
* Template Action callback
*
* @param[in] value unused
*
*/
void ui_menu_tmpl_set_action(unsigned int value) {
UNUSED(value);
LV(attributes, GPG_KEY_ATTRIBUTES_LENGTH);
@ -647,7 +749,7 @@ void ui_menu_tmpl_set_action(unsigned int value) {
break;
}
if (attributes.value[0] == 0) {
ui_info(INVALID_SELECTION, TEMPLATE_TYPE, ui_menu_template_display, 0);
ui_info(INVALID_SELECTION, TEMPLATE_TYPE, ui_menu_template_display);
return;
}
@ -668,17 +770,29 @@ void ui_menu_tmpl_set_action(unsigned int value) {
if (dest != NULL) {
nvm_write(dest, NULL, sizeof(gpg_key_t));
nvm_write(&dest->attributes, &attributes, sizeof(attributes));
ui_info(OK, EMPTY, ui_menu_template_display, 0);
ui_info(OK, EMPTY, ui_menu_template_display);
} else {
ui_info(INVALID_SELECTION, TEMPLATE_KEY, ui_menu_template_display, 0);
ui_info(INVALID_SELECTION, TEMPLATE_KEY, ui_menu_template_display);
}
}
/**
* Key Name Template Action callback
*
* @param[in] value selected key
*
*/
void ui_menu_tmpl_key_action(unsigned int value) {
G_gpg_vstate.ux_key = value;
ui_menu_template_display(0);
}
/**
* Key Type Template Action callback
*
* @param[in] value selected key
*
*/
void ui_menu_tmpl_type_action(unsigned int value) {
G_gpg_vstate.ux_type = value;
ui_menu_template_display(1);
@ -693,6 +807,15 @@ const ux_menu_entry_t ui_menu_seedmode[] = {
{ui_menu_settings, NULL, 0, &C_icon_back, "Back", NULL, 61, 40},
UX_MENU_END};
/**
* Seed Mode page display preparation callback
*
* @param[in] entry selected menu to display
* @param[in] element selected element to display
*
* @return Eelement to display
*
*/
const bagl_element_t *ui_menu_seedmode_predisplay(const ux_menu_entry_t *entry,
bagl_element_t *element) {
if (element->component.userid == 0x20) {
@ -707,10 +830,22 @@ const bagl_element_t *ui_menu_seedmode_predisplay(const ux_menu_entry_t *entry,
return element;
}
/**
* Seed Mode page display
*
* @param[in] value flow step
*
*/
void ui_menu_seedmode_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_menu_seedmode, ui_menu_seedmode_predisplay);
}
/**
* Seed Mode toggle callback
*
* @param[in] value selected seed mode
*
*/
static void toggle_seed(unsigned int value) {
if (value != 128) {
return;
@ -746,6 +881,12 @@ const ux_menu_entry_t ui_seed_warning[] = {
{NULL, toggle_seed, 128, &C_icon_validate_14, "Disable", NULL, 0, 0},
UX_MENU_END};
/**
* Seed Mode Action callback
*
* @param[in] value selected mode
*
*/
void ui_menu_seedmode_action(unsigned int value) {
if (value == 0) {
// Request deactivate
@ -772,10 +913,25 @@ const ux_menu_entry_t ui_menu_pinmode[] = {
{ui_menu_settings, NULL, 0, &C_icon_back, "Back", NULL, 61, 40},
UX_MENU_END};
/**
* Pin Mode page display
*
* @param[in] value flow step
*
*/
void ui_menu_pinmode_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_menu_pinmode, ui_menu_pinmode_predisplay);
}
/**
* Pin Mode page display preparation callback
*
* @param[in] entry selected menu to display
* @param[in] element selected element to display
*
* @return element to display
*
*/
const bagl_element_t *ui_menu_pinmode_predisplay(const ux_menu_entry_t *entry,
bagl_element_t *element) {
if (element->component.userid == 0x20) {
@ -811,6 +967,12 @@ const ux_menu_entry_t ui_trust_warning[] = {
{NULL, ui_menu_pinmode_action, 127, &C_icon_validate_14, "Select", NULL, 61, 40},
UX_MENU_END};
/**
* Pin Mode Action callback
*
* @param[in] value selected mode
*
*/
void ui_menu_pinmode_action(unsigned int value) {
unsigned char s;
value = value & 0x7FFF;
@ -819,7 +981,7 @@ void ui_menu_pinmode_action(unsigned int value) {
case 128:
if (G_gpg_vstate.pinmode != N_gpg_pstate->config_pin[0]) {
if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) {
ui_info(DEFAULT_MODE, NOT_ALLOWED, ui_menu_pinmode_display, 0);
ui_info(DEFAULT_MODE, NOT_ALLOWED, ui_menu_pinmode_display);
return;
}
// set new mode
@ -837,7 +999,7 @@ void ui_menu_pinmode_action(unsigned int value) {
break;
}
if ((gpg_pin_is_verified(PIN_ID_PW1) == 0) && (gpg_pin_is_verified(PIN_ID_PW2) == 0)) {
ui_info(PIN_USER, NOT_VERIFIED, ui_menu_pinmode_display, 0);
ui_info(PIN_USER, NOT_VERIFIED, ui_menu_pinmode_display);
return;
}
G_gpg_vstate.pinmode = value;
@ -850,7 +1012,7 @@ void ui_menu_pinmode_action(unsigned int value) {
break;
}
if (!gpg_pin_is_verified(PIN_ID_PW3)) {
ui_info(PIN_ADMIN, NOT_VERIFIED, ui_menu_pinmode_display, 0);
ui_info(PIN_ADMIN, NOT_VERIFIED, ui_menu_pinmode_display);
return;
}
// Confirm request
@ -862,7 +1024,7 @@ void ui_menu_pinmode_action(unsigned int value) {
break;
default:
value = 0;
ui_info(INVALID_SELECTION, EMPTY, ui_menu_pinmode_display, 0);
ui_info(INVALID_SELECTION, EMPTY, ui_menu_pinmode_display);
break;
}
ui_menu_pinmode_display(value);
@ -886,6 +1048,15 @@ void ui_menu_uifmode_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_menu_uifmode, ui_menu_uifmode_predisplay);
}
/**
* UIF page display preparation callback
*
* @param[in] entry selected menu to display
* @param[in] element selected element to display
*
* @return element to display
*
*/
const bagl_element_t *ui_menu_uifmode_predisplay(const ux_menu_entry_t *entry,
bagl_element_t *element) {
if (element->component.userid == 0x20) {
@ -916,6 +1087,12 @@ const bagl_element_t *ui_menu_uifmode_predisplay(const ux_menu_entry_t *entry,
return element;
}
/**
* UIF Action callback
*
* @param[in] value selected key
*
*/
void ui_menu_uifmode_action(unsigned int value) {
unsigned char *uif;
unsigned char new_uif;
@ -930,7 +1107,7 @@ void ui_menu_uifmode_action(unsigned int value) {
uif = &G_gpg_vstate.kslot->aut.UIF[0];
break;
default:
ui_info(INVALID_SELECTION, EMPTY, ui_menu_uifmode_display, 0);
ui_info(INVALID_SELECTION, EMPTY, ui_menu_uifmode_display);
return;
}
if (uif[0] == 0) {
@ -940,7 +1117,7 @@ void ui_menu_uifmode_action(unsigned int value) {
new_uif = 0;
nvm_write(&uif[0], &new_uif, 1);
} else /*if (uif[0] == 2 )*/ {
ui_info(UIF_LOCKED, EMPTY, ui_menu_uifmode_display, 0);
ui_info(UIF_LOCKED, EMPTY, ui_menu_uifmode_display);
return;
}
ui_menu_uifmode_display(value);
@ -954,17 +1131,16 @@ const ux_menu_entry_t ui_menu_reset[] = {
{NULL, ui_menu_reset_action, 0, NULL, "Yes", NULL, 0, 0},
UX_MENU_END};
/**
* Reset Action callback
*
* @param[in] value unused
*
*/
void ui_menu_reset_action(unsigned int value) {
UNUSED(value);
unsigned char magic[4];
magic[0] = 0;
magic[1] = 0;
magic[2] = 0;
magic[3] = 0;
nvm_write((void *) (N_gpg_pstate->magic), magic, 4);
gpg_init();
ui_CCID_reset();
ui_menu_main_display(0);
app_reset();
}
/* ------------------------------- SETTINGS UX ------------------------------- */
@ -998,9 +1174,18 @@ const ux_menu_entry_t ui_menu_main[] = {
{NULL, NULL, 0, NULL, "", "", 0, 0},
{ui_menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0},
{ui_menu_info, NULL, 0, NULL, "About", NULL, 0, 0},
{NULL, (void *) os_sched_exit, 0, &C_icon_dashboard, "Quit app", NULL, 50, 29},
{NULL, (void *) app_quit, 0, &C_icon_dashboard, "Quit app", NULL, 50, 29},
UX_MENU_END};
/**
* Main page display preparation callback
*
* @param[in] entry selected menu to display
* @param[in] element selected element to display
*
* @return Eelement to display
*
*/
const bagl_element_t *ui_menu_main_predisplay(const ux_menu_entry_t *entry,
bagl_element_t *element) {
if (entry == &ui_menu_main[0]) {
@ -1026,20 +1211,26 @@ const bagl_element_t *ui_menu_main_predisplay(const ux_menu_entry_t *entry,
}
return element;
}
/**
* Main page display
*
* @param[in] value flow step
*
*/
void ui_menu_main_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_menu_main, ui_menu_main_predisplay);
}
/* --- INIT --- */
/**
* home page definition
*
*/
void ui_init(void) {
ui_menu_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);
}
#endif // defined(HAVE_BAGL) && defined(TARGET_NANOS)

View File

@ -26,6 +26,7 @@
/* ----------------------------------------------------------------------- */
/* --- NanoX UI layout --- */
/* ----------------------------------------------------------------------- */
void ui_menu_tmpl_set_action(unsigned int value);
void ui_menu_tmpl_key_action(unsigned int value);
void ui_menu_tmpl_type_action(unsigned int value);
@ -51,6 +52,13 @@ UX_STEP_CB(ux_menu_popup_1_step,
UX_FLOW(ux_flow_popup, &ux_menu_popup_1_step);
/**
* Display popup message on screen
*
* @param[in] msg1 1st part of the message
* @param[in] msg2 2nd part of the message
*
*/
void ui_info(const char *msg1, const char *msg2) {
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s. %s", msg1, msg2);
ux_flow_init(0, ux_flow_popup, NULL);
@ -75,6 +83,10 @@ UX_FLOW(ux_flow_uifconfirm,
&ux_menu_uifconfirm_3_step,
&ux_menu_uifconfirm_2_step);
/**
* UIF page display preparation callback
*
*/
void ui_menu_uifconfirm_predisplay() {
switch (G_gpg_vstate.io_ins) {
case INS_INTERNAL_AUTHENTICATE:
@ -103,10 +115,24 @@ void ui_menu_uifconfirm_predisplay() {
}
}
/**
* UIF page display
*
* @param[in] value flow step
*
*/
void ui_menu_uifconfirm_display(unsigned int value) {
ui_flow_display(ux_flow_uifconfirm, value);
}
/**
* UIF Confirmation Action callback
*
* @param[in] confirm indicate if the user press 'Confirm' or 'Cancel'
*
* @return Error code
*
*/
unsigned int ui_uifconfirm_action(unsigned int value) {
unsigned int sw = SW_SECURITY_UIF_ISSUE;
@ -165,6 +191,10 @@ UX_FLOW(ux_flow_pinconfirm,
&ux_menu_pinconfirm_2_step,
&ux_menu_pinconfirm_3_step);
/**
* Pin Confirm page display preparation callback
*
*/
void ui_menu_pinconfirm_predisplay() {
if ((G_gpg_vstate.io_p2 == PIN_ID_PW1) || (G_gpg_vstate.io_p2 == PIN_ID_PW2) ||
(G_gpg_vstate.io_p2 == PIN_ID_PW3)) {
@ -178,11 +208,25 @@ void ui_menu_pinconfirm_predisplay() {
}
}
/**
* Pin Confirm page display
*
* @param[in] value flow step
*
*/
void ui_menu_pinconfirm_display(unsigned int value) {
UNUSED(value);
ux_flow_init(0, ux_flow_pinconfirm, NULL);
}
/**
* Pin Confirm Confirmation Action callback
*
* @param[in] confirm indicate if the user press 'Confirm' or 'Cancel'
*
* @return Error code
*
*/
unsigned int ui_pinconfirm_action(unsigned int value) {
unsigned int sw = SW_UNKNOWN;
@ -250,6 +294,14 @@ const bagl_element_t ui_pinentry_action[] = {
static const char C_pin_digit[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '<', 'A', 'V'};
/**
* Pin Entry page display preparation callback
*
* @param[in] element selected element to display
*
* @return Error code
*
*/
unsigned int ui_pinentry_predisplay(const bagl_element_t *element) {
if (element->component.userid == 1) {
if (G_gpg_vstate.io_ins == INS_CHANGE_REFERENCE_DATA) {
@ -301,6 +353,12 @@ unsigned int ui_pinentry_predisplay(const bagl_element_t *element) {
return 1;
}
/**
* Pin Entry page display
*
* @param[in] value indicate if pin is reset
*
*/
void ui_menu_pinentry_display(unsigned int value) {
if (value == 0) {
explicit_bzero(G_gpg_vstate.ux_pinentry, sizeof(G_gpg_vstate.ux_pinentry));
@ -310,6 +368,10 @@ void ui_menu_pinentry_display(unsigned int value) {
UX_DISPLAY(ui_pinentry_action, (void *) ui_pinentry_predisplay);
}
/**
* Pin Entry Validation callback
*
*/
static void validate_pin() {
unsigned int offset, len, sw = SW_UNKNOWN;
gpg_pin_t *pin;
@ -385,6 +447,15 @@ static void validate_pin() {
}
}
/**
* Pin Entry page Action callback
*
* @param[in] button_mask selected button
* @param[in] button_mask_counter unused
*
* @return Error code
*
*/
unsigned int ui_pinentry_action_button(unsigned int button_mask, unsigned int button_mask_counter) {
UNUSED(button_mask_counter);
unsigned int offset = G_gpg_vstate.ux_pinLen;
@ -451,14 +522,28 @@ const char *const tmpl_key_getter_values[] = {LABEL_SIG, LABEL_DEC, LABEL_AUT};
const unsigned int tmpl_key_getter_values_map[] = {1, 2, 3};
const char *tmpl_key_getter(unsigned int idx) {
/**
* Helper to get the key name
*
* @param[in] idx key index
*
* @return key name, or NULL if not found
*
*/
static const char *tmpl_key_getter(unsigned int idx) {
if (idx < ARRAYLEN(tmpl_key_getter_values)) {
return tmpl_key_getter_values[idx];
}
return NULL;
}
void tmpl_key_selector(unsigned int idx) {
/**
* Helper to select the key name and display the Template page
*
* @param[in] idx key index
*
*/
static void tmpl_key_selector(unsigned int idx) {
if (idx < ARRAYLEN(tmpl_key_getter_values)) {
idx = tmpl_key_getter_values_map[idx];
} else {
@ -486,14 +571,28 @@ const unsigned int tmpl_type_getter_values_map[] = {2048,
CX_CURVE_SECP256R1,
CX_CURVE_Ed25519};
const char *tmpl_type_getter(unsigned int idx) {
/**
* Helper to get the key type
*
* @param[in] idx key index
*
* @return key type, or NULL if not found
*
*/
static const char *tmpl_type_getter(unsigned int idx) {
if (idx < ARRAYLEN(tmpl_type_getter_values)) {
return tmpl_type_getter_values[idx];
}
return NULL;
}
void tmpl_type_selector(unsigned int idx) {
/**
* Helper to select the key type and display the Template page
*
* @param[in] idx key index
*
*/
static void tmpl_type_selector(unsigned int idx) {
if (idx < ARRAYLEN(tmpl_type_getter_values)) {
idx = tmpl_type_getter_values_map[idx];
} else {
@ -546,6 +645,10 @@ UX_FLOW(ux_flow_template,
&ux_menu_template_3_step,
&ux_menu_template_4_step);
/**
* Template page display preparation callback
*
*/
void ui_menu_template_predisplay() {
switch (G_gpg_vstate.ux_key) {
case 1:
@ -589,10 +692,21 @@ void ui_menu_template_predisplay() {
}
}
/**
* Template page display
*
* @param[in] value flow step
*
*/
void ui_menu_template_display(unsigned int value) {
ui_flow_display(ux_flow_template, value);
}
/**
* Template Action callback
*
* @param[in] value unused
*/
void ui_menu_tmpl_set_action(unsigned int value) {
UNUSED(value);
LV(attributes, GPG_KEY_ATTRIBUTES_LENGTH);
@ -696,14 +810,28 @@ UX_STEP_CB(ux_menu_seedmode_2_step,
UX_FLOW(ux_flow_seedmode, &ux_menu_seedmode_1_step, &ux_menu_seedmode_2_step);
/**
* Seed Mode page display preparation callback
*
*/
void ui_menu_seedmode_predisplay() {
snprintf(CUR_SEED_MODE, sizeof(CUR_SEED_MODE), "%s", G_gpg_vstate.seed_mode ? "ON" : "OFF");
}
/**
* Seed Mode page display
*
* @param[in] value flow step
*
*/
void ui_menu_seedmode_display(unsigned int value) {
ui_flow_display(ux_flow_seedmode, value);
}
/**
* Seed Mode toggle callback
*
*/
static void toggle_seed() {
if (G_gpg_vstate.seed_mode) {
G_gpg_vstate.seed_mode = 0;
@ -746,6 +874,12 @@ UX_FLOW(ui_seed_disabling_flow,
&ui_seed_warning_flow_cancel_step,
&ui_seed_disabling_flow_confirm_step);
/**
* Seed Mode Action callback
*
* @param[in] value seed mode state
*
*/
void ui_menu_seedmode_action(unsigned int value) {
if (value == 1) {
// Current value is 'enable' -> Confirm deactivate
@ -807,6 +941,10 @@ UX_FLOW(ux_flow_pinmode,
&ux_menu_pinmode_4_step,
&ux_menu_pinmode_5_step);
/**
* Pin Mode page display preparation callback
*
*/
void ui_menu_pinmode_predisplay() {
snprintf(ONSCR_BUFF, 5, "%s", PIN_MODE_SCREEN == G_gpg_vstate.pinmode ? "ON" : "OFF");
snprintf(CONFI_BUFF, 5, "%s", PIN_MODE_CONFIRM == G_gpg_vstate.pinmode ? "ON" : "OFF");
@ -826,6 +964,12 @@ void ui_menu_pinmode_predisplay() {
PIN_MODE_TRUST == N_gpg_pstate->config_pin[0] ? "(Default)" : "");
}
/**
* Pin Mode page display
*
* @param[in] value flow step
*
*/
void ui_menu_pinmode_display(unsigned int value) {
ui_flow_display(ux_flow_pinmode, value);
}
@ -860,6 +1004,12 @@ UX_FLOW(ui_trust_selecting_flow,
&ui_trust_warning_flow_cancel_step,
&ui_trust_selecting_flow_confirm_step);
/**
* Pin Mode Action callback
*
* @param[in] value token indication the selected action
*
*/
void ui_menu_pinmode_action(unsigned int value) {
unsigned char s;
@ -956,16 +1106,32 @@ UX_FLOW(ux_flow_uif,
&ux_menu_uif_3_step,
&ux_menu_uif_4_step);
/**
* UIF page display preparation callback
*
*/
void ui_menu_uifmode_predisplay() {
snprintf(SIG_BUFF, sizeof(SIG_BUFF), "%s", G_gpg_vstate.kslot->sig.UIF[0] ? "ON" : "OFF");
snprintf(DEC_BUFF, sizeof(DEC_BUFF), "%s", G_gpg_vstate.kslot->dec.UIF[0] ? "ON" : "OFF");
snprintf(AUT_BUFF, sizeof(AUT_BUFF), "%s", G_gpg_vstate.kslot->aut.UIF[0] ? "ON" : "OFF");
}
/**
* UIF page display
*
* @param[in] value flow step
*
*/
void ui_menu_uifmode_display(unsigned int value) {
ui_flow_display(ux_flow_uif, value);
}
/**
* UIF Confirmation Action callback
*
* @param[in] value indicate the targeted key
*
*/
void ui_menu_uifmode_action(unsigned int value) {
unsigned char *uif;
unsigned char new_uif;
@ -1009,21 +1175,26 @@ UX_STEP_CB(ux_menu_reset_2_step, bn, ui_menu_reset_action(0), {"YES!", "Reset th
UX_FLOW(ux_flow_reset, &ux_menu_reset_1_step, &ux_menu_reset_2_step);
/**
* Reset page display
*
* @param[in] value flow step
*
*/
void ui_menu_reset_display(unsigned int value) {
ux_flow_init(value, ux_flow_reset, NULL);
}
/**
* Reset Action callback
*
* @param[in] value unused
*
*/
void ui_menu_reset_action(unsigned int value) {
UNUSED(value);
unsigned char magic[4];
magic[0] = 0;
magic[1] = 0;
magic[2] = 0;
magic[3] = 0;
nvm_write((void *) (N_gpg_pstate->magic), magic, 4);
gpg_init();
ui_CCID_reset();
ui_menu_main_display(0);
app_reset();
}
/* ------------------------------- SETTINGS UX ------------------------------- */
@ -1031,6 +1202,14 @@ void ui_menu_reset_action(unsigned int value) {
const char *const settings_getter_values[] =
{"Key template", "Seed mode", "PIN mode", "UIF mode", "Reset", "Back"};
/**
* Helper to retrieve page title
*
* @param[in] idx page index
*
* @return page title, or NULL
*
*/
const char *settings_getter(unsigned int idx) {
if (idx < ARRAYLEN(settings_getter_values)) {
return settings_getter_values[idx];
@ -1038,6 +1217,12 @@ const char *settings_getter(unsigned int idx) {
return NULL;
}
/**
* Settings page display
*
* @param[in] idx page index
*
*/
void settings_selector(unsigned int idx) {
switch (idx) {
case 0:
@ -1061,6 +1246,12 @@ void settings_selector(unsigned int idx) {
}
}
/**
* Settings page display
*
* @param[in] value flow step
*
*/
void ui_menu_settings_display(unsigned int value) {
ux_menulist_init_select(G_ux.stack_count - 1, settings_getter, settings_selector, value);
}
@ -1112,6 +1303,10 @@ UX_FLOW(ux_flow_slot,
&ux_menu_slot_4_step,
&ux_menu_slot_5_step);
/**
* Slot page display preparation callback
*
*/
void ui_menu_slot_predisplay() {
snprintf(SLOT1,
sizeof(SLOT1),
@ -1130,10 +1325,22 @@ void ui_menu_slot_predisplay() {
3 == G_gpg_vstate.slot + 1 ? "+" : " ");
}
/**
* Slot page display
*
* @param[in] value flow step
*
*/
void ui_menu_slot_display(unsigned int value) {
ui_flow_display(ux_flow_slot, value);
}
/**
* Slot Action callback
*
* @param[in] value token indication the selected action
*
*/
void ui_menu_slot_action(unsigned int value) {
unsigned char s;
@ -1177,6 +1384,12 @@ UX_STEP_CB(ux_menu_info_2_step,
UX_FLOW(ux_flow_info, &ux_menu_info_1_step, &ux_menu_info_2_step);
/**
* Info page display
*
* @param[in] value flow step
*
*/
void ui_menu_info_display(unsigned int value) {
UNUSED(value);
ux_flow_init(0, ux_flow_info, NULL);
@ -1201,7 +1414,7 @@ UX_STEP_CB(ux_menu_main_3_step, pb, ui_menu_settings_display(0), {&C_icon_coggle
UX_STEP_CB(ux_menu_main_4_step, pb, ui_menu_info_display(0), {&C_icon_certificate, "About"});
UX_STEP_CB(ux_menu_main_5_step, pb, os_sched_exit(0), {&C_icon_dashboard_x, "Quit app"});
UX_STEP_CB(ux_menu_main_5_step, pb, app_quit(), {&C_icon_dashboard_x, "Quit app"});
UX_FLOW(ux_flow_main,
&ux_menu_main_1_step,
@ -1210,6 +1423,10 @@ UX_FLOW(ux_flow_main,
&ux_menu_main_4_step,
&ux_menu_main_5_step);
/**
* Main page display preparation callback
*
*/
void ui_menu_main_predisplay() {
explicit_bzero(G_gpg_vstate.ux_buff1, sizeof(G_gpg_vstate.ux_buff1));
memmove(G_gpg_vstate.ux_buff1, (void *) (N_gpg_pstate->name.value), 20);
@ -1230,6 +1447,12 @@ void ui_menu_main_predisplay() {
G_gpg_vstate.slot + 1);
}
/**
* Main page display
*
* @param[in] value flow step
*
*/
void ui_menu_main_display(unsigned int value) {
// reserve a display stack slot if none yet
if (G_ux.stack_count == 0) {
@ -1241,12 +1464,12 @@ void ui_menu_main_display(unsigned int value) {
/* --- INIT --- */
/**
* home page definition
*
*/
void ui_init(void) {
ui_menu_main_display(0);
}
void io_seproxyhal_display(const bagl_element_t *element) {
io_seproxyhal_display_default((bagl_element_t *) element);
}
#endif // defined(HAVE_BAGL) && (defined(TARGET_NANOX) || defined(TARGET_NANOS2))

View File

@ -31,32 +31,39 @@
/* ----------------------------------------------------------------------- */
/* --- NBGL UI layout --- */
/* ----------------------------------------------------------------------- */
void ui_menu_settings();
void ui_menu_slot_action();
static void ui_menu_settings();
static void ui_menu_slot_action();
static void settings_ctrl_cb(int token, uint8_t index);
static void ui_settings_template(void);
static void ui_settings_seed(void);
static void ui_settings_pin(void);
// contexts for background and modal pages
// context for background and modal pages
static nbgl_layout_t layoutCtx = {0};
enum {
TOKEN_SETTINGS_TEMPLATE = FIRST_USER_TOKEN,
TOKEN_SETTINGS_SEED,
TOKEN_SETTINGS_PIN,
TOKEN_SETTINGS_UIF,
TOKEN_SETTINGS_RESET,
};
/* ------------------------------- Helpers UX ------------------------------- */
/**
* Display popup message on screen
*
* @param[in] msg1 1st part of the message
* @param[in] msg2 2nd part of the message
*
*/
static void ui_info(const char* msg1, const char* msg2, nbgl_callback_t cb, bool isSuccess) {
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s\n%s", msg1, msg2);
nbgl_useCaseStatus((const char*) G_gpg_vstate.menu, isSuccess, cb);
};
/**
* Display Setting page header
*
* @param[in] title page title
* @param[in] back_token token for back button
* @param[in] touch_cb action callback
*
*/
static void ui_setting_header(const char* title,
uint8_t back_token,
nbgl_layoutTouchCallback_t touch_cb) {
@ -82,12 +89,10 @@ static void ui_setting_header(const char* title,
// ----------------------- HOME PAGE -------------------------
// -----------------------------------------------------------
void app_quit(void) {
// exit app here
os_sched_exit(-1);
}
// home page definition
/**
* home page definition
*
*/
void ui_init(void) {
char name[32];
unsigned int serial = U4BE(G_gpg_vstate.kslot->serial, 0);
@ -129,6 +134,13 @@ enum {
TOKEN_SLOT_BACK,
};
/**
* Slot Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void slot_cb(int token, uint8_t index) {
switch (token) {
case TOKEN_SLOT_BACK:
@ -151,7 +163,11 @@ static void slot_cb(int token, uint8_t index) {
}
}
void ui_menu_slot_action(void) {
/**
* Slot Navigation callback
*
*/
static void ui_menu_slot_action(void) {
nbgl_layoutRadioChoice_t choices = {0};
nbgl_layoutButton_t buttonInfo = {0};
static char* names[GPG_KEYS_SLOTS] = {0};
@ -191,6 +207,7 @@ void ui_menu_slot_action(void) {
// -----------------------------------------------------------
/* ------------------------------- TEMPLATE UX ------------------------------- */
enum {
TOKEN_TEMPLATE_SIG = FIRST_USER_TOKEN,
TOKEN_TEMPLATE_DEC,
@ -222,6 +239,14 @@ static const char* const keyTypeTexts[] = {LABEL_RSA2048,
LABEL_SECP256R1,
LABEL_Ed25519};
/**
* Determine the selected key type from its attributes
*
* @param[in] key token describing the selected key
*
* @return token describing the selected key type
*
*/
static uint32_t _getKeyType(const uint8_t key) {
uint8_t* attributes = NULL;
uint32_t token = 0;
@ -290,6 +315,13 @@ static uint32_t _getKeyType(const uint8_t key) {
return token;
}
/**
* Key Template Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void template_key_cb(int token, uint8_t index) {
LV(attributes, GPG_KEY_ATTRIBUTES_LENGTH);
gpg_key_t* dest = NULL;
@ -384,6 +416,13 @@ static void template_key_cb(int token, uint8_t index) {
ui_settings_template();
}
/**
* Template Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void template_cb(int token, uint8_t index) {
UNUSED(index);
static nbgl_layoutRadioChoice_t choices = {0};
@ -411,6 +450,10 @@ static void template_cb(int token, uint8_t index) {
}
}
/**
* Template Navigation callback
*
*/
static void ui_settings_template(void) {
nbgl_layoutBar_t bar = {0};
uint32_t i;
@ -458,11 +501,18 @@ static void ui_settings_template(void) {
}
/* --------------------------------- SEED UX --------------------------------- */
enum {
TOKEN_SEED = FIRST_USER_TOKEN,
TOKEN_SEED_BACK,
};
/**
* Seed Mode Confirmation callback
*
* @param[in] confirm indicate if the user press 'Confirm' or 'Cancel'
*
*/
void seed_confirm_cb(bool confirm) {
if (confirm) {
G_gpg_vstate.seed_mode = 0;
@ -473,6 +523,13 @@ void seed_confirm_cb(bool confirm) {
}
}
/**
* Seed Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void seed_cb(int token, uint8_t index) {
switch (token) {
case TOKEN_SEED_BACK:
@ -494,6 +551,10 @@ static void seed_cb(int token, uint8_t index) {
}
}
/**
* Seed Navigation callback
*
*/
static void ui_settings_seed(void) {
static nbgl_layoutSwitch_t option = {0};
@ -517,6 +578,12 @@ enum {
TOKEN_PIN_BACK,
};
/**
* Trust Mode Confirmation callback
*
* @param[in] confirm indicate if the user press 'Confirm' or 'Cancel'
*
*/
void trust_cb(bool confirm) {
if (confirm) {
G_gpg_vstate.pinmode = G_gpg_vstate.pinmode_req;
@ -526,6 +593,13 @@ void trust_cb(bool confirm) {
}
}
/**
* Pin Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void pin_cb(int token, uint8_t index) {
const char* err = NULL;
switch (token) {
@ -582,6 +656,10 @@ static void pin_cb(int token, uint8_t index) {
}
}
/**
* Pin Navigation callback
*
*/
static void ui_settings_pin(void) {
static nbgl_layoutRadioChoice_t choices = {0};
nbgl_layoutButton_t buttonInfo = {0};
@ -624,6 +702,7 @@ static void ui_settings_pin(void) {
}
/* --------------------------------- UIF UX ---------------------------------- */
enum {
TOKEN_UIF_SIG = FIRST_USER_TOKEN,
TOKEN_UIF_DEC,
@ -631,6 +710,13 @@ enum {
TOKEN_UIF_BACK,
};
/**
* UIF Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void uif_cb(int token, uint8_t index) {
unsigned char* uif = NULL;
switch (token) {
@ -657,6 +743,10 @@ static void uif_cb(int token, uint8_t index) {
}
}
/**
* UIF Navigation callback
*
*/
static void ui_settings_uif(void) {
static nbgl_layoutSwitch_t option = {0};
uint8_t nbOptions = 0;
@ -711,10 +801,18 @@ static void ui_settings_uif(void) {
}
/* -------------------------------- RESET UX --------------------------------- */
enum {
TOKEN_RESET = FIRST_USER_TOKEN,
};
/**
* Reset Navigation callback
*
* @param[in] page selected page to display
* @param[in] content describe the widgets to display on the page
*
*/
static bool reset_nav_cb(uint8_t page, nbgl_pageContent_t* content) {
UNUSED(page);
explicit_bzero(content, sizeof(nbgl_pageContent_t));
@ -728,21 +826,33 @@ static bool reset_nav_cb(uint8_t page, nbgl_pageContent_t* content) {
return true;
}
/**
* Reset Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void reset_ctrl_cb(int token, uint8_t index) {
UNUSED(index);
unsigned char magic[4] = {0, 0, 0, 0};
if (token != TOKEN_RESET) {
return;
}
nvm_write((void*) (N_gpg_pstate->magic), magic, sizeof(magic));
gpg_init();
ui_CCID_reset();
ui_init();
app_reset();
}
/* ------------------------------- SETTINGS UX ------------------------------- */
enum {
TOKEN_SETTINGS_TEMPLATE = FIRST_USER_TOKEN,
TOKEN_SETTINGS_SEED,
TOKEN_SETTINGS_PIN,
TOKEN_SETTINGS_UIF,
TOKEN_SETTINGS_RESET,
};
enum {
SETTINGS_PAGE_PARAMS,
SETTINGS_PAGE_INFO,
@ -754,6 +864,14 @@ enum {
#else
#define VERSION_STR "App " XSTR(APPVERSION)
#endif
/**
* Settings Navigation callback
*
* @param[in] page selected page to display
* @param[in] content describe the widgets to display on the page
*
*/
static bool settings_nav_cb(uint8_t page, nbgl_pageContent_t* content) {
bool ret = false;
@ -793,6 +911,13 @@ static bool settings_nav_cb(uint8_t page, nbgl_pageContent_t* content) {
return ret;
}
/**
* Settings Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void settings_ctrl_cb(int token, uint8_t index) {
UNUSED(index);
switch (token) {
@ -820,8 +945,11 @@ static void settings_ctrl_cb(int token, uint8_t index) {
}
}
// settings menu definition
void ui_menu_settings() {
/**
* Settings menu definition
*
*/
static void ui_menu_settings() {
nbgl_useCaseSettings(APPNAME,
SETTINGS_PAGE_PARAMS,
SETTINGS_PAGE_NB,
@ -832,6 +960,13 @@ void ui_menu_settings() {
}
/* ------------------------------ PIN CONFIRM UX ----------------------------- */
/**
* Pin Confirmation callback
*
* @param[in] confirm indicate if the user press 'Confirm' or 'Cancel'
*
*/
void pin_confirm_cb(bool confirm) {
gpg_pin_set_verified(G_gpg_vstate.io_p2, confirm);
@ -841,6 +976,12 @@ void pin_confirm_cb(bool confirm) {
ui_init();
}
/**
* Pin Confirmation page display
*
* @param[in] value PinCode ID to confirm
*
*/
void ui_menu_pinconfirm_display(unsigned int value) {
snprintf(G_gpg_vstate.menu,
sizeof(G_gpg_vstate.menu),
@ -851,13 +992,20 @@ void ui_menu_pinconfirm_display(unsigned int value) {
}
/* ------------------------------ PIN ENTRY UX ----------------------------- */
enum {
TOKEN_PIN_ENTRY_BACK = FIRST_USER_TOKEN,
};
static void ui_menu_pinentry_cb(void);
static void validate_pin(const uint8_t* pinentry, uint8_t length) {
/**
* Pin Entry Validation callback
*
* @param[in] value PinCode ID to confirm
*
*/
static void pinentry_validate_cb(const uint8_t* pinentry, uint8_t length) {
unsigned int sw = SW_UNKNOWN;
unsigned int len1 = 0;
unsigned char* pin1 = NULL;
@ -952,6 +1100,13 @@ static void validate_pin(const uint8_t* pinentry, uint8_t length) {
}
}
/**
* Pin Entry Action callback
*
* @param[in] token button Id pressed
* @param[in] index widget index on the page
*
*/
static void pinentry_cb(int token, uint8_t index) {
UNUSED(index);
if (token == TOKEN_PIN_ENTRY_BACK) {
@ -962,14 +1117,20 @@ static void pinentry_cb(int token, uint8_t index) {
}
}
void ui_menu_pinentry_display(unsigned int value) {
/**
* Pin Entry page display
*
* @param[in] step Pin Entry step
*
*/
void ui_menu_pinentry_display(unsigned int step) {
uint8_t minLen;
char line[10];
// Init the page title
explicit_bzero(G_gpg_vstate.line, sizeof(G_gpg_vstate.line));
if (G_gpg_vstate.io_ins == INS_CHANGE_REFERENCE_DATA) {
switch (value) {
switch (step) {
case 0:
// Default or initial case
snprintf(line, sizeof(line), "Current");
@ -983,7 +1144,7 @@ void ui_menu_pinentry_display(unsigned int value) {
default:
break;
}
G_gpg_vstate.ux_step = value;
G_gpg_vstate.ux_step = step;
} else {
snprintf(line, sizeof(line), "Enter");
}
@ -1001,10 +1162,14 @@ void ui_menu_pinentry_display(unsigned int value) {
TOKEN_PIN_ENTRY_BACK,
false,
TUNE_TAP_CASUAL,
validate_pin,
pinentry_validate_cb,
pinentry_cb);
}
/**
* Pin Entry Navigation callback
*
*/
static void ui_menu_pinentry_cb(void) {
unsigned int value = 0;
@ -1016,6 +1181,13 @@ static void ui_menu_pinentry_cb(void) {
}
/* ------------------------------ UIF CONFIRM UX ----------------------------- */
/**
* UIF Confirmation callback
*
* @param[in] confirm indicate if the user press 'Confirm' or 'Cancel'
*
*/
void uif_confirm_cb(bool confirm) {
unsigned int sw = SW_SECURITY_UIF_ISSUE;
@ -1037,6 +1209,12 @@ void uif_confirm_cb(bool confirm) {
ui_init();
}
/**
* UIF page display
*
* @param[in] step unused
*
*/
void ui_menu_uifconfirm_display(unsigned int value) {
UNUSED(value);