Add full backup/restore with python tool

app:

- support DO 'B6'/'B8'/'A4' in get/put data for full backup.
  private key are backuped encrypted with AES and a key based on the master seed
- fix missing DO 'CB' access
- fix TERMINATE_DF command: the command did not return
- fix stack corruption in ECC key generation, when key size is greater than 256bits

tools:

- add full backup/restore cli tool

misc:

- add 'make run' rules
This commit is contained in:
Cédric 2018-10-09 23:34:00 +02:00
parent 80ee7ef8d1
commit 14cfe899ff
9 changed files with 472 additions and 85 deletions

View File

@ -15,6 +15,7 @@
# limitations under the License.
#*******************************************************************************
-include Makefile.env
ifeq ($(BOLOS_SDK),)
$(error Environment variable BOLOS_SDK is not set)
endif
@ -27,8 +28,8 @@ APPNAME = OpenPGP
SPECVERSION="3.3.1"
APPVERSION_M=1
APPVERSION_N=2
APPVERSION_P=1
APPVERSION_N=3
APPVERSION_P=0
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
ifeq ($(TARGET_NAME),TARGET_BLUE)
@ -96,6 +97,9 @@ SDK_SOURCE_PATH += lib_stusb
load: all
python -m ledgerblue.loadApp $(APP_LOAD_PARAMS)
run:
python -m ledgerblue.runApp --appName $(APPNAME)
delete:
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)

View File

