1.2.0 code

SDK 1.4.2.x port
Add uif support
Refactor memory layout
Try to add more curve
  gpg 2.2.x handle curves other than ed25519 in a such strange way
  that it is very difficult to do such support.
  So secp256k1, secp256r1 and brainpoolp256 seems works, but according to gpg
  code it works by side effects :-/
Update user documentation for UIF

There is still an issue with ssh authentication with Ed25519. It works with NIST-P256, Brainpool256 curves
This commit is contained in:
Cédric 2018-05-28 16:51:23 +02:00
parent a0d537dcec
commit 281ea42cbb
20 changed files with 2197 additions and 175 deletions

View File

@ -15,13 +15,6 @@
# limitations under the License.
#*******************************************************************************
BOLOS_SDK=/home/cme/Projects/Git/ledger/nanos-secure-sdk-cslashm
CLANGPATH=/home/cme/Projects/Git/ledger/compilers/clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-16.10/bin/
GCCPATH=/home/cme/Projects/Git/ledger/compilers/gcc-arm-none-eabi-5_3-2016q1/bin/
ifeq ($(BOLOS_SDK),)
$(error Environment variable BOLOS_SDK is not set)
endif
@ -34,8 +27,8 @@ APPNAME = OpenPGP
SPECVERSION="3.3.1"
APPVERSION_M=1
APPVERSION_N=1
APPVERSION_P=1
APPVERSION_N=2
APPVERSION_P=0
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
ifeq ($(TARGET_NAME),TARGET_BLUE)
@ -96,7 +89,7 @@ LDLIBS += -lm -lgcc -lc
include $(BOLOS_SDK)/Makefile.glyphs
### variables processed by the common makefile.rules of the SDK to grab source files and include dirs
APP_SOURCE_PATH += src src/lib_stusb_impl
APP_SOURCE_PATH += src
SDK_SOURCE_PATH += lib_stusb
@ -107,7 +100,7 @@ delete:
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
# import generic rules from the sdk
include $(BOLOS_SDK)/Makefile.rules
include Makefile.rules
#add dependency on custom makefile filename
dep/%.d: %.c Makefile

29
Makefile.rules Normal file
View File

@ -0,0 +1,29 @@
#*******************************************************************************
# Ledger SDK
# (c) 2017 Ledger
#
# 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.
#*******************************************************************************
#Make the SDK modified SDK sources prioritar to the original ones
SOURCE_PATH += $(dir $(foreach libdir, $(APP_SOURCE_PATH), $(dir $(shell find $(libdir) | grep "\.c$$")))) $(BOLOS_SDK)/src $(foreach libdir, $(SDK_SOURCE_PATH), $(dir $(shell find $(BOLOS_SDK)/$(libdir) | grep "\.c$$")))
SOURCE_FILES := $(foreach path, $(SOURCE_PATH),$(shell find $(path) | grep "\.c$$") ) $(GLYPH_DESTC)
INCLUDES_PATH := $(dir $(foreach libdir, $(APP_SOURCE_PATH), $(dir $(shell find $(libdir) | grep "\.h$$")))) $(dir $(foreach libdir, $(SDK_SOURCE_PATH), $(dir $(shell find $(BOLOS_SDK)/$(libdir) | grep "\.h$$")))) include $(BOLOS_SDK)/include $(BOLOS_SDK)/include/arm
VPATH := $(dir $(SOURCE_FILES))
OBJECT_FILES := $(sort $(addprefix obj/, $(addsuffix .o, $(basename $(notdir $(SOURCE_FILES))))))
DEPEND_FILES := $(sort $(addprefix dep/, $(addsuffix .d, $(basename $(notdir $(SOURCE_FILES))))))
include $(BOLOS_SDK)/Makefile.rules_generic

Binary file not shown.

View File

@ -185,6 +185,7 @@ The full menu layout is :
| Set on
| Set off
| PIN mode
| UIF mode
| \ *Choose:*
| Host
| On Screen
@ -246,8 +247,39 @@ A key template is defined by the OpenGPG card application specification. It
describes the key to be generated with the ``generate`` command in
``gpg --card-edit``
The problem is there is no way with the ``gpg`` command line to easily set
up the desired template. The menu fixes that.
The problem is there is no way with the ``gpg --card-edit`` command line
to easily set up the desired template, except for Ed25519.
To set up a new ECC template you have tow choice: the NanoS menu or the
gpg-connect-agent tools.
**gpg-connect-agent** (recommended)
This method suppose you have correctly configured your GnuPG tool.
See the dedicated section for that.
In a terminal launch :
gpg-connect-agent "SCD SETATTR KEY-ATTR --force 1 <tag> <curvename>" /bye
gpg-connect-agent "SCD SETATTR KEY-ATTR --force 2 18 <curvename>" /bye
gpg-connect-agent "SCD SETATTR KEY-ATTR --force 3 <tag> <curvename>" /bye
This 3 commands fix, in that order, the template for Signature, Decryption, Authentication keys.
Supported curve name are:
- secp256k1 with tag 19
- nistp256 with tag 19
- brainpoolP256r1 with tag 19
- cv25519 (only for key 2)
- ed25519 with tag 22 (only for key 1 and 3)
To show the current template use the ``gpg --card-status`` command.
**NanoS menu**
First under *Choose Key* menu, select the one of three keys for which you want to modify
the template. Then under "Choose Type", select the desired key template.
@ -255,10 +287,11 @@ Finally select "Set Template" entry to set it.
To show the current template use the ``gpg --card-status`` command.
Seed mode
~~~~~~~~~
**WARNING** : SEED MODE IS EXPERIMENTAL
When generating new keys on NanoS, those keys can be generated randomly
or in a deterministic way. The deterministic way is specified in [GPGADD].
The current mode is displayed in the first sub menu. To activate the seeded
@ -266,6 +299,7 @@ The current mode is displayed in the first sub menu. To activate the seeded
When the application starts, the seeded mode is always set to *OFF*
**WARNING** : SEED MODE IS EXPERIMENTAL
PIN mode
~~~~~~~~
@ -340,6 +374,17 @@ This is the default mode after application installation.
Act as if the PIN is always validated. This is a dangerous mode which should only be
used in a highly secure environment.
UIF mode
~~~~~~~~
By activating UIF mode for either signature, decryption or authentication, a user validation
will be ask by the device each time the related operation is performed.
To activate or deactivate the UIF, select the operation to protect and press both button.
When activated, a '+' symbol appears after the operation name.
Reset
~~~~~

View File

@ -18,7 +18,9 @@
void USBD_CCID_activate_pinpad(int enabled);
int gpg_oid2curve(unsigned char* oid, unsigned int len);
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);

View File

