mirror of
https://github.com/LedgerHQ/openpgp-card-app
synced 2024-11-09 07:10:30 +00:00
Merge pull request #104 from LedgerHQ/cev/issue_101_doc
Issue 101: Improve doc readability
This commit is contained in:
commit
4f84034d41
2
Makefile
2
Makefile
@ -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"
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
158
src/gpg_io.c
158
src/gpg_io.c
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
305
src/gpg_pso.c
305
src/gpg_pso.c
@ -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]) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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];
|
||||
|
29
src/gpg_ux.c
29
src/gpg_ux.c
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user