@ -56,6 +56,9 @@ def decode_tlv(tlv) :
tlv = tlv[o+l:]
return tags
class GPGCardExcpetion(Exception):
pass
class GPGCard() :
def __init__(self):
self.reset()
@ -103,9 +106,14 @@ class GPGCard() :
self.private_02 = b''
self.private_03 = b''
#keys
self.sig_key = b''
self.dec_key = b''
self.aut_key = b''
def connect(self, device):
self.token = None
if device.startswith("ledger:"):
self.token = getDongle(True)
self.exchange = self._exchange_ledger
@ -132,7 +140,7 @@ class GPGCard() :
### APDU interface ###
def _exchange_ledger(self,cmd,sw=0x9000):
def _exchange_ledger(self,cmd,data=None, sw=0x9000):
resp = b''
cond = True
while cond:
@ -150,10 +158,25 @@ class GPGCard() :
cond = False
return resp,sw
def _exchange_pcsc(self,apdu,sw=0x9000):
#print("xch S cmd : %s"%(binascii.hexlify(apdu)))
def _exchange_pcsc(self,apdu, data=None, sw_expected=0x9000, sw_mask=0xFFFF):
if data:
data = [x for x in data]
apdu = [x for x in apdu]
#send
if data:
while len(data) > 0xFE:
apdux = apdu[0:5]+[0xfe]+data[0:0xFE]
apdux[0] |= 0x10
resp, sw1, sw2 = self.connection.transmit(apdux)
sw = (sw1<<8)|sw2
if sw != 0x9000:
return resp,sw
data = data[0xFE:]
apdu = apdu+[len(data)]+data
resp, sw1, sw2 = self.connection.transmit(apdu)
#receive
while sw1==0x61:
apdu = binascii.unhexlify(b"00c00000%.02x"%sw2)
apdu = [x for x in apdu]
@ -161,8 +184,9 @@ class GPGCard() :
resp = resp + resp2
resp = bytes(resp)
sw = (sw1<<8)|sw2
#print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw))
return resp,sw
if sw&sw_mask == sw_expected:
return resp,sw
raise GPGCardExcpetion(binascii.hexlify(resp), "%.04x"%sw)
def _disconnect_ledger(self):
return self.token.close()
@ -189,11 +213,13 @@ class GPGCard() :
return self.exchange(apdu)
def put_data(self,tag,value):
apdu = binascii.unhexlify(b"00DA%.04x%.02x"%(tag,len(value)))+value
return self.exchange(apdu)
return self.exchange(binascii.unhexlify(b"00DA%.04x"%tag), value)
def verify(self,id,value):
apdu = binascii.unhexlify(b"002000%.02x%.02x"%(id,len(value)))+value
def verify(self,id,value, pinpad=False):
if pinpad:
apdu = binascii.unhexlify(b"EF2000%.02x00"%id)
else:
apdu = binascii.unhexlify(b"002000%.02x%.02x"%(id,len(value)))+value
return self.exchange(apdu)
def change_reference_data(self,id,value,new_value):
@ -215,7 +241,7 @@ class GPGCard() :
return self.exchange(apdu)
### API interfaces ###
def get_all(self):
def get_all(self, with_key=False):
self.reset()
self.AID,sw = self.get_data(0x4f)
@ -283,7 +309,15 @@ class GPGCard() :
self.private_03,sw = self.get_data(0x0103)
self.private_04,sw = self.get_data(0x0104)
def set_all(self):
if with_key:
self.sig_key,sw = self.get_data(0x00B6)
self.dec_key,sw = self.get_data(0x00B8)
self.aut_key,sw = self.get_data(0x00A4)
return True
def set_all(self, with_key= False):
self.put_data(0x4f, self.AID[10:14])
self.put_data(0x0101, self.private_01)
self.put_data(0x0102, self.private_02)
@ -317,9 +351,15 @@ class GPGCard() :
self.put_data(0xd7, self.UIF_DEC)
self.put_data(0xd8, self.UIF_AUT)
def backup(self, file_name):
if with_key:
self.put_data(0x00B6, self.sig_key)
self.put_data(0x00B8, self.dec_key)
self.put_data(0x00A4, self.aut_key)
return True
def backup(self, file_name, with_key=False):
f = open(file_name,mode='w+b')
self.get_all();
self.get_all(with_key)
pickle.dump(
(self.AID,
self.private_01, self.private_02, self.private_03, self.private_04,
@ -330,8 +370,10 @@ class GPGCard() :
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
self.sig_date, self.dec_date, self.aut_date,
self.cardholder_cert,
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT),
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT,
self.sig_key, self.dec_key, self.aut_key),
f, 2)
return True
def restore(self, file_name, seed_key=False):
@ -340,13 +382,15 @@ class GPGCard() :
self.private_01, self.private_02, self.private_03, self.private_04,
self.name, self.login, self.sex, self.url,
self.sig_attribute, self.dec_attribute, self.aut_attribute,
self.status,
self.PW_status,
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
self.sig_date, self.dec_date, self.aut_date,
self.cardholder_cert,
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT) = pickle.load(f)
self.set_all()
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT,
self.sig_key, self.dec_key, self.aut_key) = pickle.load(f)
with_key = len(self.sig_key)>0 and len(self.dec_key)>0 and len(self.aut_key)>0
self.set_all(with_key)
if seed_key :
apdu = binascii.unhexlify(b"0047800102B600")
self.exchange(apdu)
@ -354,7 +398,7 @@ class GPGCard() :
self.exchange(apdu)
apdu = binascii.unhexlify(b"0047800102A400")
self.exchange(apdu)
return True
@ -399,9 +443,9 @@ class GPGCard() :
d['SM'] = ('Secure Messaging', "no")
if b1&0x40 :
d['CHAL'] = ('GET CHALLENGE', "yes")
d['CHAL'] = ('Get Challenge', "yes")
else:
d['CHAL'] = ('GET CHALLENGE', "no")
d['CHAL'] = ('Get Challenge', "no")
if b1&0x20 :
d['KEY'] = ('Key import', "yes")
@ -479,6 +523,12 @@ class GPGCard() :
return d
#USER Info
def set_serial(self, ser):
ser=binascii.unhexlify(ser)
self.AID = self.AID[0:10]+ser
self.put_data(0x4f, self.AID[10:14])
# internals are always store as byres, get/set automatically convert from/to
def set_name(self,name):
""" Args:
@ -532,13 +582,13 @@ class GPGCard() :
#PINs
def verify_pin(self,id,value):
def verify_pin(self,id,value, pinpad=False):
""" Args:
id (int) : 0x81, 0x82, ox83
value (str) : ascii string
"""
value = value.encode('ascii')
resp,sw = self.verify(id,value)
resp,sw = self.verify(id,value, pinpad)
return sw == 0x9000
def change_pin(self, id, value,new_value):
@ -606,6 +656,20 @@ class GPGCard() :
fprint = '-'
return fprints.decode('ascii')
def set_key_fingerprints(self, key, fprints):
fprints = binascii.unhexlify(fprints)
if key=='sig':
self.sig_fingerprints = fprints
self.put_data(0xc7, fprints)
if key=='aut':
self.aut_fingerprints = fprints
self.put_data(0xc9, fprints)
if key=='dec':
self.dec_fingerprints = fprints
self.put_data(0xc8, fprints)
def get_key_CA_fingerprints(self, key):
"""
Returns: (str) CA fingerprints hex string

