diff --git a/Makefile b/Makefile index af12712..219c2c3 100644 --- a/Makefile +++ b/Makefile @@ -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) @@ -81,7 +74,7 @@ DEFINES += HAVE_USB_CLASS_CCID CC := $(CLANGPATH)clang #CFLAGS += -O0 -gdwarf-2 -gstrict-dwarf -CFLAGS += -O3 -Os +CFLAGS += -O3 -Os #CFLAGS += -fno-jump-tables -fno-lookup-tables -fsave-optimization-record #$(info $(CFLAGS)) @@ -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 diff --git a/Makefile.rules b/Makefile.rules new file mode 100644 index 0000000..7c2d312 --- /dev/null +++ b/Makefile.rules @@ -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 \ No newline at end of file diff --git a/doc/user/blue-app-openpgp-card.pdf b/doc/user/blue-app-openpgp-card.pdf index d7e603f..da6874f 100644 Binary files a/doc/user/blue-app-openpgp-card.pdf and b/doc/user/blue-app-openpgp-card.pdf differ diff --git a/doc/user/blue-app-openpgp-card.rst b/doc/user/blue-app-openpgp-card.rst index 52cf5b8..cbbbb9e 100644 --- a/doc/user/blue-app-openpgp-card.rst +++ b/doc/user/blue-app-openpgp-card.rst @@ -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 " /bye + gpg-connect-agent "SCD SETATTR KEY-ATTR --force 2 18 " /bye + gpg-connect-agent "SCD SETATTR KEY-ATTR --force 3 " /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 ~~~~~ diff --git a/src/gpg_api.h b/src/gpg_api.h index 6886c16..378fd01 100644 --- a/src/gpg_api.h +++ b/src/gpg_api.h @@ -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); diff --git a/src/gpg_data.c b/src/gpg_data.c index 65c7d1c..8273bf9 100644 --- a/src/gpg_data.c +++ b/src/gpg_data.c @@ -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)); diff --git a/src/gpg_gen.c b/src/gpg_gen.c index 33ecf72..22564f4 100644 --- a/src/gpg_gen.c +++ b/src/gpg_gen.c @@ -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); diff --git a/src/gpg_init.c b/src/gpg_init.c index 8bf7e20..07e4d85 100644 --- a/src/gpg_init.c +++ b/src/gpg_init.c @@ -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) ) { @@ -73,21 +115,87 @@ int gpg_oid2curve(unsigned char* oid, unsigned int len) { if ( (len == sizeof(C_OID_cv25519)) && (os_memcmp(oid, C_OID_cv25519, len)==0) ) { 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); + + } } diff --git a/src/gpg_pso.c b/src/gpg_pso.c index f4d77fb..8d1895c 100644 --- a/src/gpg_pso.c +++ b/src/gpg_pso.c @@ -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) { - THROW(SW_CONDITIONS_NOT_SATISFIED); - return SW_CONDITIONS_NOT_SATISFIED; - } + 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; + } 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)) { - ui_menu_uifconfirm_display(0); - return 0; + if (G_gpg_vstate.kslot->sig.UIF[0]) { + if ((G_gpg_vstate.UIF_flags)==0) { + ui_menu_uifconfirm_display(0); + return 0; + } + G_gpg_vstate.UIF_flags = 0; } - - case 0x8680: - if ((G_gpg_vstate.kslot->dec.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) { - ui_menu_uifconfirm_display(0); - return 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,9 +344,13 @@ int gpg_apdu_pso() { int gpg_apdu_internal_authenticate() { - if ((G_gpg_vstate.kslot->aut.UIF[0]) && ((G_gpg_vstate.UIF_flags)==0)) { - ui_menu_uifconfirm_display(0); - return 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) { diff --git a/src/gpg_types.h b/src/gpg_types.h index d34fc63..c98b766 100644 --- a/src/gpg_types.h +++ b/src/gpg_types.h @@ -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; + unsigned char rsa[4]; + 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; + 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 { - 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; - struct { - cx_ecfp_public_key_t public; - cx_ecfp_private_key_t private; - }ecfp256; + 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; + 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 { diff --git a/src/gpg_ux_msg.c b/src/gpg_ux_msg.c index e455438..c684890 100644 --- a/src/gpg_ux_msg.c +++ b/src/gpg_ux_msg.c @@ -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"; diff --git a/src/gpg_ux_msg.h b/src/gpg_ux_msg.h index 1090930..38847a6 100644 --- a/src/gpg_ux_msg.h +++ b/src/gpg_ux_msg.h @@ -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 diff --git a/src/gpg_ux_nanos.c b/src/gpg_ux_nanos.c index e909c4c..d9e1808 100644 --- a/src/gpg_ux_nanos.c +++ b/src/gpg_ux_nanos.c @@ -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; - sw = gpg_apdu_pso(); + 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); @@ -499,12 +506,17 @@ static unsigned int validate_pin() { #define LABEL_AUT "Authentication" #define LABEL_DEC "Decryption" -#define LABEL_RSA2048 "RSA 2048" -#define LABEL_RSA3072 "RSA 3072" -#define LABEL_RSA4096 "RSA 4096" -#define LABEL_NISTP256 "NIST P256" -#define LABEL_BPOOLR1 "Brainpool R1" -#define LABEL_Ed25519 "Ed25519" +#define LABEL_RSA2048 "RSA 2048" +#define LABEL_RSA3072 "RSA 3072" +#define LABEL_RSA4096 "RSA 4096" +#define LABEL_NISTP256 "NIST P256" +//#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[] = { {ui_menu_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0}, @@ -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: - if (G_gpg_vstate.ux_key == 2) { + //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: @@ -623,7 +655,7 @@ void ui_menu_tmpl_set_action(unsigned int value) { } break; - default: + default: err = TEMPLATE_TYPE; goto ERROR; } @@ -670,13 +702,18 @@ void ui_menu_tmpl_key_action(unsigned int value) { const ux_menu_entry_t ui_menu_tmpl_type[] = { - {NULL, ui_menu_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0}, - {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_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0}, - {ui_menu_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40}, + {NULL, ui_menu_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0}, + {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_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 diff --git a/src/gpg_ux_nanos.h b/src/gpg_ux_nanos.h index 499c86b..ba41bf4 100644 --- a/src/gpg_ux_nanos.h +++ b/src/gpg_ux_nanos.h @@ -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 \ No newline at end of file diff --git a/src/sdk/usbd_ccid_cmd.c b/src/sdk/usbd_ccid_cmd.c new file mode 100755 index 0000000..1558d3d --- /dev/null +++ b/src/sdk/usbd_ccid_cmd.c @@ -0,0 +1,1057 @@ +/** + ****************************************************************************** + * @file usbd_ccid_cmd.c + * @author MCD Application Team + * @version V1.0.1 + * @date 31-January-2014 + * @brief CCID Commands handling + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 "usbd_ccid_cmd.h" + +#ifdef HAVE_USB_CLASS_CCID + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +#define CCID_UpdateCommandStatus(cmd_status,icc_status)\ + G_io_ccid.bulk_header.bulkin.bStatus=(cmd_status|icc_status) + /* + The Above Macro can take any of following Values + #define BM_ICC_PRESENT_ACTIVE 0x00 + #define BM_ICC_PRESENT_INACTIVE 0x01 + #define BM_ICC_NO_ICC_PRESENT 0x02 + + #define BM_COMMAND_STATUS_OFFSET 0x06 + #define BM_COMMAND_STATUS_NO_ERROR 0x00 + #define BM_COMMAND_STATUS_FAILED (0x01 << BM_COMMAND_STATUS_OFFSET) + #define BM_COMMAND_STATUS_TIME_EXTN (0x02 << BM_COMMAND_STATUS_OFFSET) + */ + +/* Private function prototypes -----------------------------------------------*/ +static uint8_t CCID_CheckCommandParams (uint32_t param_type); + +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief PC_to_RDR_IccPowerOn + * PC_TO_RDR_ICCPOWERON message execution, apply voltage and get ATR + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_IccPowerOn(void) +{ + /* Apply the ICC VCC + Fills the Response buffer with ICC ATR + This Command is returned with RDR_to_PC_DataBlock(); + */ + + uint8_t voltage; + uint8_t sc_voltage = 0; + uint8_t error; + + G_io_ccid.bulk_header.bulkin.dwLength = 0; /* Reset Number of Bytes in abData */ + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_DWLENGTH | \ + CHK_PARAM_abRFU2 |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_ABORT ); + if (error != 0) + { + return error; + } + + /* Voltage that is applied to the ICC + 00h – Automatic Voltage Selection + 01h – 5.0 volts + 02h – 3.0 volts + 03h – 1.8 volts + */ + /* G_io_ccid.bulk_header.bulkout.bSpecific_0 Contains bPowerSelect */ + voltage = G_io_ccid.bulk_header.bulkout.bSpecific_0; + if (voltage >= VOLTAGE_SELECTION_1V8) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_POWERSELECT; /* The Voltage specified is out of Spec */ + } + + /* Correct Voltage Requested by the Host */ + if ((voltage == VOLTAGE_SELECTION_AUTOMATIC) || + (voltage == VOLTAGE_SELECTION_3V)) + { + /* voltage == 00 Voltage Automatic + voltage == 01 Voltage Automatic = 5.0V + voltage == 02 Voltage Automatic = 3V + voltage == 03 Voltage Automatic = 1.8V + */ + sc_voltage = SC_VOLTAGE_3V; + } + else if (voltage == VOLTAGE_SELECTION_5V) + { + sc_voltage = SC_VOLTAGE_5V; + } + + G_io_ccid.bulk_header.bulkin.dwLength = SC_AnswerToReset(sc_voltage, G_io_ccid_data_buffer); + + /* Check if the Card has come to Active State*/ + error = CCID_CheckCommandParams(CHK_ACTIVE_STATE); + if (error != 0) + { + /* Check if Voltage is not Automatic */ + if (voltage != 0) + { /* If Specific Voltage requested by Host i.e 3V or 5V*/ + return error; + } + else + {/* Automatic Voltage selection requested by Host */ + + if (sc_voltage != SC_VOLTAGE_5V) + { /* If voltage selected was Automatic and 5V is not yet tried */ + sc_voltage = SC_VOLTAGE_5V; + G_io_ccid.bulk_header.bulkin.dwLength = SC_AnswerToReset(sc_voltage, G_io_ccid_data_buffer); + + /* Check again the State */ + error = CCID_CheckCommandParams(CHK_ACTIVE_STATE); + if (error != 0) + return error; + + } + else + { /* Voltage requested from Host was 5V already*/ + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_INACTIVE); + return error; + } + } /* Voltage Selection was automatic */ + } /* If Active State */ + + /* ATR is received, No Error Condition Found */ + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + + return SLOT_NO_ERROR; +} + +/** + * @brief PC_to_RDR_IccPowerOff + * Icc VCC is switched Off + * @param None + * @retval uint8_t error: status of the command execution + */ +uint8_t PC_to_RDR_IccPowerOff(void) +{ + /* The response to this command message is the RDR_to_PC_SlotStatus + response message. */ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_abRFU3 |\ + CHK_PARAM_DWLENGTH ); + if (error != 0) + { + return error; + } + + /* Command is ok, Check for Card Presence */ + if (SC_Detect()) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR,BM_ICC_PRESENT_INACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR,BM_ICC_NO_ICC_PRESENT); + } + + /* Power OFF the card */ + SC_Poweroff(); + + return SLOT_NO_ERROR; +} + +/** + * @brief PC_to_RDR_GetSlotStatus + * Provides the Slot status to the host + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_GetSlotStatus(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_DWLENGTH |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU3 ); + if (error != 0) + { + return error; + } + + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR,BM_ICC_PRESENT_ACTIVE); + return SLOT_NO_ERROR; +} + + +/** + * @brief PC_to_RDR_XfrBlock + * Handles the Block transfer from Host. + * Response to this command message is the RDR_to_PC_DataBlock + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_XfrBlock(void) +{ + uint16_t expectedLength, reqlen; + + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU3 |\ + CHK_PARAM_ABORT |\ + CHK_ACTIVE_STATE ); + if (error != 0) + return error; + + if (G_io_ccid.bulk_header.bulkout.dwLength > IO_CCID_DATA_BUFFER_SIZE) + { /* Check amount of Data Sent by Host is > than memory allocated ? */ + + return SLOTERROR_BAD_DWLENGTH; + } + + + /* wLevelParameter = Size of expected data to be returned by the + bulk-IN endpoint */ + expectedLength = (G_io_ccid.bulk_header.bulkout.bSpecific_2 << 8) | + G_io_ccid.bulk_header.bulkout.bSpecific_1; + + reqlen = G_io_ccid.bulk_header.bulkout.dwLength; + + G_io_ccid.bulk_header.bulkin.dwLength = (uint16_t)expectedLength; + + + error = SC_XferBlock(&G_io_ccid_data_buffer[0], + reqlen, + &expectedLength); + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + error = SLOT_NO_ERROR; + } + + return error; +} + + +/** + * @brief PC_to_RDR_GetParameters + * Provides the ICC parameters to the host + * Response to this command message is the RDR_to_PC_Parameters + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_GetParameters(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_DWLENGTH |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU3 ); + if (error != 0) + return error; + + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + + return SLOT_NO_ERROR; +} + + +/** + * @brief PC_to_RDR_ResetParameters + * Set the ICC parameters to the default + * Response to this command message is the RDR_to_PC_Parameters + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_ResetParameters(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_DWLENGTH |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU3 |\ + CHK_ACTIVE_STATE); + if (error != 0) + return error; + + /* This command resets the slot parameters to their default values */ + G_io_ccid.Protocol0_DataStructure.bmFindexDindex = DEFAULT_FIDI; + G_io_ccid.Protocol0_DataStructure.bmTCCKST0 = DEFAULT_T01CONVCHECKSUM; + G_io_ccid.Protocol0_DataStructure.bGuardTimeT0 = DEFAULT_EXTRA_GUARDTIME; + G_io_ccid.Protocol0_DataStructure.bWaitingIntegerT0 = DEFAULT_WAITINGINTEGER; + G_io_ccid.Protocol0_DataStructure.bClockStop = DEFAULT_CLOCKSTOP; + + error = SC_SetParams(&G_io_ccid.Protocol0_DataStructure); + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + error = SLOT_NO_ERROR; + } + + return error; +} + + +/** + * @brief PC_to_RDR_SetParameters + * Set the ICC parameters to the host defined parameters + * Response to this command message is the RDR_to_PC_Parameters + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_SetParameters(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU2 |\ + CHK_ACTIVE_STATE); + if (error != 0) + return error; + + error = SLOT_NO_ERROR; + + /* for Protocol T=0 (bProtocolNum=0) (dwLength=00000005h) */ + if ( (G_io_ccid.bulk_header.bulkout.dwLength == 5) && + (G_io_ccid.bulk_header.bulkout.bSpecific_0 != 0)) + error = SLOTERROR_BAD_PROTOCOLNUM; + + /* for Protocol T=1 (bProtocolNum=1) (dwLength=00000007h) */ + if ( (G_io_ccid.bulk_header.bulkout.dwLength == 7) && + (G_io_ccid.bulk_header.bulkout.bSpecific_0 != 1)) + error = SLOTERROR_CMD_NOT_SUPPORTED; + + /* For T0, Waiting Integer 0 supported */ + if (G_io_ccid_data_buffer[3] != 0) + error = SLOTERROR_BAD_WAITINGINTEGER; + + if (G_io_ccid_data_buffer[4] != DEFAULT_CLOCKSTOP) + error = SLOTERROR_BAD_CLOCKSTOP; + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + + os_memmove(&G_io_ccid.Protocol0_DataStructure, (Protocol0_DataStructure_t*)(&(G_io_ccid_data_buffer[0])), sizeof(Protocol0_DataStructure_t)); + error = SC_SetParams(&G_io_ccid.Protocol0_DataStructure); + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + error = SLOT_NO_ERROR; + } + + return error; +} + + +/** + * @brief PC_to_RDR_Escape + * Execute the Escape command. This is user specific Implementation + * Response to this command message is the RDR_to_PC_Escape + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_Escape(void) +{ + uint8_t error; + uint16_t size; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU3 |\ + CHK_PARAM_ABORT |\ + CHK_ACTIVE_STATE); + + if (error != 0) + return error; + + error = SC_ExecuteEscape(&G_io_ccid_data_buffer[0], + G_io_ccid.bulk_header.bulkout.dwLength, + &G_io_ccid_data_buffer[0], + &size); + + G_io_ccid.bulk_header.bulkin.dwLength = size; + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + } + + return error; +} + + +/** + * @brief PC_to_RDR_IccClock + * Execute the Clock specific command from host + * Response to this command message is the RDR_to_PC_SlotStatus + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_IccClock(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU2 |\ + CHK_PARAM_DWLENGTH|\ + CHK_ACTIVE_STATE); + if (error != 0) + return error; + + /* bClockCommand • 00h restarts Clock + • 01h Stops Clock in the state shown in the bClockStop + field of the PC_to_RDR_SetParameters command + and RDR_to_PC_Parameters message.*/ + if (G_io_ccid.bulk_header.bulkout.bSpecific_0 > 1) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_CLOCKCOMMAND; + } + + error = SC_SetClock(G_io_ccid.bulk_header.bulkout.bSpecific_0); + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + } + + return error; +} + + +/** + * @brief PC_to_RDR_Abort + * Execute the Abort command from host, This stops all Bulk transfers + * from host and ICC + * Response to this command message is the RDR_to_PC_SlotStatus + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_to_RDR_Abort(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_abRFU3 |\ + CHK_PARAM_DWLENGTH); + if (error != 0) + return error; + + CCID_CmdAbort (G_io_ccid.bulk_header.bulkout.bSlot, G_io_ccid.bulk_header.bulkout.bSeq); + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR,BM_ICC_PRESENT_ACTIVE); + return SLOT_NO_ERROR; +} + +/** + * @brief CCID_CmdAbort + * Execute the Abort command from Bulk EP or from Control EP, + * This stops all Bulk transfers from host and ICC + * @param uint8_t slot: slot number that host wants to abort + * @param uint8_t seq : Seq number for PC_to_RDR_Abort + * @retval uint8_t status of the command execution + */ +uint8_t CCID_CmdAbort(uint8_t slot, uint8_t seq) +{ + /* This function is called for REQUEST_ABORT & PC_to_RDR_Abort */ + + if (slot >= CCID_NUMBER_OF_SLOTS) + { /* This error condition is possible only from CLASS_REQUEST, otherwise + Slot is already checked in parameters from PC_to_RDR_Abort request */ + /* Slot requested is more than supported by Firmware */ + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_NO_ICC_PRESENT); + return SLOTERROR_BAD_SLOT; + } + + if ( G_io_ccid.usb_ccid_param.bAbortRequestFlag == 1) + { /* Abort Command was already received from ClassReq or PC_to_RDR */ + if (( G_io_ccid.usb_ccid_param.bSeq == seq) && (G_io_ccid.usb_ccid_param.bSlot == slot)) + { + /* CLASS Specific request is already Received, Reset the abort flag */ + G_io_ccid.usb_ccid_param.bAbortRequestFlag = 0; + } + } + else + { + /* Abort Command was NOT received from ClassReq or PC_to_RDR, + so save them for next ABORT command to verify */ + G_io_ccid.usb_ccid_param.bAbortRequestFlag = 1; + G_io_ccid.usb_ccid_param.bSeq = seq ; + G_io_ccid.usb_ccid_param.bSlot = slot; + } + + return 0; +} + +/** + * @brief PC_TO_RDR_T0Apdu + * Execute the PC_TO_RDR_T0APDU command from host + * Response to this command message is the RDR_to_PC_SlotStatus + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_TO_RDR_T0Apdu(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_DWLENGTH | + CHK_PARAM_ABORT ); + if (error != 0) + return error; + + if (G_io_ccid.bulk_header.bulkout.bSpecific_0 > 0x03) + {/* Bit 0 is associated with field bClassGetResponse + Bit 1 is associated with field bClassEnvelope + Other bits are RFU.*/ + + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_BMCHANGES; + } + + error = SC_T0Apdu(G_io_ccid.bulk_header.bulkout.bSpecific_0, + G_io_ccid.bulk_header.bulkout.bSpecific_1, + G_io_ccid.bulk_header.bulkout.bSpecific_2); + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + } + + return error; +} + +/** + * @brief PC_TO_RDR_Mechanical + * Execute the PC_TO_RDR_MECHANICAL command from host + * Response to this command message is the RDR_to_PC_SlotStatus + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_TO_RDR_Mechanical(void) +{ + uint8_t error; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU2 |\ + CHK_PARAM_DWLENGTH + ); + if (error != 0) + return error; + + if (G_io_ccid.bulk_header.bulkout.bSpecific_0 > 0x05) + {/* 01h – Accept Card + 02h – Eject Card + 03h – Capture Card + 04h – Lock Card + 05h – Unlock Card*/ + + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_BFUNCTION_MECHANICAL; + } + + error = SC_Mechanical(G_io_ccid.bulk_header.bulkout.bSpecific_0); + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + } + + return error; +} + +/** + * @brief PC_TO_RDR_SetDataRateAndClockFrequency + * Set the required Card Frequency and Data rate from the host. + * Response to this command message is the + * RDR_to_PC_DataRateAndClockFrequency + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_TO_RDR_SetDataRateAndClockFrequency(void) +{ + uint8_t error; + uint32_t clockFrequency; + uint32_t dataRate; + uint32_t temp =0; + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_abRFU3); + if (error != 0) + return error; + + if (G_io_ccid.bulk_header.bulkout.dwLength != 0x08) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_LENTGH; + } + + /* HERE we avoiding to an unaligned memory access*/ + clockFrequency = U4LE(G_io_ccid_data_buffer, 0); + dataRate = U4LE(G_io_ccid_data_buffer, 4); + + error = SC_SetDataRateAndClockFrequency(clockFrequency, dataRate); + G_io_ccid.bulk_header.bulkin.bError = error; + + if (error != SLOT_NO_ERROR) + { + G_io_ccid.bulk_header.bulkin.dwLength = 0; + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + G_io_ccid.bulk_header.bulkin.dwLength = 8; + + (G_io_ccid_data_buffer[0]) = clockFrequency & 0x000000FF ; + (G_io_ccid_data_buffer[1]) = (clockFrequency & 0x0000FF00) >> 8; + (G_io_ccid_data_buffer[2]) = (clockFrequency & 0x00FF0000) >> 16; + (G_io_ccid_data_buffer[3]) = (clockFrequency & 0xFF000000) >> 24; + (G_io_ccid_data_buffer[4]) = dataRate & 0x000000FF ; + (G_io_ccid_data_buffer[5]) = (dataRate & 0x0000FF00) >> 8; + (G_io_ccid_data_buffer[6]) = (dataRate & 0x00FF0000) >> 16; + (G_io_ccid_data_buffer[7]) = (dataRate & 0xFF000000) >> 24; + + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + } + + return error; +} + +/** + * @brief PC_TO_RDR_Secure + * Execute the Secure Command from the host. + * Response to this command message is the RDR_to_PC_DataBlock + * @param None + * @retval uint8_t status of the command execution + */ +uint8_t PC_TO_RDR_Secure(void) +{ + uint8_t error; + uint8_t bBWI; + uint16_t wLevelParameter; + uint32_t responseLen; + + + error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ + CHK_PARAM_CARD_PRESENT |\ + CHK_PARAM_ABORT ); + + if (error != 0) { + G_io_ccid.bulk_header.bulkin.dwLength = 0; + return error; + } + + bBWI = G_io_ccid.bulk_header.bulkout.bSpecific_0; + wLevelParameter = (G_io_ccid.bulk_header.bulkout.bSpecific_1 + ((uint16_t)G_io_ccid.bulk_header.bulkout.bSpecific_2<<8)); + + if ((EXCHANGE_LEVEL_FEATURE == TPDU_EXCHANGE) || + (EXCHANGE_LEVEL_FEATURE == SHORT_APDU_EXCHANGE)) + { + /* TPDU level & short APDU level, wLevelParameter is RFU, = 0000h */ + if (wLevelParameter != 0 ) + { + G_io_ccid.bulk_header.bulkin.dwLength = 0; + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + error = SLOTERROR_BAD_LEVELPARAMETER; + return error; + } + } + + error = SC_Secure(G_io_ccid.bulk_header.bulkout.dwLength - CCID_HEADER_SIZE, bBWI, wLevelParameter, + &G_io_ccid_data_buffer[0], &responseLen); + + G_io_ccid.bulk_header.bulkin.dwLength = responseLen; + + if (error != SLOT_NO_ERROR) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); + } + else + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_NO_ERROR, BM_ICC_PRESENT_ACTIVE); + } + + return error; +} + +/******************************************************************************/ +/* BULK IN ROUTINES */ +/******************************************************************************/ + +/** + * @brief RDR_to_PC_DataBlock + * Provide the data block response to the host + * Response for PC_to_RDR_IccPowerOn, PC_to_RDR_XfrBlock + * @param uint8_t errorCode: code to be returned to the host + * @retval None + */ +void RDR_to_PC_DataBlock(uint8_t errorCode) +{ + G_io_ccid.bulk_header.bulkin.bMessageType = RDR_TO_PC_DATABLOCK; + G_io_ccid.bulk_header.bulkin.bError = errorCode; + G_io_ccid.bulk_header.bulkin.bSpecific=0; /* bChainParameter */ + + /* void the Length Specified in Command */ + if(errorCode != SLOT_NO_ERROR) + { + G_io_ccid.bulk_header.bulkin.dwLength = 0; + } + + Transfer_Data_Request(); + +} + + +/** + * @brief RDR_to_PC_SlotStatus + * Provide the Slot status response to the host + * Response for PC_to_RDR_IccPowerOff + * PC_to_RDR_GetSlotStatus + * PC_to_RDR_IccClock + * PC_to_RDR_T0APDU + * PC_to_RDR_Mechanical + * Also the device sends this response message when it has completed + * aborting a slot after receiving both the Class Specific ABORT request + * and PC_to_RDR_Abort command message. + * @param uint8_t errorCode: code to be returned to the host + * @retval None + */ +void RDR_to_PC_SlotStatus(uint8_t errorCode) +{ + + G_io_ccid.bulk_header.bulkin.bMessageType = RDR_TO_PC_SLOTSTATUS; + G_io_ccid.bulk_header.bulkin.dwLength =0; + G_io_ccid.bulk_header.bulkin.bError = errorCode; + G_io_ccid.bulk_header.bulkin.bSpecific=0; /* bClockStatus = 00h Clock running + 01h Clock stopped in state L + 02h Clock stopped in state H + 03h Clock stopped in an unknown state + All other values are RFU. */ + + Transfer_Data_Request(); + +} + +/** + * @brief RDR_to_PC_Parameters + * Provide the data block response to the host + * Response for PC_to_RDR_GetParameters, PC_to_RDR_ResetParameters + * PC_to_RDR_SetParameters + * @param uint8_t errorCode: code to be returned to the host + * @retval None + */ +void RDR_to_PC_Parameters(uint8_t errorCode) +{ + + G_io_ccid.bulk_header.bulkin.bMessageType = RDR_TO_PC_PARAMETERS; + G_io_ccid.bulk_header.bulkin.bError = errorCode; + + if(errorCode == SLOT_NO_ERROR) + { + G_io_ccid.bulk_header.bulkin.dwLength = LEN_PROTOCOL_STRUCT_T0; + } + else + { + G_io_ccid.bulk_header.bulkin.dwLength = 0; + } + + os_memmove(G_io_ccid_data_buffer, &G_io_ccid.Protocol0_DataStructure, sizeof(G_io_ccid.Protocol0_DataStructure)); + + /* bProtocolNum */ + G_io_ccid.bulk_header.bulkin.bSpecific = BPROTOCOL_NUM_T0; + + Transfer_Data_Request(); +} + +/** + * @brief RDR_to_PC_Escape + * Provide the Escaped data block response to the host + * Response for PC_to_RDR_Escape + * @param uint8_t errorCode: code to be returned to the host + * @retval None + */ +void RDR_to_PC_Escape(uint8_t errorCode) +{ + G_io_ccid.bulk_header.bulkin.bMessageType = RDR_TO_PC_ESCAPE; + + G_io_ccid.bulk_header.bulkin.bSpecific=0; /* Reserved for Future Use */ + G_io_ccid.bulk_header.bulkin.bError = errorCode; + + /* void the Length Specified in Command */ + if(errorCode != SLOT_NO_ERROR) + { + G_io_ccid.bulk_header.bulkin.dwLength = 0; + } + + Transfer_Data_Request(); +} + + + +/** + * @brief RDR_to_PC_DataRateAndClockFrequency + * Provide the Clock and Data Rate information to host + * Response for PC_TO_RDR_SetDataRateAndClockFrequency + * @param uint8_t errorCode: code to be returned to the host + * @retval None + */ +void RDR_to_PC_DataRateAndClockFrequency(uint8_t errorCode) +{ + /* + uint16_t length = CCID_RESPONSE_HEADER_SIZE; + */ + + G_io_ccid.bulk_header.bulkin.bMessageType = RDR_TO_PC_DATARATEANDCLOCKFREQUENCY; + G_io_ccid.bulk_header.bulkin.bError = errorCode; + G_io_ccid.bulk_header.bulkin.bSpecific=0; /* Reserved for Future Use */ + + /* void the Length Specified in Command */ + if(errorCode != SLOT_NO_ERROR) + { + G_io_ccid.bulk_header.bulkin.dwLength = 0; + } + + Transfer_Data_Request(); +} + +#ifdef HAVE_CCID_INTERRUPT +/** + * @brief RDR_to_PC_NotifySlotChange + * Interrupt message to be sent to the host, Checks the card presence + * status and update the buffer accordingly + * @param None + * @retval None + */ +void RDR_to_PC_NotifySlotChange(void) +{ + G_io_ccid.UsbIntMessageBuffer[OFFSET_INT_BMESSAGETYPE] = RDR_TO_PC_NOTIFYSLOTCHANGE; + + if (SC_Detect() ) + { + /* + SLOT_ICC_PRESENT 0x01 : LSb : (0b = no ICC present, 1b = ICC present) + SLOT_ICC_CHANGE 0x02 : MSb : (0b = no change, 1b = change). + */ + G_io_ccid.UsbIntMessageBuffer[OFFSET_INT_BMSLOTICCSTATE] = SLOT_ICC_PRESENT | + SLOT_ICC_CHANGE; + } + else + { + G_io_ccid.UsbIntMessageBuffer[OFFSET_INT_BMSLOTICCSTATE] = SLOT_ICC_CHANGE; + + /* Power OFF the card */ + SC_Poweroff(); + } +} +#endif // HAVE_CCID_INTERRUPT + + +/** + * @brief CCID_UpdSlotStatus + * Updates the variable for the slot status + * @param uint8_t slotStatus : slot status from the calling function + * @retval None + */ +void CCID_UpdSlotStatus (uint8_t slotStatus) +{ + G_io_ccid.Ccid_SlotStatus.SlotStatus = slotStatus; +} + +/** + * @brief CCID_UpdSlotChange + * Updates the variable for the slot change status + * @param uint8_t changeStatus : slot change status from the calling function + * @retval None + */ +void CCID_UpdSlotChange (uint8_t changeStatus) +{ + G_io_ccid.Ccid_SlotStatus.SlotStatusChange = changeStatus; +} + +/** + * @brief CCID_IsSlotStatusChange + * Provides the value of the variable for the slot change status + * @param None + * @retval uint8_t slot change status + */ +uint8_t CCID_IsSlotStatusChange (void) +{ + return G_io_ccid.Ccid_SlotStatus.SlotStatusChange; +} + +/** + * @brief CCID_CheckCommandParams + * Checks the specific parameters requested by the function and update + * status accordingly. This function is called from all + * PC_to_RDR functions + * @param uint32_t param_type : Parameter enum to be checked by calling function + * @retval uint8_t status + */ +static uint8_t CCID_CheckCommandParams (uint32_t param_type) +{ + uint32_t parameter; + + G_io_ccid.bulk_header.bulkin.bStatus = BM_ICC_PRESENT_ACTIVE | BM_COMMAND_STATUS_NO_ERROR ; + + parameter = (uint32_t)param_type; + + if (parameter & CHK_PARAM_SLOT) + { + /* + The slot number (bSlot) identifies which ICC slot is being addressed + by the message, if the CCID supports multiple slots. + The slot number is zero-relative, and is in the range of zero to FFh. + */ + + /* SLOT Number is 0 onwards, so always < CCID_NUMBER_OF_SLOTs */ + /* Error Condition !!! */ + if (G_io_ccid.bulk_header.bulkout.bSlot >= CCID_NUMBER_OF_SLOTS) + { /* Slot requested is more than supported by Firmware */ + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_NO_ICC_PRESENT); + return SLOTERROR_BAD_SLOT; + } + } + + if (parameter & CHK_PARAM_CARD_PRESENT) + { + /* Commands Parameters ok, Check the Card Status */ + if (SC_Detect() == 0) + { /* Card is Not detected */ + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_NO_ICC_PRESENT); + return SLOTERROR_ICC_MUTE; + } + } + + /* Check that DwLength is 0 */ + if (parameter & CHK_PARAM_DWLENGTH) + { + if (G_io_ccid.bulk_header.bulkout.dwLength != 0) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_LENTGH; + } + } + + /* abRFU 2 : Reserved for Future Use*/ + if (parameter & CHK_PARAM_abRFU2) + { + + if ((G_io_ccid.bulk_header.bulkout.bSpecific_1 != 0) || + (G_io_ccid.bulk_header.bulkout.bSpecific_2 != 0)) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_ABRFU_2B; /* bSpecific_1 */ + } + } + + if (parameter & CHK_PARAM_abRFU3) + { + /* abRFU 3 : Reserved for Future Use*/ + if ((G_io_ccid.bulk_header.bulkout.bSpecific_0 != 0) || + (G_io_ccid.bulk_header.bulkout.bSpecific_1 != 0) || + (G_io_ccid.bulk_header.bulkout.bSpecific_2 != 0)) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_PRESENT_ACTIVE); + return SLOTERROR_BAD_ABRFU_3B; + } + } + + + if (parameter & CHK_PARAM_ABORT) + { + if( G_io_ccid.usb_ccid_param.bAbortRequestFlag ) + { + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_PRESENT_INACTIVE); + return SLOTERROR_CMD_ABORTED; + } + } + + if (parameter & CHK_ACTIVE_STATE) + { + /* Commands Parameters ok, Check the Card Status */ + /* Card is detected */ + if (! SC_Detect()) + { + /* Check that from Lower Layers, the SmartCard come to known state */ + CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED,BM_ICC_PRESENT_INACTIVE); + return SLOTERROR_HW_ERROR; + } + } + + return 0; +} + +#endif // HAVE_USB_CLASS_CCID + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/sdk/usbd_ccid_if.c b/src/sdk/usbd_ccid_if.c new file mode 100755 index 0000000..a709032 --- /dev/null +++ b/src/sdk/usbd_ccid_if.c @@ -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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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****/ diff --git a/src/lib_stusb_impl/usbd_ccid_impl.h b/src/sdk/usbd_ccid_impl.h similarity index 100% rename from src/lib_stusb_impl/usbd_ccid_impl.h rename to src/sdk/usbd_ccid_impl.h diff --git a/src/lib_stusb_impl/usbd_hid_impl.h b/src/sdk/usbd_hid_impl.h similarity index 100% rename from src/lib_stusb_impl/usbd_hid_impl.h rename to src/sdk/usbd_hid_impl.h diff --git a/src/lib_stusb_impl/usbd_impl.c b/src/sdk/usbd_impl.c similarity index 96% rename from src/lib_stusb_impl/usbd_impl.c rename to src/sdk/usbd_impl.c index 212e3b8..9c82900 100644 --- a/src/lib_stusb_impl/usbd_impl.c +++ b/src/sdk/usbd_impl.c @@ -44,8 +44,11 @@ * ****************************************************************************** */ +#pragma message "Override SDK source file :" __FILE__ + #include "os.h" + /* Includes ------------------------------------------------------------------*/ #include "usbd_hid.h" diff --git a/src/lib_stusb_impl/usbd_impl.h b/src/sdk/usbd_impl.h similarity index 100% rename from src/lib_stusb_impl/usbd_impl.h rename to src/sdk/usbd_impl.h