@ -367,34 +367,25 @@ int gpg_apdu_put_data(unsigned int ref) {
//check length
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
ksz = ksz >> 3;
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa.private;
pkey = &keygpg->priv_key.rsa;
switch(ksz) {
case 1024/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa1024.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa1024.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa1024;
pkey_size = sizeof(cx_rsa_1024_private_key_t);
pq = G_gpg_vstate.work.rsa1024.public.n;
pq = G_gpg_vstate.work.rsa.public1024.n;
break;
case 2048/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa2048.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa2048.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa2048;
pkey_size = sizeof(cx_rsa_2048_private_key_t);
pq = G_gpg_vstate.work.rsa2048.public.n;
pq = G_gpg_vstate.work.rsa.public2048.n;
break;
case 3072/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa3072.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa3072.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa3072;
pkey_size = sizeof(cx_rsa_3072_private_key_t);
pq = G_gpg_vstate.work.rsa3072.public.n;
pq = G_gpg_vstate.work.rsa.public3072.n;
break;
case 4096/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa4096.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa4096.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa4096;
pkey_size = sizeof(cx_rsa_4096_private_key_t);
pq = G_gpg_vstate.work.rsa4096.public.n;
pq = G_gpg_vstate.work.rsa.public4096.n;
break;
}
ksz = ksz>>1;
@ -460,14 +451,14 @@ int gpg_apdu_put_data(unsigned int ref) {
THROW(SW_WRONG_DATA);
return 0;
}
ksz = 32;
if (ksz == 32) {
G_gpg_vstate.work.ecfp256.private.curve = curve;
G_gpg_vstate.work.ecfp256.private.d_len = ksz;
os_memmove(G_gpg_vstate.work.ecfp256.private.d, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,ksz);
cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp256.public, &G_gpg_vstate.work.ecfp256.private, 1);
nvm_write(&keygpg->pub_key.ecfp256, &G_gpg_vstate.work.ecfp256.public, sizeof(cx_ecfp_public_key_t));
nvm_write(&keygpg->key.ecfp256, &G_gpg_vstate.work.ecfp256.private, sizeof(cx_ecfp_private_key_t));
ksz = gpg_curve2domainlen(curve);
if (ksz == len_p) {
G_gpg_vstate.work.ecfp.private.curve = curve;
G_gpg_vstate.work.ecfp.private.d_len = ksz;
os_memmove(G_gpg_vstate.work.ecfp.private.d, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,ksz);
cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp.public, &G_gpg_vstate.work.ecfp.private, 1);
nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));

View File

@ -113,29 +113,20 @@ int gpg_apdu_gen() {
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
ksz = ksz >> 3;
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa.private;
pkey = &keygpg->priv_key.rsa;
switch(ksz) {
case 1024/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa1024.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa1024.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa1024;
pkey_size = sizeof(cx_rsa_1024_private_key_t);
break;
case 2048/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa2048.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa2048.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa2048;
pkey_size = sizeof(cx_rsa_2048_private_key_t);
break;
case 3072/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa3072.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa3072.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa3072;
pkey_size = sizeof(cx_rsa_3072_private_key_t);
break;
case 4096/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa4096.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa4096.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa4096;
pkey_size = sizeof(cx_rsa_4096_private_key_t);
break;
}
@ -173,19 +164,24 @@ int gpg_apdu_gen() {
unsigned int curve,keepprivate;
keepprivate = 0;
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
if (curve == CX_CURVE_NONE) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
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, 32);
cx_ecfp_init_private_key(curve,seed, 32, &G_gpg_vstate.work.ecfp256.private);
gpg_pso_derive_key_seed(seed, name, 1, seed, ksz);
cx_ecfp_init_private_key(curve,seed, ksz, &G_gpg_vstate.work.ecfp.private);
keepprivate = 1;
}
cx_ecfp_generate_pair(curve,
&G_gpg_vstate.work.ecfp256.public,
&G_gpg_vstate.work.ecfp256.private,
&G_gpg_vstate.work.ecfp.public,
&G_gpg_vstate.work.ecfp.private,
keepprivate);
nvm_write(&keygpg->key.ecfp256, &G_gpg_vstate.work.ecfp256.private, sizeof(cx_ecfp_private_key_t));
nvm_write(&keygpg->pub_key.ecfp256, &G_gpg_vstate.work.ecfp256.public, sizeof(cx_ecfp_public_key_t));
nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
@ -207,32 +203,32 @@ int gpg_apdu_gen() {
gpg_io_mark();
switch(ksz) {
case 1024/8:
if (keygpg->key.rsa1024.size == 0) {
if (keygpg->priv_key.rsa1024.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa1024.n);
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa1024.n);
break;
case 2048/8:
if (keygpg->key.rsa2048.size == 0) {
if (keygpg->priv_key.rsa2048.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa2048.n);
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa2048.n);
break;
case 3072/8:
if (keygpg->key.rsa3072.size == 0) {
if (keygpg->priv_key.rsa3072.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa3072.n);
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa3072.n);
break;
case 4096/8:
if (keygpg->key.rsa4096.size == 0) {
if (keygpg->priv_key.rsa4096.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa4096.n);
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa4096.n);
break;
}
gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa);

View File