123
pytools/gpgcard/gpgcli.py Normal file
View File

@ -0,0 +1,123 @@
# Copyright 2018 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import sys
import argparse
from .gpgcard import GPGCard
def get_argparser():
parser = argparse.ArgumentParser(epilog="""
Note 1: reset, backup, restore are always executed in THIS order
"""
)
parser.add_argument('--adm-pin', metavar='PIN', help='Administrative PIN, if pinpad not used')
parser.add_argument('--backup', help='Perfom a full backup except the key', action='store_true')
parser.add_argument('--backup-keys', help='Perfom keys encrypted backup', action='store_true')
parser.add_argument('--file', help='basckup/restore file', type=str, default='backup_card.pickle')
parser.add_argument('--pinpad', help='PIN validation will be deledated to pinpad', action='store_true')
parser.add_argument('--reader', help='PCSC reader', type=str, default='pcsc:Ledger')
parser.add_argument('--reset', help='Reset the application. All data are erased', action='store_true')
parser.add_argument('--restore', help='Perfom a full restore except the key', action='store_true')
parser.add_argument('--set-serial', metavar='SERIAL', help='set the four serial bytes')
parser.add_argument('--set-fp', metavar='SIG:DEC:AUT', help='sig:dec:aut fingerprints, 20 bytes each in hexa')
parser.add_argument('--seed-key', help='Regenerate all keys, based on seed mode', action='store_true')
parser.add_argument('--user-pin', metavar='PIN', help='User PIN, if pinpad not used')
return parser
def banner():
print(
"""
GPG Ledger Admin Tool v0.1.
Copyright 2018 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
"""
)
def error(msg) :
print("Error: ")
print(" "+msg)
sys.exit()
banner()
args = get_argparser().parse_args()
if args.backup and args.restore:
error('Only one backup or restore must be specified')
if not args.pinpad:
if not args.adm_pin is None or not args.user_pin:
error('If pinpad is not use, userpin and admpin must be provided')
try:
print("Connect to card...", end='', flush=True)
gpgcard = GPGCard()
gpgcard.connect(args.reader)
print("OK")
print("Verfify PINs...", end='', flush=True)
if args.pinpad:
if not gpgcard.verify_pin(0x82, "", True) or not gpgcard.verify_pin(0x83, "", True):
error("PIN not verified")
else:
if not gpgcard.verify_pin(0x82, args.user_pin) or not gpgcard.verify_pin(0x83, args.adm_pin):
error("PIN not verified")
print("OK")
if args.reset:
print("Reset application...", end='', flush=True)
if not gpgcard.terminate() or not gpgcard.activate():
error ("NOK")
print("OK")
print("Get card info...", end='', flush=True)
gpgcard.get_all()
print("OK", flush=True)
if args.backup:
print("Backup application...", end='', flush=True)
if not gpgcard.backup(args.file, args.backup_keys):
error("NOK")
print("OK")
if args.restore:
print("Restore application...", end='', flush=True)
if not gpgcard.restore(args.file, args.seed_key):
error("NOK")
print("OK", flush=True)
if args.set_fp:
print("Set fingerprints...", end='', flush=True)
sig,dec,aut = args.setfp.split(":")
if (not gpgcard.set_key_fingerprints("sig", sig) or
not gpgcard.set_key_fingerprints("dec", dec) or
not gpgcard.set_key_fingerprints("aut", aut)):
error("NOK")
print("OK", flush=True)
if args.set_serial:
print("Set serial...", end='', flush=True)
serial = binascii.unhexilify(args.set_serial)
if len(serial>8) :
error('Serial must be a 4 bytes hexa string value (8 characters)')
gpgcard.set_serial(args.set_serial)
print("OK", flush=True)
except Exception as e:
error(str(e))

View File

@ -31,7 +31,12 @@ int gpg_apdu_select_data(unsigned int ref, int reccord) ;
int gpg_apdu_get_data(unsigned int ref) ;
int gpg_apdu_get_next_data(unsigned int ref) ;
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);
void gpg_pso_derive_slot_seed(int slot, unsigned char *seed);
void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx,
unsigned char *Ski, unsigned int Ski_len);
int gpg_apdu_pso(void);
int gpg_apdu_internal_authenticate(void);
int gpg_apdu_gen(void );

View File

