1.0 RC1
Add-on Spec: Add intermediate SHA256 in seeded key derivation Beautify spec Pytool: Remove some log App: Fix GET_CHALLENGE commande to support addon mode Add '01F2' '01F1' access control Replace ugly temporary cx_sha_t address definition by clean union Rewrite dynamic menu management in ui Add 'About' menu Build: Rename application from GNUPG3 to OpenPGP and version to 1.0 Lock path & curve Compile in optimization mode
This commit is contained in:
parent
f188805766
commit
278d85a821
16
Makefile
16
Makefile
@ -14,15 +14,15 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
#extract TARGET_ID from the SDK to allow for makefile choices
|
#extract TARGET_ID from the SDK to allow for makefile choices
|
||||||
APPNAME = "GNUPG3"
|
APPNAME = "OpenPGP"
|
||||||
APPVERSION = "0.9"
|
APPVERSION = "1.0RC1"
|
||||||
TARGET_ID = 0x31100002
|
TARGET_ID = 0x31100002
|
||||||
$(info TARGET_ID=$(TARGET_ID))
|
$(info TARGET_ID=$(TARGET_ID))
|
||||||
|
|
||||||
APP_LOAD_PARAMS=--appFlags 0
|
APP_LOAD_PARAMS=--appFlags 0 --path "2152157255" --curve secp256k1
|
||||||
LOADFLAGS = --params --appVersion $(APPVERSION)
|
LOADFLAGS = --params --appVersion $(APPVERSION)
|
||||||
|
|
||||||
ICONNAME=icon.gif
|
ICONNAME=icon_pgp.gif
|
||||||
|
|
||||||
|
|
||||||
################
|
################
|
||||||
@ -60,10 +60,8 @@ DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=128
|
|||||||
DEFINES += HAVE_BAGL HAVE_PRINTF HAVE_SPRINTF
|
DEFINES += HAVE_BAGL HAVE_PRINTF HAVE_SPRINTF
|
||||||
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
||||||
DEFINES += HAVE_USB_CLASS_CCID
|
DEFINES += HAVE_USB_CLASS_CCID
|
||||||
#DEFINES += PRINTF=screen_printf
|
|
||||||
DEFINES += PRINTF\(...\)=
|
|
||||||
|
|
||||||
DEFINES += $(GPG_CONFIG)
|
DEFINES += $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME)
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# Compiler #
|
# Compiler #
|
||||||
@ -75,8 +73,8 @@ CC := $(CLANGPATH)/clang
|
|||||||
CFLAGS :=
|
CFLAGS :=
|
||||||
CFLAGS += -gdwarf-2 -gstrict-dwarf
|
CFLAGS += -gdwarf-2 -gstrict-dwarf
|
||||||
#CFLAGS += -O0
|
#CFLAGS += -O0
|
||||||
CFLAGS += -O0 -g3
|
#CFLAGS += -O0 -g3
|
||||||
#CFLAGS += -O3 -Os
|
CFLAGS += -O3 -Os
|
||||||
CFLAGS += -mcpu=cortex-m0 -mthumb
|
CFLAGS += -mcpu=cortex-m0 -mthumb
|
||||||
CFLAGS += -fno-common -mtune=cortex-m0 -mlittle-endian
|
CFLAGS += -fno-common -mtune=cortex-m0 -mlittle-endian
|
||||||
CFLAGS += -std=gnu99 -Werror=int-to-pointer-cast -Wall -Wextra -Wno-unused-variable #-save-temps
|
CFLAGS += -std=gnu99 -Werror=int-to-pointer-cast -Wall -Wextra -Wno-unused-variable #-save-temps
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
GnuPG application for Ledger Blue and Nano S
|
GnuPG application for Ledger Blue and Nano S
|
||||||
|
|
||||||
This application implements "The OpenPGP card" specification revision 3.0. This specification is available in *doc* directory and at:
|
This application implements "The OpenPGP card" specification revision 3.0. This specification is available in *doc* directory and at https://g10code.com/p-card.html .
|
||||||
ttps://g10code.com/p-card.html
|
|
||||||
|
|
||||||
The application supports:
|
The application supports:
|
||||||
- RSA with key up to 4096 bits
|
- RSA with key up to 4096 bits
|
||||||
@ -46,6 +45,8 @@ When installed the default slot is "1". You can change it in settings.
|
|||||||
A seeded mode is implemented in order to restore private keys on a new token.
|
A seeded mode is implemented in order to restore private keys on a new token.
|
||||||
In this mode key material is generated from the global token seeded.
|
In this mode key material is generated from the global token seeded.
|
||||||
|
|
||||||
|
Please consider SEED mode as experimental.
|
||||||
|
|
||||||
More details to come...
|
More details to come...
|
||||||
|
|
||||||
### On screen reset
|
### On screen reset
|
||||||
|
@ -94,7 +94,7 @@ Sn = BIP32_derive (/0x80475047/n)
|
|||||||
|
|
||||||
Then specific seeds are derived with the SHA3-XOF function for each of the four key :
|
Then specific seeds are derived with the SHA3-XOF function for each of the four key :
|
||||||
|
|
||||||
Sk[i] = SHA3-XOF(Sn \| <key_name> \| int16(i), length)
|
Sk[i] = SHA3-XOF(SHA256(Sn \| <key_name> \| int16(i)), length)
|
||||||
|
|
||||||
Sn is the dedicated slot seed from step 1.
|
Sn is the dedicated slot seed from step 1.
|
||||||
key_name is one of 'sig ','dec ', 'aut ', 'sym0', each four characters.
|
key_name is one of 'sig ','dec ', 'aut ', 'sym0', each four characters.
|
||||||
@ -142,7 +142,7 @@ Deterministic random number
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The deterministic random number generation relies on the BIP32 scheme.
|
The deterministic random number generation relies on the BIP32 scheme.
|
||||||
The master install path of GPG-ledger is set to /0x80/'G'/'P'/'G', aka /0x80/0x47/0x50/0x47
|
The master install path of GPG-ledger is set to /0x80'GPG', aka /80475047
|
||||||
|
|
||||||
**Random prime number generation** :
|
**Random prime number generation** :
|
||||||
|
|
||||||
@ -156,8 +156,8 @@ The master install path of GPG-ledger is set to /0x80/'G'/'P'/'G', aka /0x80/0x4
|
|||||||
|
|
||||||
For a given length *L* and seed *S*:
|
For a given length *L* and seed *S*:
|
||||||
|
|
||||||
- generate Sr = BIP32_derive (/0x80/'G'/'P'/'G'/0)
|
- generate Sr = BIP32_derive(/0x80475047/0x0F0F0F0F)
|
||||||
- generate r = SHA3-XOF(Sr \| 'rnd' \| S, L)
|
- generate r = SHA3-XOF(SHA256(Sr \| 'rnd' \| S), L)
|
||||||
- return r
|
- return r
|
||||||
|
|
||||||
**Seeded prime number generation** :
|
**Seeded prime number generation** :
|
||||||
@ -178,10 +178,10 @@ Key Slot management
|
|||||||
Key slots are managed by data object 01F1 and 01F2 witch are
|
Key slots are managed by data object 01F1 and 01F2 witch are
|
||||||
manageable by PUT/GET DATA command as for others DO and organized as follow.
|
manageable by PUT/GET DATA command as for others DO and organized as follow.
|
||||||
|
|
||||||
On application reset the *01F2* content is set to *Default Slot* value
|
On application reset, the *01F2* content is set to *Default Slot* value
|
||||||
of *01F1*.
|
of *01F1*.
|
||||||
|
|
||||||
*01F1*
|
*01F1:*
|
||||||
|
|
||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
|bytes | description | R/W |
|
|bytes | description | R/W |
|
||||||
@ -190,15 +190,23 @@ of *01F1*.
|
|||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
| 2 | Default slot | R/W |
|
| 2 | Default slot | R/W |
|
||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
| 3 | Allowed slot selection method: | R/W |
|
| 3 | Allowed slot selection method | R/W |
|
||||||
| | 0: selection not allowed (locked to default) | |
|
|
||||||
| | 1: selection by APDU | |
|
|
||||||
| | 2: selection by screen | |
|
|
||||||
| | 3: selection by APDU and screen | |
|
|
||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
|
|
||||||
|
Byte 3 is endoced as follow:
|
||||||
|
|
||||||
*01F2*
|
+----+----+----+----+----+----+----+----+-------------------------+
|
||||||
|
| b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning |
|
||||||
|
+----+----+----+----+----+----+----+----+-------------------------+
|
||||||
|
| \- | \- | \- | \- | \- | \- | \- | x | selection by APDU |
|
||||||
|
+----+----+----+----+----+----+----+----+-------------------------+
|
||||||
|
| \- | \- | \- | \- | \- | \- | x | \- | selection by screen |
|
||||||
|
+----+----+----+----+----+----+----+----+-------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*01F2:*
|
||||||
|
|
||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
|bytes | Description | R/W |
|
|bytes | Description | R/W |
|
||||||
@ -206,7 +214,7 @@ of *01F1*.
|
|||||||
| 1 | Current slot | R/W |
|
| 1 | Current slot | R/W |
|
||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
|
|
||||||
*01F0*
|
*01F0:*
|
||||||
|
|
||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
|bytes | Description | R/W |
|
|bytes | Description | R/W |
|
||||||
@ -217,17 +225,17 @@ of *01F1*.
|
|||||||
+------+--------------------------------------------------+--------+
|
+------+--------------------------------------------------+--------+
|
||||||
|
|
||||||
|
|
||||||
*Access Conditions*
|
*Access Conditions:*
|
||||||
|
|
||||||
+------+--------------+-------------+
|
+-------+------------+-------------+
|
||||||
| DO | Read | Write |
|
| DO | Read | Write |
|
||||||
+======+=============+=============+
|
+=======+============+=============+
|
||||||
| 01F0 | Always | Never |
|
| 01F0 | Always | Never |
|
||||||
+------+-------------+-------------+
|
+-------+------------+-------------+
|
||||||
| 01F1 | Always | Verify PW3 |
|
| 01F1 | Always | Verify PW3 |
|
||||||
+------+-------------+-------------+
|
+-------+------------+-------------+
|
||||||
| 01F2 | Always | Verify PW1 |
|
| 01F2 | Always | Verify PW1 |
|
||||||
+------+-------------+-------------+
|
+-------+------------+-------------+
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -242,13 +250,19 @@ P2 parameter of GENERATE ASYMMETRIC KEY PAIR is set to (hex value):
|
|||||||
Deterministic random number
|
Deterministic random number
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
P1 parameter of GET CHALLENGE is set to (hex value):
|
P1 parameter of GET CHALLENGE is a bits field encoded as follow:
|
||||||
- 00 for true random
|
|
||||||
- 81 for prime true random
|
|
||||||
- 82 for seeded random
|
|
||||||
- 83 for prime seeded random
|
|
||||||
|
|
||||||
When P1 is set to 82 or 83, Data field contains the seed
|
+----+-----+----+----+----+----+----+----+-------------------------+
|
||||||
|
| b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning |
|
||||||
|
+----+-----+----+----+----+----+----+----+-------------------------+
|
||||||
|
| \- | \- | \- | \- | \- | \- | \- | x | prime random |
|
||||||
|
+----+-----+----+----+----+----+----+----+-------------------------+
|
||||||
|
| \- | \- | \- | \- | \- | \- | x | \- | seeded random |
|
||||||
|
+----+-----+----+----+----+----+----+----+-------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
When bit b2 is set, data field contains the seed and P2 contains
|
||||||
|
the length of random bytes to generate.
|
||||||
|
|
||||||
|
|
||||||
Other minor add-on
|
Other minor add-on
|
||||||
|
Before Width: | Height: | Size: 90 B After Width: | Height: | Size: 90 B |
@ -113,7 +113,7 @@ class GPGCard() :
|
|||||||
allreaders = readers()
|
allreaders = readers()
|
||||||
for r in allreaders:
|
for r in allreaders:
|
||||||
rname = str(r)
|
rname = str(r)
|
||||||
print('try: %s : %s'%(rname,device[5:]))
|
#print('try: %s : %s'%(rname,device[5:]))
|
||||||
if rname.startswith(device[5:]):
|
if rname.startswith(device[5:]):
|
||||||
r.createConnection()
|
r.createConnection()
|
||||||
self.token = r
|
self.token = r
|
||||||
@ -121,7 +121,8 @@ class GPGCard() :
|
|||||||
self.connection.connect()
|
self.connection.connect()
|
||||||
self.exchange = self._exchange_pcsc
|
self.exchange = self._exchange_pcsc
|
||||||
else:
|
else:
|
||||||
print("No")
|
#print("No")
|
||||||
|
pass
|
||||||
if not self.token:
|
if not self.token:
|
||||||
print("No token")
|
print("No token")
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ class GPGCard() :
|
|||||||
return resp,sw
|
return resp,sw
|
||||||
|
|
||||||
def _exchange_pcsc(self,apdu,sw=0x9000):
|
def _exchange_pcsc(self,apdu,sw=0x9000):
|
||||||
print("xch S cmd : %s"%(binascii.hexlify(apdu)))
|
#print("xch S cmd : %s"%(binascii.hexlify(apdu)))
|
||||||
apdu = [x for x in apdu]
|
apdu = [x for x in apdu]
|
||||||
resp, sw1, sw2 = self.connection.transmit(apdu)
|
resp, sw1, sw2 = self.connection.transmit(apdu)
|
||||||
while sw1==0x61:
|
while sw1==0x61:
|
||||||
@ -156,7 +157,7 @@ class GPGCard() :
|
|||||||
resp = resp + resp2
|
resp = resp + resp2
|
||||||
resp = bytes(resp)
|
resp = bytes(resp)
|
||||||
sw = (sw1<<8)|sw2
|
sw = (sw1<<8)|sw2
|
||||||
print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw))
|
#print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw))
|
||||||
return resp,sw
|
return resp,sw
|
||||||
|
|
||||||
def select(self):
|
def select(self):
|
||||||
@ -730,5 +731,3 @@ class GPGCard() :
|
|||||||
'd': tags[0x98],
|
'd': tags[0x98],
|
||||||
}
|
}
|
||||||
|
|
||||||
def dump():
|
|
||||||
pass
|
|
||||||
|
@ -20,20 +20,47 @@
|
|||||||
#include "gpg_vars.h"
|
#include "gpg_vars.h"
|
||||||
|
|
||||||
int gpg_apdu_get_challenge() {
|
int gpg_apdu_get_challenge() {
|
||||||
|
unsigned int olen,hlen;
|
||||||
|
|
||||||
if (G_gpg_vstate.io_le > GPG_EXT_CHALLENGE_LENTH) {
|
if ((G_gpg_vstate.io_p1&0x80) == 0x80) {
|
||||||
|
olen = G_gpg_vstate.io_p2;
|
||||||
|
} else {
|
||||||
|
olen = G_gpg_vstate.io_le;
|
||||||
|
}
|
||||||
|
if (olen > GPG_EXT_CHALLENGE_LENTH) {
|
||||||
THROW(SW_WRONG_LENGTH);
|
THROW(SW_WRONG_LENGTH);
|
||||||
}
|
}
|
||||||
gpg_io_discard(1);
|
|
||||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
if ((G_gpg_vstate.io_p1&0x82) == 0x82) {
|
||||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
unsigned int path[2];
|
||||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
unsigned char chain[32];
|
||||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
unsigned char Sr[32];
|
||||||
cx_rng(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_le);
|
|
||||||
|
|
||||||
if (G_gpg_vstate.io_p1 & 0x80) {
|
os_memset(chain, 0, 32);
|
||||||
cx_math_next_prime(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,G_gpg_vstate.io_le);
|
path[0] = 0x80475047;
|
||||||
|
path[1] = 0x0F0F0F0F;
|
||||||
|
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2 , Sr, chain);
|
||||||
|
chain[0] = 'r'; chain[1]='n'; chain[2] = 'd';
|
||||||
|
|
||||||
|
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
||||||
|
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL);
|
||||||
|
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL);
|
||||||
|
hlen=cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256,
|
||||||
|
CX_LAST, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
||||||
|
G_gpg_vstate.work.io_buffer);
|
||||||
|
|
||||||
|
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
|
||||||
|
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3,
|
||||||
|
CX_LAST, G_gpg_vstate.work.io_buffer, hlen,
|
||||||
|
G_gpg_vstate.work.io_buffer);
|
||||||
|
} else {
|
||||||
|
cx_rng(G_gpg_vstate.work.io_buffer, olen);
|
||||||
}
|
}
|
||||||
gpg_io_inserted(G_gpg_vstate.io_le);
|
|
||||||
|
if ((G_gpg_vstate.io_p1&0x81) == 0x81) {
|
||||||
|
cx_math_next_prime(G_gpg_vstate.work.io_buffer,olen);
|
||||||
|
}
|
||||||
|
gpg_io_discard(0);
|
||||||
|
gpg_io_inserted(olen);
|
||||||
return SW_OK;
|
return SW_OK;
|
||||||
}
|
}
|
||||||
|
@ -244,10 +244,11 @@ int gpg_apdu_put_data(unsigned int ref) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x01F2:
|
case 0x01F2:
|
||||||
if (G_gpg_vstate.io_length != 1) {
|
if ((N_gpg_pstate->config_slot[2] & 2) == 0) {
|
||||||
THROW(SW_WRONG_LENGTH);
|
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||||
}
|
}
|
||||||
if (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS) {
|
if ((G_gpg_vstate.io_length != 1) ||
|
||||||
|
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS)) {
|
||||||
THROW(SW_WRONG_DATA);
|
THROW(SW_WRONG_DATA);
|
||||||
}
|
}
|
||||||
G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
|
G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
|
||||||
|
@ -156,7 +156,8 @@ void gpg_check_access_write_DO() {
|
|||||||
switch(ref) {
|
switch(ref) {
|
||||||
//PW1
|
//PW1
|
||||||
case 0x0101:
|
case 0x0101:
|
||||||
case 0x0103:
|
case 0x0103:
|
||||||
|
case 0x01F2:
|
||||||
if (gpg_is_verified(ID_PW1)) {
|
if (gpg_is_verified(ID_PW1)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -167,6 +168,7 @@ void gpg_check_access_write_DO() {
|
|||||||
case 0x4f:
|
case 0x4f:
|
||||||
case 0x0102:
|
case 0x0102:
|
||||||
case 0x0104:
|
case 0x0104:
|
||||||
|
case 0x01F1:
|
||||||
case 0x005E:
|
case 0x005E:
|
||||||
case 0x005B:
|
case 0x005B:
|
||||||
case 0x5F2D:
|
case 0x5F2D:
|
||||||
@ -265,7 +267,6 @@ int gpg_dispatch() {
|
|||||||
#endif
|
#endif
|
||||||
/* --- CHALLENGE --- */
|
/* --- CHALLENGE --- */
|
||||||
case INS_GET_CHALLENGE:
|
case INS_GET_CHALLENGE:
|
||||||
|
|
||||||
sw = gpg_apdu_get_challenge();
|
sw = gpg_apdu_get_challenge();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -39,17 +39,19 @@ static void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
|
|||||||
* @in Ski_len sub-seed length
|
* @in Ski_len sub-seed length
|
||||||
*/
|
*/
|
||||||
static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx,
|
static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx,
|
||||||
unsigned char *Ski, unsigned int Ski_len,
|
unsigned char *Ski, unsigned int Ski_len) {
|
||||||
cx_sha3_t *xof) {
|
|
||||||
|
|
||||||
unsigned char idx16[2];
|
unsigned char h[32];
|
||||||
idx16[0] = idx >>8;
|
h[0] = idx >>8;
|
||||||
idx16[1] = idx;
|
h[1] = idx;
|
||||||
|
|
||||||
cx_sha3_xof_init(xof, 256, Ski_len);
|
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
||||||
cx_hash((cx_hash_t *)xof, 0, Sn, 32, NULL);
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL);
|
||||||
cx_hash((cx_hash_t *)xof, 0, (unsigned char *)key_name, 4, NULL);
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, (unsigned char *)key_name, 4, NULL);
|
||||||
cx_hash((cx_hash_t *)xof, CX_LAST, idx16 , 2, Ski);
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, CX_LAST, h , 2, h);
|
||||||
|
|
||||||
|
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len);
|
||||||
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,8 +142,8 @@ int gpg_apdu_gen() {
|
|||||||
unsigned int size;
|
unsigned int size;
|
||||||
size = ksz>>1;
|
size = ksz>>1;
|
||||||
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
|
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
|
||||||
gpg_pso_derive_key_seed(seed, name, 1, pq, size, (cx_sha3_t*)((unsigned int)&G_gpg_vstate.work.io_buffer[1024] & (~3)));
|
gpg_pso_derive_key_seed(seed, name, 1, pq, size);
|
||||||
gpg_pso_derive_key_seed(seed, name, 2, pq+size, size, (cx_sha3_t*)((unsigned int)&G_gpg_vstate.work.io_buffer[1024] & (~3)));
|
gpg_pso_derive_key_seed(seed, name, 2, pq+size, size);
|
||||||
*pq |= 0x80;
|
*pq |= 0x80;
|
||||||
*(pq+size) |= 0x80;
|
*(pq+size) |= 0x80;
|
||||||
cx_math_next_prime(pq,size);
|
cx_math_next_prime(pq,size);
|
||||||
@ -172,7 +174,7 @@ int gpg_apdu_gen() {
|
|||||||
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
|
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
|
||||||
if ((G_gpg_vstate.io_p2 == 0x01) | (G_gpg_vstate.seed_mode)) {
|
if ((G_gpg_vstate.io_p2 == 0x01) | (G_gpg_vstate.seed_mode)) {
|
||||||
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
|
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
|
||||||
gpg_pso_derive_key_seed(seed, name, 1, seed, 32, (cx_sha3_t*)&G_gpg_vstate.work.io_buffer[1024]);
|
gpg_pso_derive_key_seed(seed, name, 1, seed, 32);
|
||||||
cx_ecfp_init_private_key(curve,seed, 32, &G_gpg_vstate.work.ecfp256.private);
|
cx_ecfp_init_private_key(curve,seed, 32, &G_gpg_vstate.work.ecfp256.private);
|
||||||
keepprivate = 1;
|
keepprivate = 1;
|
||||||
}
|
}
|
||||||
|
@ -219,12 +219,8 @@ void gpg_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void gpg_init_ux() {
|
void gpg_init_ux() {
|
||||||
snprintf(G_gpg_vstate.menu_cur_slot, 16, ">>SLOT: %d<<", G_gpg_vstate.slot+1);
|
G_gpg_vstate.ux_type = -1;
|
||||||
snprintf(G_gpg_vstate.menu_seed_mode, 16, ">>%s<<", G_gpg_vstate.seed_mode?"ON":"OFF");
|
G_gpg_vstate.ux_key = -1;
|
||||||
snprintf(G_gpg_vstate.menu_template_key, 16, "choose key...");
|
|
||||||
snprintf(G_gpg_vstate.menu_template_type, 16, "choose type...");
|
|
||||||
G_gpg_vstate.ux_type = 0;
|
|
||||||
G_gpg_vstate.ux_key = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
@ -283,11 +283,15 @@ int gpg_io_do() {
|
|||||||
switch (G_gpg_vstate.io_ins) {
|
switch (G_gpg_vstate.io_ins) {
|
||||||
case INS_GET_DATA:
|
case INS_GET_DATA:
|
||||||
case INS_GET_RESPONSE:
|
case INS_GET_RESPONSE:
|
||||||
case INS_GET_CHALLENGE:
|
|
||||||
case INS_TERMINATE_DF:
|
case INS_TERMINATE_DF:
|
||||||
case INS_ACTIVATE_FILE:
|
case INS_ACTIVATE_FILE:
|
||||||
G_gpg_vstate.io_le = G_io_apdu_buffer[4];
|
G_gpg_vstate.io_le = G_io_apdu_buffer[4];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INS_GET_CHALLENGE:
|
||||||
|
if (G_gpg_vstate.io_p1 == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
|
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
|
||||||
os_memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer+5, G_gpg_vstate.io_lc);
|
os_memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer+5, G_gpg_vstate.io_lc);
|
||||||
|
458
src/gpg_main.c
458
src/gpg_main.c
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* --- UI layout --- */
|
/* --- Blue UI layout --- */
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* screeen size:
|
/* screeen size:
|
||||||
blue; 320x480
|
blue; 320x480
|
||||||
@ -153,50 +153,53 @@ unsigned int ui_idle_blue_button(unsigned int button_mask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
/* --- NanoS UI layout --- */
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_sub_template[];
|
||||||
|
void ui_idle_sub_template_display(unsigned int value);
|
||||||
|
const bagl_element_t* ui_idle_sub_template_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
|
||||||
|
void ui_idle_sub_tmpl_set_action(unsigned int value) ;
|
||||||
|
const ux_menu_entry_t ui_idle_sub_tmpl_key[];
|
||||||
|
void ui_idle_sub_tmpl_key_action(unsigned int value);
|
||||||
|
const ux_menu_entry_t ui_idle_sub_tmpl_type[];
|
||||||
|
void ui_idle_sub_tmpl_type_action(unsigned int value);
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_sub_seed[];
|
||||||
|
void ui_idle_sub_seed_display(unsigned int value);
|
||||||
|
const bagl_element_t* ui_idle_sub_seed_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) ;
|
||||||
|
void ui_idle_sub_seed_action(unsigned int value) ;
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_sub_reset[] ;
|
||||||
|
void ui_idle_sub_reset_action(unsigned int value);
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_sub_slot[];
|
||||||
|
void ui_idle_sub_slot_display(unsigned int value);
|
||||||
|
const bagl_element_t* ui_idle_sub_slot_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
|
||||||
|
void ui_idle_sub_slot_action(unsigned int value);
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_settings[] ;
|
||||||
|
|
||||||
const ux_menu_entry_t ui_idle_mainmenu[];
|
const ux_menu_entry_t ui_idle_mainmenu[];
|
||||||
|
void ui_idle_main_display(unsigned int value) ;
|
||||||
|
const bagl_element_t* ui_idle_main_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
|
||||||
|
|
||||||
/* ----- Helpers UX ----- */
|
|
||||||
void ui_info(const ux_menu_entry_t *back, const char* msg1, const char* msg2) {
|
/* ------------------------------- Helpers UX ------------------------------- */
|
||||||
ux_menu_entry_t ui_invalid[2] = {
|
|
||||||
{back, NULL, 0, NULL, msg1, msg2, 0, 0},
|
void ui_info(const char* msg1, const char* msg2, const void *menu_display, unsigned int entry) {
|
||||||
|
ux_menu_entry_t ui_dogsays[2] = {
|
||||||
|
{NULL, menu_display, 0, NULL, msg1, msg2, 0, 0},
|
||||||
UX_MENU_END
|
UX_MENU_END
|
||||||
};
|
};
|
||||||
UX_MENU_DISPLAY(0, ui_invalid, NULL);
|
UX_MENU_DISPLAY(entry, ui_dogsays, NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----- SLOT UX ----- */
|
|
||||||
void ui_idle_sub_slot_action(unsigned int value) {
|
|
||||||
unsigned char s;
|
|
||||||
|
|
||||||
if (value == 0) {
|
/* ------------------------------- template UX ------------------------------- */
|
||||||
s = G_gpg_vstate.slot;
|
|
||||||
gpg_nvm_write(&N_gpg_pstate->config_slot[1], &s,1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s = (unsigned char)(value-1);
|
|
||||||
G_gpg_vstate.slot = s;
|
|
||||||
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
|
||||||
|
|
||||||
}
|
|
||||||
// redisplay first entry of the idle menu
|
|
||||||
gpg_init_ux();
|
|
||||||
UX_MENU_DISPLAY(0, ui_idle_mainmenu, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ux_menu_entry_t ui_idle_sub_slot[] = {
|
|
||||||
#if GPG_KEYS_SLOTS != 3
|
|
||||||
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
|
||||||
#endif
|
|
||||||
{NULL, ui_idle_sub_slot_action, 1, NULL, "Select slot 1", NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_slot_action, 2, NULL, "Select slot 2", NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_slot_action, 3, NULL, "Select slot 3", NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_slot_action, 0, NULL, "Set as default", NULL, 0, 0},
|
|
||||||
{ui_idle_mainmenu, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
|
||||||
UX_MENU_END
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ----- template UX ----- */
|
|
||||||
#define LABEL_SIG "Signature"
|
#define LABEL_SIG "Signature"
|
||||||
#define LABEL_AUT "Authentication"
|
#define LABEL_AUT "Authentication"
|
||||||
#define LABEL_DEC "Decryption"
|
#define LABEL_DEC "Decryption"
|
||||||
@ -208,84 +211,66 @@ const ux_menu_entry_t ui_idle_sub_slot[] = {
|
|||||||
#define LABEL_BPOOLR1 "Brainpool R1"
|
#define LABEL_BPOOLR1 "Brainpool R1"
|
||||||
#define LABEL_Ed25519 "Ed25519"
|
#define LABEL_Ed25519 "Ed25519"
|
||||||
|
|
||||||
const ux_menu_entry_t ui_idle_sub_template[];
|
const ux_menu_entry_t ui_idle_sub_template[] = {
|
||||||
const ux_menu_entry_t ui_idle_sub_tmpl_key[];
|
{ui_idle_sub_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0},
|
||||||
const ux_menu_entry_t ui_idle_sub_tmpl_type[];
|
{ui_idle_sub_tmpl_type, NULL, -1, NULL, "Choose type...", NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_tmpl_set_action, -1, NULL, "Set template", NULL, 0, 0},
|
||||||
|
{ui_idle_settings, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
|
UX_MENU_END
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
void ui_idle_sub_template_display(unsigned int value) {
|
||||||
const bagl_element_t* ui_idle_sub_tmpl_key_prepocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
UX_MENU_DISPLAY(value, ui_idle_sub_template, ui_idle_sub_template_preprocessor);
|
||||||
if (entry == &ui_idle_sub_tmpl_key[2]) {
|
}
|
||||||
if(element->component.userid==0x20) {
|
|
||||||
element->component.stroke = 10; // 1 second stop in each way
|
const bagl_element_t* ui_idle_sub_template_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
||||||
element->component.icon_id = 26; // roundtrip speed in pixel/s
|
if(element->component.userid==0x20) {
|
||||||
UX_CALLBACK_SET_INTERVAL(MAX(3000, 2*(1000+bagl_label_roundtrip_duration_ms(element, 7))));
|
if (entry == &ui_idle_sub_template[0]) {
|
||||||
|
switch(G_gpg_vstate.ux_key) {
|
||||||
|
case 1:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_SIG);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_DEC);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_AUT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Choose key...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
element->text = G_gpg_vstate.menu;
|
||||||
|
}
|
||||||
|
if (entry == &ui_idle_sub_template[1]) {
|
||||||
|
switch(G_gpg_vstate.ux_type) {
|
||||||
|
case 2048:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA2048);
|
||||||
|
break;
|
||||||
|
case 3072:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA3072);
|
||||||
|
break;
|
||||||
|
case 4096:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA4096);
|
||||||
|
break;
|
||||||
|
case CX_CURVE_SECP256R1:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP256);
|
||||||
|
break;
|
||||||
|
case CX_CURVE_BrainPoolP256R1:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOLR1);
|
||||||
|
break;
|
||||||
|
case CX_CURVE_Ed25519:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_Ed25519);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Choose type...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
element->text = G_gpg_vstate.menu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
void ui_idle_sub_tmpl_key_action(unsigned int value) {
|
|
||||||
|
|
||||||
switch(value) {
|
|
||||||
case 1:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_key, 16, "%s", LABEL_SIG);
|
|
||||||
G_gpg_vstate.ux_key = 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_key, 16, "%s", LABEL_AUT);
|
|
||||||
G_gpg_vstate.ux_key = 2;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_key, 16," %s", LABEL_DEC);
|
|
||||||
G_gpg_vstate.ux_key = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
UX_MENU_DISPLAY(0, ui_idle_sub_template, NULL);
|
|
||||||
}
|
|
||||||
const ux_menu_entry_t ui_idle_sub_tmpl_key[] = {
|
|
||||||
{NULL, ui_idle_sub_tmpl_key_action, 1, NULL, LABEL_SIG, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_key_action, 2, NULL, LABEL_DEC, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_key_action, 3, NULL, LABEL_AUT, NULL, 0, 0},
|
|
||||||
{ui_idle_sub_template, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
|
|
||||||
UX_MENU_END
|
|
||||||
};
|
|
||||||
|
|
||||||
void ui_idle_sub_tmpl_type_action(unsigned int value) {
|
|
||||||
switch(value) {
|
|
||||||
case 2048:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_RSA2048);
|
|
||||||
break;
|
|
||||||
case 3072:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_RSA3072);
|
|
||||||
break;
|
|
||||||
case 4096:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_RSA4096);
|
|
||||||
break;
|
|
||||||
case CX_CURVE_SECP256R1:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_NISTP256);
|
|
||||||
break;
|
|
||||||
case CX_CURVE_BrainPoolP256R1:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_BPOOLR1);
|
|
||||||
break;
|
|
||||||
case CX_CURVE_Ed25519:
|
|
||||||
snprintf(G_gpg_vstate.menu_template_type, 16," %s", LABEL_Ed25519);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
G_gpg_vstate.ux_type = value;
|
|
||||||
UX_MENU_DISPLAY(1, ui_idle_sub_template, NULL);
|
|
||||||
}
|
|
||||||
const ux_menu_entry_t ui_idle_sub_tmpl_type[] = {
|
|
||||||
{NULL, ui_idle_sub_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOLR1, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
|
|
||||||
{ui_idle_sub_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
|
||||||
UX_MENU_END
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
||||||
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
||||||
@ -293,15 +278,7 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
|||||||
char* err;
|
char* err;
|
||||||
|
|
||||||
err = NULL;
|
err = NULL;
|
||||||
if (!G_gpg_vstate.ux_key) {
|
|
||||||
err = "key";
|
|
||||||
goto ERROR;
|
|
||||||
}
|
|
||||||
if (!G_gpg_vstate.ux_type){
|
|
||||||
err = "type ";
|
|
||||||
goto ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
os_memset(&attributes, 0, sizeof(attributes));
|
os_memset(&attributes, 0, sizeof(attributes));
|
||||||
switch (G_gpg_vstate.ux_type) {
|
switch (G_gpg_vstate.ux_type) {
|
||||||
case 2048:
|
case 2048:
|
||||||
@ -349,7 +326,7 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = "not supported";
|
err = "type";
|
||||||
goto ERROR;
|
goto ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,97 +342,236 @@ void ui_idle_sub_tmpl_set_action(unsigned int value) {
|
|||||||
dest = &G_gpg_vstate.kslot->aut;
|
dest = &G_gpg_vstate.kslot->aut;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = "key not found";
|
err = "key";
|
||||||
goto ERROR;
|
goto ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpg_nvm_write(dest, NULL, sizeof(gpg_key_t));
|
gpg_nvm_write(dest, NULL, sizeof(gpg_key_t));
|
||||||
gpg_nvm_write(&dest->attributes, &attributes, sizeof(attributes));
|
gpg_nvm_write(&dest->attributes, &attributes, sizeof(attributes));
|
||||||
ui_info(ui_idle_sub_template, "Template set!", NULL);
|
ui_info("Template set!", NULL, ui_idle_sub_template_display, 0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ERROR:
|
ERROR:
|
||||||
ui_info(ui_idle_sub_template, "Invalid selection:", err);
|
ui_info("Invalid selection:", err, ui_idle_sub_template_display, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
void ui_idle_sub_tmpl_key_display(unsigned int value) {
|
|
||||||
UX_MENU_DISPLAY(0,ui_idle_sub_tmpl_key,ui_idle_sub_tmpl_key_prepocessor);
|
const ux_menu_entry_t ui_idle_sub_tmpl_key[] = {
|
||||||
}
|
{NULL, ui_idle_sub_tmpl_key_action, 1, NULL, LABEL_SIG, NULL, 0, 0},
|
||||||
*/
|
{NULL, ui_idle_sub_tmpl_key_action, 2, NULL, LABEL_DEC, NULL, 0, 0},
|
||||||
const ux_menu_entry_t ui_idle_sub_template[] = {
|
{NULL, ui_idle_sub_tmpl_key_action, 3, NULL, LABEL_AUT, NULL, 0, 0},
|
||||||
{ui_idle_sub_tmpl_key, NULL, 0, NULL, G_gpg_vstate.menu_template_key, NULL, 0, 0},
|
{ui_idle_sub_template, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
{ui_idle_sub_tmpl_type, NULL, 0, NULL, G_gpg_vstate.menu_template_type, NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_tmpl_set_action, 0, NULL, "Set template", NULL, 0, 0},
|
|
||||||
{ui_idle_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40},
|
|
||||||
UX_MENU_END
|
UX_MENU_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ui_idle_sub_tmpl_key_action(unsigned int value) {
|
||||||
/* ----- SEED UX ----- */
|
G_gpg_vstate.ux_key = value;
|
||||||
const ux_menu_entry_t ui_idle_sub_seed[];
|
ui_idle_sub_template_display(0);
|
||||||
void ui_idle_sub_seed_action(unsigned int value) {
|
|
||||||
G_gpg_vstate.seed_mode = value;
|
|
||||||
gpg_init_ux();
|
|
||||||
UX_MENU_DISPLAY(0, ui_idle_sub_seed, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_sub_tmpl_type[] = {
|
||||||
|
{NULL, ui_idle_sub_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOLR1, NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
|
||||||
|
{ui_idle_sub_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
|
UX_MENU_END
|
||||||
|
};
|
||||||
|
|
||||||
|
void ui_idle_sub_tmpl_type_action(unsigned int value) {
|
||||||
|
G_gpg_vstate.ux_type = value;
|
||||||
|
ui_idle_sub_template_display(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------- SEED UX --------------------------------- */
|
||||||
|
|
||||||
const ux_menu_entry_t ui_idle_sub_seed[] = {
|
const ux_menu_entry_t ui_idle_sub_seed[] = {
|
||||||
#if GPG_KEYS_SLOTS != 3
|
#if GPG_KEYS_SLOTS != 3
|
||||||
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_seed_mode, NULL, 0, 0},
|
{NULL, NULL, 0, NULL, "", NULL, 0, 0},
|
||||||
{NULL, ui_idle_sub_seed_action, 1, NULL, "Set on", NULL, 0, 0},
|
{NULL, ui_idle_sub_seed_action, 1, NULL, "Set on", NULL, 0, 0},
|
||||||
{NULL, ui_idle_sub_seed_action, 0, NULL, "Set off", NULL, 0, 0},
|
{NULL, ui_idle_sub_seed_action, 0, NULL, "Set off", NULL, 0, 0},
|
||||||
{ui_idle_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40},
|
{ui_idle_settings, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
|
UX_MENU_END
|
||||||
|
};
|
||||||
|
|
||||||
|
void ui_idle_sub_seed_display(unsigned int value) {
|
||||||
|
UX_MENU_DISPLAY(value, ui_idle_sub_seed, ui_idle_sub_seed_preprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bagl_element_t* ui_idle_sub_seed_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
||||||
|
if(element->component.userid==0x20) {
|
||||||
|
if (entry == &ui_idle_sub_seed[0]) {
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "< %s >", G_gpg_vstate.seed_mode?"ON":"OFF");
|
||||||
|
element->text = G_gpg_vstate.menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_idle_sub_seed_action(unsigned int value) {
|
||||||
|
G_gpg_vstate.seed_mode = value;
|
||||||
|
ui_idle_sub_seed_display(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------- RESET UX --------------------------------- */
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_sub_reset[] = {
|
||||||
|
#if GPG_KEYS_SLOTS != 3
|
||||||
|
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
||||||
|
#endif
|
||||||
|
{NULL, NULL, 0, NULL, "Really Reset ?", NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_main_display, 0, &C_badge_back, "Oh No!", NULL, 61, 40},
|
||||||
|
{NULL, ui_idle_sub_reset_action, 0, NULL, "Yes!", NULL, 0, 0},
|
||||||
UX_MENU_END
|
UX_MENU_END
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----- RESET UX ----- */
|
|
||||||
void ui_idle_sub_reset_action(unsigned int value) {
|
void ui_idle_sub_reset_action(unsigned int value) {
|
||||||
unsigned char magic[4];
|
unsigned char magic[4];
|
||||||
magic[0] = 0; magic[1] = 0; magic[2] = 0; magic[3] = 0;
|
magic[0] = 0; magic[1] = 0; magic[2] = 0; magic[3] = 0;
|
||||||
gpg_nvm_write(N_gpg_pstate->magic, magic, 4);
|
gpg_nvm_write(N_gpg_pstate->magic, magic, 4);
|
||||||
gpg_init();
|
gpg_init();
|
||||||
UX_MENU_DISPLAY(0, ui_idle_mainmenu, NULL);
|
ui_idle_main_display(0);
|
||||||
}
|
}
|
||||||
const ux_menu_entry_t ui_idle_sub_reset[] = {
|
|
||||||
#if GPG_KEYS_SLOTS != 3
|
|
||||||
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
|
||||||
#endif
|
|
||||||
{NULL, NULL, 0, NULL, "Really Reset ?", NULL, 0, 0},
|
|
||||||
{NULL, ui_idle_sub_reset_action, 0, NULL, "Yes!", NULL, 0, 0},
|
|
||||||
{ui_idle_mainmenu, NULL, 0, &C_badge_back, "Oh No!", NULL, 61, 40},
|
|
||||||
UX_MENU_END
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ----- SETTINGS UX ----- */
|
/* ------------------------------- SETTINGS UX ------------------------------- */
|
||||||
|
|
||||||
const ux_menu_entry_t ui_idle_settings[] = {
|
const ux_menu_entry_t ui_idle_settings[] = {
|
||||||
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_cur_slot, NULL, 0, 0},
|
{NULL, ui_idle_sub_template_display, 0, NULL, "Key template", NULL, 0, 0},
|
||||||
{ui_idle_sub_template, NULL, 0, NULL, "Key template", NULL, 0, 0},
|
{NULL, ui_idle_sub_seed_display, 0, NULL, "Seed mode", NULL, 0, 0},
|
||||||
{ui_idle_sub_seed, NULL, 0, NULL, "Seed mode", NULL, 0, 0},
|
{ui_idle_sub_reset, NULL, 0, NULL, "Reset", NULL, 0, 0},
|
||||||
{ui_idle_sub_reset, NULL, 0, NULL, "Reset", NULL, 0, 0},
|
{NULL, ui_idle_main_display, 2, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
{ui_idle_mainmenu, NULL, 2, &C_badge_back, "Back", NULL, 61, 40},
|
UX_MENU_END
|
||||||
|
};
|
||||||
|
/* --------------------------------- SLOT UX --------------------------------- */
|
||||||
|
|
||||||
|
#if GPG_KEYS_SLOTS != 3
|
||||||
|
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_sub_slot[] = {
|
||||||
|
{NULL, NULL, -1, NULL, "Choose:", NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_slot_action, 1, NULL, "", NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_slot_action, 2, NULL, "", NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_slot_action, 3, NULL, "", NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_sub_slot_action, 128, NULL, "Set Default", NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_main_display, 1, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
|
UX_MENU_END
|
||||||
|
};
|
||||||
|
void ui_idle_sub_slot_display(unsigned int value) {
|
||||||
|
UX_MENU_DISPLAY(value, ui_idle_sub_slot, ui_idle_sub_slot_preprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const bagl_element_t* ui_idle_sub_slot_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
||||||
|
unsigned int slot;
|
||||||
|
if(element->component.userid==0x20) {
|
||||||
|
for (slot = 1; slot <= 3; slot ++) {
|
||||||
|
if (entry == &ui_idle_sub_slot[slot]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slot != 4) {
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Slot %d %s %s",
|
||||||
|
slot,
|
||||||
|
slot == N_gpg_pstate->config_slot[1]+1?"#":" ", /* default */
|
||||||
|
slot == G_gpg_vstate.slot+1?"+":" " /* selected*/);
|
||||||
|
element->text = G_gpg_vstate.menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
void ui_idle_sub_slot_action(unsigned int value) {
|
||||||
|
unsigned char s;
|
||||||
|
|
||||||
|
if (value == 128) {
|
||||||
|
s = G_gpg_vstate.slot;
|
||||||
|
gpg_nvm_write(&N_gpg_pstate->config_slot[1], &s,1);
|
||||||
|
value = s+1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s = (unsigned char)(value-1);
|
||||||
|
G_gpg_vstate.slot = s;
|
||||||
|
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
||||||
|
|
||||||
|
}
|
||||||
|
// redisplay first entry of the idle menu
|
||||||
|
ui_idle_sub_slot_display(value);
|
||||||
|
}
|
||||||
|
/* --------------------------------- INFO UX --------------------------------- */
|
||||||
|
|
||||||
|
#if GPG_KEYS_SLOTS != 3
|
||||||
|
#error menu definition not correct for current value of GPG_KEYS_SLOTS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STR(x) #x
|
||||||
|
#define XSTR(x) STR(x)
|
||||||
|
|
||||||
|
const ux_menu_entry_t ui_idle_info[] = {
|
||||||
|
{NULL, NULL, -1, NULL, "OpenPGP Card", NULL, 0, 0},
|
||||||
|
{NULL, NULL, -1, NULL, "(c) Ledger SAS", NULL, 0, 0},
|
||||||
|
{NULL, NULL, -1, NULL, "Spec 3.0", NULL, 0, 0},
|
||||||
|
{NULL, NULL, -1, NULL, "App " XSTR(GPG_VERSION), NULL, 0, 0},
|
||||||
|
{NULL, ui_idle_main_display, 3, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
UX_MENU_END
|
UX_MENU_END
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----- MAIN UX ----- */
|
#undef STR
|
||||||
|
#undef XSTR
|
||||||
|
|
||||||
|
/* --------------------------------- MAIN UX --------------------------------- */
|
||||||
|
|
||||||
const ux_menu_entry_t ui_idle_mainmenu[] = {
|
const ux_menu_entry_t ui_idle_mainmenu[] = {
|
||||||
{NULL, NULL, 0, NULL, G_gpg_vstate.menu_cur_slot, NULL, 0, 0},
|
{NULL, NULL, 0, NULL, "", NULL, 0, 0},
|
||||||
{ui_idle_sub_slot, NULL, 0, NULL, "Select slot", NULL, 0, 0},
|
{NULL, ui_idle_sub_slot_display, 0, NULL, "Select slot", NULL, 0, 0},
|
||||||
{ui_idle_settings, NULL, 0, NULL, "Settings", NULL, 0, 0},
|
{ui_idle_settings, NULL, 0, NULL, "Settings", NULL, 0, 0},
|
||||||
{NULL, os_sched_exit, 0, &C_icon_dashboard, "Quit app" , NULL, 50, 29},
|
{ui_idle_info, NULL, 0, NULL, "About", NULL, 0, 0},
|
||||||
|
{NULL, os_sched_exit, 0, &C_icon_dashboard, "Quit app" , NULL, 50, 29},
|
||||||
UX_MENU_END
|
UX_MENU_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const bagl_element_t* ui_idle_main_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
||||||
|
if (entry == &ui_idle_mainmenu[0]) {
|
||||||
|
if(element->component.userid==0x20) {
|
||||||
|
unsigned int serial;
|
||||||
|
char name[20];
|
||||||
|
|
||||||
|
serial = MIN(N_gpg_pstate->name.length,19);
|
||||||
|
os_memset(name, 0, 20);
|
||||||
|
os_memmove(name, N_gpg_pstate->name.value, serial);
|
||||||
|
serial = (N_gpg_pstate->AID[10] << 24) |
|
||||||
|
(N_gpg_pstate->AID[11] << 16) |
|
||||||
|
(N_gpg_pstate->AID[12] << 8) |
|
||||||
|
(N_gpg_pstate->AID[13]);
|
||||||
|
os_memset(G_gpg_vstate.menu, 0, sizeof(G_gpg_vstate.menu));
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "< User: %s / SLOT: %d / Serial: %x >",
|
||||||
|
name, G_gpg_vstate.slot+1, serial);
|
||||||
|
element->component.stroke = 10; // 1 second stop in each way
|
||||||
|
element->component.icon_id = 26; // roundtrip speed in pixel/s
|
||||||
|
element->text = G_gpg_vstate.menu;
|
||||||
|
UX_CALLBACK_SET_INTERVAL(bagl_label_roundtrip_duration_ms(element, 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
void ui_idle_main_display(unsigned int value) {
|
||||||
|
UX_MENU_DISPLAY(value, ui_idle_mainmenu, ui_idle_main_preprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_idle_init(void) {
|
||||||
|
ui_idle_main_display(0);
|
||||||
|
// setup the first screen changing
|
||||||
|
UX_CALLBACK_SET_INTERVAL(1000);
|
||||||
|
}
|
||||||
|
|
||||||
void io_seproxyhal_display(const bagl_element_t *element) {
|
void io_seproxyhal_display(const bagl_element_t *element) {
|
||||||
io_seproxyhal_display_default((bagl_element_t *)element);
|
io_seproxyhal_display_default((bagl_element_t *)element);
|
||||||
}
|
}
|
||||||
void ui_idle_init(void) {
|
|
||||||
UX_MENU_DISPLAY(0, ui_idle_mainmenu, NULL);
|
|
||||||
// setup the first screen changing
|
|
||||||
UX_CALLBACK_SET_INTERVAL(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* --- Application Entry --- */
|
/* --- Application Entry --- */
|
||||||
|
@ -23,13 +23,13 @@
|
|||||||
|
|
||||||
|
|
||||||
/* big private DO */
|
/* big private DO */
|
||||||
#define GPG_EXT_PRIVATE_DO_LENGTH 1024
|
#define GPG_EXT_PRIVATE_DO_LENGTH 512
|
||||||
/* will be fixed..1024 is not enougth */
|
/* will be fixed..1024 is not enougth */
|
||||||
#define GPG_EXT_CARD_HOLDER_CERT_LENTH 4096
|
#define GPG_EXT_CARD_HOLDER_CERT_LENTH 2560
|
||||||
/* random choice */
|
/* random choice */
|
||||||
#define GPG_EXT_CHALLENGE_LENTH 254
|
#define GPG_EXT_CHALLENGE_LENTH 254
|
||||||
/* accpet long PW, but less than one sha256 block */
|
/* accpet long PW, but less than one sha256 block */
|
||||||
#define GPG_MAX_PW_LENGTH 48
|
#define GPG_MAX_PW_LENGTH 12
|
||||||
|
|
||||||
#define GPG_KEYS_SLOTS 3
|
#define GPG_KEYS_SLOTS 3
|
||||||
|
|
||||||
@ -201,6 +201,13 @@ struct gpg_v_state_s {
|
|||||||
cx_ecfp_public_key_t public;
|
cx_ecfp_public_key_t public;
|
||||||
cx_ecfp_private_key_t private;
|
cx_ecfp_private_key_t private;
|
||||||
}ecfp256;
|
}ecfp256;
|
||||||
|
struct {
|
||||||
|
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH-MAX(sizeof(cx_sha3_t),sizeof(cx_sha256_t))];
|
||||||
|
union {
|
||||||
|
cx_sha3_t sha3;
|
||||||
|
cx_sha256_t sha256;
|
||||||
|
};
|
||||||
|
} md ;
|
||||||
} work;
|
} work;
|
||||||
|
|
||||||
/* data state */
|
/* data state */
|
||||||
@ -213,10 +220,7 @@ struct gpg_v_state_s {
|
|||||||
|
|
||||||
|
|
||||||
/* ux menus */
|
/* ux menus */
|
||||||
char menu_cur_slot[16];
|
char menu[64];
|
||||||
char menu_seed_mode[16];
|
|
||||||
char menu_template_key[16];
|
|
||||||
char menu_template_type[16];
|
|
||||||
unsigned int ux_key;
|
unsigned int ux_key;
|
||||||
unsigned int ux_type;
|
unsigned int ux_type;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user