@ -32,24 +32,47 @@ const unsigned char C_MAGIC[8] = {
/* --ECC OID -- */
/* ----------------------*/
/*
//brainpool 256t1: 1.3.36.3.3.2.8.1.1.8
const unsigned char C_OID_BRAINPOOL256T1[9] = {
0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07
};
*/
//secp256r1 / NIST P256 /ansi-x9.62 : 1.2.840.10045.3.1.7
const unsigned char C_OID_SECP256R1[8] = {
0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07
};
//secp384r1 / NIST P384 /ansi-x9.62 :1.3.132.0.34
const unsigned char C_OID_SECP384R1[5] = {
0x2B, 0x81, 0x04, 0x00 , 0x22
};
//secp521r1 / NIST P521 /ansi-x9.62 : 1.3.132.0.35
const unsigned char C_OID_SECP521R1[5] = {
0x2B, 0x81, 0x04, 0x00, 0x23
};
//secp256k1: 1.3.132.0.10
const unsigned char C_OID_SECP256K1[5] = {
0x2B, 0x81, 0x04, 0x00, 0x0A
};
//secp256r1 / NIST P256 /ansi-x9.62 : 1.2.840.10045.3.1.7
const unsigned char C_OID_SECP256R1[8] = {
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
};
//brainpool 256r1: 1.3.36.3.3.2.8.1.1.7
const unsigned char C_OID_BRAINPOOL256R1[9] = {
0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x08
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x08
};
//brainpool 256t1: 1.3.36.3.3.2.8.1.1.8
const unsigned char C_OID_BRAINPOOL256T1[9] = {
0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07
//brainpool 284r1: 1.3.36.3.3.2.8.1.1.11
const unsigned char C_OID_BRAINPOOL384R1[9] = {
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B
};
//brainpool 512r1: 1.3.36.3.3.2.8.1.1.13
const unsigned char C_OID_BRAINPOOL512R1[9] = {
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D
};
//Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1
const unsigned char C_OID_Ed25519[9] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
@ -60,10 +83,29 @@ const unsigned char C_OID_cv25519[10] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
};
int gpg_oid2curve(unsigned char* oid, unsigned int len) {
unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len) {
if ( (len == sizeof(C_OID_SECP256K1)) && (os_memcmp(oid, C_OID_SECP256K1, len)==0) ) {
return CX_CURVE_SECP256K1;
}
if ( (len == sizeof(C_OID_SECP256R1)) && (os_memcmp(oid, C_OID_SECP256R1, len)==0) ) {
return CX_CURVE_256R1;
return CX_CURVE_SECP256R1;
}
if ( (len == sizeof(C_OID_SECP384R1)) && (os_memcmp(oid, C_OID_SECP384R1, len)==0) ) {
return CX_CURVE_SECP384R1;
}
if ( (len == sizeof(C_OID_SECP521R1)) && (os_memcmp(oid, C_OID_SECP521R1, len)==0) ) {
return CX_CURVE_SECP521R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL256R1)) && (os_memcmp(oid, C_OID_BRAINPOOL256R1, len)==0) ) {
return CX_CURVE_BrainPoolP256R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL384R1)) && (os_memcmp(oid, C_OID_BRAINPOOL384R1, len)==0) ) {
return CX_CURVE_BrainPoolP384R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL512R1)) && (os_memcmp(oid, C_OID_BRAINPOOL512R1, len)==0) ) {
return CX_CURVE_BrainPoolP512R1;
}
if ( (len == sizeof(C_OID_Ed25519)) && (os_memcmp(oid, C_OID_Ed25519, len)==0) ) {
@ -74,20 +116,86 @@ int gpg_oid2curve(unsigned char* oid, unsigned int len) {
return CX_CURVE_Curve25519;
}
/*
if ( (len == sizeof(C_OID_SECP256K1)) && (os_memcmp(oid, C_OID_SECP256K1, len)==0) ) {
return CX_CURVE_256K1;
}
if ( (len == sizeof(C_OID_BRAINPOOL256R1)) && (os_memcmp(oid, C_OID_BRAINPOOL256R1, len)==0) ) {
return CX_CURVE_BrainPoolP256R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL256T1)) && (os_memcmp(oid, C_OID_BRAINPOOL256T1, len)==0) ) {
return CX_CURVE_BrainPoolP256T1;
}
*/
return CX_CURVE_NONE;
}
unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
switch (cv) {
case CX_CURVE_SECP256K1:
*len = sizeof(C_OID_SECP256K1);
return (unsigned char*)PIC(C_OID_SECP256K1);
case CX_CURVE_SECP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1);
case CX_CURVE_SECP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_SECP521R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
case CX_CURVE_BrainPoolP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1);
case CX_CURVE_BrainPoolP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_BrainPoolP512R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
case CX_CURVE_Ed25519:
*len = sizeof(C_OID_Ed25519);
return (unsigned char*)PIC(C_OID_Ed25519);
case CX_CURVE_Curve25519:
*len = sizeof(C_OID_cv25519);
return (unsigned char*)PIC(C_OID_cv25519);
}
*len = 0;
return NULL;
}
unsigned int gpg_curve2domainlen(unsigned int cv) {
switch (cv) {
case CX_CURVE_SECP256K1:
case CX_CURVE_SECP256R1:
case CX_CURVE_BrainPoolP256R1:
case CX_CURVE_Ed25519:
case CX_CURVE_Curve25519:
return 32;
case CX_CURVE_SECP384R1:
case CX_CURVE_BrainPoolP384R1:
return 48;
case CX_CURVE_BrainPoolP512R1:
return 64;
case CX_CURVE_SECP521R1:
return 66;
}
return 0;
}
/* -------------------------------*/
/* -- Non Mutable Capabilities -- */
/* -------------------------------*/
@ -123,7 +231,7 @@ const unsigned char C_ext_length[8] = {
const unsigned char C_default_AID[] = {
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
//version
0x03, 0x00,
0x03, 0x03,
//manufacturer
0x2C, 0x97,
//serial
@ -155,7 +263,7 @@ const unsigned char C_default_AlgoAttrRSA[] = {
0x01
};
#if 1
#if 0
const unsigned char C_default_AlgoAttrECC_sig[] = {
// ecdsa
0x13,
@ -168,8 +276,20 @@ const unsigned char C_default_AlgoAttrECC_dec[] = {
// NIST-P256
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
};
#else
#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[] = {
// eddsa
0x16,
@ -283,7 +403,6 @@ int gpg_install(unsigned char app_state) {
gpg_nvm_write(&N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer, 3);
//config rsa pub
#define GPG_RSA_DEFAULT_PUB 0x00010001
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB>>24)&0xFF;
G_gpg_vstate.work.io_buffer[1] = (GPG_RSA_DEFAULT_PUB>>16)&0xFF;
G_gpg_vstate.work.io_buffer[2] = (GPG_RSA_DEFAULT_PUB>>8)&0xFF;
@ -304,7 +423,10 @@ int gpg_install(unsigned char app_state) {
//default key template: RSA 2048)
for (int s = 0; s< GPG_KEYS_SLOTS; s++) {
#if 0
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);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.length, &l, sizeof(unsigned int));
@ -322,6 +444,11 @@ int gpg_install(unsigned char app_state) {
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);
}
}

View File

@ -18,6 +18,7 @@
#include "gpg_types.h"
#include "gpg_api.h"
#include "gpg_vars.h"
#include "gpg_ux_nanos.h"
const unsigned char gpg_oid_sha256[] = {
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
@ -41,16 +42,16 @@ static int gpg_sign(gpg_key_t *sigkey) {
ksz = ksz>>3;
switch(ksz) {
case 1024/8:
key = (cx_rsa_private_key_t *)&sigkey->key.rsa1024;
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa1024;
break;
case 2048/8:
key = (cx_rsa_private_key_t *)&sigkey->key.rsa2048;
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa2048;
break;
case 3072/8:
key = (cx_rsa_private_key_t *)&sigkey->key.rsa3072;
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa3072;
break;
case 4096/8:
key = (cx_rsa_private_key_t *)&sigkey->key.rsa4096;
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa4096;
break;
}
if (key->size != ksz) {
@ -83,21 +84,21 @@ static int gpg_sign(gpg_key_t *sigkey) {
if ((sigkey->attributes.value[0] == 19) ||
(sigkey->attributes.value[0] == 22)) {
cx_ecfp_private_key_t *key;
unsigned int sz,i,rs_len,info;
unsigned int sz,i,rs_len;
unsigned char *rs;
key = &sigkey->key.ecfp256;
if (key->d_len != 32) {
key = &sigkey->priv_key.ecfp;
//sign
if (sigkey->attributes.value[0] == 19) {
sz = gpg_curve2domainlen(key->curve);
if ((sz == 0) || (key->d_len != sz)) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
//sign
if (sigkey->attributes.value[0] == 19) {
sz = cx_ecdsa_sign(key,
CX_RND_TRNG,
CX_NONE,
G_gpg_vstate.work.io_buffer, 32/*G_gpg_vstate.io_length*/,
G_gpg_vstate.work.io_buffer, sz,
G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH,
NULL);
//reencode r,s in MPI format
@ -149,19 +150,27 @@ int gpg_apdu_pso() {
switch(pso) {
// --- PSO:CDS ---
case 0x9e9a:
if ((G_gpg_vstate.kslot->sig.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) {
if (G_gpg_vstate.kslot->sig.UIF[0]) {
if ((G_gpg_vstate.UIF_flags)==0) {
ui_menu_uifconfirm_display(0);
return 0;
}
case 0x8680:
if ((G_gpg_vstate.kslot->dec.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) {
G_gpg_vstate.UIF_flags = 0;
}
break;
// --- PSO:DEC ---
case 0x8096:
if (G_gpg_vstate.kslot->dec.UIF[0]) {
if ((G_gpg_vstate.UIF_flags)==0) {
ui_menu_uifconfirm_display(0);
return 0;
}
G_gpg_vstate.UIF_flags = 0;
}
break;
}
// --- PSO:ENC ---
switch(pso) {
// --- PSO:CDS ---
case 0x9e9a: {
@ -214,16 +223,16 @@ int gpg_apdu_pso() {
key = NULL;
switch(ksz) {
case 1024/8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->key.rsa1024;
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa1024;
break;
case 2048/8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->key.rsa2048;
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->key.rsa3072;
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa3072;
break;
case 4096/8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->key.rsa4096;
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa4096;
break;
}
@ -272,11 +281,7 @@ int gpg_apdu_pso() {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
key = &G_gpg_vstate.mse_dec->key.ecfp256;
if (key->d_len != 32) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
key = &G_gpg_vstate.mse_dec->priv_key.ecfp;
gpg_io_fetch_l(&l);
gpg_io_fetch_tl(&t, &l);
if (t != 0x7f49) {
@ -290,6 +295,10 @@ int gpg_apdu_pso() {
}
curve = gpg_oid2curve(G_gpg_vstate.mse_dec->attributes.value+1, G_gpg_vstate.mse_dec->attributes.length-1);
if (key->curve != curve) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
if (curve == CX_CURVE_Curve25519) {
unsigned int i;
@ -335,10 +344,14 @@ int gpg_apdu_pso() {
int gpg_apdu_internal_authenticate() {
if ((G_gpg_vstate.kslot->aut.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) {
// --- PSO:AUTH ---
if (G_gpg_vstate.kslot->aut.UIF[0]) {
if ((G_gpg_vstate.UIF_flags)==0) {
ui_menu_uifconfirm_display(0);
return 0;
}
G_gpg_vstate.UIF_flags = 0;
}
if (G_gpg_vstate.mse_aut->attributes.value[0] == 1) {
if ( G_gpg_vstate.io_length > ((G_gpg_vstate.mse_aut->attributes.value[1]<<8)|G_gpg_vstate.mse_aut->attributes.value[2])*40/100) {

View File

@ -36,7 +36,7 @@
#define GPG_KEY_ATTRIBUTES_LENGTH 12
#define GPG_RSA_DEFAULT_PUB 0x010001U
#define GPG_RSA_DEFAULT_PUB 0x00010001U
struct gpg_pin_s {
unsigned int ref;
@ -66,15 +66,25 @@ typedef struct gpg_key_s {
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
/* key value */
union {
cx_rsa_private_key_t rsa;
cx_rsa_1024_private_key_t rsa1024;
cx_rsa_2048_private_key_t rsa2048;
cx_rsa_3072_private_key_t rsa3072;
cx_rsa_4096_private_key_t rsa4096;
cx_ecfp_private_key_t ecfp256;
} key;
cx_ecfp_private_key_t ecfp;
cx_ecfp_256_private_key_t ecfp256;
cx_ecfp_384_private_key_t ecfp384;
cx_ecfp_512_private_key_t ecfp512;
cx_ecfp_640_private_key_t ecfp640;
} priv_key;
union {
unsigned char rsa[4];
cx_ecfp_public_key_t ecfp256;
cx_ecfp_public_key_t ecfp;
cx_ecfp_256_public_key_t ecfp256;
cx_ecfp_384_public_key_t ecfp384;
cx_ecfp_512_public_key_t ecfp512;
cx_ecfp_640_public_key_t ecfp640;
} pub_key;
/* C7 C8 C9 , C5 = C7|C8|C9*/
unsigned char fingerprints[20];
@ -193,26 +203,41 @@ struct gpg_v_state_s {
unsigned short io_mark;
union {
unsigned char io_buffer[GPG_IO_BUFFER_LENGTH];
struct {
cx_rsa_1024_public_key_t public;
cx_rsa_1024_private_key_t private;
}rsa1024;
struct {
cx_rsa_2048_public_key_t public;
cx_rsa_2048_private_key_t private;
}rsa2048;
struct {
cx_rsa_3072_public_key_t public;
cx_rsa_3072_private_key_t private;
}rsa3072;
struct {
cx_rsa_4096_public_key_t public;
cx_rsa_4096_private_key_t private;
}rsa4096;
union {
cx_rsa_public_key_t public;
cx_rsa_1024_public_key_t public1024;
cx_rsa_2048_public_key_t public2048;
cx_rsa_3072_public_key_t public3072;
cx_rsa_4096_public_key_t public4096;
};
union {
cx_rsa_private_key_t private;
cx_rsa_1024_private_key_t private1024;
cx_rsa_2048_private_key_t private2048;
cx_rsa_3072_private_key_t private3072;
cx_rsa_4096_private_key_t private4096;
};
} rsa;
struct {
union{
cx_ecfp_public_key_t public;
cx_ecfp_256_public_key_t public256;
cx_ecfp_384_public_key_t public384;
cx_ecfp_512_public_key_t public512;
cx_ecfp_640_public_key_t public640;
};
union {
cx_ecfp_private_key_t private;
}ecfp256;
cx_ecfp_256_private_key_t private256;
cx_ecfp_384_private_key_t private384;
cx_ecfp_512_private_key_t private512;
cx_ecfp_640_private_key_t private640;
};
}ecfp;
struct {
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH-MAX(sizeof(cx_sha3_t),sizeof(cx_sha256_t))];
union {

View File

@ -34,3 +34,5 @@ const char * const C_NOT_ALLOWED = "Not Allowed ";
const char * const C_DEFAULT_MODE = "Default mode";
const char * const C_UIF_LOCKED = "UIF locked";

View File

@ -36,6 +36,9 @@ extern const char * const C_NOT_ALLOWED;
extern const char * const C_DEFAULT_MODE;
extern const char * const C_UIF_LOCKED;
extern const char * const C_UIF_INVALID;
#define PICSTR(x) ((char*)PIC(x))
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
@ -54,5 +57,7 @@ extern const char * const C_DEFAULT_MODE;
#define ALLOWED PICSTR(C_ALLOWED)
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
#define UIF_LOCKED PICSTR(C_UIF_LOCKED)
#define UIF_INVALID PICSTR(C_UIF_INVALID)
#endif

View File

@ -134,7 +134,7 @@ void ui_menu_uifconfirm_display(unsigned int value) {
unsigned int ui_uifconfirm_prepro(const bagl_element_t* element) {
if (element->component.userid == 1) {
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Confirm Operation:");
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Confirm:");
return 1;
}
if (element->component.userid == 2) {
@ -175,7 +175,14 @@ unsigned int ui_uifconfirm_nanos_button(unsigned int button_mask, unsigned int b
BEGIN_TRY {
TRY {
G_gpg_vstate.UIF_flags = 1;
if (G_gpg_vstate.io_ins == INS_PSO) {
sw = gpg_apdu_pso();
} else if (G_gpg_vstate.io_ins == INS_INTERNAL_AUTHENTICATE) {
sw = gpg_apdu_internal_authenticate();
} else {
gpg_io_discard(1);
sw = 0x6985;
}
}
CATCH_OTHER(e) {
gpg_io_discard(1);
@ -503,7 +510,12 @@ static unsigned int validate_pin() {
#define LABEL_RSA3072 "RSA 3072"
#define LABEL_RSA4096 "RSA 4096"
#define LABEL_NISTP256 "NIST P256"
#define LABEL_BPOOLR1 "Brainpool R1"
//#define LABEL_NISTP384 "NIST P384"
//#define LABEL_NISTP521 "NIST P521"
#define LABEL_SECP256K1 "SEPC 256K1"
#define LABEL_BPOOL256R1 "Brainpool 256R1"
//#define LABEL_BPOOL384R1 "Brainpool 384R1"
//#define LABEL_BPOOL512R1 "Brainpool 512R1"
#define LABEL_Ed25519 "Ed25519"
const ux_menu_entry_t ui_menu_template[] = {
@ -548,12 +560,34 @@ const bagl_element_t* ui_menu_template_preprocessor(const ux_menu_entry_t* entry
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);
/*
case CX_CURVE_SECP384R1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP384);
break;
case CX_CURVE_SECP521R1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP521);
break;
*/
case CX_CURVE_SECP256K1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_SECP256K1);
break;
case CX_CURVE_BrainPoolP256R1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOL256R1);
break;
/*
case CX_CURVE_BrainPoolP384R1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOL384R1);
break;
case CX_CURVE_BrainPoolP512R1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOL512R1);
break;
*/
case CX_CURVE_Ed25519:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_Ed25519);
break;
@ -574,7 +608,8 @@ void ui_menu_tmpl_set_action(unsigned int value) {
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
gpg_key_t* dest;
const char* err;
const unsigned char *oid;
unsigned int oid_len;
err = NULL;
os_memset(&attributes, 0, sizeof(attributes));
@ -591,24 +626,21 @@ void ui_menu_tmpl_set_action(unsigned int value) {
attributes.length = 6;
break;
case CX_CURVE_SECP256K1:
case CX_CURVE_SECP256R1:
if (G_gpg_vstate.ux_key == 2) {
attributes.value[0] = 18; //ecdh
} else {
attributes.value[0] = 19; //ecdsa
}
os_memmove(attributes.value+1, C_OID_SECP256R1, sizeof(C_OID_SECP256R1));
attributes.length = 1+sizeof(C_OID_SECP256R1);
break;
//case CX_CURVE_SECP384R1:
//case CX_CURVE_SECP521R1:
case CX_CURVE_BrainPoolP256R1:
//case CX_CURVE_BrainPoolP384R1:
//case CX_CURVE_BrainPoolP512R1:
if (G_gpg_vstate.ux_key == 2) {
attributes.value[0] = 18; //ecdh
} else {
attributes.value[0] = 19; //ecdsa
}
os_memmove(attributes.value+1, C_OID_BRAINPOOL256R1, sizeof(C_OID_BRAINPOOL256R1));
attributes.length = 1+sizeof(C_OID_BRAINPOOL256R1);
oid = gpg_curve2oid(G_gpg_vstate.ux_type, &oid_len);
os_memmove(attributes.value+1, oid, sizeof(oid_len));
attributes.length = 1+oid_len;
break;
case CX_CURVE_Ed25519:
@ -674,7 +706,12 @@ const ux_menu_entry_t ui_menu_tmpl_type[] = {
{NULL, ui_menu_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
{NULL, ui_menu_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
{NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
{NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOLR1, NULL, 0, 0},
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP384R1, NULL, LABEL_NISTP384, NULL, 0, 0},
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP521R1, NULL, LABEL_NISTP521, NULL, 0, 0},
{NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP256K1, NULL, LABEL_SECP256K1, NULL, 0, 0},
{NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOL256R1, NULL, 0, 0},
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP384R1, NULL, LABEL_BPOOL384R1, NULL, 0, 0},
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP512R1, NULL, LABEL_BPOOL512R1, NULL, 0, 0},
{NULL, ui_menu_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
{ui_menu_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
@ -803,6 +840,84 @@ void ui_menu_pinmode_action(unsigned int value) {
// redisplay first entry of the idle menu
ui_menu_pinmode_display(0);
}
/* ------------------------------- UIF MODE UX ------------------------------ */
const ux_menu_entry_t ui_menu_uifmode[];
void ui_menu_uifmode_display(unsigned int value);
const bagl_element_t* ui_menu_uifmode_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
void ui_menu_uifmode_action(unsigned int value);
const ux_menu_entry_t ui_menu_uifmode[] = {
{NULL, NULL, -1, NULL, "Activate (+) for:", NULL, 0, 0},
{NULL, ui_menu_uifmode_action, 1, NULL, "Signature", NULL, 0, 0},
{NULL, ui_menu_uifmode_action, 2, NULL, "Decryption", NULL, 0, 0},
{NULL, ui_menu_uifmode_action, 3, NULL, "Authentication", NULL, 0, 0},
{ui_menu_settings, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_menu_uifmode_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_menu_uifmode, ui_menu_uifmode_preprocessor);
}
const bagl_element_t* ui_menu_uifmode_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
if (element->component.userid==0x20) {
if ((entry->userid >= 1) && (entry->userid<=3)) {
unsigned char uif[2] ;
uif[0] = 0;
uif[1] = 0;
switch (entry->userid) {
case 1:
*uif = G_gpg_vstate.kslot->sig.UIF[0]?'+':' ';
break;
case 2:
*uif = G_gpg_vstate.kslot->dec.UIF[0]?'+':' ';
break;
case 3:
*uif = G_gpg_vstate.kslot->aut.UIF[0]?'+':' ';
break;
}
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s %s",
(char*)PIC(entry->line1), uif);
element->text = G_gpg_vstate.menu;
element->component.height = 32;
}
}
return element;
}
void ui_menu_uifmode_action(unsigned int value) {
unsigned char *uif;
unsigned char new_uif;
switch (value) {
case 1:
uif = &G_gpg_vstate.kslot->sig.UIF[0];
break;
case 2:
uif = &G_gpg_vstate.kslot->dec.UIF[0];
break;
case 3:
uif = &G_gpg_vstate.kslot->aut.UIF[0];
break;
default:
ui_info(INVALID_SELECTION, NULL, ui_menu_uifmode_display,0);
return;
}
if (uif[0] == 0) {
new_uif = 1;
gpg_nvm_write(&uif[0], &new_uif, 1);
} else if (uif[0] == 1) {
new_uif = 0;
gpg_nvm_write(&uif[0], &new_uif, 1) ;
} else /*if (uif[0] == 2 )*/ {
ui_info(UIF_LOCKED, NULL, ui_menu_uifmode_display,0);
return;
}
ui_menu_uifmode_display(value);
}
/* -------------------------------- RESET UX --------------------------------- */
const ux_menu_entry_t ui_menu_reset[] = {
@ -829,6 +944,7 @@ const ux_menu_entry_t ui_menu_settings[] = {
{NULL, ui_menu_template_display, 0, NULL, "Key template", NULL, 0, 0},
{NULL, ui_menu_seed_display, 0, NULL, "Seed mode", NULL, 0, 0},
{NULL, ui_menu_pinmode_display, 0, NULL, "PIN mode", NULL, 0, 0},
{NULL, ui_menu_uifmode_display, 0, NULL, "UIF mode", NULL, 0, 0},
{ui_menu_reset, NULL, 0, NULL, "Reset", NULL, 0, 0},
{NULL, ui_menu_main_display, 2, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END

View File

@ -22,4 +22,5 @@ void ui_init(void);
void ui_main_display(unsigned int value);
void ui_menu_pinconfirm_display(unsigned int value);
void ui_menu_pinentry_display(unsigned int value);
void ui_menu_uifconfirm_display(unsigned int value);
#endif

1057
src/sdk/usbd_ccid_cmd.c Executable file

File diff suppressed because it is too large Load Diff

617
src/sdk/usbd_ccid_if.c Executable file
View File

@ -0,0 +1,617 @@
/**
******************************************************************************
* @file usbd_ccid_if.c
* @author MCD Application Team
* @version V1.0.1
* @date 31-January-2014
* @brief This file provides all the functions for USB Interface for CCID
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2
*
* 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.
*
******************************************************************************
*/
#pragma message "Override SDK source file :" __FILE__
/* Includes ------------------------------------------------------------------*/
#include "os.h"
#include "usbd_ccid_if.h"
#ifdef HAVE_USB_CLASS_CCID
#if CCID_BULK_EPIN_SIZE > USB_SEGMENT_SIZE
#error configuration error, the USB MAX SEGMENT SIZE does not support the CCID endpoint (CCID_BULK_EPIN_SIZE vs USB_SEGMENT_SIZE)
#endif
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
usb_class_ccid_t G_io_ccid;
/* Private function prototypes -----------------------------------------------*/
static void CCID_Response_SendData (USBD_HandleTypeDef *pdev,
uint8_t* pbuf,
uint16_t len);
/* Private function ----------------------------------------------------------*/
/**
* @brief CCID_Init
* Initialize the CCID USB Layer
* @param pdev: device instance
* @retval None
*/
void CCID_Init (USBD_HandleTypeDef *pdev)
{
memset(&G_io_ccid, 0, sizeof(G_io_ccid));
/* CCID Related Initialization */
#ifdef HAVE_CCID_INTERRUPT
CCID_SetIntrTransferStatus(1); /* Transfer Complete Status */
#endif // HAVE_CCID_INTERRUPT
CCID_UpdSlotChange(1);
SC_InitParams();
/* Prepare Out endpoint to receive 1st packet */
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
// send the smartcard as inserted state at boot time
io_usb_ccid_set_card_inserted(1);
}
/**
* @brief CCID_DeInit
* Uninitialize the CCID Machine
* @param pdev: device instance
* @retval None
*/
void CCID_DeInit (USBD_HandleTypeDef *pdev)
{
UNUSED(pdev);
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
}
/**
* @brief CCID_Message_In
* Handle Bulk IN & Intr IN data stage
* @param pdev: device instance
* @param uint8_t epnum: endpoint index
* @retval None
*/
void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
if (epnum == (CCID_BULK_IN_EP & 0x7F))
{/* Filter the epnum by masking with 0x7f (mask of IN Direction) */
/*************** Handle Bulk Transfer IN data completion *****************/
switch (G_io_ccid.Ccid_BulkState)
{
case CCID_STATE_SEND_RESP: {
unsigned int remLen = G_io_ccid.UsbMessageLength;
// advance with acknowledged sent chunk
if (G_io_ccid.pUsbMessageBuffer == &G_io_ccid.bulk_header) {
// first part of the bulk in sent.
// advance in the data buffer to transmit. (mixed source leap)
G_io_ccid.pUsbMessageBuffer = G_io_ccid_data_buffer+MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength)-CCID_HEADER_SIZE;
}
else {
G_io_ccid.pUsbMessageBuffer += MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength);
}
G_io_ccid.UsbMessageLength -= MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength);
// if remaining length is > EPIN_SIZE: send a filled bulk packet
if (G_io_ccid.UsbMessageLength >= CCID_BULK_EPIN_SIZE) {
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
// use the header declared size packet must be well formed
CCID_BULK_EPIN_SIZE);
}
// if remaining length is 0; send an empty packet and prepare to receive a new command
else if (G_io_ccid.UsbMessageLength == 0 && remLen == CCID_BULK_EPIN_SIZE) {
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
// use the header declared size packet must be well formed
0);
goto last_xfer; // won't wait ack to avoid missing a command
}
// else if no more data, then last packet sent, go back to idle (done on transfer ack)
else if (G_io_ccid.UsbMessageLength == 0) { // robustness only
last_xfer:
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
/* Prepare EP to Receive First Cmd */
// not timeout compliant // USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
}
// if remaining length is < EPIN_SIZE: send packet and prepare to receive a new command
else if (G_io_ccid.UsbMessageLength < CCID_BULK_EPIN_SIZE) {
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
// use the header declared size packet must be well formed
G_io_ccid.UsbMessageLength);
goto last_xfer; // won't wait ack to avoid missing a command
}
break;
}
default:
break;
}
}
#ifdef HAVE_CCID_INTERRUPT
else if (epnum == (CCID_INTR_IN_EP & 0x7F))
{
/* Filter the epnum by masking with 0x7f (mask of IN Direction) */
CCID_SetIntrTransferStatus(1); /* Transfer Complete Status */
}
#endif // HAVE_CCID_INTERRUPT
}
void CCID_Send_Reply(USBD_HandleTypeDef *pdev) {
/********** Decide for all commands ***************/
if (G_io_ccid.Ccid_BulkState == CCID_STATE_SEND_RESP)
{
G_io_ccid.UsbMessageLength = G_io_ccid.bulk_header.bulkin.dwLength+CCID_HEADER_SIZE; /* Store for future use */
/* Expected Data Length Packet Received */
G_io_ccid.pUsbMessageBuffer = (uint8_t*) &G_io_ccid.bulk_header;
// send bulk header and first pat of the message at once
os_memmove(G_io_usb_ep_buffer, &G_io_ccid.bulk_header, CCID_HEADER_SIZE);
if (G_io_ccid.UsbMessageLength>CCID_HEADER_SIZE) {
// copy start of data if bigger size than a header
os_memmove(G_io_usb_ep_buffer+CCID_HEADER_SIZE, G_io_ccid_data_buffer, MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength)-CCID_HEADER_SIZE);
}
// send the first mixed source chunk
CCID_Response_SendData(pdev, G_io_usb_ep_buffer,
// use the header declared size packet must be well formed
MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength));
}
}
/**
* @brief CCID_BulkMessage_Out
* Proccess CCID OUT data
* @param pdev: device instance
* @param uint8_t epnum: endpoint index
* @retval None
*/
void CCID_BulkMessage_Out (USBD_HandleTypeDef *pdev,
uint8_t epnum, uint8_t* buffer, uint16_t dataLen)
{
if (epnum == (CCID_BULK_OUT_EP & 0x7F)) {
switch (G_io_ccid.Ccid_BulkState)
{
// after a timeout, could be in almost any state :) therefore, clean it and process the newly received command
default:
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
// no break is intentional
case CCID_STATE_IDLE:
// prepare to receive another packet later on (to avoid troubles with timeout due to other hid command timeouting the ccid endpoint reply)
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
if (dataLen == 0x00)
{ /* Zero Length Packet Received, end of transfer */
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
}
else if (dataLen >= CCID_HEADER_SIZE)
{
G_io_ccid.UsbMessageLength = dataLen; /* Store for future use */
/* Expected Data Length Packet Received */
// endianness is little :) useful for our ARM convention
G_io_ccid.pUsbMessageBuffer = (uint8_t*) &G_io_ccid.bulk_header;
// copy the ccid bulk header only
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, CCID_HEADER_SIZE);
// copy remaining part in the data buffer (split from the ccid to allow for overlaying with another ressource buffer)
if (dataLen>CCID_HEADER_SIZE) {
os_memmove(G_io_ccid_data_buffer, buffer+CCID_HEADER_SIZE, dataLen-CCID_HEADER_SIZE);
// we're now receiving in the data buffer (all subsequent calls)
G_io_ccid.pUsbMessageBuffer = G_io_ccid_data_buffer;
}
if (G_io_ccid.bulk_header.bulkout.dwLength > IO_CCID_DATA_BUFFER_SIZE)
{ /* Check if length of data to be sent by host is > buffer size */
/* Too long data received.... Error ! */
G_io_ccid.Ccid_BulkState = CCID_STATE_UNCORRECT_LENGTH;
}
else
// everything received in the first packet
if (G_io_ccid.UsbMessageLength == (G_io_ccid.bulk_header.bulkout.dwLength + CCID_HEADER_SIZE)) {
/* Short message, less than the EP Out Size, execute the command,
if parameter like dwLength is too big, the appropriate command will
give an error */
CCID_CmdDecode(pdev);
}
else
{ /* Long message, receive additional data with command */
G_io_ccid.Ccid_BulkState = CCID_STATE_RECEIVE_DATA;
G_io_ccid.pUsbMessageBuffer += dataLen-CCID_HEADER_SIZE; /* Point to new offset */
}
}
break;
case CCID_STATE_RECEIVE_DATA:
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
G_io_ccid.UsbMessageLength += dataLen;
if (dataLen < CCID_BULK_EPOUT_SIZE)
{/* Short message, less than the EP Out Size, execute the command,
if parameter like dwLength is too big, the appropriate command will
give an error */
/* Full command is received, process the Command */
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
CCID_CmdDecode(pdev);
}
else //if (dataLen == CCID_BULK_EPOUT_SIZE)
{
if (G_io_ccid.UsbMessageLength < (G_io_ccid.bulk_header.bulkout.dwLength + CCID_HEADER_SIZE))
{
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
G_io_ccid.pUsbMessageBuffer += dataLen;
/* Increment the pointer to receive more data */
/* Prepare EP to Receive next Cmd */
// not timeout compliant // USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
}
else if (G_io_ccid.UsbMessageLength == (G_io_ccid.bulk_header.bulkout.dwLength + CCID_HEADER_SIZE))
{
/* Full command is received, process the Command */
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
CCID_CmdDecode(pdev);
}
else
{
/* Too long data received.... Error ! */
G_io_ccid.Ccid_BulkState = CCID_STATE_UNCORRECT_LENGTH;
}
}
break;
/*
case CCID_STATE_UNCORRECT_LENGTH:
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
break;
default:
break;
*/
}
}
}
/**
* @brief CCID_CmdDecode
* Parse the commands and Proccess command
* @param pdev: device instance
* @retval None
*/
void CCID_CmdDecode(USBD_HandleTypeDef *pdev)
{
uint8_t errorCode;
switch (G_io_ccid.bulk_header.bulkout.bMessageType)
{
case PC_TO_RDR_ICCPOWERON:
errorCode = PC_to_RDR_IccPowerOn();
RDR_to_PC_DataBlock(errorCode);
break;
case PC_TO_RDR_ICCPOWEROFF:
errorCode = PC_to_RDR_IccPowerOff();
RDR_to_PC_SlotStatus(errorCode);
break;
case PC_TO_RDR_GETSLOTSTATUS:
errorCode = PC_to_RDR_GetSlotStatus();
RDR_to_PC_SlotStatus(errorCode);
break;
case PC_TO_RDR_XFRBLOCK:
errorCode = PC_to_RDR_XfrBlock();
// asynchronous // RDR_to_PC_DataBlock(errorCode);
break;
case PC_TO_RDR_GETPARAMETERS:
errorCode = PC_to_RDR_GetParameters();
RDR_to_PC_Parameters(errorCode);
break;
case PC_TO_RDR_RESETPARAMETERS:
errorCode = PC_to_RDR_ResetParameters();
RDR_to_PC_Parameters(errorCode);
break;
case PC_TO_RDR_SETPARAMETERS:
errorCode = PC_to_RDR_SetParameters();
RDR_to_PC_Parameters(errorCode);
break;
case PC_TO_RDR_ESCAPE:
errorCode = PC_to_RDR_Escape();
RDR_to_PC_Escape(errorCode);
break;
case PC_TO_RDR_ICCCLOCK:
errorCode = PC_to_RDR_IccClock();
RDR_to_PC_SlotStatus(errorCode);
break;
case PC_TO_RDR_ABORT:
errorCode = PC_to_RDR_Abort();
RDR_to_PC_SlotStatus(errorCode);
break;
case PC_TO_RDR_T0APDU:
errorCode = PC_TO_RDR_T0Apdu();
RDR_to_PC_SlotStatus(errorCode);
break;
case PC_TO_RDR_MECHANICAL:
errorCode = PC_TO_RDR_Mechanical();
RDR_to_PC_SlotStatus(errorCode);
break;
case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
errorCode = PC_TO_RDR_SetDataRateAndClockFrequency();
RDR_to_PC_DataRateAndClockFrequency(errorCode);
break;
case PC_TO_RDR_SECURE:
errorCode = PC_TO_RDR_Secure();
// asynchronous // RDR_to_PC_DataBlock(errorCode);
break;
default:
RDR_to_PC_SlotStatus(SLOTERROR_CMD_NOT_SUPPORTED);
break;
}
CCID_Send_Reply(pdev);
}
/**
* @brief Transfer_Data_Request
* Prepare the request response to be sent to the host
* @param uint8_t* dataPointer: Pointer to the data buffer to send
* @param uint16_t dataLen : number of bytes to send
* @retval None
*/
void Transfer_Data_Request(void)
{
/********** Update Global Variables ***************/
G_io_ccid.Ccid_BulkState = CCID_STATE_SEND_RESP;
}
/**
* @brief CCID_Response_SendData
* Send the data on bulk-in EP
* @param pdev: device instance
* @param uint8_t* buf: pointer to data buffer
* @param uint16_t len: Data Length
* @retval None
*/
static void CCID_Response_SendData(USBD_HandleTypeDef *pdev,
uint8_t* buf,
uint16_t len)
{
UNUSED(pdev);
// don't ask the MCU to perform bulk split, we could quickly get into a buffer overflow
if (len > CCID_BULK_EPIN_SIZE) {
THROW(EXCEPTION_IO_OVERFLOW);
}
G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_USB_EP_PREPARE;
G_io_seproxyhal_spi_buffer[1] = (3+len)>>8;
G_io_seproxyhal_spi_buffer[2] = (3+len);
G_io_seproxyhal_spi_buffer[3] = CCID_BULK_IN_EP;
G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN;
G_io_seproxyhal_spi_buffer[5] = len;
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 6);
io_seproxyhal_spi_send(buf, len);
}
#ifdef HAVE_CCID_INTERRUPT
/**
* @brief CCID_IntMessage
* Send the Interrupt-IN data to the host
* @param pdev: device instance
* @retval None
*/
void CCID_IntMessage(USBD_HandleTypeDef *pdev)
{
UNUSED(pdev);
/* Check if there us change in Smartcard Slot status */
if ( CCID_IsSlotStatusChange() && CCID_IsIntrTransferComplete() )
{
#ifdef HAVE_CCID_INTERRUPT
/* Check Slot Status is changed. Card is Removed/ Fitted */
RDR_to_PC_NotifySlotChange();
#endif // HAVE_CCID_INTERRUPT
CCID_SetIntrTransferStatus(0); /* Reset the Status */
CCID_UpdSlotChange(0); /* Reset the Status of Slot Change */
G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_USB_EP_PREPARE;
G_io_seproxyhal_spi_buffer[1] = (3+2)>>8;
G_io_seproxyhal_spi_buffer[2] = (3+2);
G_io_seproxyhal_spi_buffer[3] = CCID_INTR_IN_EP;
G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN;
G_io_seproxyhal_spi_buffer[5] = 2;
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 6);
io_seproxyhal_spi_send(G_io_ccid.UsbIntMessageBuffer, 2);
}
}
/**
* @brief CCID_IsIntrTransferComplete
* Provides the status of previous Interrupt transfer status
* @param None
* @retval uint8_t PrevXferComplete_IntrIn: Value of the previous transfer status
*/
uint8_t CCID_IsIntrTransferComplete (void)
{
return G_io_ccid.PrevXferComplete_IntrIn;
}
/**
* @brief CCID_IsIntrTransferComplete
* Set the value of the Interrupt transfer status
* @param uint8_t xfer_Status: Value of the Interrupt transfer status to set
* @retval None
*/
void CCID_SetIntrTransferStatus (uint8_t xfer_Status)
{
G_io_ccid.PrevXferComplete_IntrIn = xfer_Status;
}
#endif // HAVE_CCID_INTERRUPT
uint8_t SC_Detect(void) {
return G_io_ccid.ccid_card_inserted;
}
void SC_InitParams (void) {
// nothing to do
}
uint8_t SC_SetParams (Protocol0_DataStructure_t* pt0) {
UNUSED(pt0);
return SLOT_NO_ERROR;
}
uint8_t SC_SetClock (uint8_t bClockCommand) {
UNUSED(bClockCommand);
return SLOT_NO_ERROR;
}
uint8_t SC_Request_GetClockFrequencies(uint8_t* pbuf, uint16_t* len);
uint8_t SC_Request_GetDataRates(uint8_t* pbuf, uint16_t* len);
uint8_t SC_T0Apdu(uint8_t bmChanges, uint8_t bClassGetResponse,
uint8_t bClassEnvelope) {
UNUSED(bmChanges);
UNUSED(bClassGetResponse);
UNUSED(bClassEnvelope);
return SLOTERROR_CMD_NOT_SUPPORTED;
}
uint8_t SC_Mechanical(uint8_t bFunction) {
UNUSED(bFunction);
return SLOTERROR_CMD_NOT_SUPPORTED;
}
uint8_t SC_SetDataRateAndClockFrequency(uint32_t dwClockFrequency,
uint32_t dwDataRate) {
UNUSED(dwClockFrequency);
UNUSED(dwDataRate);
return SLOT_NO_ERROR;
}
uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
uint8_t* pbuf, uint32_t* returnLen ) {
UNUSED(bBWI);
UNUSED(wLevelParameter);
UNUSED(returnLen);
// return SLOTERROR_CMD_NOT_SUPPORTED;
uint16_t ret_len,off;
switch(pbuf[0])
{
case 0: // verify pin
off = 15;
//ret_len = dwLength - 15;
ret_len = 5;
break;
case 1: // modify pin
switch(pbuf[11])
{
case 3:
off = 20;
break;
case 2:
case 1:
off = 19;
break;
// 0 and 4-0xFF
default:
off = 18;
break;
}
//ret_len = dwLength - off;
ret_len = 5;
break;
default: // unsupported
G_io_ccid.bulk_header.bulkin.dwLength = 0;
RDR_to_PC_DataBlock(SLOTERROR_CMD_NOT_SUPPORTED);
CCID_Send_Reply(&USBD_Device);
return SLOTERROR_CMD_NOT_SUPPORTED;
}
pbuf += off;
pbuf[0] = 0xEF;
return SC_XferBlock(pbuf, ret_len, &ret_len);
}
// prepare the apdu to be processed by the application
uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen, uint16_t* expectedLen) {
UNUSED(expectedLen);
// check for overflow
if (blockLen > IO_APDU_BUFFER_SIZE) {
return SLOTERROR_BAD_LENTGH;
}
// copy received apdu // if G_io_ccid_data_buffer is the buffer apdu, then the memmove will do nothing
os_memmove(G_io_apdu_buffer, ptrBlock, blockLen);
G_io_apdu_length = blockLen;
G_io_apdu_media = IO_APDU_MEDIA_USB_CCID; // for application code
G_io_apdu_state = APDU_USB_CCID; // for next call to io_exchange
return SLOT_NO_ERROR;
}
void io_usb_ccid_reply(unsigned char* buffer, unsigned short length) {
// avoid memory overflow
if (length > IO_CCID_DATA_BUFFER_SIZE) {
THROW(EXCEPTION_IO_OVERFLOW);
}
// copy the responde apdu
os_memmove(G_io_ccid_data_buffer, buffer, length);
G_io_ccid.bulk_header.bulkin.dwLength = length;
// forge reply
RDR_to_PC_DataBlock(SLOT_NO_ERROR);
// start sending rpely
CCID_Send_Reply(&USBD_Device);
}
// ask for power on
void io_usb_ccid_set_card_inserted(unsigned int inserted) {
G_io_ccid.ccid_card_inserted = inserted;
CCID_UpdSlotChange(1);
#ifdef HAVE_CCID_INTERRUPT
CCID_IntMessage(&USBD_Device);
#endif // HAVE_CCID_INTERRUPT
}
#endif // HAVE_USB_CLASS_CCID
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -44,8 +44,11 @@
*
******************************************************************************
*/
#pragma message "Override SDK source file :" __FILE__
#include "os.h"
/* Includes ------------------------------------------------------------------*/
#include "usbd_hid.h"