@ -700,3 +700,181 @@ int gpg_apdu_put_data(unsigned int ref) {
}
static void gpg_init_keyenc(cx_aes_key_t *keyenc) {
unsigned char seed[32];
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, (unsigned char*)PIC("key "), 1, seed, 16);
cx_aes_init_key(seed, 16, keyenc);
}
//cmd
//resp TID API COMPAT len_pub len_priv priv
int gpg_apdu_get_key_data(unsigned int ref) {
cx_aes_key_t keyenc;
gpg_key_t *keygpg;
unsigned int len = 0;
gpg_init_keyenc(&keyenc);
switch(ref) {
case 0x00B6:
keygpg = &G_gpg_vstate.kslot->sig;
break;
case 0x00B8:
keygpg = &G_gpg_vstate.kslot->dec;
break;
case 0x00A4:
keygpg = &G_gpg_vstate.kslot->aut;
break;
default:
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_io_discard(1);
//clear part
gpg_io_insert_u32(TARGET_ID);
gpg_io_insert_u32(CX_APILEVEL);
gpg_io_insert_u32(CX_COMPAT_APILEVEL);
//encrypted part
switch(keygpg->attributes.value[0]) {
case 0x01: //RSA
//insert pubkey;
gpg_io_insert_u32(4);
gpg_io_insert(keygpg->pub_key.rsa, 4);
//insert privkey
gpg_io_mark();
len = cx_aes(&keyenc,
CX_ENCRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST,
(unsigned char*)&keygpg->priv_key.rsa4096, sizeof(cx_rsa_4096_private_key_t),
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, GPG_IO_BUFFER_LENGTH-G_gpg_vstate.io_offset);
gpg_io_inserted(len);
gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_u32(len);
gpg_io_set_offset(IO_OFFSET_END);
break;
case 18: //ECC
case 19:
case 22:
//insert pubkey;
gpg_io_insert_u32(sizeof(cx_ecfp_640_public_key_t));
gpg_io_insert((unsigned char*)&keygpg->pub_key.ecfp640, sizeof(cx_ecfp_640_public_key_t));
//insert privkey
gpg_io_mark();
len = cx_aes(&keyenc,
CX_ENCRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST,
(unsigned char*)&keygpg->priv_key.ecfp640, sizeof(cx_ecfp_640_private_key_t),
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, GPG_IO_BUFFER_LENGTH-G_gpg_vstate.io_offset);
gpg_io_inserted(len);
gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_u32(len);
gpg_io_set_offset(IO_OFFSET_END);
break;
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
return SW_OK;
}
//cmd TID API COMPAT len_pub len_priv priv
//resp -
int gpg_apdu_put_key_data(unsigned int ref) {
cx_aes_key_t keyenc;
gpg_key_t *keygpg;
unsigned int len;
unsigned int offset;
gpg_init_keyenc(&keyenc);
switch(ref) {
case 0xB6:
keygpg = &G_gpg_vstate.kslot->sig;
break;
case 0xB8:
keygpg = &G_gpg_vstate.kslot->dec;
break;
case 0xA4:
keygpg = &G_gpg_vstate.kslot->aut;
break;
default:
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
/* unsigned int target_id = */
gpg_io_fetch_u32();
/* unsigned int cx_apilevel = */
gpg_io_fetch_u32();
/* unsigned int cx_compat_apilevel = */
gpg_io_fetch_u32();
switch(keygpg->attributes.value[0]) {
case 0x01: //RSA
//insert pubkey;
len = gpg_io_fetch_u32();
if (len != 4) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_io_fetch_nv(keygpg->pub_key.rsa, len);
//insert privkey
len = gpg_io_fetch_u32();
if (len > (G_gpg_vstate.io_length-G_gpg_vstate.io_offset)) {
THROW(SW_WRONG_DATA);
}
offset = G_gpg_vstate.io_offset;
gpg_io_discard(0);
len = cx_aes(&keyenc,
CX_DECRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST,
G_gpg_vstate.work.io_buffer+offset, len,
G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
if (len != sizeof(cx_rsa_4096_private_key_t)) {
THROW(SW_WRONG_DATA);
}
gpg_nvm_write((unsigned char*)&keygpg->priv_key.rsa4096, G_gpg_vstate.work.io_buffer, len);
break;
case 18: //ECC
case 19:
case 22:
//insert pubkey;
len = gpg_io_fetch_u32();
if (len != sizeof(cx_ecfp_640_public_key_t)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_io_fetch_nv((unsigned char*)&keygpg->pub_key.ecfp640, len);
//insert privkey
len = gpg_io_fetch_u32();
if (len > (G_gpg_vstate.io_length-G_gpg_vstate.io_offset)) {
THROW(SW_WRONG_DATA);
}
offset = G_gpg_vstate.io_offset;
gpg_io_discard(0);
len = cx_aes(&keyenc,
CX_DECRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST,
G_gpg_vstate.work.io_buffer+offset, len,
G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
if (len != sizeof(cx_ecfp_640_private_key_t)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_nvm_write((unsigned char*)&keygpg->priv_key.ecfp640, G_gpg_vstate.work.io_buffer, len);
break;
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_discard(1);
return SW_OK;
}

View File

@ -91,6 +91,10 @@ void gpg_check_access_ins() {
case INS_ACTIVATE_FILE:
return;
default:
THROW(SW_INS_NOT_SUPPORTED);
break;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
}
@ -144,7 +148,7 @@ void gpg_check_access_read_DO() {
case 0x00D8:
return;
//PW1
//PW2
case 0x0103:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
@ -152,6 +156,9 @@ void gpg_check_access_read_DO() {
break;
//PW3
case 0x00B6:
case 0x00A4:
case 0x00B8:
case 0x0104:
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
@ -173,7 +180,7 @@ void gpg_check_access_write_DO() {
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
switch(ref) {
//PW1
//PW2
case 0x0101:
case 0x0103:
case 0x01F2:
@ -196,6 +203,9 @@ void gpg_check_access_write_DO() {
case 0x5F50:
case 0x5F48:
case 0x7F21:
case 0x00B6:
case 0x00A4:
case 0x00B8:
case 0x00C1:
case 0x00C2:
case 0x00C3:
@ -206,8 +216,9 @@ void gpg_check_access_write_DO() {
case 0x00C9:
case 0x00C6:
case 0x00CA:
case 0x00CD:
case 0x00CB:
case 0x00CC:
case 0x00CD:
case 0x00CE:
case 0x00CF:
case 0x00D0:
@ -223,9 +234,7 @@ void gpg_check_access_write_DO() {
return;
}
break;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
}
@ -252,7 +261,6 @@ int gpg_dispatch() {
return sw;
break;
/* --- ACTIVATE/TERMINATE FILE --- */
case INS_ACTIVATE_FILE:
gpg_io_discard(0);
@ -270,6 +278,7 @@ int gpg_dispatch() {
break;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
break;
}
@ -322,8 +331,16 @@ int gpg_dispatch() {
case INS_GET_DATA:
gpg_check_access_read_DO();
sw = gpg_apdu_get_data(tag);
switch(tag) {
case 0x00B6:
case 0x00A4:
case 0x00B8:
sw = gpg_apdu_get_key_data(tag);
break;
default:
sw = gpg_apdu_get_data(tag);
break;
}
break;
case INS_GET_NEXT_DATA:
@ -335,7 +352,16 @@ int gpg_dispatch() {
case INS_PUT_DATA_ODD:
case INS_PUT_DATA:
gpg_check_access_write_DO();
sw = gpg_apdu_put_data(tag);
switch(tag) {
case 0x00B6:
case 0x00A4:
case 0x00B8:
sw = gpg_apdu_put_key_data(tag);
break;
default:
sw = gpg_apdu_put_data(tag);
break;
}
break;
/* --- PIN -- */

View File

@ -22,7 +22,7 @@
/* @in slot slot num [0 ; GPG_KEYS_SLOTS[
* @out seed 32 bytes master seed for given slot
*/
static void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
unsigned int path[2];
unsigned char chain[32];
@ -38,8 +38,8 @@ static void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
* @out Ski generated sub_seed
* @in Ski_len sub-seed length
*/
static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx,
unsigned char *Ski, unsigned int Ski_len) {
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 h[32];
h[0] = idx >>8;
@ -59,7 +59,7 @@ static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name,
int gpg_apdu_gen() {
unsigned int t,l,ksz,reset_cnt;
gpg_key_t *keygpg;
unsigned char seed[32];
unsigned char seed[66];
unsigned char* name;
switch ((G_gpg_vstate.io_p1<<8)|G_gpg_vstate.io_p2) {
@ -168,7 +168,7 @@ int gpg_apdu_gen() {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
if ((G_gpg_vstate.io_p2 == 0x01) | (G_gpg_vstate.seed_mode)) {
if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) {
ksz = gpg_curve2domainlen(curve);
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, seed, ksz);

View File

@ -252,7 +252,10 @@ const unsigned char C_default_Histo[] = {
0x90, 0x00
};
const unsigned char C_default_AlgoAttrRSA[] = {
// Default template: RSA2048
#if 1
const unsigned char C_default_AlgoAttr_sig[] = {
// RSA
0x01,
// Modulus default length 2048
@ -262,41 +265,44 @@ const unsigned char C_default_AlgoAttrRSA[] = {
// std: e,p,q with modulus (n)
0x01
};
const unsigned char C_default_AlgoAttr_dec[] = {
// RSA
0x01,
// Modulus default length 2048
0x08, 0x00,
// PubExp length 32
0x00, 0x20,
// std: e,p,q with modulus (n)
0x01
};
#endif
// Default template: NIST P256
#if 0
const unsigned char C_default_AlgoAttrECC_sig[] = {
const unsigned char C_default_AlgoAttr_sig[] = {
// ecdsa
0x13,
// NIST-P256
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
};
const unsigned char C_default_AlgoAttrECC_dec[] = {
const unsigned char C_default_AlgoAttr_dec[] = {
// ecdh
0x12,
// NIST-P256
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
};
#elif 0
const unsigned char C_default_AlgoAttrECC_sig[] = {
// ecdsa
0x13,
// NIST-P384
0x2B, 0x81, 0x04, 0x00 , 0x22
};
const unsigned char C_default_AlgoAttrECC_dec[] = {
// ecdh
0x12,
// NIST-P384
0x2B, 0x81, 0x04, 0x00 , 0x22
};
#elif 1
const unsigned char C_default_AlgoAttrECC_sig[] = {
#endif
// Default template: Ed/Cv-25519
#if 0
const unsigned char C_default_AlgoAttr_sig[] = {
// eddsa
0x16,
// ed25519
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
};
const unsigned char C_default_AlgoAttrECC_dec[] = {
const unsigned char C_default_AlgoAttr_dec[] = {
// ecdh
0x12,
//cv25519
@ -410,15 +416,9 @@ int gpg_install(unsigned char app_state) {
nvm_write(&N_gpg_pstate->default_RSA_exponent, G_gpg_vstate.work.io_buffer, 4);
//config pin
#if 1
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM;
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1);
USBD_CCID_activate_pinpad(3);
#else
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_HOST;
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1);
USBD_CCID_activate_pinpad(0);
#endif
//default key template: RSA 2048)
@ -426,32 +426,19 @@ int gpg_install(unsigned char app_state) {
unsigned char uif[2];
uif[0] = 0x00;
uif[1] = 0x20;
#if 1
l = sizeof(C_default_AlgoAttrRSA);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.value, (void*)C_default_AlgoAttrRSA, l);
l = sizeof(C_default_AlgoAttr_sig);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.value, (void*)C_default_AlgoAttr_sig, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.length, &l, sizeof(unsigned int));
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.attributes.value, (void*)C_default_AlgoAttrRSA, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.attributes.value, (void*)C_default_AlgoAttr_sig, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.attributes.length, &l, sizeof(unsigned int));
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.value, (void*)C_default_AlgoAttrRSA, l);
l = sizeof(C_default_AlgoAttr_dec);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.value, (void*)C_default_AlgoAttr_dec, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.length, &l, sizeof(unsigned int));
#else
l = sizeof(C_default_AlgoAttrECC_sig);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.value, (void*)C_default_AlgoAttrECC_sig, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.length, &l, sizeof(unsigned int));
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.attributes.value, (void*)C_default_AlgoAttrECC_sig, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.attributes.length, &l, sizeof(unsigned int));
l = sizeof(C_default_AlgoAttrECC_dec);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.value, (void*)C_default_AlgoAttrECC_dec, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.length, &l, sizeof(unsigned int));
#endif
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.UIF, &uif, 2);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.UIF, &uif, 2);
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.UIF, &uif, 2);
}
}
return 0;
}

View File

@ -65,6 +65,9 @@ typedef struct gpg_key_s {
/* C1 C2 C3 */
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
/* key value */
/* WARN: changing the cx_<key>_t structures breaks backup/restore. Adapt backup/restore code
* to ensure backward compatibility.
*/
union {
cx_rsa_private_key_t rsa;
cx_rsa_1024_private_key_t rsa1024;
@ -96,9 +99,6 @@ typedef struct gpg_key_s {
unsigned char date[4];
/* D6/D7/D8- */
unsigned char UIF[2];
} gpg_key_t;