Compare commits
32 commits
Author | SHA1 | Date | |
---|---|---|---|
1e23cb6425 | |||
27cd81de7a | |||
![]() |
c07cb00cb6 | ||
![]() |
dfbfb893ef | ||
![]() |
281ea42cbb | ||
![]() |
a0d537dcec | ||
![]() |
b71d2d02d7 | ||
![]() |
81090d3f23 | ||
![]() |
e6026d5809 | ||
![]() |
2c06e06261 | ||
![]() |
92cdb83293 | ||
![]() |
4fb1610360 | ||
![]() |
8c83524536 | ||
![]() |
783cf580ab | ||
![]() |
77548b1ddd | ||
![]() |
cf6e295e47 | ||
![]() |
38e143d248 | ||
![]() |
f15451f62a | ||
![]() |
a1c8e7766c | ||
![]() |
582928a16d | ||
![]() |
b049197c02 | ||
![]() |
9fffb46d87 | ||
![]() |
e80bea28b2 | ||
![]() |
8e992a5c63 | ||
![]() |
bb745c7cdb | ||
![]() |
d067dcb144 | ||
![]() |
fcf12c5c3f | ||
![]() |
3f4da471c4 | ||
![]() |
f8522808b6 | ||
![]() |
4733d6f8ba | ||
![]() |
2f273469fa | ||
![]() |
8f1811313d |
65
Makefile
|
@ -1,59 +1,82 @@
|
||||||
# Copyright 2017 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
|
#*******************************************************************************
|
||||||
#
|
# Ledger App
|
||||||
|
# (c) 2016-2018 Ledger
|
||||||
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
#
|
#
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
#
|
#
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#*******************************************************************************
|
||||||
|
|
||||||
ifeq ($(BOLOS_SDK),)
|
ifeq ($(BOLOS_SDK),)
|
||||||
$(error Environment variable BOLOS_SDK is not set)
|
$(error Environment variable BOLOS_SDK is not set)
|
||||||
endif
|
endif
|
||||||
include $(BOLOS_SDK)/Makefile.defines
|
include $(BOLOS_SDK)/Makefile.defines
|
||||||
|
|
||||||
APPNAME = "OpenPGP"
|
APP_LOAD_PARAMS=--appFlags 0x40 --path "2152157255'" --curve secp256k1 $(COMMON_LOAD_PARAMS)
|
||||||
APP_LOAD_PARAMS=--appFlags 0x40 --path "2152157255" --curve secp256k1 $(COMMON_LOAD_PARAMS)
|
|
||||||
|
APPNAME = OpenPGP
|
||||||
|
|
||||||
|
SPECVERSION="3.3.1"
|
||||||
|
|
||||||
APPVERSION_M=1
|
APPVERSION_M=1
|
||||||
APPVERSION_N=0
|
APPVERSION_N=2
|
||||||
APPVERSION_P=RC7
|
APPVERSION_P=1
|
||||||
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
|
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
|
||||||
|
|
||||||
ICONNAME=icon_pgp.gif
|
ifeq ($(TARGET_NAME),TARGET_BLUE)
|
||||||
|
ICONNAME=images/icon_pgp_blue.gif
|
||||||
|
else
|
||||||
|
ICONNAME=images/icon_pgp.gif
|
||||||
|
endif
|
||||||
|
|
||||||
|
DEFINES += $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME) SPEC_VERSION=$(SPECVERSION)
|
||||||
|
|
||||||
################
|
################
|
||||||
# Default rule #
|
# Default rule #
|
||||||
################
|
################
|
||||||
|
|
||||||
all: default
|
all: default
|
||||||
|
|
||||||
############
|
############
|
||||||
# Platform #
|
# Platform #
|
||||||
############
|
############
|
||||||
|
#SCRIPT_LD := script.ld
|
||||||
|
|
||||||
|
ifneq ($(NO_CONSENT),)
|
||||||
|
DEFINES += NO_CONSENT
|
||||||
|
endif
|
||||||
|
|
||||||
|
DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300
|
||||||
|
DEFINES += HAVE_BAGL HAVE_SPRINTF
|
||||||
|
#DEFINES += HAVE_PRINTF PRINTF=screen_printf
|
||||||
|
DEFINES += PRINTF\(...\)=
|
||||||
|
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
||||||
|
#DEFINES += HAVE_BLE
|
||||||
|
DEFINES += UNUSED\(x\)=\(void\)x
|
||||||
|
DEFINES += APPVERSION=\"$(APPVERSION)\"
|
||||||
|
DEFINES += CUSTOM_IO_APDU_BUFFER_SIZE=\(255+5+64\)
|
||||||
|
|
||||||
DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=128
|
|
||||||
DEFINES += HAVE_BAGL HAVE_PRINTF HAVE_SPRINTF
|
|
||||||
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
|
||||||
DEFINES += HAVE_USB_CLASS_CCID
|
DEFINES += HAVE_USB_CLASS_CCID
|
||||||
|
|
||||||
DEFINES += $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME)
|
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# Compiler #
|
# Compiler #
|
||||||
##############
|
##############
|
||||||
#GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
|
#GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
|
||||||
#CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
|
#CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
|
||||||
CC := $(CLANGPATH)clang
|
CC := $(CLANGPATH)clang
|
||||||
|
|
||||||
#CFLAGS += -O0 -gdwarf-2 -gstrict-dwarf
|
#CFLAGS += -O0 -gdwarf-2 -gstrict-dwarf
|
||||||
CFLAGS += -O3 -Os
|
CFLAGS += -O3 -Os
|
||||||
|
#CFLAGS += -fno-jump-tables -fno-lookup-tables -fsave-optimization-record
|
||||||
|
#$(info $(CFLAGS))
|
||||||
|
|
||||||
AS := $(GCCPATH)arm-none-eabi-gcc
|
AS := $(GCCPATH)arm-none-eabi-gcc
|
||||||
|
|
||||||
|
@ -65,9 +88,9 @@ LDLIBS += -lm -lgcc -lc
|
||||||
# import rules to compile glyphs(/pone)
|
# import rules to compile glyphs(/pone)
|
||||||
include $(BOLOS_SDK)/Makefile.glyphs
|
include $(BOLOS_SDK)/Makefile.glyphs
|
||||||
|
|
||||||
### computed variables
|
### variables processed by the common makefile.rules of the SDK to grab source files and include dirs
|
||||||
APP_SOURCE_PATH += src
|
APP_SOURCE_PATH += src
|
||||||
SDK_SOURCE_PATH += lib_stusb lib_stusb_impl
|
SDK_SOURCE_PATH += lib_stusb
|
||||||
|
|
||||||
|
|
||||||
load: all
|
load: all
|
||||||
|
@ -77,8 +100,8 @@ delete:
|
||||||
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
|
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
|
||||||
|
|
||||||
# import generic rules from the sdk
|
# import generic rules from the sdk
|
||||||
include $(BOLOS_SDK)/Makefile.rules
|
include Makefile.rules
|
||||||
|
|
||||||
#add dependency on custom makefile filename
|
#add dependency on custom makefile filename
|
||||||
dep/%.d: %.c Makefile.genericwallet
|
dep/%.d: %.c Makefile
|
||||||
|
|
||||||
|
|
29
Makefile.rules
Normal 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
|
57
README.md
|
@ -11,64 +11,15 @@ The application supports:
|
||||||
- ECDH with secp256k1, secp256r1, brainpool 256r1, brainpool 256t1 and curve25519 curves
|
- ECDH with secp256k1, secp256r1, brainpool 256r1, brainpool 256t1 and curve25519 curves
|
||||||
|
|
||||||
|
|
||||||
This release is in beta stage with known missing parts (see also Add-on) :
|
This release has known missing parts (see also Add-on) :
|
||||||
|
|
||||||
* Ledger Blue support
|
* Ledger Blue support
|
||||||
* Seed mode ON/OFF via apdu
|
* Seed mode ON/OFF via apdu
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation and Usage
|
||||||
|
|
||||||
### NanoS
|
See the full doc at https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/user/blue-app-openpgp-card.pdf
|
||||||
|
|
||||||
For both, source and binary installation, use the 1RC7 tag.
|
|
||||||
|
|
||||||
#### From source
|
|
||||||
|
|
||||||
Building from sources requires the the Nano S SDK 1.3.1.4 on firmware 1.3.1. See
|
|
||||||
https://github.com/LedgerHQ/nanos-secure-sdk
|
|
||||||
|
|
||||||
The SDK must be slightly modified:
|
|
||||||
|
|
||||||
- replace lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c and - replace lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/usbd_ccid_if.h by the one provided in sdk/ directory
|
|
||||||
- edit script.ld and modify the stack size : STACK_SIZE = 832;
|
|
||||||
|
|
||||||
#### From Binary
|
|
||||||
|
|
||||||
Use the Chrome App "Ledger Manager". See https://www.ledgerwallet.com/apps/manager for details.
|
|
||||||
|
|
||||||
As "OpenPGP card" application is not fully released, click on "Show delevoppers items" on the bottom right corner.
|
|
||||||
|
|
||||||
### Host
|
|
||||||
|
|
||||||
#### Linux
|
|
||||||
|
|
||||||
You have to have to add the NanoS to /etc/libccid_Info.plist
|
|
||||||
|
|
||||||
In <key>ifdVendorID</key> add the entry <string>0x2C97</string>
|
|
||||||
In <key>ifdProductID</key> add the entry <string>0x0001</string>
|
|
||||||
In <key>ifdFriendlyName</key> add the entry <string>Ledger Token</string>
|
|
||||||
|
|
||||||
This 3 entries must be added at the end of each list.
|
|
||||||
|
|
||||||
#### MAC
|
|
||||||
|
|
||||||
1. First it is necessary to [disable SIP](https://developer.apple.com/library/mac/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html) That doesn't allow the editing of files in /usr/.
|
|
||||||
|
|
||||||
2. You have to have to add the NanoS to /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
|
|
||||||
|
|
||||||
|
|
||||||
In <key>ifdVendorID</key> add the entry <string>0x2C97</string>
|
|
||||||
In <key>ifdProductID</key> add the entry <string>0x0001</string>
|
|
||||||
In <key>ifdFriendlyName</key> add the entry <string>Ledger Token</string>
|
|
||||||
|
|
||||||
This 3 entries must be added at the end of each list.
|
|
||||||
|
|
||||||
3. [Enable SIP](https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html)
|
|
||||||
|
|
||||||
#### Windows
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
|
|
||||||
## Add-on
|
## Add-on
|
||||||
|
@ -79,7 +30,7 @@ The GnuPG application implements the following addon:
|
||||||
- 3 independent key slots
|
- 3 independent key slots
|
||||||
- seeded key generation
|
- seeded key generation
|
||||||
|
|
||||||
Technical specification is available in doc/gpgcard3.0-addon.rst
|
Technical specification is available at https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/developper/gpgcard3.0-addon.rst
|
||||||
|
|
||||||
|
|
||||||
### Key slot
|
### Key slot
|
||||||
|
|
BIN
doc/common/LogoLedgerV.png
Normal file
After Width: | Height: | Size: 15 KiB |
196
doc/developper/quick-test.txt
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
Step1: ...
|
||||||
|
-----
|
||||||
|
Jump into any temp dir
|
||||||
|
|
||||||
|
|
||||||
|
Step2: install nanos
|
||||||
|
-----
|
||||||
|
Do a fresh install of gpg application 1.1.0 from google app manager
|
||||||
|
|
||||||
|
|
||||||
|
Step3: setup conf
|
||||||
|
-----
|
||||||
|
Create a 'manual-test' directory
|
||||||
|
$ mkdir manual-test
|
||||||
|
|
||||||
|
Create a 'manual-test/gnupg'
|
||||||
|
$ mkdir manual-test/gnupg
|
||||||
|
|
||||||
|
Create a 'manual-test/gnupg/scdaemon.conf' file with content:
|
||||||
|
reader-port "Ledger Token [Nano S] (0001) 01 00"
|
||||||
|
allow-admin
|
||||||
|
card-timeout 1
|
||||||
|
debug-level expert
|
||||||
|
debug 11
|
||||||
|
log-file /tmp/scdaemon.log
|
||||||
|
|
||||||
|
Jump into manual-test dir
|
||||||
|
|
||||||
|
Step4: change to host pin style
|
||||||
|
-----
|
||||||
|
Launch gpg NanoS application and:
|
||||||
|
$ killall scdaemon gpg-agent
|
||||||
|
$ gpg2 --homedir `pwd`/gnupg --card-edit
|
||||||
|
gpg: WARNING: unsafe permissions on homedir '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg'
|
||||||
|
gpg: keybox '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg/pubring.kbx' created
|
||||||
|
|
||||||
|
Reader ...........: Ledger Token [Nano S] (0001) 01 00
|
||||||
|
Application ID ...: D2760001240103002C97DDD38BA90000
|
||||||
|
Version ..........: 3.0
|
||||||
|
Manufacturer .....: unknown
|
||||||
|
Serial number ....: DDD38BA9
|
||||||
|
Name of cardholder: [not set]
|
||||||
|
Language prefs ...: [not set]
|
||||||
|
Sex ..............: unspecified
|
||||||
|
URL of public key : [not set]
|
||||||
|
Login data .......: [not set]
|
||||||
|
Signature PIN ....: not forced
|
||||||
|
Key attributes ...: rsa2048 rsa2048 rsa2048
|
||||||
|
Max. PIN lengths .: 12 12 12
|
||||||
|
PIN retry counter : 3 0 3
|
||||||
|
Signature counter : 0
|
||||||
|
Signature key ....: [none]
|
||||||
|
Encryption key....: [none]
|
||||||
|
Authentication key: [none]
|
||||||
|
General key info..: [none]
|
||||||
|
|
||||||
|
gpg/card> verify
|
||||||
|
|
||||||
|
Reader ...........: Ledger Token [Nano S] (0001) 01 00
|
||||||
|
Application ID ...: D2760001240103002C97DDD38BA90000
|
||||||
|
Version ..........: 3.0
|
||||||
|
Manufacturer .....: unknown
|
||||||
|
Serial number ....: DDD38BA9
|
||||||
|
Name of cardholder: [not set]
|
||||||
|
Language prefs ...: [not set]
|
||||||
|
Sex ..............: unspecified
|
||||||
|
URL of public key : [not set]
|
||||||
|
Login data .......: [not set]
|
||||||
|
Signature PIN ....: not forced
|
||||||
|
Key attributes ...: rsa2048 rsa2048 rsa2048
|
||||||
|
Max. PIN lengths .: 12 12 12
|
||||||
|
PIN retry counter : 3 0 3
|
||||||
|
Signature counter : 0
|
||||||
|
Signature key ....: [none]
|
||||||
|
Encryption key....: [none]
|
||||||
|
Authentication key: [none]
|
||||||
|
General key info..: [none]
|
||||||
|
|
||||||
|
gpg/card>
|
||||||
|
|
||||||
|
Then on nanos, goto settings->PIN mode, and select 'Host'
|
||||||
|
Then on nanos, goto settings->PIN mode, and select 'Set as default'
|
||||||
|
|
||||||
|
unplug and replug the nanos
|
||||||
|
|
||||||
|
relaunch the openpgp application
|
||||||
|
|
||||||
|
Goto settings->PIN mode, and check you have "Host # +" (DASH and PLUS)
|
||||||
|
|
||||||
|
|
||||||
|
Step5: create 2048bits RSA keys
|
||||||
|
-----
|
||||||
|
|
||||||
|
|
||||||
|
In 'manual-test' directory, ask key generation. Nota that during this phase PIN has to be validate on Nanos
|
||||||
|
|
||||||
|
$ killall scdaemon gpg-agent
|
||||||
|
$ gpg2 --homedir `pwd`/gnupg --card-edit
|
||||||
|
gpg: WARNING: unsafe permissions on homedir '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg'
|
||||||
|
|
||||||
|
Reader ...........: Ledger Token [Nano S] (0001) 01 00
|
||||||
|
Application ID ...: D2760001240103002C97DDD38BA90000
|
||||||
|
Version ..........: 3.0
|
||||||
|
Manufacturer .....: unknown
|
||||||
|
Serial number ....: DDD38BA9
|
||||||
|
Name of cardholder: [not set]
|
||||||
|
Language prefs ...: [not set]
|
||||||
|
Sex ..............: unspecified
|
||||||
|
URL of public key : [not set]
|
||||||
|
Login data .......: [not set]
|
||||||
|
Signature PIN ....: not forced
|
||||||
|
Key attributes ...: rsa2048 rsa2048 rsa2048
|
||||||
|
Max. PIN lengths .: 12 12 12
|
||||||
|
PIN retry counter : 3 0 3
|
||||||
|
Signature counter : 0
|
||||||
|
Signature key ....: [none]
|
||||||
|
Encryption key....: [none]
|
||||||
|
Authentication key: [none]
|
||||||
|
General key info..: [none]
|
||||||
|
|
||||||
|
gpg/card> admin
|
||||||
|
Admin commands are allowed
|
||||||
|
|
||||||
|
gpg/card> generate
|
||||||
|
Make off-card backup of encryption key? (Y/n) n
|
||||||
|
|
||||||
|
Please note that the factory settings of the PINs are
|
||||||
|
PIN = '123456' Admin PIN = '12345678'
|
||||||
|
You should change them using the command --change-pin
|
||||||
|
|
||||||
|
What keysize do you want for the Signature key? (2048) 2048
|
||||||
|
What keysize do you want for the Encryption key? (2048) 2048
|
||||||
|
What keysize do you want for the Authentication key? (2048) 2048
|
||||||
|
Please specify how long the key should be valid.
|
||||||
|
0 = key does not expire
|
||||||
|
<n> = key expires in n days
|
||||||
|
<n>w = key expires in n weeks
|
||||||
|
<n>m = key expires in n months
|
||||||
|
<n>y = key expires in n years
|
||||||
|
Key is valid for? (0) 0
|
||||||
|
Key does not expire at all
|
||||||
|
Is this correct? (y/N) y
|
||||||
|
|
||||||
|
GnuPG needs to construct a user ID to identify your key.
|
||||||
|
|
||||||
|
Real name: testkey
|
||||||
|
Email address:
|
||||||
|
Comment:
|
||||||
|
You selected this USER-ID:
|
||||||
|
"testkey"
|
||||||
|
|
||||||
|
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
|
||||||
|
gpg: /home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg/trustdb.gpg: trustdb created
|
||||||
|
gpg: key 5ED17DF289C757A2 marked as ultimately trusted
|
||||||
|
gpg: directory '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg/openpgp-revocs.d' created
|
||||||
|
gpg: revocation certificate stored as '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg/openpgp-revocs.d/7FDC3D2FCD3558CB06631EAB5ED17DF289C757A2.rev'
|
||||||
|
public and secret key created and signed.
|
||||||
|
|
||||||
|
|
||||||
|
gpg/card> quit
|
||||||
|
pub rsa2048 2017-10-03 [SC]
|
||||||
|
7FDC3D2FCD3558CB06631EAB5ED17DF289C757A2
|
||||||
|
uid testkey
|
||||||
|
sub rsa2048 2017-10-03 [A]
|
||||||
|
sub rsa2047 2017-10-03 [E]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Step6: encrypt/decrypt
|
||||||
|
-----
|
||||||
|
encrypt
|
||||||
|
|
||||||
|
$ killall scdaemon gpg-agent
|
||||||
|
$ echo CLEAR > foo.txt
|
||||||
|
$ gpg2 --homedir `pwd`/gnupg -e -r testkey foo.txt
|
||||||
|
gpg: WARNING: unsafe permissions on homedir '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg'
|
||||||
|
gpg: checking the trustdb
|
||||||
|
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
|
||||||
|
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
|
||||||
|
|
||||||
|
Force pin to asked
|
||||||
|
|
||||||
|
$ killall gpg-agent scdaemon
|
||||||
|
|
||||||
|
decrypt
|
||||||
|
|
||||||
|
$ gpg2 --homedir `pwd`/gnupg foo.txt.gpg
|
||||||
|
gpg: WARNING: unsafe permissions on homedir '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg'
|
||||||
|
gpg: encrypted with 2047-bit RSA key, ID 602FE5EB7BFA4B00, created 2017-10-03
|
||||||
|
"testkey"
|
||||||
|
File 'foo.txt' exists. Overwrite? (y/N) y
|
||||||
|
|
||||||
|
Step7: pin on screen
|
||||||
|
------
|
||||||
|
|
||||||
|
Restart from Step1, but skip step4
|
BIN
doc/user/blue-app-openpgp-card.pdf
Normal file
1125
doc/user/blue-app-openpgp-card.rst
Normal file
275
doc/user/blue-app-openpgp-card.template
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(papersize)$$papersize$paper,$endif$$for(classoption)$$classoption$$sep$,$endfor$,towside]{report}
|
||||||
|
$if(fontfamily)$
|
||||||
|
\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
|
||||||
|
$else$
|
||||||
|
\usepackage{lmodern}
|
||||||
|
$endif$
|
||||||
|
$if(linestretch)$
|
||||||
|
\usepackage{setspace}
|
||||||
|
\setstretch{$linestretch$}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
\usepackage{amssymb,amsmath}
|
||||||
|
\usepackage{ifxetex,ifluatex}
|
||||||
|
\usepackage{fixltx2e} % provides \textsubscript
|
||||||
|
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
|
||||||
|
\usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
$if(euro)$
|
||||||
|
\usepackage{eurosym}
|
||||||
|
$endif$
|
||||||
|
\else % if luatex or xelatex
|
||||||
|
\ifxetex
|
||||||
|
\usepackage{mathspec}
|
||||||
|
\else
|
||||||
|
\usepackage{fontspec}
|
||||||
|
\fi
|
||||||
|
\defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
|
||||||
|
$for(fontfamilies)$
|
||||||
|
\newfontfamily{$fontfamilies.name$}[$fontfamilies.options$]{$fontfamilies.font$}
|
||||||
|
$endfor$
|
||||||
|
$if(euro)$
|
||||||
|
\newcommand{\euro}{€}
|
||||||
|
$endif$
|
||||||
|
$if(mainfont)$
|
||||||
|
\setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
|
||||||
|
$endif$
|
||||||
|
$if(sansfont)$
|
||||||
|
\setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
|
||||||
|
$endif$
|
||||||
|
$if(monofont)$
|
||||||
|
\setmonofont[Mapping=tex-ansi$if(monofontoptions)$,$for(monofontoptions)$$monofontoptions$$sep$,$endfor$$endif$]{$monofont$}
|
||||||
|
$endif$
|
||||||
|
$if(mathfont)$
|
||||||
|
\setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
|
||||||
|
$endif$
|
||||||
|
$if(CJKmainfont)$
|
||||||
|
\usepackage{xeCJK}
|
||||||
|
\setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
|
||||||
|
$endif$
|
||||||
|
\fi
|
||||||
|
% use upquote if available, for straight quotes in verbatim environments
|
||||||
|
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
|
||||||
|
% use microtype if available
|
||||||
|
\IfFileExists{microtype.sty}{%
|
||||||
|
\usepackage{microtype}
|
||||||
|
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
|
||||||
|
}{}
|
||||||
|
|
||||||
|
$if(geometry)$
|
||||||
|
\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
\usepackage[unicode=true]{hyperref}
|
||||||
|
$if(colorlinks)$
|
||||||
|
\PassOptionsToPackage{usenames,dvipsnames}{color} % color is loaded by hyperref
|
||||||
|
$endif$
|
||||||
|
\hypersetup{
|
||||||
|
$if(title-meta)$
|
||||||
|
pdftitle={$title-meta$},
|
||||||
|
$endif$
|
||||||
|
$if(author-meta)$
|
||||||
|
pdfauthor={$author-meta$},
|
||||||
|
$endif$
|
||||||
|
$if(keywords)$
|
||||||
|
pdfkeywords={$for(keywords)$$keywords$$sep$; $endfor$},
|
||||||
|
$endif$
|
||||||
|
$if(colorlinks)$
|
||||||
|
colorlinks=true,
|
||||||
|
linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$,
|
||||||
|
citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
|
||||||
|
urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
|
||||||
|
$else$
|
||||||
|
pdfborder={0 0 0},
|
||||||
|
$endif$
|
||||||
|
breaklinks=true}
|
||||||
|
\urlstyle{same} % don't use monospace font for urls
|
||||||
|
$if(lang)$
|
||||||
|
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
|
||||||
|
\usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
|
||||||
|
$if(babel-newcommands)$
|
||||||
|
$babel-newcommands$
|
||||||
|
$endif$
|
||||||
|
\else
|
||||||
|
\usepackage{polyglossia}
|
||||||
|
\setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
|
||||||
|
$for(polyglossia-otherlangs)$
|
||||||
|
\setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
|
||||||
|
$endfor$
|
||||||
|
\fi
|
||||||
|
$endif$
|
||||||
|
$if(natbib)$
|
||||||
|
\usepackage{natbib}
|
||||||
|
\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
|
||||||
|
$endif$
|
||||||
|
$if(biblatex)$
|
||||||
|
\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
|
||||||
|
$for(bibliography)$
|
||||||
|
\addbibresource{$bibliography$}
|
||||||
|
$endfor$
|
||||||
|
$endif$
|
||||||
|
$if(listings)$
|
||||||
|
\usepackage{listings}
|
||||||
|
$endif$
|
||||||
|
$if(lhs)$
|
||||||
|
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
|
||||||
|
$endif$
|
||||||
|
$if(highlighting-macros)$
|
||||||
|
$highlighting-macros$
|
||||||
|
$endif$
|
||||||
|
$if(verbatim-in-note)$
|
||||||
|
\usepackage{fancyvrb}
|
||||||
|
\VerbatimFootnotes % allows verbatim text in footnotes
|
||||||
|
$endif$
|
||||||
|
$if(tables)$
|
||||||
|
\usepackage{longtable,booktabs}
|
||||||
|
$endif$
|
||||||
|
$if(graphics)$
|
||||||
|
\usepackage{graphicx,grffile,float}
|
||||||
|
\makeatletter
|
||||||
|
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
|
||||||
|
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
|
||||||
|
\makeatother
|
||||||
|
% Scale images if necessary, so that they will not overflow the page
|
||||||
|
% margins by default, and it is still possible to overwrite the defaults
|
||||||
|
% using explicit options in \includegraphics[width, height, ...]{}
|
||||||
|
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
|
||||||
|
$endif$
|
||||||
|
$if(links-as-notes)$
|
||||||
|
% Make links footnotes instead of hotlinks:
|
||||||
|
\renewcommand{\href}[2]{#2\footnote{\url{#1}}}
|
||||||
|
$endif$
|
||||||
|
$if(strikeout)$
|
||||||
|
\usepackage[normalem]{ulem}
|
||||||
|
% avoid problems with \sout in headers with hyperref:
|
||||||
|
\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
|
||||||
|
$endif$
|
||||||
|
$if(indent)$
|
||||||
|
$else$
|
||||||
|
\IfFileExists{parskip.sty}{%
|
||||||
|
\usepackage{parskip}
|
||||||
|
}{% else
|
||||||
|
\setlength{\parindent}{0pt}
|
||||||
|
\setlength{\parskip}{6pt plus 2pt minus 1pt}
|
||||||
|
}
|
||||||
|
$endif$
|
||||||
|
\setlength{\emergencystretch}{3em} % prevent overfull lines
|
||||||
|
\providecommand{\tightlist}{%
|
||||||
|
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
|
||||||
|
$if(numbersections)$
|
||||||
|
\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
|
||||||
|
$else$
|
||||||
|
\setcounter{secnumdepth}{0}
|
||||||
|
$endif$
|
||||||
|
$if(subparagraph)$
|
||||||
|
$else$
|
||||||
|
% Redefines (sub)paragraphs to behave more like sections
|
||||||
|
\ifx\paragraph\undefined\else
|
||||||
|
\let\oldparagraph\paragraph
|
||||||
|
\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
|
||||||
|
\fi
|
||||||
|
\ifx\subparagraph\undefined\else
|
||||||
|
\let\oldsubparagraph\subparagraph
|
||||||
|
\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
|
||||||
|
\fi
|
||||||
|
$endif$
|
||||||
|
$if(dir)$
|
||||||
|
\ifxetex
|
||||||
|
% load bidi as late as possible as it modifies e.g. graphicx
|
||||||
|
$if(latex-dir-rtl)$
|
||||||
|
\usepackage[RTLdocument]{bidi}
|
||||||
|
$else$
|
||||||
|
\usepackage{bidi}
|
||||||
|
$endif$
|
||||||
|
\fi
|
||||||
|
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
|
||||||
|
\TeXXeTstate=1
|
||||||
|
\newcommand{\RL}[1]{\beginR #1\endR}
|
||||||
|
\newcommand{\LR}[1]{\beginL #1\endL}
|
||||||
|
\newenvironment{RTL}{\beginR}{\endR}
|
||||||
|
\newenvironment{LTR}{\beginL}{\endL}
|
||||||
|
\fi
|
||||||
|
$endif$
|
||||||
|
$for(header-includes)$
|
||||||
|
$header-includes$
|
||||||
|
$endfor$
|
||||||
|
|
||||||
|
|
||||||
|
\title{OpenPGP Card Application}
|
||||||
|
\author{Cedric Mesnil cedric@ledger.fr}
|
||||||
|
\date{$date$}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\begin{titlepage}
|
||||||
|
\centering
|
||||||
|
% \includegraphics[width=0.15\textwidth]{example-image-1x1}\par\vspace{1cm}
|
||||||
|
{\scshape\LARGE OpenPGP Card Application \par}
|
||||||
|
{\scshape \LARGE User Guide \par}
|
||||||
|
\vspace{1cm}
|
||||||
|
|
||||||
|
% {\scshape\Large Ledger SAS \par}
|
||||||
|
\vspace{1cm}
|
||||||
|
\begin{figure}[h]
|
||||||
|
\includegraphics{../common/LogoLedgerV.png}
|
||||||
|
\centering
|
||||||
|
\end{figure}
|
||||||
|
{\Large\itshape Cédric Mesnil (cedric@ledger.fr)\par}
|
||||||
|
\vfill
|
||||||
|
|
||||||
|
% Bottom of the page
|
||||||
|
{\large \today\par}
|
||||||
|
\end{titlepage}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$if(abstract)$
|
||||||
|
\begin{abstract}
|
||||||
|
$abstract$
|
||||||
|
\end{abstract}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
$for(include-before)$
|
||||||
|
$include-before$
|
||||||
|
|
||||||
|
$endfor$
|
||||||
|
$if(toc)$
|
||||||
|
{
|
||||||
|
$if(colorlinks)$
|
||||||
|
\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$black$endif$}
|
||||||
|
$endif$
|
||||||
|
\setcounter{tocdepth}{$toc-depth$}
|
||||||
|
\tableofcontents
|
||||||
|
}
|
||||||
|
$endif$
|
||||||
|
$if(lot)$
|
||||||
|
\listoftables
|
||||||
|
$endif$
|
||||||
|
$if(lof)$
|
||||||
|
\listoffigures
|
||||||
|
$endif$
|
||||||
|
$body$
|
||||||
|
|
||||||
|
$if(natbib)$
|
||||||
|
$if(bibliography)$
|
||||||
|
$if(biblio-title)$
|
||||||
|
$if(book-class)$
|
||||||
|
\renewcommand\bibname{$biblio-title$}
|
||||||
|
$else$
|
||||||
|
\renewcommand\refname{$biblio-title$}
|
||||||
|
$endif$
|
||||||
|
$endif$
|
||||||
|
\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
|
||||||
|
|
||||||
|
$endif$
|
||||||
|
$endif$
|
||||||
|
$if(biblatex)$
|
||||||
|
\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
|
||||||
|
|
||||||
|
$endif$
|
||||||
|
$for(include-after)$
|
||||||
|
$include-after$
|
||||||
|
|
||||||
|
$endfor$
|
||||||
|
\end{document}
|
5
doc/user/generate.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
rm -f blue-app-monero.pdf blue-app-monero.latex
|
||||||
|
|
||||||
|
pandoc -s --template=blue-app-openpgp-card.template -f rst+raw_tex+line_blocks+citations -t latex --toc -N -o blue-app-openpgp-card.pdf blue-app-openpgp-card.rst
|
BIN
doc/user/pin_abort.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
doc/user/pin_cancel.png
Normal file
After Width: | Height: | Size: 129 KiB |
BIN
doc/user/pin_confirm.png
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
doc/user/pin_entry.png
Normal file
After Width: | Height: | Size: 134 KiB |
BIN
doc/user/pin_validate.png
Normal file
After Width: | Height: | Size: 130 KiB |
11
images/LICENSE
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
LICENSE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Files "manager_gnupg.xcf" and "manager_gnupg.png" are covered by Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||||
|
See https://creativecommons.org/licenses/by-sa/3.0/legalcode .
|
||||||
|
Thanks to gnupg.org for the original images.
|
||||||
|
|
||||||
|
|
||||||
|
Others under this directory are covered by Apache License Version 2.0,
|
||||||
|
|
Before Width: | Height: | Size: 88 B After Width: | Height: | Size: 88 B |
BIN
images/manager_gnupg.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
|
@ -109,6 +109,7 @@ class GPGCard() :
|
||||||
if device.startswith("ledger:"):
|
if device.startswith("ledger:"):
|
||||||
self.token = getDongle(True)
|
self.token = getDongle(True)
|
||||||
self.exchange = self._exchange_ledger
|
self.exchange = self._exchange_ledger
|
||||||
|
self.disconnect = self._disconnect_ledger
|
||||||
elif device.startswith("pcsc:"):
|
elif device.startswith("pcsc:"):
|
||||||
allreaders = readers()
|
allreaders = readers()
|
||||||
for r in allreaders:
|
for r in allreaders:
|
||||||
|
@ -120,6 +121,7 @@ class GPGCard() :
|
||||||
self.connection = r.createConnection()
|
self.connection = r.createConnection()
|
||||||
self.connection.connect()
|
self.connection.connect()
|
||||||
self.exchange = self._exchange_pcsc
|
self.exchange = self._exchange_pcsc
|
||||||
|
self.disconnect = self._disconnect_pcsc
|
||||||
else:
|
else:
|
||||||
#print("No")
|
#print("No")
|
||||||
pass
|
pass
|
||||||
|
@ -127,6 +129,8 @@ class GPGCard() :
|
||||||
print("No token")
|
print("No token")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### APDU interface ###
|
### APDU interface ###
|
||||||
def _exchange_ledger(self,cmd,sw=0x9000):
|
def _exchange_ledger(self,cmd,sw=0x9000):
|
||||||
resp = b''
|
resp = b''
|
||||||
|
@ -160,6 +164,14 @@ class GPGCard() :
|
||||||
#print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw))
|
#print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw))
|
||||||
return resp,sw
|
return resp,sw
|
||||||
|
|
||||||
|
def _disconnect_ledger(self):
|
||||||
|
return self.token.close()
|
||||||
|
|
||||||
|
def _disconnect_pcsc(self):
|
||||||
|
r = self.connection.disconnect()
|
||||||
|
#self.connection.releaseContext()
|
||||||
|
return r
|
||||||
|
|
||||||
def select(self):
|
def select(self):
|
||||||
apdu = binascii.unhexlify(b"00A4040006D27600012401")
|
apdu = binascii.unhexlify(b"00A4040006D27600012401")
|
||||||
return self.exchange(apdu)
|
return self.exchange(apdu)
|
||||||
|
@ -254,7 +266,7 @@ class GPGCard() :
|
||||||
self.sig_date = dates[0:4]
|
self.sig_date = dates[0:4]
|
||||||
self.dec_date = dates[4:8]
|
self.dec_date = dates[4:8]
|
||||||
self.aut_date = dates[8:12]
|
self.aut_date = dates[8:12]
|
||||||
|
|
||||||
self.cardholder_cert = self.get_data(0x7f21)
|
self.cardholder_cert = self.get_data(0x7f21)
|
||||||
|
|
||||||
self.UIF_SIG,sw = self.get_data(0xD6)
|
self.UIF_SIG,sw = self.get_data(0xD6)
|
||||||
|
@ -277,13 +289,13 @@ class GPGCard() :
|
||||||
self.put_data(0x0102, self.private_02)
|
self.put_data(0x0102, self.private_02)
|
||||||
self.put_data(0x0103, self.private_03)
|
self.put_data(0x0103, self.private_03)
|
||||||
self.put_data(0x0104, self.private_04)
|
self.put_data(0x0104, self.private_04)
|
||||||
|
|
||||||
self.put_data(0x5b, self.name)
|
self.put_data(0x5b, self.name)
|
||||||
self.put_data(0x5e, self.login)
|
self.put_data(0x5e, self.login)
|
||||||
self.put_data(0x5f2d, self.lang)
|
self.put_data(0x5f2d, self.lang)
|
||||||
self.put_data(0x5f35, self.sex)
|
self.put_data(0x5f35, self.sex)
|
||||||
self.put_data(0x5f50, self.url)
|
self.put_data(0x5f50, self.url)
|
||||||
|
|
||||||
self.put_data(0xc1, self.sig_attribute)
|
self.put_data(0xc1, self.sig_attribute)
|
||||||
self.put_data(0xc2, self.dec_attribute)
|
self.put_data(0xc2, self.dec_attribute)
|
||||||
self.put_data(0xc3, self.aut_attribute)
|
self.put_data(0xc3, self.aut_attribute)
|
||||||
|
@ -314,13 +326,13 @@ class GPGCard() :
|
||||||
self.name, self.login, self.sex, self.url,
|
self.name, self.login, self.sex, self.url,
|
||||||
self.sig_attribute, self.dec_attribute, self.aut_attribute,
|
self.sig_attribute, self.dec_attribute, self.aut_attribute,
|
||||||
self.PW_status,
|
self.PW_status,
|
||||||
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
||||||
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
||||||
self.sig_date, self.dec_date, self.aut_date,
|
self.sig_date, self.dec_date, self.aut_date,
|
||||||
self.cardholder_cert,
|
self.cardholder_cert,
|
||||||
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT),
|
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT),
|
||||||
f, 2)
|
f, 2)
|
||||||
|
|
||||||
|
|
||||||
def restore(self, file_name, seed_key=False):
|
def restore(self, file_name, seed_key=False):
|
||||||
f = open(file_name,mode='r+b')
|
f = open(file_name,mode='r+b')
|
||||||
|
@ -329,9 +341,9 @@ class GPGCard() :
|
||||||
self.name, self.login, self.sex, self.url,
|
self.name, self.login, self.sex, self.url,
|
||||||
self.sig_attribute, self.dec_attribute, self.aut_attribute,
|
self.sig_attribute, self.dec_attribute, self.aut_attribute,
|
||||||
self.status,
|
self.status,
|
||||||
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
||||||
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
||||||
self.sig_date, self.dec_date, self.aut_date,
|
self.sig_date, self.dec_date, self.aut_date,
|
||||||
self.cardholder_cert,
|
self.cardholder_cert,
|
||||||
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT) = pickle.load(f)
|
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT) = pickle.load(f)
|
||||||
self.set_all()
|
self.set_all()
|
||||||
|
|
35
pytools/gpgcard/restore_perso.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
from gpgcard import GPGCard
|
||||||
|
|
||||||
|
print("Connecting to device ...")
|
||||||
|
gpgcard = GPGCard()
|
||||||
|
gpgcard.connect("pcsc:Ledger")
|
||||||
|
gpgcard.get_all()
|
||||||
|
|
||||||
|
gpgcard.verify_pin(0x81, "123456")
|
||||||
|
gpgcard.verify_pin(0x83, "12345678")
|
||||||
|
|
||||||
|
print("Generating key 1/3 ...")
|
||||||
|
gpgcard.generate_asym_key_pair(0x80, 0xb600)
|
||||||
|
print("Generating key 2/3 ...")
|
||||||
|
gpgcard.generate_asym_key_pair(0x80, 0xb800)
|
||||||
|
print("Generating key 3/3 ...")
|
||||||
|
gpgcard.generate_asym_key_pair(0x80, 0xa400)
|
||||||
|
|
||||||
|
# Use 'gpg -k --with-subkey-fingerprint' to find fingerprints
|
||||||
|
|
||||||
|
print("Setting fingerprints ...")
|
||||||
|
sig_fingerprint = b'A3F35A5124D47C3195FF07B7F85D93686A3A9063'
|
||||||
|
aut_fingerprint = b'9C686F97A39B4A34E0C9D37CDBF45893AB524BBC'
|
||||||
|
dec_fingerprint = b'E4FE54969060DBF2756FC0EFD8203245E390CAEA'
|
||||||
|
|
||||||
|
sig_fingerprint_bin = binascii.unhexlify(sig_fingerprint)
|
||||||
|
aut_fingerprint_bin = binascii.unhexlify(aut_fingerprint)
|
||||||
|
dec_fingerprint_bin = binascii.unhexlify(dec_fingerprint)
|
||||||
|
|
||||||
|
gpgcard.sig_fingerprints = sig_fingerprint_bin
|
||||||
|
gpgcard.aut_fingerprints = aut_fingerprint_bin
|
||||||
|
gpgcard.dec_fingerprints = dec_fingerprint_bin
|
||||||
|
|
||||||
|
gpgcard.set_all()
|
167
script.ld
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Ledger Blue - Secure firmware
|
||||||
|
* (c) 2016, 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.
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global chip memory layout and constants
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
DISCARD (rwx) : ORIGIN = 0xd0000000, LENGTH = 1M
|
||||||
|
|
||||||
|
FLASH (rx) : ORIGIN = 0xc0d00000, LENGTH = 400K
|
||||||
|
SRAM (rwx) : ORIGIN = 0x20001800, LENGTH = 4K
|
||||||
|
}
|
||||||
|
|
||||||
|
PAGE_SIZE = 64;
|
||||||
|
STACK_SIZE = 768;
|
||||||
|
END_STACK = ORIGIN(SRAM) + LENGTH(SRAM);
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
ENTRY(main)
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* This section locates the code in FLASH */
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
/** put text in Flash memory, VMA will be equal to LMA */
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
/* provide start code symbol, shall be zero */
|
||||||
|
_text = .;
|
||||||
|
_nvram = .;
|
||||||
|
|
||||||
|
PROVIDE(_setjmp = setjmp); /*thanks clang*/
|
||||||
|
|
||||||
|
/* ensure main is always @ 0xC0D00000 */
|
||||||
|
*(.boot*)
|
||||||
|
|
||||||
|
/* place the other code and rodata defined BUT nvram variables that are displaced in a r/w area */
|
||||||
|
*(.text*)
|
||||||
|
*(.rodata.[^UN]*) /*.data.rel.ro* not here to detect invalid PIC usage */
|
||||||
|
*(.rodata.N[^_]*)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
/* all code placed */
|
||||||
|
_etext = .;
|
||||||
|
|
||||||
|
. = ALIGN(PAGE_SIZE);
|
||||||
|
|
||||||
|
_nvram_data = .;
|
||||||
|
|
||||||
|
/* NVM data (ex-filesystem) */
|
||||||
|
*(.rodata.USBD_CfgDesc)
|
||||||
|
*(.bss.N_* .rodata.N_* .rodata.USBD_CfgDesc)
|
||||||
|
. = ALIGN(PAGE_SIZE);
|
||||||
|
_install_parameters = .;
|
||||||
|
PROVIDE(N_install_parameters = .);
|
||||||
|
_envram = .;
|
||||||
|
_nvram_data_size = _envram - _nvram_data;
|
||||||
|
|
||||||
|
} > FLASH = 0x00
|
||||||
|
|
||||||
|
.data (NOLOAD):
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place RAM initialized variables
|
||||||
|
*/
|
||||||
|
_data = .;
|
||||||
|
|
||||||
|
*(vtable)
|
||||||
|
*(.data*)
|
||||||
|
|
||||||
|
_edata = .;
|
||||||
|
|
||||||
|
} > DISCARD /*> SRAM AT>FLASH = 0x00 */
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Place RAM uninitialized variables
|
||||||
|
*/
|
||||||
|
_bss = .;
|
||||||
|
*(.bss*)
|
||||||
|
_ebss = .;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserve stack size
|
||||||
|
*/
|
||||||
|
. = ALIGN(4);
|
||||||
|
app_stack_canary = .;
|
||||||
|
PROVIDE(app_stack_canary = .);
|
||||||
|
. += 4;
|
||||||
|
_stack = .;
|
||||||
|
. = _stack + STACK_SIZE;
|
||||||
|
PROVIDE( _stack_size = STACK_SIZE );
|
||||||
|
PROVIDE( _estack = ABSOLUTE(END_STACK) );
|
||||||
|
|
||||||
|
} > SRAM = 0x00
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* DEBUG */
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
/* remove the debugging information from the standard libraries */
|
||||||
|
DEBUG (NOLOAD) :
|
||||||
|
{
|
||||||
|
libc.a ( * )
|
||||||
|
libm.a ( * )
|
||||||
|
libgcc.a ( * )
|
||||||
|
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
|
||||||
|
}
|
|
@ -1,209 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file usbd_ccid_if.h
|
|
||||||
* @author MCD Application Team
|
|
||||||
* @version V1.0.1
|
|
||||||
* @date 31-January-2014
|
|
||||||
* @brief This file provides all the functions prototypes for USB CCID
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© 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.
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
|
||||||
#ifndef __USBD_CCID_IF_H
|
|
||||||
#define __USBD_CCID_IF_H
|
|
||||||
|
|
||||||
#include "usbd_core.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_USB_CLASS_CCID
|
|
||||||
|
|
||||||
|
|
||||||
/* Exported defines ----------------------------------------------------------*/
|
|
||||||
/* Bulk-only Command Block Wrapper */
|
|
||||||
#define ABDATA_SIZE 261
|
|
||||||
#define CCID_CMD_HEADER_SIZE 10
|
|
||||||
#define CCID_RESPONSE_HEADER_SIZE 10
|
|
||||||
|
|
||||||
|
|
||||||
#define CCID_INT_BUFF_SIZ 2
|
|
||||||
|
|
||||||
#define CARD_SLOT_FITTED 1
|
|
||||||
#define CARD_SLOT_REMOVED 0
|
|
||||||
|
|
||||||
#define BULK_MAX_PACKET_SIZE 0x40
|
|
||||||
#define CCID_IN_EP_SIZE 0x40
|
|
||||||
#define INTR_MAX_PACKET_SIZE 8
|
|
||||||
#define CCID_MESSAGE_HEADER_SIZE 10
|
|
||||||
#define CCID_NUMBER_OF_SLOTS 1
|
|
||||||
/* Number of SLOTS. For single card, this value is 1 */
|
|
||||||
|
|
||||||
/* Following Parameters used in PC_to_RDR_IccPowerOn */
|
|
||||||
#define VOLTAGE_SELECTION_AUTOMATIC 0xFF
|
|
||||||
#define VOLTAGE_SELECTION_3V 0x02
|
|
||||||
#define VOLTAGE_SELECTION_5V 0x01
|
|
||||||
#define VOLTAGE_SELECTION_1V8 0x03
|
|
||||||
|
|
||||||
#define PC_TO_RDR_ICCPOWERON 0x62
|
|
||||||
#define PC_TO_RDR_ICCPOWEROFF 0x63
|
|
||||||
#define PC_TO_RDR_GETSLOTSTATUS 0x65
|
|
||||||
#define PC_TO_RDR_XFRBLOCK 0x6F
|
|
||||||
#define PC_TO_RDR_GETPARAMETERS 0x6C
|
|
||||||
#define PC_TO_RDR_RESETPARAMETERS 0x6D
|
|
||||||
#define PC_TO_RDR_SETPARAMETERS 0x61
|
|
||||||
#define PC_TO_RDR_ESCAPE 0x6B
|
|
||||||
#define PC_TO_RDR_ICCCLOCK 0x6E
|
|
||||||
#define PC_TO_RDR_T0APDU 0x6A
|
|
||||||
#define PC_TO_RDR_SECURE 0x69
|
|
||||||
#define PC_TO_RDR_MECHANICAL 0x71
|
|
||||||
#define PC_TO_RDR_ABORT 0x72
|
|
||||||
#define PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY 0x73
|
|
||||||
|
|
||||||
#define RDR_TO_PC_DATABLOCK 0x80
|
|
||||||
#define RDR_TO_PC_SLOTSTATUS 0x81
|
|
||||||
#define RDR_TO_PC_PARAMETERS 0x82
|
|
||||||
#define RDR_TO_PC_ESCAPE 0x83
|
|
||||||
#define RDR_TO_PC_DATARATEANDCLOCKFREQUENCY 0x84
|
|
||||||
|
|
||||||
#define RDR_TO_PC_NOTIFYSLOTCHANGE 0x50
|
|
||||||
#define RDR_TO_PC_HARDWAREERROR 0x51
|
|
||||||
|
|
||||||
#define OFFSET_INT_BMESSAGETYPE 0
|
|
||||||
#define OFFSET_INT_BMSLOTICCSTATE 1
|
|
||||||
#define SLOT_ICC_PRESENT 0x01
|
|
||||||
/* LSb : (0b = no ICC present, 1b = ICC present) */
|
|
||||||
|
|
||||||
#define SLOT_ICC_CHANGE 0x02 /* MSb : (0b = no change, 1b = change) */
|
|
||||||
/*****************************************************************************/
|
|
||||||
/*********************** CCID Bulk Transfer State machine ********************/
|
|
||||||
/*****************************************************************************/
|
|
||||||
#define CCID_STATE_IDLE 0 /* Idle state */
|
|
||||||
#define CCID_STATE_DATA_OUT 1 /* Data Out state */
|
|
||||||
#define CCID_STATE_RECEIVE_DATA 2
|
|
||||||
#define CCID_STATE_SEND_RESP 3
|
|
||||||
#define CCID_STATE_DATAIN 4
|
|
||||||
#define CCID_STATE_UNCORRECT_LENGTH 5
|
|
||||||
|
|
||||||
#define DIR_IN 0
|
|
||||||
#define DIR_OUT 1
|
|
||||||
#define BOTH_DIR 2
|
|
||||||
|
|
||||||
/* Exported types ------------------------------------------------------------*/
|
|
||||||
#pragma pack(1)
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
#pragma pack(1)
|
|
||||||
union {
|
|
||||||
#pragma pack(1)
|
|
||||||
struct {
|
|
||||||
uint8_t bMessageType; /* Offset = 0*/
|
|
||||||
uint32_t dwLength; /* Offset = 1, The length field (dwLength) is the length
|
|
||||||
of the message not including the 10-byte header.*/
|
|
||||||
uint8_t bSlot; /* Offset = 5*/
|
|
||||||
uint8_t bSeq; /* Offset = 6*/
|
|
||||||
uint8_t bSpecific_0; /* Offset = 7*/
|
|
||||||
uint8_t bSpecific_1; /* Offset = 8*/
|
|
||||||
uint8_t bSpecific_2; /* Offset = 9*/
|
|
||||||
} bulkout;
|
|
||||||
#pragma pack(1)
|
|
||||||
struct {
|
|
||||||
uint8_t bMessageType; /* Offset = 0*/
|
|
||||||
uint32_t dwLength; /* Offset = 1*/
|
|
||||||
uint8_t bSlot; /* Offset = 5, Same as Bulk-OUT message */
|
|
||||||
uint8_t bSeq; /* Offset = 6, Same as Bulk-OUT message */
|
|
||||||
uint8_t bStatus; /* Offset = 7, Slot status as defined in § 6.2.6*/
|
|
||||||
uint8_t bError; /* Offset = 8, Slot error as defined in § 6.2.6*/
|
|
||||||
uint8_t bSpecific; /* Offset = 9*/
|
|
||||||
} bulkin;
|
|
||||||
} header;
|
|
||||||
uint8_t abData [ABDATA_SIZE]; /* Offset = 10, For reference, the absolute
|
|
||||||
maximum block size for a TPDU T=0 block is 260 bytes
|
|
||||||
(5 bytes command; 255 bytes data),
|
|
||||||
or for a TPDU T=1 block is 259 bytes,
|
|
||||||
or for a short APDU T=1 block is 261 bytes,
|
|
||||||
or for an extended APDU T=1 block is 65544 bytes.*/
|
|
||||||
} Ccid_bulk_data_t;
|
|
||||||
#pragma pack()
|
|
||||||
|
|
||||||
|
|
||||||
#pragma pack()
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
__IO uint8_t SlotStatus;
|
|
||||||
__IO uint8_t SlotStatusChange;
|
|
||||||
} Ccid_SlotStatus_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
__IO uint8_t bAbortRequestFlag;
|
|
||||||
__IO uint8_t bSeq;
|
|
||||||
__IO uint8_t bSlot;
|
|
||||||
} usb_ccid_param_t;
|
|
||||||
|
|
||||||
|
|
||||||
#pragma pack(1)
|
|
||||||
typedef struct _Protocol0_DataStructure_t
|
|
||||||
{
|
|
||||||
uint8_t bmFindexDindex;
|
|
||||||
uint8_t bmTCCKST0;
|
|
||||||
uint8_t bGuardTimeT0;
|
|
||||||
uint8_t bWaitingIntegerT0;
|
|
||||||
uint8_t bClockStop;
|
|
||||||
} Protocol0_DataStructure_t;
|
|
||||||
#pragma pack()
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "usbd_ccid_core.h"
|
|
||||||
|
|
||||||
extern usb_ccid_param_t usb_ccid_param;
|
|
||||||
extern Ccid_bulk_data_t Ccid_bulk_data; /* Buffer for the Out Data */
|
|
||||||
extern Ccid_SlotStatus_t Ccid_SlotStatus;
|
|
||||||
extern uint8_t UsbIntMessageBuffer[];
|
|
||||||
|
|
||||||
extern Protocol0_DataStructure_t Protocol0_DataStructure;
|
|
||||||
|
|
||||||
/* Exported macros -----------------------------------------------------------*/
|
|
||||||
/* Exported variables --------------------------------------------------------*/
|
|
||||||
/* Exported functions ------------------------------------------------------- */
|
|
||||||
void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t epnum);
|
|
||||||
|
|
||||||
void CCID_BulkMessage_Out (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t epnum, uint8_t* buffer, uint16_t buflen);
|
|
||||||
|
|
||||||
void CCID_ReceiveCmdHeader(uint8_t* pDst, uint8_t u8length);
|
|
||||||
void CCID_CmdDecode(USBD_HandleTypeDef *pdev);
|
|
||||||
|
|
||||||
void CCID_IntMessage(USBD_HandleTypeDef *pdev);
|
|
||||||
void CCID_Init(USBD_HandleTypeDef *pdev);
|
|
||||||
void CCID_DeInit(USBD_HandleTypeDef *pdev);
|
|
||||||
|
|
||||||
uint8_t CCID_IsIntrTransferComplete(void);
|
|
||||||
void CCID_SetIntrTransferStatus (uint8_t );
|
|
||||||
void Transfer_Data_Request(void);
|
|
||||||
void Set_CSW (uint8_t CSW_Status, uint8_t Send_Permission);
|
|
||||||
|
|
||||||
void io_usb_ccid_set_card_inserted(unsigned int inserted);
|
|
||||||
|
|
||||||
#endif // HAVE_USB_CLASS_CCID
|
|
||||||
|
|
||||||
#endif /* __USBD_CCID_IF_H */
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
|
@ -16,7 +16,11 @@
|
||||||
#ifndef GPG_API_H
|
#ifndef GPG_API_H
|
||||||
#define GPG_API_H
|
#define GPG_API_H
|
||||||
|
|
||||||
int gpg_oid2curve(unsigned char* oid, unsigned int len);
|
void USBD_CCID_activate_pinpad(int enabled);
|
||||||
|
|
||||||
|
unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len);
|
||||||
|
unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len);
|
||||||
|
unsigned int gpg_curve2domainlen(unsigned int cv);
|
||||||
|
|
||||||
void gpg_init(void);
|
void gpg_init(void);
|
||||||
void gpg_init_ux(void);
|
void gpg_init_ux(void);
|
||||||
|
@ -28,7 +32,7 @@ int gpg_apdu_get_data(unsigned int ref) ;
|
||||||
int gpg_apdu_get_next_data(unsigned int ref) ;
|
int gpg_apdu_get_next_data(unsigned int ref) ;
|
||||||
int gpg_apdu_put_data(unsigned int ref) ;
|
int gpg_apdu_put_data(unsigned int ref) ;
|
||||||
|
|
||||||
int gpg_apdu_pso(unsigned int ref);
|
int gpg_apdu_pso(void);
|
||||||
int gpg_apdu_internal_authenticate(void);
|
int gpg_apdu_internal_authenticate(void);
|
||||||
int gpg_apdu_gen(void );
|
int gpg_apdu_gen(void );
|
||||||
int gpg_apdu_get_challenge(void) ;
|
int gpg_apdu_get_challenge(void) ;
|
||||||
|
@ -40,12 +44,14 @@ int gpg_apdu_change_ref_data(void) ;
|
||||||
int gpg_apdu_reset_retry_counter(void) ;
|
int gpg_apdu_reset_retry_counter(void) ;
|
||||||
|
|
||||||
gpg_pin_t *gpg_pin_get_pin(int id);
|
gpg_pin_t *gpg_pin_get_pin(int id);
|
||||||
int gpg_pin_is_verified(gpg_pin_t *pin);
|
|
||||||
int gpg_pin_is_blocked(gpg_pin_t *pin);
|
int gpg_pin_is_blocked(gpg_pin_t *pin);
|
||||||
int gpg_pin_set_verified(gpg_pin_t *pin, int verified);
|
int gpg_pin_is_verified(int pinID);
|
||||||
int gpg_pin_check(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
|
int gpg_pin_set_verified(int pinID, int verified);
|
||||||
|
int gpg_pin_check(gpg_pin_t *pin, int pinID,unsigned char *pin_val, unsigned int pin_len);
|
||||||
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
|
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
|
||||||
void gpg_pin_sync12(void) ;
|
|
||||||
|
int gpg_mse_reset();
|
||||||
|
int gpg_apdu_mse();
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* --- IO ---- */
|
/* --- IO ---- */
|
||||||
|
|
|
@ -44,16 +44,16 @@ int gpg_apdu_get_challenge() {
|
||||||
chain[0] = 'r'; chain[1]='n'; chain[2] = 'd';
|
chain[0] = 'r'; chain[1]='n'; chain[2] = 'd';
|
||||||
|
|
||||||
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
||||||
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL);
|
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL, 0);
|
||||||
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL);
|
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL, 0);
|
||||||
hlen=cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256,
|
hlen=cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256,
|
||||||
CX_LAST, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
CX_LAST, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
||||||
G_gpg_vstate.work.io_buffer);
|
G_gpg_vstate.work.io_buffer, 32);
|
||||||
|
|
||||||
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
|
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
|
||||||
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3,
|
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3,
|
||||||
CX_LAST, G_gpg_vstate.work.io_buffer, hlen,
|
CX_LAST, G_gpg_vstate.work.io_buffer, hlen,
|
||||||
G_gpg_vstate.work.io_buffer);
|
G_gpg_vstate.work.io_buffer,olen);
|
||||||
} else {
|
} else {
|
||||||
cx_rng(G_gpg_vstate.work.io_buffer, olen);
|
cx_rng(G_gpg_vstate.work.io_buffer, olen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ int gpg_apdu_get_data(unsigned int ref) {
|
||||||
break;
|
break;
|
||||||
/* ----------------- Config RSA exponent ----------------- */
|
/* ----------------- Config RSA exponent ----------------- */
|
||||||
case 0x01F8:
|
case 0x01F8:
|
||||||
gpg_io_insert_u32(N_gpg_pstate->default_RSA_exponent);
|
gpg_io_insert(N_gpg_pstate->default_RSA_exponent,4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------- Application ----------------- */
|
/* ----------------- Application ----------------- */
|
||||||
|
@ -282,7 +282,7 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||||
if (G_gpg_vstate.io_length != 4) {
|
if (G_gpg_vstate.io_length != 4) {
|
||||||
THROW(SW_WRONG_LENGTH);
|
THROW(SW_WRONG_LENGTH);
|
||||||
}
|
}
|
||||||
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] &= ~0x07;
|
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+3] &= ~0x07;
|
||||||
nvm_write(&N_gpg_pstate->AID[10], &G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset], 4);
|
nvm_write(&N_gpg_pstate->AID[10], &G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset], 4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
//fecth 7f78
|
//fecth 7f78
|
||||||
gpg_io_fetch_tl(&t,&l);
|
gpg_io_fetch_tl(&t,&l);
|
||||||
|
@ -343,6 +343,7 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||||
case 0x95:
|
case 0x95:
|
||||||
case 0x96:
|
case 0x96:
|
||||||
case 0x97:
|
case 0x97:
|
||||||
|
case 0x99:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
||||||
|
@ -366,34 +367,25 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||||
//check length
|
//check length
|
||||||
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
|
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
|
||||||
ksz = ksz >> 3;
|
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) {
|
switch(ksz) {
|
||||||
case 1024/8:
|
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);
|
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;
|
break;
|
||||||
case 2048/8:
|
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);
|
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;
|
break;
|
||||||
case 3072/8:
|
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);
|
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;
|
break;
|
||||||
case 4096/8:
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
ksz = ksz>>1;
|
ksz = ksz>>1;
|
||||||
|
@ -432,7 +424,12 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||||
os_memset(pq+ksz, 0, ksz-len_q);
|
os_memset(pq+ksz, 0, ksz-len_q);
|
||||||
|
|
||||||
//regenerate RSA private key
|
//regenerate RSA private key
|
||||||
cx_rsa_generate_pair(ksz<<1, rsa_pub, rsa_priv, e, pq);
|
unsigned char _e[4];
|
||||||
|
_e[0] = e>>24;
|
||||||
|
_e[1] = e>>16;
|
||||||
|
_e[2] = e>>8;
|
||||||
|
_e[3] = e>>0;
|
||||||
|
cx_rsa_generate_pair(ksz<<1, rsa_pub, rsa_priv, _e, 4, pq);
|
||||||
|
|
||||||
//write keys
|
//write keys
|
||||||
nvm_write(&keygpg->pub_key.rsa, rsa_pub->e, 4);
|
nvm_write(&keygpg->pub_key.rsa, rsa_pub->e, 4);
|
||||||
|
@ -454,14 +451,14 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||||
THROW(SW_WRONG_DATA);
|
THROW(SW_WRONG_DATA);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ksz = 32;
|
ksz = gpg_curve2domainlen(curve);
|
||||||
if (ksz == 32) {
|
if (ksz == len_p) {
|
||||||
G_gpg_vstate.work.ecfp256.private.curve = curve;
|
G_gpg_vstate.work.ecfp.private.curve = curve;
|
||||||
G_gpg_vstate.work.ecfp256.private.d_len = ksz;
|
G_gpg_vstate.work.ecfp.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);
|
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.ecfp256.public, &G_gpg_vstate.work.ecfp256.private, 1);
|
cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp.public, &G_gpg_vstate.work.ecfp.private, 1);
|
||||||
nvm_write(&keygpg->pub_key.ecfp256, &G_gpg_vstate.work.ecfp256.public, sizeof(cx_ecfp_public_key_t));
|
nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
|
||||||
nvm_write(&keygpg->key.ecfp256, &G_gpg_vstate.work.ecfp256.private, sizeof(cx_ecfp_private_key_t));
|
nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
|
||||||
if (reset_cnt) {
|
if (reset_cnt) {
|
||||||
reset_cnt = 0;
|
reset_cnt = 0;
|
||||||
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
|
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
|
||||||
|
@ -653,10 +650,27 @@ int gpg_apdu_put_data(unsigned int ref) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------- RC ----------------- */
|
/* ----------------- RC ----------------- */
|
||||||
case 0xD3:
|
case 0xD3: {
|
||||||
sw = gpg_apdu_change_ref_data();
|
gpg_pin_t *pin;
|
||||||
break;
|
|
||||||
|
|
||||||
|
pin = gpg_pin_get_pin(PIN_ID_RC);
|
||||||
|
if (G_gpg_vstate.io_length == 0) {
|
||||||
|
gpg_nvm_write(pin, NULL, sizeof(gpg_pin_t));
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ((G_gpg_vstate.io_length > GPG_MAX_PW_LENGTH) ||
|
||||||
|
(G_gpg_vstate.io_length < 8)) {
|
||||||
|
THROW(SW_WRONG_DATA);
|
||||||
|
return SW_WRONG_DATA;
|
||||||
|
} else {
|
||||||
|
gpg_pin_set(pin,
|
||||||
|
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
||||||
|
G_gpg_vstate.io_length);
|
||||||
|
}
|
||||||
|
sw = SW_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------- UIF ----------------- */
|
/* ----------------- UIF ----------------- */
|
||||||
case 0xD6:
|
case 0xD6:
|
||||||
ptr_v = G_gpg_vstate.kslot->sig.UIF;
|
ptr_v = G_gpg_vstate.kslot->sig.UIF;
|
||||||
|
|
|
@ -23,12 +23,7 @@
|
||||||
|
|
||||||
void gpg_check_access_ins() {
|
void gpg_check_access_ins() {
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
gpg_pin_t *pin_pw1, *pin_pw2, *pin_pw3, *pin_rc;
|
|
||||||
|
|
||||||
pin_pw1 = gpg_pin_get_pin(PIN_ID_PW1);
|
|
||||||
pin_pw2 = gpg_pin_get_pin(PIN_ID_PW2);
|
|
||||||
pin_pw3 = gpg_pin_get_pin(PIN_ID_PW3);
|
|
||||||
pin_rc = gpg_pin_get_pin(PIN_ID_RC);
|
|
||||||
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
|
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
|
||||||
|
|
||||||
switch (G_gpg_vstate.io_ins) {
|
switch (G_gpg_vstate.io_ins) {
|
||||||
|
@ -45,7 +40,7 @@ void gpg_check_access_ins() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case INS_RESET_RETRY_COUNTER:
|
case INS_RESET_RETRY_COUNTER:
|
||||||
if (gpg_pin_is_verified(pin_pw3) || gpg_pin_is_verified(pin_rc)) {
|
if (gpg_pin_is_verified(PIN_ID_PW3) || gpg_pin_is_verified(PIN_ID_RC)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,27 +52,30 @@ void gpg_check_access_ins() {
|
||||||
if (G_gpg_vstate.io_p1 == 0x81) {
|
if (G_gpg_vstate.io_p1 == 0x81) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (gpg_pin_is_verified(pin_pw3)) {
|
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INS_MSE:
|
||||||
|
return ;
|
||||||
|
|
||||||
case INS_PSO:
|
case INS_PSO:
|
||||||
if ((ref == 0x9e9a) && gpg_pin_is_verified(pin_pw1)) {
|
if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) {
|
||||||
//pso:sign
|
//pso:sign
|
||||||
if (N_gpg_pstate->PW_status[0] == 0) {
|
if (N_gpg_pstate->PW_status[0] == 0) {
|
||||||
gpg_pin_set_verified(pin_pw1, 0);
|
gpg_pin_set_verified(PIN_ID_PW1, 0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((ref == 0x8086 ) && gpg_pin_is_verified(pin_pw2)) {
|
if (((ref == 0x8086 )||(ref == 0x8680)) && gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||||
//pso:dec
|
//pso:dec/enc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INS_INTERNAL_AUTHENTICATE:
|
case INS_INTERNAL_AUTHENTICATE:
|
||||||
if (gpg_pin_is_verified(pin_pw2)) {
|
if (gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -86,7 +84,7 @@ void gpg_check_access_ins() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case INS_TERMINATE_DF:
|
case INS_TERMINATE_DF:
|
||||||
if (gpg_pin_is_verified(pin_pw3)) {
|
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -99,10 +97,6 @@ void gpg_check_access_ins() {
|
||||||
|
|
||||||
void gpg_check_access_read_DO() {
|
void gpg_check_access_read_DO() {
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
gpg_pin_t *pin_pw2, *pin_pw3;
|
|
||||||
|
|
||||||
pin_pw2 = gpg_pin_get_pin(PIN_ID_PW2);
|
|
||||||
pin_pw3 = gpg_pin_get_pin(PIN_ID_PW3);
|
|
||||||
|
|
||||||
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
|
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
|
||||||
|
|
||||||
|
@ -152,14 +146,14 @@ void gpg_check_access_read_DO() {
|
||||||
|
|
||||||
//PW1
|
//PW1
|
||||||
case 0x0103:
|
case 0x0103:
|
||||||
if (gpg_pin_is_verified(pin_pw2)) {
|
if (gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//PW3
|
//PW3
|
||||||
case 0x0104:
|
case 0x0104:
|
||||||
if (gpg_pin_is_verified(pin_pw3)) {
|
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -183,7 +177,7 @@ void gpg_check_access_write_DO() {
|
||||||
case 0x0101:
|
case 0x0101:
|
||||||
case 0x0103:
|
case 0x0103:
|
||||||
case 0x01F2:
|
case 0x01F2:
|
||||||
if (gpg_pin_is_verified(pin_pw2)) {
|
if (gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -225,7 +219,7 @@ void gpg_check_access_write_DO() {
|
||||||
case 0x00D6:
|
case 0x00D6:
|
||||||
case 0x00D7:
|
case 0x00D7:
|
||||||
case 0x00D8:
|
case 0x00D8:
|
||||||
if (gpg_pin_is_verified(pin_pw3)) {
|
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -242,7 +236,12 @@ int gpg_dispatch() {
|
||||||
unsigned int tag,t,l;
|
unsigned int tag,t,l;
|
||||||
int sw;
|
int sw;
|
||||||
|
|
||||||
|
if ((G_gpg_vstate.io_cla != 0x00) &&
|
||||||
|
(G_gpg_vstate.io_cla != 0x10) &&
|
||||||
|
(G_gpg_vstate.io_cla != 0xEF)) {
|
||||||
|
THROW(SW_CLA_NOT_SUPPORTED);
|
||||||
|
return SW_CLA_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
tag = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
|
tag = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
|
||||||
|
|
||||||
|
@ -265,7 +264,7 @@ int gpg_dispatch() {
|
||||||
|
|
||||||
case INS_TERMINATE_DF:
|
case INS_TERMINATE_DF:
|
||||||
gpg_io_discard(0);
|
gpg_io_discard(0);
|
||||||
if (gpg_pin_is_verified(gpg_pin_get_pin(PIN_ID_PW3)) || (N_gpg_pstate->PW3.counter == 0)) {
|
if (gpg_pin_is_verified(PIN_ID_PW3) || (N_gpg_pstate->PW3.counter == 0)) {
|
||||||
gpg_install(STATE_TERMINATE);
|
gpg_install(STATE_TERMINATE);
|
||||||
return(SW_OK);
|
return(SW_OK);
|
||||||
break;
|
break;
|
||||||
|
@ -274,7 +273,6 @@ int gpg_dispatch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Other commands allowed if not terminated */
|
/* Other commands allowed if not terminated */
|
||||||
if (N_gpg_pstate->histo[7] != 0x07) {
|
if (N_gpg_pstate->histo[7] != 0x07) {
|
||||||
THROW(SW_STATE_TERMINATED);
|
THROW(SW_STATE_TERMINATED);
|
||||||
|
@ -361,7 +359,7 @@ int gpg_dispatch() {
|
||||||
THROW(SW_INCORRECT_P1P2);
|
THROW(SW_INCORRECT_P1P2);
|
||||||
|
|
||||||
case INS_RESET_RETRY_COUNTER:
|
case INS_RESET_RETRY_COUNTER:
|
||||||
if ((G_gpg_vstate.io_p2 == 0x81) &&
|
if ((G_gpg_vstate.io_p2 == 0x81) &&
|
||||||
( (G_gpg_vstate.io_p1 == 0) ||
|
( (G_gpg_vstate.io_p1 == 0) ||
|
||||||
(G_gpg_vstate.io_p1 == 2) )
|
(G_gpg_vstate.io_p1 == 2) )
|
||||||
) {
|
) {
|
||||||
|
@ -375,10 +373,16 @@ int gpg_dispatch() {
|
||||||
sw = gpg_apdu_gen();
|
sw = gpg_apdu_gen();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* --- MSE --- */
|
||||||
|
case INS_MSE:
|
||||||
|
sw = gpg_apdu_mse(tag);
|
||||||
|
break;
|
||||||
|
|
||||||
/* --- PSO --- */
|
/* --- PSO --- */
|
||||||
case INS_PSO:
|
case INS_PSO:
|
||||||
sw = gpg_apdu_pso(tag);
|
sw = gpg_apdu_pso();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INS_INTERNAL_AUTHENTICATE:
|
case INS_INTERNAL_AUTHENTICATE:
|
||||||
sw = gpg_apdu_internal_authenticate();
|
sw = gpg_apdu_internal_authenticate();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,12 +46,12 @@ static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name,
|
||||||
h[1] = idx;
|
h[1] = idx;
|
||||||
|
|
||||||
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
||||||
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL);
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL, 0);
|
||||||
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, (unsigned char *)key_name, 4, NULL);
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, (unsigned char *)key_name, 4, NULL, 0);
|
||||||
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, CX_LAST, h , 2, h);
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, CX_LAST, h , 2, h,32);
|
||||||
|
|
||||||
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len);
|
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len);
|
||||||
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski);
|
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski, Ski_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,29 +113,20 @@ int gpg_apdu_gen() {
|
||||||
|
|
||||||
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
|
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
|
||||||
ksz = ksz >> 3;
|
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) {
|
switch(ksz) {
|
||||||
case 1024/8:
|
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);
|
pkey_size = sizeof(cx_rsa_1024_private_key_t);
|
||||||
break;
|
break;
|
||||||
case 2048/8:
|
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);
|
pkey_size = sizeof(cx_rsa_2048_private_key_t);
|
||||||
break;
|
break;
|
||||||
case 3072/8:
|
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);
|
pkey_size = sizeof(cx_rsa_3072_private_key_t);
|
||||||
break;
|
break;
|
||||||
case 4096/8:
|
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);
|
pkey_size = sizeof(cx_rsa_4096_private_key_t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -153,8 +144,7 @@ int gpg_apdu_gen() {
|
||||||
cx_math_next_prime(pq+size,size);
|
cx_math_next_prime(pq+size,size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, N_gpg_pstate->default_RSA_exponent, 4, pq);
|
||||||
cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, N_gpg_pstate->default_RSA_exponent, pq);
|
|
||||||
|
|
||||||
nvm_write(pkey, rsa_priv, pkey_size);
|
nvm_write(pkey, rsa_priv, pkey_size);
|
||||||
nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4);
|
nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4);
|
||||||
|
@ -174,19 +164,24 @@ int gpg_apdu_gen() {
|
||||||
unsigned int curve,keepprivate;
|
unsigned int curve,keepprivate;
|
||||||
keepprivate = 0;
|
keepprivate = 0;
|
||||||
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
|
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)) {
|
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_slot_seed(G_gpg_vstate.slot, seed);
|
||||||
gpg_pso_derive_key_seed(seed, name, 1, seed, 32);
|
gpg_pso_derive_key_seed(seed, name, 1, seed, ksz);
|
||||||
cx_ecfp_init_private_key(curve,seed, 32, &G_gpg_vstate.work.ecfp256.private);
|
cx_ecfp_init_private_key(curve,seed, ksz, &G_gpg_vstate.work.ecfp.private);
|
||||||
keepprivate = 1;
|
keepprivate = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cx_ecfp_generate_pair(curve,
|
cx_ecfp_generate_pair(curve,
|
||||||
&G_gpg_vstate.work.ecfp256.public,
|
&G_gpg_vstate.work.ecfp.public,
|
||||||
&G_gpg_vstate.work.ecfp256.private,
|
&G_gpg_vstate.work.ecfp.private,
|
||||||
keepprivate);
|
keepprivate);
|
||||||
nvm_write(&keygpg->key.ecfp256, &G_gpg_vstate.work.ecfp256.private, sizeof(cx_ecfp_private_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.ecfp256, &G_gpg_vstate.work.ecfp256.public, sizeof(cx_ecfp_public_key_t));
|
nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
|
||||||
if (reset_cnt) {
|
if (reset_cnt) {
|
||||||
reset_cnt = 0;
|
reset_cnt = 0;
|
||||||
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
|
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
|
||||||
|
@ -208,32 +203,32 @@ int gpg_apdu_gen() {
|
||||||
gpg_io_mark();
|
gpg_io_mark();
|
||||||
switch(ksz) {
|
switch(ksz) {
|
||||||
case 1024/8:
|
case 1024/8:
|
||||||
if (keygpg->key.rsa1024.size == 0) {
|
if (keygpg->priv_key.rsa1024.size == 0) {
|
||||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||||
return 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;
|
break;
|
||||||
case 2048/8:
|
case 2048/8:
|
||||||
if (keygpg->key.rsa2048.size == 0) {
|
if (keygpg->priv_key.rsa2048.size == 0) {
|
||||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||||
return 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;
|
break;
|
||||||
case 3072/8:
|
case 3072/8:
|
||||||
if (keygpg->key.rsa3072.size == 0) {
|
if (keygpg->priv_key.rsa3072.size == 0) {
|
||||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||||
return 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;
|
break;
|
||||||
case 4096/8:
|
case 4096/8:
|
||||||
if (keygpg->key.rsa4096.size == 0) {
|
if (keygpg->priv_key.rsa4096.size == 0) {
|
||||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||||
return 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;
|
break;
|
||||||
}
|
}
|
||||||
gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa);
|
gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa);
|
||||||
|
@ -262,7 +257,7 @@ int gpg_apdu_gen() {
|
||||||
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
|
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
|
||||||
if (curve == CX_CURVE_Ed25519) {
|
if (curve == CX_CURVE_Ed25519) {
|
||||||
os_memmove(G_gpg_vstate.work.io_buffer+128, keygpg->pub_key.ecfp256.W,keygpg->pub_key.ecfp256.W_len);
|
os_memmove(G_gpg_vstate.work.io_buffer+128, keygpg->pub_key.ecfp256.W,keygpg->pub_key.ecfp256.W_len);
|
||||||
cx_edward_compress_point(CX_CURVE_Ed25519, G_gpg_vstate.work.io_buffer+128);
|
cx_edward_compress_point(CX_CURVE_Ed25519, G_gpg_vstate.work.io_buffer+128, 65);
|
||||||
gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer+129); //129: discard 02
|
gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer+129); //129: discard 02
|
||||||
} else if (curve == CX_CURVE_Curve25519) {
|
} else if (curve == CX_CURVE_Curve25519) {
|
||||||
unsigned int i,len;
|
unsigned int i,len;
|
||||||
|
|
213
src/gpg_init.c
|
@ -18,6 +18,7 @@
|
||||||
#include "gpg_types.h"
|
#include "gpg_types.h"
|
||||||
#include "gpg_api.h"
|
#include "gpg_api.h"
|
||||||
#include "gpg_vars.h"
|
#include "gpg_vars.h"
|
||||||
|
#include "usbd_impl.h"
|
||||||
|
|
||||||
#define SHORT(x) ((x)>>8)&0xFF, (x)&0xFF
|
#define SHORT(x) ((x)>>8)&0xFF, (x)&0xFF
|
||||||
/* ----------------------*/
|
/* ----------------------*/
|
||||||
|
@ -31,24 +32,47 @@ const unsigned char C_MAGIC[8] = {
|
||||||
/* --ECC OID -- */
|
/* --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
|
//secp256k1: 1.3.132.0.10
|
||||||
const unsigned char C_OID_SECP256K1[5] = {
|
const unsigned char C_OID_SECP256K1[5] = {
|
||||||
0x2B, 0x81, 0x04, 0x00, 0x0A
|
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
|
//brainpool 256r1: 1.3.36.3.3.2.8.1.1.7
|
||||||
const unsigned char C_OID_BRAINPOOL256R1[9] = {
|
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
|
//brainpool 284r1: 1.3.36.3.3.2.8.1.1.11
|
||||||
const unsigned char C_OID_BRAINPOOL256T1[9] = {
|
const unsigned char C_OID_BRAINPOOL384R1[9] = {
|
||||||
0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07
|
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
|
//Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1
|
||||||
const unsigned char C_OID_Ed25519[9] = {
|
const unsigned char C_OID_Ed25519[9] = {
|
||||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
|
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
|
||||||
|
@ -59,10 +83,29 @@ const unsigned char C_OID_cv25519[10] = {
|
||||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
|
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) ) {
|
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) ) {
|
if ( (len == sizeof(C_OID_Ed25519)) && (os_memcmp(oid, C_OID_Ed25519, len)==0) ) {
|
||||||
|
@ -72,27 +115,93 @@ int gpg_oid2curve(unsigned char* oid, unsigned int len) {
|
||||||
if ( (len == sizeof(C_OID_cv25519)) && (os_memcmp(oid, C_OID_cv25519, len)==0) ) {
|
if ( (len == sizeof(C_OID_cv25519)) && (os_memcmp(oid, C_OID_cv25519, len)==0) ) {
|
||||||
return CX_CURVE_Curve25519;
|
return CX_CURVE_Curve25519;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if ( (len == sizeof(C_OID_SECP256K1)) && (os_memcmp(oid, C_OID_SECP256K1, len)==0) ) {
|
if ( (len == sizeof(C_OID_SECP256K1)) && (os_memcmp(oid, C_OID_SECP256K1, len)==0) ) {
|
||||||
return CX_CURVE_256K1;
|
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) ) {
|
if ( (len == sizeof(C_OID_BRAINPOOL256T1)) && (os_memcmp(oid, C_OID_BRAINPOOL256T1, len)==0) ) {
|
||||||
return CX_CURVE_BrainPoolP256T1;
|
return CX_CURVE_BrainPoolP256T1;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return CX_CURVE_NONE;
|
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 -- */
|
/* -- Non Mutable Capabilities -- */
|
||||||
/* -------------------------------*/
|
/* -------------------------------*/
|
||||||
|
|
||||||
const unsigned char C_ext_capabilities[10] = {
|
const unsigned char C_ext_capabilities[10] = {
|
||||||
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -RFU
|
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -KDF
|
||||||
0x7E,
|
0x7E,
|
||||||
// No SM,
|
// No SM,
|
||||||
0x00,
|
0x00,
|
||||||
|
@ -104,8 +213,8 @@ const unsigned char C_ext_capabilities[10] = {
|
||||||
SHORT(GPG_EXT_PRIVATE_DO_LENGTH),
|
SHORT(GPG_EXT_PRIVATE_DO_LENGTH),
|
||||||
//PIN block formart 2 not supported
|
//PIN block formart 2 not supported
|
||||||
0x00,
|
0x00,
|
||||||
//RFU
|
//MSE
|
||||||
0x00
|
0x01
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -122,7 +231,7 @@ const unsigned char C_ext_length[8] = {
|
||||||
const unsigned char C_default_AID[] = {
|
const unsigned char C_default_AID[] = {
|
||||||
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
|
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
|
||||||
//version
|
//version
|
||||||
0x03, 0x00,
|
0x03, 0x03,
|
||||||
//manufacturer
|
//manufacturer
|
||||||
0x2C, 0x97,
|
0x2C, 0x97,
|
||||||
//serial
|
//serial
|
||||||
|
@ -154,7 +263,7 @@ const unsigned char C_default_AlgoAttrRSA[] = {
|
||||||
0x01
|
0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
const unsigned char C_default_AlgoAttrECC_sig[] = {
|
const unsigned char C_default_AlgoAttrECC_sig[] = {
|
||||||
// ecdsa
|
// ecdsa
|
||||||
0x13,
|
0x13,
|
||||||
|
@ -167,17 +276,29 @@ const unsigned char C_default_AlgoAttrECC_dec[] = {
|
||||||
// NIST-P256
|
// NIST-P256
|
||||||
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
|
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
|
||||||
};
|
};
|
||||||
|
#elif 0
|
||||||
#else
|
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[] = {
|
const unsigned char C_default_AlgoAttrECC_sig[] = {
|
||||||
// eddsa
|
// eddsa
|
||||||
22,
|
0x16,
|
||||||
// ed25519
|
// ed25519
|
||||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
|
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
|
||||||
};
|
};
|
||||||
const unsigned char C_default_AlgoAttrECC_dec[] = {
|
const unsigned char C_default_AlgoAttrECC_dec[] = {
|
||||||
// ecdh
|
// ecdh
|
||||||
18,
|
0x12,
|
||||||
//cv25519
|
//cv25519
|
||||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
|
0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
|
||||||
};
|
};
|
||||||
|
@ -211,11 +332,11 @@ void gpg_init() {
|
||||||
gpg_nvm_write(N_gpg_pstate->magic, (void*)C_MAGIC, sizeof(C_MAGIC));
|
gpg_nvm_write(N_gpg_pstate->magic, (void*)C_MAGIC, sizeof(C_MAGIC));
|
||||||
os_memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
|
os_memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
|
||||||
}
|
}
|
||||||
//ensure pin1 and pin2 are sync in case of powerloss
|
|
||||||
gpg_pin_sync12();
|
|
||||||
//key conf
|
//key conf
|
||||||
G_gpg_vstate.slot = N_gpg_pstate->config_slot[1];
|
G_gpg_vstate.slot = N_gpg_pstate->config_slot[1];
|
||||||
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
||||||
|
gpg_mse_reset();
|
||||||
//pin conf
|
//pin conf
|
||||||
G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0];
|
G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0];
|
||||||
//ux conf
|
//ux conf
|
||||||
|
@ -260,8 +381,6 @@ int gpg_install(unsigned char app_state) {
|
||||||
pin.counter = 3;
|
pin.counter = 3;
|
||||||
pin.ref = PIN_ID_PW1;
|
pin.ref = PIN_ID_PW1;
|
||||||
gpg_nvm_write(&N_gpg_pstate->PW1, &pin, sizeof(gpg_pin_t));
|
gpg_nvm_write(&N_gpg_pstate->PW1, &pin, sizeof(gpg_pin_t));
|
||||||
pin.ref = PIN_ID_PW2;
|
|
||||||
gpg_nvm_write(&N_gpg_pstate->PW2, &pin, sizeof(gpg_pin_t));
|
|
||||||
|
|
||||||
//default PW3: 1 2 3 4 5 6 7 8
|
//default PW3: 1 2 3 4 5 6 7 8
|
||||||
os_memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2));
|
os_memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2));
|
||||||
|
@ -284,16 +403,29 @@ int gpg_install(unsigned char app_state) {
|
||||||
gpg_nvm_write(&N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer, 3);
|
gpg_nvm_write(&N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer, 3);
|
||||||
|
|
||||||
//config rsa pub
|
//config rsa pub
|
||||||
l = GPG_RSA_DEFAULT_PUB;
|
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB>>24)&0xFF;
|
||||||
nvm_write(&N_gpg_pstate->default_RSA_exponent, &l, sizeof(unsigned int));
|
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;
|
||||||
|
G_gpg_vstate.work.io_buffer[3] = (GPG_RSA_DEFAULT_PUB>>0)&0xFF;
|
||||||
|
nvm_write(&N_gpg_pstate->default_RSA_exponent, G_gpg_vstate.work.io_buffer, 4);
|
||||||
|
|
||||||
//config pin
|
//config pin
|
||||||
|
#if 1
|
||||||
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM;
|
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM;
|
||||||
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1);
|
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1);
|
||||||
|
USBD_CCID_activate_pinpad(3);
|
||||||
|
#else
|
||||||
|
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_HOST;
|
||||||
|
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1);
|
||||||
|
USBD_CCID_activate_pinpad(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
//default key template: RSA 2048)
|
//default key template: RSA 2048)
|
||||||
|
|
||||||
for (int s = 0; s< GPG_KEYS_SLOTS; s++) {
|
for (int s = 0; s< GPG_KEYS_SLOTS; s++) {
|
||||||
|
unsigned char uif[2];
|
||||||
|
uif[0] = 0x00;
|
||||||
|
uif[1] = 0x20;
|
||||||
#if 1
|
#if 1
|
||||||
l = sizeof(C_default_AlgoAttrRSA);
|
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.value, (void*)C_default_AlgoAttrRSA, l);
|
||||||
|
@ -312,8 +444,25 @@ 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.value, (void*)C_default_AlgoAttrECC_dec, l);
|
||||||
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.length, &l, sizeof(unsigned int));
|
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.length, &l, sizeof(unsigned int));
|
||||||
#endif
|
#endif
|
||||||
|
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.UIF, &uif, 2);
|
||||||
|
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.UIF, &uif, 2);
|
||||||
|
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.UIF, &uif, 2);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define USBD_OFFSET_CfgDesc_bPINSupport (sizeof(USBD_CfgDesc)-16)
|
||||||
|
void USBD_CCID_activate_pinpad(int enabled) {
|
||||||
|
unsigned short length;
|
||||||
|
uint8_t *cfgDesc;
|
||||||
|
unsigned char e;
|
||||||
|
e = enabled?3:0;
|
||||||
|
length = 0;
|
||||||
|
cfgDesc = USBD_GetCfgDesc_impl(&length);
|
||||||
|
nvm_write(cfgDesc+(length-16), &e,1);
|
||||||
|
}
|
||||||
|
|
|
@ -149,10 +149,7 @@ void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) {
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* FECTH data from received buffer */
|
/* FECTH data from received buffer */
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
void gpg_io_fetch_buffer(unsigned char* buffer, unsigned int len) {
|
|
||||||
os_memmove(buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, len);
|
|
||||||
G_gpg_vstate.io_offset += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int gpg_io_fetch_u32() {
|
unsigned int gpg_io_fetch_u32() {
|
||||||
unsigned int v32;
|
unsigned int v32;
|
||||||
|
@ -247,7 +244,7 @@ int gpg_io_fetch(unsigned char* buffer, int len) {
|
||||||
int gpg_io_do(unsigned int io_flags) {
|
int gpg_io_do(unsigned int io_flags) {
|
||||||
|
|
||||||
//if pending input chaining
|
//if pending input chaining
|
||||||
if (G_gpg_vstate.io_cla & 0x01) {
|
if (G_gpg_vstate.io_cla & 0x10) {
|
||||||
goto in_chaining;
|
goto in_chaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ __attribute__((section(".boot"))) int main(void) {
|
||||||
//start communication with MCU
|
//start communication with MCU
|
||||||
io_seproxyhal_init();
|
io_seproxyhal_init();
|
||||||
|
|
||||||
USB_CCID_power(1);
|
USB_power(1);
|
||||||
io_usb_ccid_set_card_inserted(1);
|
io_usb_ccid_set_card_inserted(1);
|
||||||
|
|
||||||
|
|
||||||
|
|
78
src/gpg_mse.c
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* Copyright 2017 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
#include "cx.h"
|
||||||
|
#include "gpg_types.h"
|
||||||
|
#include "gpg_api.h"
|
||||||
|
#include "gpg_vars.h"
|
||||||
|
|
||||||
|
static int gpg_mse_set(int crt, int ref) {
|
||||||
|
|
||||||
|
if (crt == 0xA4) {
|
||||||
|
if (ref == 0x02) {
|
||||||
|
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->dec;
|
||||||
|
}
|
||||||
|
if (ref == 0x03) {
|
||||||
|
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->aut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crt == 0xB8) {
|
||||||
|
if (ref == 0x02) {
|
||||||
|
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->dec;
|
||||||
|
}
|
||||||
|
if (ref == 0x03) {
|
||||||
|
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->aut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int gpg_mse_reset() {
|
||||||
|
gpg_mse_set(0xA4, 0x03);
|
||||||
|
gpg_mse_set(0xB8, 0x02);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpg_apdu_mse() {
|
||||||
|
int crt,ref;
|
||||||
|
|
||||||
|
|
||||||
|
if ((G_gpg_vstate.io_p1 != 0x41) ||
|
||||||
|
((G_gpg_vstate.io_p2 != 0xA4)&&(G_gpg_vstate.io_p2 != 0xB8))) {
|
||||||
|
THROW(SW_INCORRECT_P1P2);
|
||||||
|
return SW_INCORRECT_P1P2;
|
||||||
|
}
|
||||||
|
|
||||||
|
crt = gpg_io_fetch_u16();
|
||||||
|
if (crt != 0x8301) {
|
||||||
|
THROW(SW_WRONG_DATA);
|
||||||
|
return SW_WRONG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref = gpg_io_fetch_u8();
|
||||||
|
if ((ref != 0x02) && (ref != 0x03)) {
|
||||||
|
THROW(SW_WRONG_DATA);
|
||||||
|
return SW_WRONG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpg_mse_set(crt,ref);
|
||||||
|
gpg_io_discard(1);
|
||||||
|
return SW_OK;
|
||||||
|
|
||||||
|
}
|
146
src/gpg_pin.c
|
@ -21,12 +21,11 @@
|
||||||
|
|
||||||
#include "gpg_ux_nanos.h"
|
#include "gpg_ux_nanos.h"
|
||||||
|
|
||||||
gpg_pin_t *gpg_pin_get_pin(int id) {
|
gpg_pin_t *gpg_pin_get_pin(int pinref) {
|
||||||
switch (id) {
|
switch (pinref) {
|
||||||
case PIN_ID_PW1 :
|
case PIN_ID_PW1 :
|
||||||
return &N_gpg_pstate->PW1;
|
|
||||||
case PIN_ID_PW2 :
|
case PIN_ID_PW2 :
|
||||||
return &N_gpg_pstate->PW2;
|
return &N_gpg_pstate->PW1;
|
||||||
case PIN_ID_PW3:
|
case PIN_ID_PW3:
|
||||||
return &N_gpg_pstate->PW3;
|
return &N_gpg_pstate->PW3;
|
||||||
case PIN_ID_RC:
|
case PIN_ID_RC:
|
||||||
|
@ -37,8 +36,8 @@ gpg_pin_t *gpg_pin_get_pin(int id) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int gpg_pin_get_index(unsigned int id) {
|
static int gpg_pin_get_state_index(unsigned int pinref) {
|
||||||
switch (id) {
|
switch (pinref) {
|
||||||
case PIN_ID_PW1 :
|
case PIN_ID_PW1 :
|
||||||
return 1;
|
return 1;
|
||||||
case PIN_ID_PW2 :
|
case PIN_ID_PW2 :
|
||||||
|
@ -52,28 +51,10 @@ static int gpg_pin_get_index(unsigned int id) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpg_pin_sync12() {
|
static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int pin_len) {
|
||||||
gpg_pin_t *pin1, *pin2;
|
|
||||||
pin1 = gpg_pin_get_pin(PIN_ID_PW1);
|
|
||||||
pin2 = gpg_pin_get_pin(PIN_ID_PW2);
|
|
||||||
if (os_memcmp(pin1, pin2, sizeof(gpg_pin_t))) {
|
|
||||||
pin1 = gpg_pin_get_pin(PIN_ID_PW1);
|
|
||||||
pin2 = gpg_pin_get_pin(PIN_ID_PW2);
|
|
||||||
gpg_nvm_write(pin2, pin1, sizeof(gpg_pin_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int pin_len) {
|
|
||||||
cx_sha256_t sha256;
|
cx_sha256_t sha256;
|
||||||
unsigned int counter;
|
unsigned int counter;
|
||||||
gpg_pin_t *brother;
|
|
||||||
|
|
||||||
brother = NULL;
|
|
||||||
if (pin->ref == PIN_ID_PW1) {
|
|
||||||
brother = gpg_pin_get_pin(PIN_ID_PW2);
|
|
||||||
} else if (pin->ref == PIN_ID_PW2) {
|
|
||||||
brother = gpg_pin_get_pin(PIN_ID_PW1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pin->counter == 0) {
|
if (pin->counter == 0) {
|
||||||
return SW_PIN_BLOCKED;
|
return SW_PIN_BLOCKED;
|
||||||
|
@ -81,40 +62,37 @@ static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int pi
|
||||||
|
|
||||||
counter = pin->counter-1;
|
counter = pin->counter-1;
|
||||||
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
|
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
|
||||||
if (brother) {
|
|
||||||
gpg_nvm_write(&(brother->counter), &counter, sizeof(int));
|
|
||||||
}
|
|
||||||
cx_sha256_init(&sha256);
|
cx_sha256_init(&sha256);
|
||||||
cx_hash((cx_hash_t*)&sha256, CX_LAST, pin_val, pin_len, NULL);
|
cx_hash((cx_hash_t*)&sha256, CX_LAST, pin_val, pin_len, NULL, 0);
|
||||||
if (os_memcmp(sha256.acc, pin->value, 32)) {
|
if (os_memcmp(sha256.acc, pin->value, 32)) {
|
||||||
return SW_SECURITY_STATUS_NOT_SATISFIED;
|
return SW_SECURITY_STATUS_NOT_SATISFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
counter = 3;
|
counter = 3;
|
||||||
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
|
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
|
||||||
if (brother) {
|
|
||||||
gpg_nvm_write(&(brother->counter), &counter, sizeof(int));
|
|
||||||
}
|
|
||||||
return SW_OK;
|
return SW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gpg_pin_check_throw(gpg_pin_t *pin, unsigned char *pin_val, int pin_len) {
|
static void gpg_pin_check_throw(gpg_pin_t *pin, int pinID,
|
||||||
|
unsigned char *pin_val, int pin_len) {
|
||||||
int sw;
|
int sw;
|
||||||
gpg_pin_set_verified(pin,0);
|
gpg_pin_set_verified(pinID,0);
|
||||||
sw = gpg_pin_check_internal(pin,pin_val,pin_len);
|
sw = gpg_pin_check_internal(pin,pin_val,pin_len);
|
||||||
if (sw == SW_OK) {
|
if (sw == SW_OK) {
|
||||||
gpg_pin_set_verified(pin,1);
|
gpg_pin_set_verified(pinID,1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
THROW(sw);
|
THROW(sw);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpg_pin_check(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len) {
|
int gpg_pin_check(gpg_pin_t *pin, int pinID,
|
||||||
|
unsigned char *pin_val, unsigned int pin_len) {
|
||||||
int sw;
|
int sw;
|
||||||
|
gpg_pin_set_verified(pinID,0);
|
||||||
sw = gpg_pin_check_internal(pin,pin_val,pin_len);
|
sw = gpg_pin_check_internal(pin,pin_val,pin_len);
|
||||||
gpg_pin_set_verified(pin,0);
|
|
||||||
if (sw == SW_OK) {
|
if (sw == SW_OK) {
|
||||||
gpg_pin_set_verified(pin,1);
|
gpg_pin_set_verified(pinID,1);
|
||||||
}
|
}
|
||||||
return sw;
|
return sw;
|
||||||
}
|
}
|
||||||
|
@ -125,17 +103,16 @@ void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len) {
|
||||||
gpg_pin_t newpin;
|
gpg_pin_t newpin;
|
||||||
|
|
||||||
cx_sha256_init(&sha256);
|
cx_sha256_init(&sha256);
|
||||||
cx_hash((cx_hash_t*)&sha256, CX_LAST, pin_val, pin_len, newpin.value);
|
cx_hash((cx_hash_t*)&sha256, CX_LAST, pin_val, pin_len, newpin.value, 32);
|
||||||
newpin.length = pin_len;
|
newpin.length = pin_len;
|
||||||
newpin.counter = 3;
|
newpin.counter = 3;
|
||||||
|
|
||||||
gpg_nvm_write(pin, &newpin, sizeof(gpg_pin_t));
|
gpg_nvm_write(pin, &newpin, sizeof(gpg_pin_t));
|
||||||
gpg_pin_sync12();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpg_pin_set_verified(gpg_pin_t *pin, int verified) {
|
int gpg_pin_set_verified(int pinID, int verified) {
|
||||||
int idx;
|
int idx;
|
||||||
idx = gpg_pin_get_index(pin->ref);
|
idx = gpg_pin_get_state_index(pinID);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
G_gpg_vstate.verified_pin[idx]=verified;
|
G_gpg_vstate.verified_pin[idx]=verified;
|
||||||
return verified;
|
return verified;
|
||||||
|
@ -143,9 +120,9 @@ int gpg_pin_set_verified(gpg_pin_t *pin, int verified) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpg_pin_is_verified(gpg_pin_t *pin) {
|
int gpg_pin_is_verified(int pinID) {
|
||||||
int idx;
|
int idx;
|
||||||
idx = gpg_pin_get_index(pin->ref);
|
idx = gpg_pin_get_state_index(pinID);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
return G_gpg_vstate.verified_pin[idx];
|
return G_gpg_vstate.verified_pin[idx];
|
||||||
}
|
}
|
||||||
|
@ -167,12 +144,13 @@ int gpg_apdu_verify() {
|
||||||
return SW_WRONG_DATA;
|
return SW_WRONG_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpg_pin_set_verified(pin,0);
|
//PINPAD
|
||||||
if (gpg_pin_is_blocked(pin)) {
|
if (G_gpg_vstate.io_cla == 0xEF) {
|
||||||
THROW(SW_PIN_BLOCKED);
|
if (gpg_pin_is_blocked(pin)) {
|
||||||
return SW_PIN_BLOCKED;
|
THROW(SW_PIN_BLOCKED);
|
||||||
}
|
return SW_PIN_BLOCKED;
|
||||||
if (G_gpg_vstate.io_length == 0) {
|
}
|
||||||
|
|
||||||
if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) {
|
if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) {
|
||||||
//Delegate pin check to ui
|
//Delegate pin check to ui
|
||||||
gpg_io_discard(1);
|
gpg_io_discard(1);
|
||||||
|
@ -186,16 +164,46 @@ int gpg_apdu_verify() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) {
|
if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) {
|
||||||
gpg_pin_set_verified(pin,1);
|
gpg_pin_set_verified(G_gpg_vstate.io_p2,1);
|
||||||
gpg_io_discard(1);
|
gpg_io_discard(1);
|
||||||
return SW_OK;
|
return SW_OK;
|
||||||
}
|
}
|
||||||
|
THROW(SW_WRONG_DATA);
|
||||||
|
return SW_WRONG_DATA;
|
||||||
}
|
}
|
||||||
gpg_pin_check_throw(pin,
|
|
||||||
G_gpg_vstate.work.io_buffer+ G_gpg_vstate.io_offset,
|
//NORMAL CHECK
|
||||||
G_gpg_vstate.io_length);
|
if ((G_gpg_vstate.io_p1==0) && G_gpg_vstate.io_length) {
|
||||||
|
if (gpg_pin_is_blocked(pin)) {
|
||||||
|
THROW(SW_PIN_BLOCKED);
|
||||||
|
return SW_PIN_BLOCKED;
|
||||||
|
}
|
||||||
|
gpg_pin_check_throw(pin, G_gpg_vstate.io_p2,
|
||||||
|
G_gpg_vstate.work.io_buffer+ G_gpg_vstate.io_offset,
|
||||||
|
G_gpg_vstate.io_length);
|
||||||
|
gpg_io_discard(1);
|
||||||
|
return SW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
gpg_io_discard(1);
|
gpg_io_discard(1);
|
||||||
return SW_OK;
|
|
||||||
|
//STATUS REQUEST
|
||||||
|
if ((G_gpg_vstate.io_p1==0) && G_gpg_vstate.io_length==0) {
|
||||||
|
if (gpg_pin_is_verified(G_gpg_vstate.io_p2)) {
|
||||||
|
return SW_OK;
|
||||||
|
}
|
||||||
|
return 0x63C0 | pin->counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//RESET REQUEST
|
||||||
|
if ((G_gpg_vstate.io_p1==0xFF) && G_gpg_vstate.io_length==0) {
|
||||||
|
gpg_pin_set_verified(G_gpg_vstate.io_p2,0);
|
||||||
|
return SW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
THROW(SW_WRONG_DATA);
|
||||||
|
return SW_WRONG_DATA;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpg_apdu_change_ref_data() {
|
int gpg_apdu_change_ref_data() {
|
||||||
|
@ -208,28 +216,10 @@ int gpg_apdu_change_ref_data() {
|
||||||
return SW_WRONG_DATA;
|
return SW_WRONG_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpg_pin_set_verified(pin,0);
|
gpg_pin_set_verified(pin->ref,0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --- RC pin ---
|
|
||||||
if (pin->ref == PIN_ID_RC) {
|
|
||||||
newlen = G_gpg_vstate.io_length;
|
|
||||||
if (newlen == 0) {
|
|
||||||
gpg_nvm_write(pin, NULL, sizeof(gpg_pin_t));
|
|
||||||
|
|
||||||
}
|
|
||||||
else if ((newlen > GPG_MAX_PW_LENGTH) ||
|
|
||||||
(newlen < 8)) {
|
|
||||||
THROW(SW_WRONG_DATA);
|
|
||||||
return SW_WRONG_DATA;
|
|
||||||
} else {
|
|
||||||
gpg_pin_set(pin,
|
|
||||||
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
|
||||||
newlen);
|
|
||||||
}
|
|
||||||
gpg_io_discard(1);
|
|
||||||
return SW_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- PW1/PW3 pin ---
|
// --- PW1/PW3 pin ---
|
||||||
if (gpg_pin_is_blocked(pin)) {
|
if (gpg_pin_is_blocked(pin)) {
|
||||||
|
@ -252,7 +242,7 @@ int gpg_apdu_change_ref_data() {
|
||||||
len = pin->length;
|
len = pin->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpg_pin_check_throw(pin,
|
gpg_pin_check_throw(pin, pin->ref,
|
||||||
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
||||||
len);
|
len);
|
||||||
|
|
||||||
|
@ -281,7 +271,7 @@ int gpg_apdu_reset_retry_counter() {
|
||||||
pin_rc = gpg_pin_get_pin(PIN_ID_RC);
|
pin_rc = gpg_pin_get_pin(PIN_ID_RC);
|
||||||
|
|
||||||
if (G_gpg_vstate.io_p1 == 2) {
|
if (G_gpg_vstate.io_p1 == 2) {
|
||||||
if (!gpg_pin_is_verified(pin_pw3)) {
|
if (!gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||||
THROW(SW_SECURITY_STATUS_NOT_SATISFIED);
|
THROW(SW_SECURITY_STATUS_NOT_SATISFIED);
|
||||||
return SW_SECURITY_STATUS_NOT_SATISFIED;
|
return SW_SECURITY_STATUS_NOT_SATISFIED;
|
||||||
}
|
}
|
||||||
|
@ -296,7 +286,7 @@ int gpg_apdu_reset_retry_counter() {
|
||||||
rc_len = pin_rc->length;
|
rc_len = pin_rc->length;
|
||||||
}
|
}
|
||||||
pw1_len = G_gpg_vstate.io_length-rc_len;
|
pw1_len = G_gpg_vstate.io_length-rc_len;
|
||||||
gpg_pin_check_throw(pin_rc,
|
gpg_pin_check_throw(pin_rc,pin_rc->ref,
|
||||||
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
||||||
rc_len);
|
rc_len);
|
||||||
}
|
}
|
||||||
|
|
157
src/gpg_pso.c
|
@ -18,6 +18,7 @@
|
||||||
#include "gpg_types.h"
|
#include "gpg_types.h"
|
||||||
#include "gpg_api.h"
|
#include "gpg_api.h"
|
||||||
#include "gpg_vars.h"
|
#include "gpg_vars.h"
|
||||||
|
#include "gpg_ux_nanos.h"
|
||||||
|
|
||||||
const unsigned char gpg_oid_sha256[] = {
|
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
|
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
|
||||||
|
@ -28,7 +29,7 @@ const unsigned char gpg_oid_sha512[] = {
|
||||||
|
|
||||||
static void gpg_pso_reset_PW1() {
|
static void gpg_pso_reset_PW1() {
|
||||||
if (N_gpg_pstate->PW_status[0] ==0) {
|
if (N_gpg_pstate->PW_status[0] ==0) {
|
||||||
gpg_pin_set_verified(gpg_pin_get_pin(PIN_ID_PW1),0);
|
gpg_pin_set_verified(PIN_ID_PW1,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,16 +42,16 @@ static int gpg_sign(gpg_key_t *sigkey) {
|
||||||
ksz = ksz>>3;
|
ksz = ksz>>3;
|
||||||
switch(ksz) {
|
switch(ksz) {
|
||||||
case 1024/8:
|
case 1024/8:
|
||||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa1024;
|
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa1024;
|
||||||
break;
|
break;
|
||||||
case 2048/8:
|
case 2048/8:
|
||||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa2048;
|
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa2048;
|
||||||
break;
|
break;
|
||||||
case 3072/8:
|
case 3072/8:
|
||||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa3072;
|
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa3072;
|
||||||
break;
|
break;
|
||||||
case 4096/8:
|
case 4096/8:
|
||||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa4096;
|
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa4096;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (key->size != ksz) {
|
if (key->size != ksz) {
|
||||||
|
@ -86,23 +87,27 @@ static int gpg_sign(gpg_key_t *sigkey) {
|
||||||
unsigned int sz,i,rs_len;
|
unsigned int sz,i,rs_len;
|
||||||
unsigned char *rs;
|
unsigned char *rs;
|
||||||
|
|
||||||
key = &sigkey->key.ecfp256;
|
key = &sigkey->priv_key.ecfp;
|
||||||
if (key->d_len != 32) {
|
|
||||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
|
||||||
return SW_CONDITIONS_NOT_SATISFIED;
|
|
||||||
}
|
|
||||||
//sign
|
//sign
|
||||||
|
#define RS (G_gpg_vstate.work.io_buffer+(GPG_IO_BUFFER_LENGTH-256))
|
||||||
if (sigkey->attributes.value[0] == 19) {
|
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,
|
sz = cx_ecdsa_sign(key,
|
||||||
CX_RND_TRNG,
|
CX_RND_TRNG,
|
||||||
CX_NONE,
|
CX_NONE,
|
||||||
G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
G_gpg_vstate.work.io_buffer, sz,
|
||||||
G_gpg_vstate.work.io_buffer);
|
RS, 256,
|
||||||
|
NULL);
|
||||||
//reencode r,s in MPI format
|
//reencode r,s in MPI format
|
||||||
gpg_io_discard(0);
|
gpg_io_discard(0);
|
||||||
|
|
||||||
rs_len = G_gpg_vstate.work.io_buffer[3];
|
rs_len = RS[3];
|
||||||
rs = &G_gpg_vstate.work.io_buffer[4];
|
rs = &RS[4];
|
||||||
|
|
||||||
for (i = 0; i<2; i++) {
|
for (i = 0; i<2; i++) {
|
||||||
if (*rs == 0) {
|
if (*rs == 0) {
|
||||||
|
@ -116,15 +121,18 @@ static int gpg_sign(gpg_key_t *sigkey) {
|
||||||
rs += 2;
|
rs += 2;
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
sz = cx_eddsa_sign(key, NULL,
|
sz = cx_eddsa_sign(key,
|
||||||
CX_NONE,
|
CX_NONE,
|
||||||
CX_SHA512,
|
CX_SHA512,
|
||||||
G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
||||||
G_gpg_vstate.work.io_buffer+128);
|
NULL, 0,
|
||||||
|
RS, 256,
|
||||||
|
NULL);
|
||||||
gpg_io_discard(0);
|
gpg_io_discard(0);
|
||||||
gpg_io_insert(G_gpg_vstate.work.io_buffer+128, sz);
|
gpg_io_insert(RS, sz);
|
||||||
}
|
}
|
||||||
|
#undef RS
|
||||||
|
|
||||||
//send
|
//send
|
||||||
gpg_pso_reset_PW1();
|
gpg_pso_reset_PW1();
|
||||||
return SW_OK;
|
return SW_OK;
|
||||||
|
@ -134,9 +142,38 @@ static int gpg_sign(gpg_key_t *sigkey) {
|
||||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gpg_apdu_pso() {
|
||||||
int gpg_apdu_pso(unsigned int pso) {
|
|
||||||
unsigned int t,l,ksz;
|
unsigned int t,l,ksz;
|
||||||
|
|
||||||
|
unsigned int pso;
|
||||||
|
|
||||||
|
pso = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
|
||||||
|
|
||||||
|
//UIF HANDLE
|
||||||
|
switch(pso) {
|
||||||
|
// --- PSO:CDS ---
|
||||||
|
case 0x9e9a:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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) {
|
switch(pso) {
|
||||||
// --- PSO:CDS ---
|
// --- PSO:CDS ---
|
||||||
case 0x9e9a: {
|
case 0x9e9a: {
|
||||||
|
@ -147,6 +184,27 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
nvm_write(&G_gpg_vstate.kslot->sig_count,&cnt,sizeof(unsigned int));
|
nvm_write(&G_gpg_vstate.kslot->sig_count,&cnt,sizeof(unsigned int));
|
||||||
return sw;
|
return sw;
|
||||||
}
|
}
|
||||||
|
// --- PSO:ENC ---
|
||||||
|
case 0x8680: {
|
||||||
|
unsigned int msg_len;
|
||||||
|
cx_aes_key_t *key;
|
||||||
|
unsigned int sz;
|
||||||
|
key = &G_gpg_vstate.kslot->AES_dec;
|
||||||
|
if (!(key->size != 16)) {
|
||||||
|
THROW(SW_CONDITIONS_NOT_SATISFIED+5);
|
||||||
|
return SW_CONDITIONS_NOT_SATISFIED;
|
||||||
|
}
|
||||||
|
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
|
||||||
|
sz = cx_aes(key,
|
||||||
|
CX_ENCRYPT|CX_CHAIN_CBC|CX_LAST,
|
||||||
|
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, msg_len,
|
||||||
|
G_gpg_vstate.work.io_buffer+1, GPG_IO_BUFFER_LENGTH-1);
|
||||||
|
//send
|
||||||
|
gpg_io_discard(0);
|
||||||
|
G_gpg_vstate.work.io_buffer[0] = 0x02;
|
||||||
|
gpg_io_inserted(1+sz);
|
||||||
|
return SW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// --- PSO:DEC ---
|
// --- PSO:DEC ---
|
||||||
case 0x8086: {
|
case 0x8086: {
|
||||||
|
@ -159,31 +217,31 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
// --- PSO:DEC:RSA
|
// --- PSO:DEC:RSA
|
||||||
case 0x00: {
|
case 0x00: {
|
||||||
cx_rsa_private_key_t *key;
|
cx_rsa_private_key_t *key;
|
||||||
if (G_gpg_vstate.kslot->dec.attributes.value[0] != 0x01) {
|
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x01) {
|
||||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||||
return SW_CONDITIONS_NOT_SATISFIED;
|
return SW_CONDITIONS_NOT_SATISFIED;
|
||||||
}
|
}
|
||||||
ksz = (G_gpg_vstate.kslot->dec.attributes.value[1]<<8) | G_gpg_vstate.kslot->dec.attributes.value[2];
|
ksz = (G_gpg_vstate.mse_dec->attributes.value[1]<<8) | G_gpg_vstate.mse_dec->attributes.value[2];
|
||||||
ksz = ksz>>3;
|
ksz = ksz>>3;
|
||||||
key = NULL;
|
key = NULL;
|
||||||
switch(ksz) {
|
switch(ksz) {
|
||||||
case 1024/8:
|
case 1024/8:
|
||||||
key = (cx_rsa_private_key_t *)&G_gpg_vstate.kslot->dec.key.rsa1024;
|
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa1024;
|
||||||
break;
|
break;
|
||||||
case 2048/8:
|
case 2048/8:
|
||||||
key = (cx_rsa_private_key_t *)&G_gpg_vstate.kslot->dec.key.rsa2048;
|
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa2048;
|
||||||
break;
|
break;
|
||||||
case 3072/8:
|
case 3072/8:
|
||||||
key = (cx_rsa_private_key_t *)&G_gpg_vstate.kslot->dec.key.rsa3072;
|
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa3072;
|
||||||
break;
|
break;
|
||||||
case 4096/8:
|
case 4096/8:
|
||||||
key = (cx_rsa_private_key_t *)&G_gpg_vstate.kslot->dec.key.rsa4096;
|
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa4096;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((key == NULL) || (key->size != ksz)) {
|
if ((key == NULL) || (key->size != ksz)) {
|
||||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||||
return 0;
|
return SW_CONDITIONS_NOT_SATISFIED;
|
||||||
}
|
}
|
||||||
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
|
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
|
||||||
sz = cx_rsa_decrypt(key,
|
sz = cx_rsa_decrypt(key,
|
||||||
|
@ -208,9 +266,9 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
}
|
}
|
||||||
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
|
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
|
||||||
sz = cx_aes(key,
|
sz = cx_aes(key,
|
||||||
CX_DECRYPT|CX_LAST,
|
CX_DECRYPT|CX_CHAIN_CBC|CX_LAST,
|
||||||
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, msg_len,
|
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, msg_len,
|
||||||
G_gpg_vstate.work.io_buffer);
|
G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
|
||||||
//send
|
//send
|
||||||
gpg_io_discard(0);
|
gpg_io_discard(0);
|
||||||
gpg_io_inserted(sz);
|
gpg_io_inserted(sz);
|
||||||
|
@ -222,15 +280,11 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
cx_ecfp_private_key_t *key;
|
cx_ecfp_private_key_t *key;
|
||||||
unsigned int sz;
|
unsigned int sz;
|
||||||
unsigned int curve;
|
unsigned int curve;
|
||||||
if (G_gpg_vstate.kslot->dec.attributes.value[0] != 18) {
|
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x12) {
|
||||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||||
return SW_CONDITIONS_NOT_SATISFIED;
|
return SW_CONDITIONS_NOT_SATISFIED;
|
||||||
}
|
}
|
||||||
key = &G_gpg_vstate.kslot->dec.key.ecfp256;
|
key = &G_gpg_vstate.mse_dec->priv_key.ecfp;
|
||||||
if (key->d_len != 32) {
|
|
||||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
|
||||||
return SW_CONDITIONS_NOT_SATISFIED;
|
|
||||||
}
|
|
||||||
gpg_io_fetch_l(&l);
|
gpg_io_fetch_l(&l);
|
||||||
gpg_io_fetch_tl(&t, &l);
|
gpg_io_fetch_tl(&t, &l);
|
||||||
if (t != 0x7f49) {
|
if (t != 0x7f49) {
|
||||||
|
@ -243,7 +297,11 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
return SW_WRONG_DATA;
|
return SW_WRONG_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
curve = gpg_oid2curve(G_gpg_vstate.kslot->dec.attributes.value+1, G_gpg_vstate.kslot->dec.attributes.length-1);
|
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) {
|
if (curve == CX_CURVE_Curve25519) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -253,8 +311,8 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
G_gpg_vstate.work.io_buffer[511] = 0x02;
|
G_gpg_vstate.work.io_buffer[511] = 0x02;
|
||||||
sz = cx_ecdh(key,
|
sz = cx_ecdh(key,
|
||||||
CX_ECDH_X,
|
CX_ECDH_X,
|
||||||
G_gpg_vstate.work.io_buffer+511,
|
G_gpg_vstate.work.io_buffer+511, 65,
|
||||||
G_gpg_vstate.work.io_buffer+256);
|
G_gpg_vstate.work.io_buffer+256, 160);
|
||||||
for (i = 0; i <=31; i++) {
|
for (i = 0; i <=31; i++) {
|
||||||
G_gpg_vstate.work.io_buffer[128+i] = G_gpg_vstate.work.io_buffer[287-i];
|
G_gpg_vstate.work.io_buffer[128+i] = G_gpg_vstate.work.io_buffer[287-i];
|
||||||
}
|
}
|
||||||
|
@ -262,8 +320,8 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
} else {
|
} else {
|
||||||
sz = cx_ecdh(key,
|
sz = cx_ecdh(key,
|
||||||
CX_ECDH_X,
|
CX_ECDH_X,
|
||||||
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, 65,
|
||||||
G_gpg_vstate.work.io_buffer+128);
|
G_gpg_vstate.work.io_buffer+128, 160);
|
||||||
}
|
}
|
||||||
//send
|
//send
|
||||||
gpg_io_discard(0);
|
gpg_io_discard(0);
|
||||||
|
@ -276,7 +334,6 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
||||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--- PSO:yy NOT SUPPPORTED ---
|
//--- PSO:yy NOT SUPPPORTED ---
|
||||||
|
@ -290,14 +347,20 @@ int gpg_apdu_pso(unsigned int pso) {
|
||||||
|
|
||||||
|
|
||||||
int gpg_apdu_internal_authenticate() {
|
int gpg_apdu_internal_authenticate() {
|
||||||
gpg_key_t *sigkey;
|
// --- PSO:AUTH ---
|
||||||
sigkey = &G_gpg_vstate.kslot->aut;
|
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.kslot->aut.attributes.value[0] == 1) {
|
if (G_gpg_vstate.mse_aut->attributes.value[0] == 1) {
|
||||||
if ( G_gpg_vstate.io_length > ((G_gpg_vstate.kslot->aut.attributes.value[1]<<8)|G_gpg_vstate.kslot->aut.attributes.value[2])*40/100) {
|
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) {
|
||||||
THROW(SW_WRONG_LENGTH);
|
THROW(SW_WRONG_LENGTH);
|
||||||
return SW_WRONG_LENGTH;
|
return SW_WRONG_LENGTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gpg_sign(&G_gpg_vstate.kslot->aut);
|
return gpg_sign(G_gpg_vstate.mse_aut);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#ifndef GPG_DEBUG_MAIN
|
#ifndef GPG_DEBUG_MAIN
|
||||||
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
|
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
|
||||||
ux_state_t ux;
|
ux_state_t ux;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
|
extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
|
||||||
int apdu_n;
|
int apdu_n;
|
||||||
|
|
|
@ -19,10 +19,19 @@
|
||||||
#include "gpg_types.h"
|
#include "gpg_types.h"
|
||||||
#include "gpg_api.h"
|
#include "gpg_api.h"
|
||||||
#include "gpg_vars.h"
|
#include "gpg_vars.h"
|
||||||
|
const unsigned char C_MF[] = {0x3F, 0x00};
|
||||||
|
|
||||||
int gpg_apdu_select() {
|
int gpg_apdu_select() {
|
||||||
int sw;
|
int sw;
|
||||||
if ( (G_gpg_vstate.io_length == 6) &&
|
|
||||||
|
//MF
|
||||||
|
if ( (G_gpg_vstate.io_length == 2) &&
|
||||||
|
(os_memcmp(G_gpg_vstate.work.io_buffer, C_MF, G_gpg_vstate.io_length) == 0) ) {
|
||||||
|
gpg_io_discard(0);
|
||||||
|
sw = SW_OK;
|
||||||
|
}
|
||||||
|
//AID APP
|
||||||
|
else if ( (G_gpg_vstate.io_length == 6) &&
|
||||||
(os_memcmp(G_gpg_vstate.work.io_buffer, N_gpg_pstate->AID, G_gpg_vstate.io_length) == 0) ) {
|
(os_memcmp(G_gpg_vstate.work.io_buffer, N_gpg_pstate->AID, G_gpg_vstate.io_length) == 0) ) {
|
||||||
G_gpg_vstate.DO_current = 0;
|
G_gpg_vstate.DO_current = 0;
|
||||||
G_gpg_vstate.DO_reccord = 0;
|
G_gpg_vstate.DO_reccord = 0;
|
||||||
|
@ -36,8 +45,13 @@ int gpg_apdu_select() {
|
||||||
}
|
}
|
||||||
|
|
||||||
gpg_io_discard(0);
|
gpg_io_discard(0);
|
||||||
|
if (N_gpg_pstate->histo[7] != 0x07) {
|
||||||
|
THROW(SW_STATE_TERMINATED);
|
||||||
|
}
|
||||||
sw = SW_OK;
|
sw = SW_OK;
|
||||||
} else {
|
}
|
||||||
|
//NOT FOUND
|
||||||
|
else {
|
||||||
THROW(SW_FILE_NOT_FOUND);
|
THROW(SW_FILE_NOT_FOUND);
|
||||||
return SW_FILE_NOT_FOUND;
|
return SW_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
#define GPG_KEY_ATTRIBUTES_LENGTH 12
|
#define GPG_KEY_ATTRIBUTES_LENGTH 12
|
||||||
|
|
||||||
#define GPG_RSA_DEFAULT_PUB 0x010001U
|
#define GPG_RSA_DEFAULT_PUB 0x00010001U
|
||||||
|
|
||||||
struct gpg_pin_s {
|
struct gpg_pin_s {
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
|
@ -66,15 +66,25 @@ typedef struct gpg_key_s {
|
||||||
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
||||||
/* key value */
|
/* key value */
|
||||||
union {
|
union {
|
||||||
|
cx_rsa_private_key_t rsa;
|
||||||
cx_rsa_1024_private_key_t rsa1024;
|
cx_rsa_1024_private_key_t rsa1024;
|
||||||
cx_rsa_2048_private_key_t rsa2048;
|
cx_rsa_2048_private_key_t rsa2048;
|
||||||
cx_rsa_3072_private_key_t rsa3072;
|
cx_rsa_3072_private_key_t rsa3072;
|
||||||
cx_rsa_4096_private_key_t rsa4096;
|
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 {
|
union {
|
||||||
unsigned char rsa[4];
|
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;
|
} pub_key;
|
||||||
/* C7 C8 C9 , C5 = C7|C8|C9*/
|
/* C7 C8 C9 , C5 = C7|C8|C9*/
|
||||||
unsigned char fingerprints[20];
|
unsigned char fingerprints[20];
|
||||||
|
@ -116,7 +126,7 @@ struct gpg_nv_state_s {
|
||||||
/* 01F1 (01F2 is volatile)*/
|
/* 01F1 (01F2 is volatile)*/
|
||||||
unsigned char config_slot[3];
|
unsigned char config_slot[3];
|
||||||
/* RSA exponent */
|
/* RSA exponent */
|
||||||
unsigned int default_RSA_exponent;
|
unsigned char default_RSA_exponent[4];
|
||||||
|
|
||||||
/* 0101 0102 0103 0104 */
|
/* 0101 0102 0103 0104 */
|
||||||
LV(private_DO1, GPG_EXT_PRIVATE_DO_LENGTH);
|
LV(private_DO1, GPG_EXT_PRIVATE_DO_LENGTH);
|
||||||
|
@ -152,7 +162,6 @@ struct gpg_nv_state_s {
|
||||||
|
|
||||||
/* PINs */
|
/* PINs */
|
||||||
gpg_pin_t PW1;
|
gpg_pin_t PW1;
|
||||||
gpg_pin_t PW2;
|
|
||||||
gpg_pin_t PW3;
|
gpg_pin_t PW3;
|
||||||
gpg_pin_t RC;
|
gpg_pin_t RC;
|
||||||
|
|
||||||
|
@ -174,10 +183,15 @@ struct gpg_v_state_s {
|
||||||
/* app state */
|
/* app state */
|
||||||
unsigned char selected;
|
unsigned char selected;
|
||||||
unsigned char slot; /* DO 01F2 */
|
unsigned char slot; /* DO 01F2 */
|
||||||
gpg_key_slot_t *kslot;
|
gpg_key_slot_t *kslot;
|
||||||
|
gpg_key_t *mse_aut;
|
||||||
|
gpg_key_t *mse_dec;
|
||||||
unsigned char seed_mode;
|
unsigned char seed_mode;
|
||||||
|
|
||||||
|
unsigned char UIF_flags;
|
||||||
|
|
||||||
/* io state*/
|
/* io state*/
|
||||||
|
|
||||||
unsigned char io_cla;
|
unsigned char io_cla;
|
||||||
unsigned char io_ins;
|
unsigned char io_ins;
|
||||||
unsigned char io_p1;
|
unsigned char io_p1;
|
||||||
|
@ -189,26 +203,41 @@ struct gpg_v_state_s {
|
||||||
unsigned short io_mark;
|
unsigned short io_mark;
|
||||||
union {
|
union {
|
||||||
unsigned char io_buffer[GPG_IO_BUFFER_LENGTH];
|
unsigned char io_buffer[GPG_IO_BUFFER_LENGTH];
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
cx_rsa_1024_public_key_t public;
|
union {
|
||||||
cx_rsa_1024_private_key_t private;
|
cx_rsa_public_key_t public;
|
||||||
}rsa1024;
|
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 {
|
struct {
|
||||||
cx_rsa_2048_public_key_t public;
|
union{
|
||||||
cx_rsa_2048_private_key_t private;
|
cx_ecfp_public_key_t public;
|
||||||
}rsa2048;
|
cx_ecfp_256_public_key_t public256;
|
||||||
struct {
|
cx_ecfp_384_public_key_t public384;
|
||||||
cx_rsa_3072_public_key_t public;
|
cx_ecfp_512_public_key_t public512;
|
||||||
cx_rsa_3072_private_key_t private;
|
cx_ecfp_640_public_key_t public640;
|
||||||
}rsa3072;
|
};
|
||||||
struct {
|
union {
|
||||||
cx_rsa_4096_public_key_t public;
|
cx_ecfp_private_key_t private;
|
||||||
cx_rsa_4096_private_key_t private;
|
cx_ecfp_256_private_key_t private256;
|
||||||
}rsa4096;
|
cx_ecfp_384_private_key_t private384;
|
||||||
struct {
|
cx_ecfp_512_private_key_t private512;
|
||||||
cx_ecfp_public_key_t public;
|
cx_ecfp_640_private_key_t private640;
|
||||||
cx_ecfp_private_key_t private;
|
};
|
||||||
}ecfp256;
|
}ecfp;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH-MAX(sizeof(cx_sha3_t),sizeof(cx_sha256_t))];
|
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH-MAX(sizeof(cx_sha3_t),sizeof(cx_sha256_t))];
|
||||||
union {
|
union {
|
||||||
|
@ -228,7 +257,7 @@ struct gpg_v_state_s {
|
||||||
unsigned char pinmode;
|
unsigned char pinmode;
|
||||||
|
|
||||||
/* ux menus */
|
/* ux menus */
|
||||||
char menu[64];
|
char menu[112];
|
||||||
unsigned char ux_pinentry[12];
|
unsigned char ux_pinentry[12];
|
||||||
unsigned int ux_key;
|
unsigned int ux_key;
|
||||||
unsigned int ux_type;
|
unsigned int ux_type;
|
||||||
|
@ -285,6 +314,7 @@ typedef struct gpg_v_state_s gpg_v_state_t;
|
||||||
#define INS_PUT_DATA_ODD 0xdb
|
#define INS_PUT_DATA_ODD 0xdb
|
||||||
|
|
||||||
#define INS_VERIFY 0x20
|
#define INS_VERIFY 0x20
|
||||||
|
#define INS_MSE 0x22
|
||||||
#define INS_CHANGE_REFERENCE_DATA 0x24
|
#define INS_CHANGE_REFERENCE_DATA 0x24
|
||||||
#define INS_RESET_RETRY_COUNTER 0x2c
|
#define INS_RESET_RETRY_COUNTER 0x2c
|
||||||
|
|
||||||
|
|
|
@ -34,3 +34,5 @@ const char * const C_NOT_ALLOWED = "Not Allowed ";
|
||||||
|
|
||||||
const char * const C_DEFAULT_MODE = "Default mode";
|
const char * const C_DEFAULT_MODE = "Default mode";
|
||||||
|
|
||||||
|
|
||||||
|
const char * const C_UIF_LOCKED = "UIF locked";
|
||||||
|
|
|
@ -36,6 +36,9 @@ extern const char * const C_NOT_ALLOWED;
|
||||||
|
|
||||||
extern const char * const C_DEFAULT_MODE;
|
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 PICSTR(x) ((char*)PIC(x))
|
||||||
|
|
||||||
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
|
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
|
||||||
|
@ -54,5 +57,7 @@ extern const char * const C_DEFAULT_MODE;
|
||||||
#define ALLOWED PICSTR(C_ALLOWED)
|
#define ALLOWED PICSTR(C_ALLOWED)
|
||||||
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
|
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
|
||||||
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
|
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
|
||||||
|
#define UIF_LOCKED PICSTR(C_UIF_LOCKED)
|
||||||
|
#define UIF_INVALID PICSTR(C_UIF_INVALID)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -91,6 +91,122 @@ void ui_info(const char* msg1, const char* msg2, const void *menu_display, unsig
|
||||||
UX_MENU_DISPLAY(0, G_gpg_vstate.ui_dogsays, NULL);
|
UX_MENU_DISPLAY(0, G_gpg_vstate.ui_dogsays, NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------ UIF CONFIRM UX ----------------------------- */
|
||||||
|
unsigned int ui_uifconfirm_nanos_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||||
|
unsigned int ui_uifconfirm_prepro(const bagl_element_t* element);
|
||||||
|
|
||||||
|
const bagl_element_t ui_uifconfirm_nanos[] = {
|
||||||
|
// type userid x y w h str rad fill fg bg font_id icon_id
|
||||||
|
{ {BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, 0, 0},
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
0, 0,
|
||||||
|
NULL, NULL, NULL},
|
||||||
|
|
||||||
|
{ {BAGL_ICON, 0x00, 3, 12, 7, 7, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CROSS },
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
0, 0,
|
||||||
|
NULL, NULL, NULL },
|
||||||
|
|
||||||
|
{ {BAGL_ICON, 0x00, 117, 13, 8, 6, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CHECK },
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
0, 0,
|
||||||
|
NULL, NULL, NULL },
|
||||||
|
|
||||||
|
{ {BAGL_LABELINE, 0x01, 0, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 },
|
||||||
|
G_gpg_vstate.menu,
|
||||||
|
0,
|
||||||
|
0, 0,
|
||||||
|
NULL, NULL, NULL },
|
||||||
|
{ {BAGL_LABELINE, 0x02, 0, 26, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 },
|
||||||
|
G_gpg_vstate.menu,
|
||||||
|
0,
|
||||||
|
0, 0,
|
||||||
|
NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
void ui_menu_uifconfirm_display(unsigned int value) {
|
||||||
|
UX_DISPLAY(ui_uifconfirm_nanos, (void*)ui_uifconfirm_prepro);
|
||||||
|
}
|
||||||
|
|
||||||
|
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:");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (element->component.userid == 2) {
|
||||||
|
unsigned int uif_case = (G_gpg_vstate.io_ins<<16)|(G_gpg_vstate.io_p1<<8)|(G_gpg_vstate.io_p2);
|
||||||
|
switch (uif_case) {
|
||||||
|
case 0x002A9E9A:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Signature");
|
||||||
|
return 1;
|
||||||
|
case 0x002A8680:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Encryption");
|
||||||
|
return 1;
|
||||||
|
case 0x002A8086:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Decryption");
|
||||||
|
return 1;
|
||||||
|
case 0x0088000:
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Authentication");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Please Cancel");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ui_uifconfirm_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||||
|
unsigned int sw;
|
||||||
|
|
||||||
|
sw = 0x6985;
|
||||||
|
switch(button_mask) {
|
||||||
|
case BUTTON_EVT_RELEASED|BUTTON_LEFT: // CANCEL
|
||||||
|
gpg_io_discard(1);
|
||||||
|
gpg_io_insert_u16(sw);
|
||||||
|
gpg_io_do(IO_RETURN_AFTER_TX);
|
||||||
|
ui_menu_main_display(0);
|
||||||
|
sw = 0x6985;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_EVT_RELEASED|BUTTON_RIGHT: // OK
|
||||||
|
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);
|
||||||
|
if ( (e & 0xFFFF0000) ||
|
||||||
|
( ((e&0xF000)!=0x6000) && ((e&0xF000)!=0x9000) ) ) {
|
||||||
|
gpg_io_insert_u32(e);
|
||||||
|
sw = 0x6f42;
|
||||||
|
} else {
|
||||||
|
sw = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FINALLY {
|
||||||
|
G_gpg_vstate.UIF_flags = 0;
|
||||||
|
gpg_io_insert_u16(sw);
|
||||||
|
gpg_io_do(IO_RETURN_AFTER_TX);
|
||||||
|
ui_menu_main_display(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
} END_TRY;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------ PIN CONFIRM UX ----------------------------- */
|
/* ------------------------------ PIN CONFIRM UX ----------------------------- */
|
||||||
|
|
||||||
const bagl_element_t ui_pinconfirm_nanos[] = {
|
const bagl_element_t ui_pinconfirm_nanos[] = {
|
||||||
|
@ -152,12 +268,12 @@ unsigned int ui_pinconfirm_nanos_button(unsigned int button_mask, unsigned int b
|
||||||
sw = 0x6985;
|
sw = 0x6985;
|
||||||
switch(button_mask) {
|
switch(button_mask) {
|
||||||
case BUTTON_EVT_RELEASED|BUTTON_LEFT: // CANCEL
|
case BUTTON_EVT_RELEASED|BUTTON_LEFT: // CANCEL
|
||||||
gpg_pin_set_verified(gpg_pin_get_pin(G_gpg_vstate.io_p2),0);
|
gpg_pin_set_verified(G_gpg_vstate.io_p2,0);
|
||||||
sw = 0x6985;
|
sw = 0x6985;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_EVT_RELEASED|BUTTON_RIGHT: // OK
|
case BUTTON_EVT_RELEASED|BUTTON_RIGHT: // OK
|
||||||
gpg_pin_set_verified(gpg_pin_get_pin(G_gpg_vstate.io_p2),1);
|
gpg_pin_set_verified(G_gpg_vstate.io_p2,1);
|
||||||
sw = 0x9000;
|
sw = 0x9000;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -240,9 +356,17 @@ unsigned int ui_pinentry_prepro(const bagl_element_t* element) {
|
||||||
else if (element->component.userid == 2) {
|
else if (element->component.userid == 2) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
G_gpg_vstate.menu[0] = ' ';
|
G_gpg_vstate.menu[0] = ' ';
|
||||||
|
#if 1
|
||||||
for (i = 1; i<= G_gpg_vstate.ux_pinentry[0]; i++) {
|
for (i = 1; i<= G_gpg_vstate.ux_pinentry[0]; i++) {
|
||||||
G_gpg_vstate.menu[i] = C_pin_digit[G_gpg_vstate.ux_pinentry[i]];
|
G_gpg_vstate.menu[i] = C_pin_digit[G_gpg_vstate.ux_pinentry[i]];
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
for (i = 1; i< G_gpg_vstate.ux_pinentry[0]; i++) {
|
||||||
|
G_gpg_vstate.menu[i] = '*';
|
||||||
|
}
|
||||||
|
G_gpg_vstate.menu[i] = C_pin_digit[G_gpg_vstate.ux_pinentry[i]];
|
||||||
|
i++;
|
||||||
|
#endif
|
||||||
for (; i<= GPG_MAX_PW_LENGTH;i++) {
|
for (; i<= GPG_MAX_PW_LENGTH;i++) {
|
||||||
G_gpg_vstate.menu[i] = '-';
|
G_gpg_vstate.menu[i] = '-';
|
||||||
}
|
}
|
||||||
|
@ -325,15 +449,16 @@ static unsigned int validate_pin() {
|
||||||
|
|
||||||
if (G_gpg_vstate.io_ins == 0x20) {
|
if (G_gpg_vstate.io_ins == 0x20) {
|
||||||
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
|
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
|
||||||
sw = gpg_pin_check(pin, (unsigned char*)(G_gpg_vstate.menu+1), G_gpg_vstate.ux_pinentry[0]);
|
sw = gpg_pin_check(pin, G_gpg_vstate.io_p2, (unsigned char*)(G_gpg_vstate.menu+1), G_gpg_vstate.ux_pinentry[0]);
|
||||||
gpg_io_discard(1);
|
gpg_io_discard(1);
|
||||||
gpg_io_insert_u16(sw);
|
gpg_io_insert_u16(sw);
|
||||||
gpg_io_do(IO_RETURN_AFTER_TX);
|
gpg_io_do(IO_RETURN_AFTER_TX);
|
||||||
if (sw == SW_CONDITIONS_NOT_SATISFIED) {
|
if (sw != SW_OK) {
|
||||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), " %d tries remaining", pin->counter );
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), " %d tries remaining", pin->counter );
|
||||||
ui_info(WRONG_PIN, G_gpg_vstate.menu, ui_menu_main_display, 0);
|
ui_info(WRONG_PIN, G_gpg_vstate.menu, ui_menu_main_display, 0);
|
||||||
}
|
} else {
|
||||||
return 0;
|
ui_menu_main_display(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (G_gpg_vstate.io_ins == 0x24) {
|
if (G_gpg_vstate.io_ins == 0x24) {
|
||||||
|
@ -344,7 +469,7 @@ static unsigned int validate_pin() {
|
||||||
}
|
}
|
||||||
if (G_gpg_vstate.io_p1 == 3) {
|
if (G_gpg_vstate.io_p1 == 3) {
|
||||||
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
|
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
|
||||||
if (gpg_pin_check(pin, G_gpg_vstate.work.io_buffer+1, G_gpg_vstate.work.io_buffer[0])!=SW_OK) {
|
if (gpg_pin_check(pin, G_gpg_vstate.io_p2, G_gpg_vstate.work.io_buffer+1, G_gpg_vstate.work.io_buffer[0])!=SW_OK) {
|
||||||
gpg_io_discard(1);
|
gpg_io_discard(1);
|
||||||
gpg_io_insert_u16(SW_CONDITIONS_NOT_SATISFIED);
|
gpg_io_insert_u16(SW_CONDITIONS_NOT_SATISFIED);
|
||||||
gpg_io_do(IO_RETURN_AFTER_TX);
|
gpg_io_do(IO_RETURN_AFTER_TX);
|
||||||
|
@ -381,12 +506,17 @@ static unsigned int validate_pin() {
|
||||||
#define LABEL_AUT "Authentication"
|
#define LABEL_AUT "Authentication"
|
||||||
#define LABEL_DEC "Decryption"
|
#define LABEL_DEC "Decryption"
|
||||||
|
|
||||||
#define LABEL_RSA2048 "RSA 2048"
|
#define LABEL_RSA2048 "RSA 2048"
|
||||||
#define LABEL_RSA3072 "RSA 3072"
|
#define LABEL_RSA3072 "RSA 3072"
|
||||||
#define LABEL_RSA4096 "RSA 4096"
|
#define LABEL_RSA4096 "RSA 4096"
|
||||||
#define LABEL_NISTP256 "NIST P256"
|
#define LABEL_NISTP256 "NIST P256"
|
||||||
#define LABEL_BPOOLR1 "Brainpool R1"
|
//#define LABEL_NISTP384 "NIST P384"
|
||||||
#define LABEL_Ed25519 "Ed25519"
|
//#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[] = {
|
const ux_menu_entry_t ui_menu_template[] = {
|
||||||
{ui_menu_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0},
|
{ui_menu_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0},
|
||||||
|
@ -430,12 +560,34 @@ const bagl_element_t* ui_menu_template_preprocessor(const ux_menu_entry_t* entry
|
||||||
case 4096:
|
case 4096:
|
||||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA4096);
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA4096);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CX_CURVE_SECP256R1:
|
case CX_CURVE_SECP256R1:
|
||||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP256);
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP256);
|
||||||
break;
|
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;
|
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:
|
case CX_CURVE_Ed25519:
|
||||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_Ed25519);
|
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_Ed25519);
|
||||||
break;
|
break;
|
||||||
|
@ -456,7 +608,8 @@ void ui_menu_tmpl_set_action(unsigned int value) {
|
||||||
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
||||||
gpg_key_t* dest;
|
gpg_key_t* dest;
|
||||||
const char* err;
|
const char* err;
|
||||||
|
const unsigned char *oid;
|
||||||
|
unsigned int oid_len;
|
||||||
err = NULL;
|
err = NULL;
|
||||||
|
|
||||||
os_memset(&attributes, 0, sizeof(attributes));
|
os_memset(&attributes, 0, sizeof(attributes));
|
||||||
|
@ -473,24 +626,21 @@ void ui_menu_tmpl_set_action(unsigned int value) {
|
||||||
attributes.length = 6;
|
attributes.length = 6;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CX_CURVE_SECP256K1:
|
||||||
case CX_CURVE_SECP256R1:
|
case CX_CURVE_SECP256R1:
|
||||||
if (G_gpg_vstate.ux_key == 2) {
|
//case CX_CURVE_SECP384R1:
|
||||||
attributes.value[0] = 18; //ecdh
|
//case CX_CURVE_SECP521R1:
|
||||||
} 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_BrainPoolP256R1:
|
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
|
attributes.value[0] = 18; //ecdh
|
||||||
} else {
|
} else {
|
||||||
attributes.value[0] = 19; //ecdsa
|
attributes.value[0] = 19; //ecdsa
|
||||||
}
|
}
|
||||||
os_memmove(attributes.value+1, C_OID_BRAINPOOL256R1, sizeof(C_OID_BRAINPOOL256R1));
|
oid = gpg_curve2oid(G_gpg_vstate.ux_type, &oid_len);
|
||||||
attributes.length = 1+sizeof(C_OID_BRAINPOOL256R1);
|
os_memmove(attributes.value+1, oid, sizeof(oid_len));
|
||||||
|
attributes.length = 1+oid_len;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CX_CURVE_Ed25519:
|
case CX_CURVE_Ed25519:
|
||||||
|
@ -505,7 +655,7 @@ void ui_menu_tmpl_set_action(unsigned int value) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = TEMPLATE_TYPE;
|
err = TEMPLATE_TYPE;
|
||||||
goto ERROR;
|
goto ERROR;
|
||||||
}
|
}
|
||||||
|
@ -552,13 +702,18 @@ void ui_menu_tmpl_key_action(unsigned int value) {
|
||||||
|
|
||||||
|
|
||||||
const ux_menu_entry_t ui_menu_tmpl_type[] = {
|
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, 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, 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, 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_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_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
|
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP521R1, NULL, LABEL_NISTP521, NULL, 0, 0},
|
||||||
{ui_menu_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
{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
|
UX_MENU_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -654,6 +809,7 @@ void ui_menu_pinmode_action(unsigned int value) {
|
||||||
} else {
|
} else {
|
||||||
s = 3;
|
s = 3;
|
||||||
}
|
}
|
||||||
|
//#warning USBD_CCID_activate_pinpad commented
|
||||||
USBD_CCID_activate_pinpad(s);
|
USBD_CCID_activate_pinpad(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,15 +817,16 @@ void ui_menu_pinmode_action(unsigned int value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case PIN_MODE_HOST:
|
case PIN_MODE_HOST:
|
||||||
case PIN_MODE_SCREEN:
|
case PIN_MODE_SCREEN:
|
||||||
if (!gpg_pin_is_verified(gpg_pin_get_pin(PIN_ID_PW2))) {
|
case PIN_MODE_CONFIRM:
|
||||||
|
if (!gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||||
ui_info(PIN_USER, NOT_VERIFIED, ui_menu_pinmode_display,0);
|
ui_info(PIN_USER, NOT_VERIFIED, ui_menu_pinmode_display,0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PIN_MODE_CONFIRM:
|
|
||||||
case PIN_MODE_TRUST:
|
case PIN_MODE_TRUST:
|
||||||
if (!gpg_pin_is_verified(gpg_pin_get_pin(PIN_ID_PW3))) {
|
if (!gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||||
ui_info(PIN_ADMIN, NOT_VERIFIED, ui_menu_pinmode_display,0);
|
ui_info(PIN_ADMIN, NOT_VERIFIED, ui_menu_pinmode_display,0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -683,6 +840,84 @@ void ui_menu_pinmode_action(unsigned int value) {
|
||||||
// redisplay first entry of the idle menu
|
// redisplay first entry of the idle menu
|
||||||
ui_menu_pinmode_display(0);
|
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 --------------------------------- */
|
/* -------------------------------- RESET UX --------------------------------- */
|
||||||
|
|
||||||
const ux_menu_entry_t ui_menu_reset[] = {
|
const ux_menu_entry_t ui_menu_reset[] = {
|
||||||
|
@ -709,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_template_display, 0, NULL, "Key template", NULL, 0, 0},
|
||||||
{NULL, ui_menu_seed_display, 0, NULL, "Seed mode", 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_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},
|
{ui_menu_reset, NULL, 0, NULL, "Reset", NULL, 0, 0},
|
||||||
{NULL, ui_menu_main_display, 2, &C_badge_back, "Back", NULL, 61, 40},
|
{NULL, ui_menu_main_display, 2, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
UX_MENU_END
|
UX_MENU_END
|
||||||
|
@ -766,6 +1002,7 @@ void ui_menu_slot_action(unsigned int value) {
|
||||||
if (s!= G_gpg_vstate.slot) {
|
if (s!= G_gpg_vstate.slot) {
|
||||||
G_gpg_vstate.slot = s;
|
G_gpg_vstate.slot = s;
|
||||||
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
||||||
|
gpg_mse_reset();
|
||||||
ui_CCID_reset();
|
ui_CCID_reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -784,7 +1021,7 @@ void ui_menu_slot_action(unsigned int value) {
|
||||||
const ux_menu_entry_t ui_menu_info[] = {
|
const ux_menu_entry_t ui_menu_info[] = {
|
||||||
{NULL, NULL, -1, NULL, "OpenPGP Card", NULL, 0, 0},
|
{NULL, NULL, -1, NULL, "OpenPGP Card", NULL, 0, 0},
|
||||||
{NULL, NULL, -1, NULL, "(c) Ledger SAS", NULL, 0, 0},
|
{NULL, NULL, -1, NULL, "(c) Ledger SAS", NULL, 0, 0},
|
||||||
{NULL, NULL, -1, NULL, "Spec 3.0", NULL, 0, 0},
|
{NULL, NULL, -1, NULL, "Spec " XSTR(SPEC_VERSION),NULL, 0, 0},
|
||||||
{NULL, NULL, -1, NULL, "App " XSTR(GPG_VERSION), NULL, 0, 0},
|
{NULL, NULL, -1, NULL, "App " XSTR(GPG_VERSION), NULL, 0, 0},
|
||||||
{NULL, ui_menu_main_display, 3, &C_badge_back, "Back", NULL, 61, 40},
|
{NULL, ui_menu_main_display, 3, &C_badge_back, "Back", NULL, 61, 40},
|
||||||
UX_MENU_END
|
UX_MENU_END
|
||||||
|
|
|
@ -22,4 +22,5 @@ void ui_init(void);
|
||||||
void ui_main_display(unsigned int value);
|
void ui_main_display(unsigned int value);
|
||||||
void ui_menu_pinconfirm_display(unsigned int value);
|
void ui_menu_pinconfirm_display(unsigned int value);
|
||||||
void ui_menu_pinentry_display(unsigned int value);
|
void ui_menu_pinentry_display(unsigned int value);
|
||||||
|
void ui_menu_uifconfirm_display(unsigned int value);
|
||||||
#endif
|
#endif
|
1057
src/sdk/usbd_ccid_cmd.c
Executable file
415
sdk/usbd_ccid_if.c → src/sdk/usbd_ccid_if.c
Normal file → Executable file
|
@ -25,27 +25,23 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma message "Override SDK source file :" __FILE__
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
#include "os.h"
|
||||||
#include "usbd_ccid_if.h"
|
#include "usbd_ccid_if.h"
|
||||||
|
|
||||||
#ifdef HAVE_USB_CLASS_CCID
|
#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 typedef -----------------------------------------------------------*/
|
||||||
/* Private define ------------------------------------------------------------*/
|
/* Private define ------------------------------------------------------------*/
|
||||||
/* Private macro -------------------------------------------------------------*/
|
/* Private macro -------------------------------------------------------------*/
|
||||||
/* Private variables ---------------------------------------------------------*/
|
/* Private variables ---------------------------------------------------------*/
|
||||||
uint8_t Ccid_BulkState;
|
usb_class_ccid_t G_io_ccid;
|
||||||
uint8_t ccid_card_inserted;
|
|
||||||
uint8_t UsbIntMessageBuffer[INTR_MAX_PACKET_SIZE]; /* data buffer*/
|
|
||||||
__IO uint8_t PrevXferComplete_IntrIn;
|
|
||||||
usb_ccid_param_t usb_ccid_param;
|
|
||||||
|
|
||||||
uint8_t* pUsbMessageBuffer;
|
|
||||||
static uint32_t UsbMessageLength;
|
|
||||||
Ccid_SlotStatus_t Ccid_SlotStatus;
|
|
||||||
Protocol0_DataStructure_t Protocol0_DataStructure;
|
|
||||||
|
|
||||||
Ccid_bulk_data_t Ccid_bulk_data;
|
|
||||||
|
|
||||||
/* Private function prototypes -----------------------------------------------*/
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
static void CCID_Response_SendData (USBD_HandleTypeDef *pdev,
|
static void CCID_Response_SendData (USBD_HandleTypeDef *pdev,
|
||||||
|
@ -60,23 +56,17 @@ static void CCID_Response_SendData (USBD_HandleTypeDef *pdev,
|
||||||
*/
|
*/
|
||||||
void CCID_Init (USBD_HandleTypeDef *pdev)
|
void CCID_Init (USBD_HandleTypeDef *pdev)
|
||||||
{
|
{
|
||||||
memset(&Ccid_BulkState, 0, sizeof(Ccid_BulkState));
|
memset(&G_io_ccid, 0, sizeof(G_io_ccid));
|
||||||
memset(&UsbIntMessageBuffer, 0, sizeof(UsbIntMessageBuffer));
|
|
||||||
memset(&PrevXferComplete_IntrIn, 0, sizeof(PrevXferComplete_IntrIn));
|
|
||||||
memset(&usb_ccid_param, 0, sizeof(usb_ccid_param));
|
|
||||||
memset(&pUsbMessageBuffer, 0, sizeof(pUsbMessageBuffer));
|
|
||||||
memset(&UsbMessageLength, 0, sizeof(UsbMessageLength));
|
|
||||||
memset(&Ccid_SlotStatus, 0, sizeof(Ccid_SlotStatus));
|
|
||||||
memset(&Protocol0_DataStructure, 0, sizeof(Protocol0_DataStructure));
|
|
||||||
memset(&Ccid_bulk_data, 0, sizeof(Ccid_bulk_data));
|
|
||||||
ccid_card_inserted = 0;
|
|
||||||
/* CCID Related Initialization */
|
/* CCID Related Initialization */
|
||||||
|
#ifdef HAVE_CCID_INTERRUPT
|
||||||
CCID_SetIntrTransferStatus(1); /* Transfer Complete Status */
|
CCID_SetIntrTransferStatus(1); /* Transfer Complete Status */
|
||||||
|
#endif // HAVE_CCID_INTERRUPT
|
||||||
CCID_UpdSlotChange(1);
|
CCID_UpdSlotChange(1);
|
||||||
SC_InitParams();
|
SC_InitParams();
|
||||||
|
|
||||||
/* Prepare Out endpoint to receive 1st packet */
|
/* Prepare Out endpoint to receive 1st packet */
|
||||||
Ccid_BulkState = CCID_STATE_IDLE;
|
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||||
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
||||||
|
|
||||||
// send the smartcard as inserted state at boot time
|
// send the smartcard as inserted state at boot time
|
||||||
|
@ -92,7 +82,7 @@ void CCID_Init (USBD_HandleTypeDef *pdev)
|
||||||
void CCID_DeInit (USBD_HandleTypeDef *pdev)
|
void CCID_DeInit (USBD_HandleTypeDef *pdev)
|
||||||
{
|
{
|
||||||
UNUSED(pdev);
|
UNUSED(pdev);
|
||||||
Ccid_BulkState = CCID_STATE_IDLE;
|
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,43 +100,50 @@ void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
|
||||||
|
|
||||||
/*************** Handle Bulk Transfer IN data completion *****************/
|
/*************** Handle Bulk Transfer IN data completion *****************/
|
||||||
|
|
||||||
switch (Ccid_BulkState)
|
switch (G_io_ccid.Ccid_BulkState)
|
||||||
{
|
{
|
||||||
case CCID_STATE_SEND_RESP: {
|
case CCID_STATE_SEND_RESP: {
|
||||||
unsigned int remLen = UsbMessageLength;
|
unsigned int remLen = G_io_ccid.UsbMessageLength;
|
||||||
|
|
||||||
// advance with acknowledged sent chunk
|
// advance with acknowledged sent chunk
|
||||||
pUsbMessageBuffer += MIN(CCID_BULK_EPIN_SIZE, UsbMessageLength);
|
if (G_io_ccid.pUsbMessageBuffer == &G_io_ccid.bulk_header) {
|
||||||
UsbMessageLength -= MIN(CCID_BULK_EPIN_SIZE, UsbMessageLength);
|
// 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 remaining length is > EPIN_SIZE: send a filled bulk packet
|
||||||
if (UsbMessageLength >= CCID_BULK_EPIN_SIZE) {
|
if (G_io_ccid.UsbMessageLength >= CCID_BULK_EPIN_SIZE) {
|
||||||
CCID_Response_SendData(pdev, pUsbMessageBuffer,
|
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
|
||||||
// use the header declared size packet must be well formed
|
// use the header declared size packet must be well formed
|
||||||
CCID_BULK_EPIN_SIZE);
|
CCID_BULK_EPIN_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if remaining length is 0; send an empty packet and prepare to receive a new command
|
// if remaining length is 0; send an empty packet and prepare to receive a new command
|
||||||
else if (UsbMessageLength == 0 && remLen == CCID_BULK_EPIN_SIZE) {
|
else if (G_io_ccid.UsbMessageLength == 0 && remLen == CCID_BULK_EPIN_SIZE) {
|
||||||
CCID_Response_SendData(pdev, pUsbMessageBuffer,
|
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
|
||||||
// use the header declared size packet must be well formed
|
// use the header declared size packet must be well formed
|
||||||
0);
|
0);
|
||||||
goto last_xfer; // won't wait ack to avoid missing a command
|
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 no more data, then last packet sent, go back to idle (done on transfer ack)
|
||||||
else if (UsbMessageLength == 0) { // robustness only
|
else if (G_io_ccid.UsbMessageLength == 0) { // robustness only
|
||||||
last_xfer:
|
last_xfer:
|
||||||
Ccid_BulkState = CCID_STATE_IDLE;
|
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||||
|
|
||||||
/* Prepare EP to Receive First Cmd */
|
/* Prepare EP to Receive First Cmd */
|
||||||
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
// 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
|
// if remaining length is < EPIN_SIZE: send packet and prepare to receive a new command
|
||||||
else if (UsbMessageLength < CCID_BULK_EPIN_SIZE) {
|
else if (G_io_ccid.UsbMessageLength < CCID_BULK_EPIN_SIZE) {
|
||||||
CCID_Response_SendData(pdev, pUsbMessageBuffer,
|
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
|
||||||
// use the header declared size packet must be well formed
|
// use the header declared size packet must be well formed
|
||||||
UsbMessageLength);
|
G_io_ccid.UsbMessageLength);
|
||||||
goto last_xfer; // won't wait ack to avoid missing a command
|
goto last_xfer; // won't wait ack to avoid missing a command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,11 +154,35 @@ void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_CCID_INTERRUPT
|
||||||
else if (epnum == (CCID_INTR_IN_EP & 0x7F))
|
else if (epnum == (CCID_INTR_IN_EP & 0x7F))
|
||||||
{
|
{
|
||||||
/* Filter the epnum by masking with 0x7f (mask of IN Direction) */
|
/* Filter the epnum by masking with 0x7f (mask of IN Direction) */
|
||||||
CCID_SetIntrTransferStatus(1); /* Transfer Complete Status */
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,123 +195,113 @@ void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
|
||||||
void CCID_BulkMessage_Out (USBD_HandleTypeDef *pdev,
|
void CCID_BulkMessage_Out (USBD_HandleTypeDef *pdev,
|
||||||
uint8_t epnum, uint8_t* buffer, uint16_t dataLen)
|
uint8_t epnum, uint8_t* buffer, uint16_t dataLen)
|
||||||
{
|
{
|
||||||
|
if (epnum == (CCID_BULK_OUT_EP & 0x7F)) {
|
||||||
switch (Ccid_BulkState)
|
switch (G_io_ccid.Ccid_BulkState)
|
||||||
{
|
|
||||||
case CCID_STATE_IDLE:
|
|
||||||
if (dataLen == 0x00)
|
|
||||||
{ /* Zero Length Packet Received */
|
|
||||||
Ccid_BulkState = CCID_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (dataLen >= CCID_MESSAGE_HEADER_SIZE)
|
|
||||||
{
|
{
|
||||||
UsbMessageLength = dataLen; /* Store for future use */
|
|
||||||
|
// after a timeout, could be in almost any state :) therefore, clean it and process the newly received command
|
||||||
/* Expected Data Length Packet Received */
|
default:
|
||||||
pUsbMessageBuffer = (uint8_t*) &Ccid_bulk_data;
|
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||||
|
// no break is intentional
|
||||||
/* Fill CCID_BulkOut Data Buffer from USB Buffer */
|
|
||||||
memmove(pUsbMessageBuffer, buffer, dataLen);
|
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);
|
||||||
Refer : 6 CCID Messages
|
|
||||||
The response messages always contain the exact same slot number,
|
if (dataLen == 0x00)
|
||||||
and sequence number fields from the header that was contained in
|
{ /* Zero Length Packet Received, end of transfer */
|
||||||
the Bulk-OUT command message.
|
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||||
*/
|
|
||||||
Ccid_bulk_data.header.bulkin.bSlot = Ccid_bulk_data.header.bulkout.bSlot;
|
|
||||||
Ccid_bulk_data.header.bulkin.bSeq = Ccid_bulk_data.header.bulkout.bSeq;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
CCID_CmdDecode(pdev);
|
|
||||||
}
|
}
|
||||||
else
|
else if (dataLen >= CCID_HEADER_SIZE)
|
||||||
{ /* Long message, receive additional data with command */
|
{
|
||||||
/* (u8dataLen == CCID_BULK_EPOUT_SIZE) */
|
G_io_ccid.UsbMessageLength = dataLen; /* Store for future use */
|
||||||
|
|
||||||
if (Ccid_bulk_data.header.bulkout.dwLength > ABDATA_SIZE)
|
/* 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 */
|
{ /* Check if length of data to be sent by host is > buffer size */
|
||||||
|
|
||||||
/* Too long data received.... Error ! */
|
/* Too long data received.... Error ! */
|
||||||
Ccid_BulkState = CCID_STATE_UNCORRECT_LENGTH;
|
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 */
|
||||||
|
|
||||||
else
|
/* Full command is received, process the Command */
|
||||||
{ /* Expect more data on OUT EP */
|
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
|
||||||
Ccid_BulkState = CCID_STATE_RECEIVE_DATA;
|
CCID_CmdDecode(pdev);
|
||||||
pUsbMessageBuffer += dataLen; /* Point to new offset */
|
}
|
||||||
|
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 */
|
/* Prepare EP to Receive next Cmd */
|
||||||
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
// not timeout compliant // USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
||||||
|
}
|
||||||
} /* if (dataLen == CCID_BULK_EPOUT_SIZE) ends */
|
else if (G_io_ccid.UsbMessageLength == (G_io_ccid.bulk_header.bulkout.dwLength + CCID_HEADER_SIZE))
|
||||||
} /* if (dataLen >= CCID_BULK_EPOUT_SIZE) ends */
|
{
|
||||||
} /* if (dataLen >= CCID_MESSAGE_HEADER_SIZE) ends */
|
/* Full command is received, process the Command */
|
||||||
break;
|
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
|
||||||
|
CCID_CmdDecode(pdev);
|
||||||
case CCID_STATE_RECEIVE_DATA:
|
}
|
||||||
|
else
|
||||||
UsbMessageLength += dataLen;
|
{
|
||||||
|
/* Too long data received.... Error ! */
|
||||||
if (dataLen < CCID_BULK_EPOUT_SIZE)
|
G_io_ccid.Ccid_BulkState = CCID_STATE_UNCORRECT_LENGTH;
|
||||||
{/* 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 */
|
break;
|
||||||
memmove(pUsbMessageBuffer, buffer, dataLen);
|
|
||||||
CCID_CmdDecode(pdev);
|
|
||||||
}
|
|
||||||
else if (dataLen == CCID_BULK_EPOUT_SIZE)
|
|
||||||
{
|
|
||||||
if (UsbMessageLength < (Ccid_bulk_data.header.bulkout.dwLength + CCID_CMD_HEADER_SIZE))
|
|
||||||
{
|
|
||||||
memmove(pUsbMessageBuffer, buffer, dataLen);
|
|
||||||
pUsbMessageBuffer += dataLen;
|
|
||||||
/* Increment the pointer to receive more data */
|
|
||||||
|
|
||||||
/* Prepare EP to Receive next Cmd */
|
|
||||||
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
|
||||||
}
|
|
||||||
else if (UsbMessageLength == (Ccid_bulk_data.header.bulkout.dwLength + CCID_CMD_HEADER_SIZE))
|
|
||||||
{
|
|
||||||
/* Full command is received, process the Command */
|
|
||||||
memmove(pUsbMessageBuffer, buffer, dataLen);
|
|
||||||
CCID_CmdDecode(pdev);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Too long data received.... Error ! */
|
|
||||||
Ccid_BulkState = CCID_STATE_UNCORRECT_LENGTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
/*
|
||||||
|
case CCID_STATE_UNCORRECT_LENGTH:
|
||||||
case CCID_STATE_UNCORRECT_LENGTH:
|
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||||
Ccid_BulkState = CCID_STATE_IDLE;
|
break;
|
||||||
break;
|
|
||||||
|
default:
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCID_Send_Reply(USBD_HandleTypeDef *pdev) {
|
break;
|
||||||
/********** Decide for all commands ***************/
|
*/
|
||||||
if (Ccid_BulkState == CCID_STATE_SEND_RESP)
|
}
|
||||||
{
|
|
||||||
UsbMessageLength = Ccid_bulk_data.header.bulkin.dwLength+CCID_MESSAGE_HEADER_SIZE; /* Store for future use */
|
|
||||||
|
|
||||||
/* Expected Data Length Packet Received */
|
|
||||||
pUsbMessageBuffer = (uint8_t*) &Ccid_bulk_data;
|
|
||||||
|
|
||||||
CCID_Response_SendData(pdev, pUsbMessageBuffer,
|
|
||||||
// use the header declared size packet must be well formed
|
|
||||||
MIN(CCID_BULK_EPIN_SIZE, UsbMessageLength));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +315,7 @@ void CCID_CmdDecode(USBD_HandleTypeDef *pdev)
|
||||||
{
|
{
|
||||||
uint8_t errorCode;
|
uint8_t errorCode;
|
||||||
|
|
||||||
switch (Ccid_bulk_data.header.bulkout.bMessageType)
|
switch (G_io_ccid.bulk_header.bulkout.bMessageType)
|
||||||
{
|
{
|
||||||
case PC_TO_RDR_ICCPOWERON:
|
case PC_TO_RDR_ICCPOWERON:
|
||||||
errorCode = PC_to_RDR_IccPowerOn();
|
errorCode = PC_to_RDR_IccPowerOn();
|
||||||
|
@ -380,7 +391,7 @@ void CCID_CmdDecode(USBD_HandleTypeDef *pdev)
|
||||||
void Transfer_Data_Request(void)
|
void Transfer_Data_Request(void)
|
||||||
{
|
{
|
||||||
/********** Update Global Variables ***************/
|
/********** Update Global Variables ***************/
|
||||||
Ccid_BulkState = CCID_STATE_SEND_RESP;
|
G_io_ccid.Ccid_BulkState = CCID_STATE_SEND_RESP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -396,6 +407,7 @@ static void CCID_Response_SendData(USBD_HandleTypeDef *pdev,
|
||||||
uint8_t* buf,
|
uint8_t* buf,
|
||||||
uint16_t len)
|
uint16_t len)
|
||||||
{
|
{
|
||||||
|
UNUSED(pdev);
|
||||||
// don't ask the MCU to perform bulk split, we could quickly get into a buffer overflow
|
// don't ask the MCU to perform bulk split, we could quickly get into a buffer overflow
|
||||||
if (len > CCID_BULK_EPIN_SIZE) {
|
if (len > CCID_BULK_EPIN_SIZE) {
|
||||||
THROW(EXCEPTION_IO_OVERFLOW);
|
THROW(EXCEPTION_IO_OVERFLOW);
|
||||||
|
@ -411,6 +423,7 @@ static void CCID_Response_SendData(USBD_HandleTypeDef *pdev,
|
||||||
io_seproxyhal_spi_send(buf, len);
|
io_seproxyhal_spi_send(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_CCID_INTERRUPT
|
||||||
/**
|
/**
|
||||||
* @brief CCID_IntMessage
|
* @brief CCID_IntMessage
|
||||||
* Send the Interrupt-IN data to the host
|
* Send the Interrupt-IN data to the host
|
||||||
|
@ -419,11 +432,14 @@ static void CCID_Response_SendData(USBD_HandleTypeDef *pdev,
|
||||||
*/
|
*/
|
||||||
void CCID_IntMessage(USBD_HandleTypeDef *pdev)
|
void CCID_IntMessage(USBD_HandleTypeDef *pdev)
|
||||||
{
|
{
|
||||||
|
UNUSED(pdev);
|
||||||
/* Check if there us change in Smartcard Slot status */
|
/* Check if there us change in Smartcard Slot status */
|
||||||
if ( CCID_IsSlotStatusChange() && CCID_IsIntrTransferComplete() )
|
if ( CCID_IsSlotStatusChange() && CCID_IsIntrTransferComplete() )
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_CCID_INTERRUPT
|
||||||
/* Check Slot Status is changed. Card is Removed/ Fitted */
|
/* Check Slot Status is changed. Card is Removed/ Fitted */
|
||||||
RDR_to_PC_NotifySlotChange();
|
RDR_to_PC_NotifySlotChange();
|
||||||
|
#endif // HAVE_CCID_INTERRUPT
|
||||||
|
|
||||||
CCID_SetIntrTransferStatus(0); /* Reset the Status */
|
CCID_SetIntrTransferStatus(0); /* Reset the Status */
|
||||||
CCID_UpdSlotChange(0); /* Reset the Status of Slot Change */
|
CCID_UpdSlotChange(0); /* Reset the Status of Slot Change */
|
||||||
|
@ -435,7 +451,7 @@ void CCID_IntMessage(USBD_HandleTypeDef *pdev)
|
||||||
G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN;
|
G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN;
|
||||||
G_io_seproxyhal_spi_buffer[5] = 2;
|
G_io_seproxyhal_spi_buffer[5] = 2;
|
||||||
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 6);
|
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 6);
|
||||||
io_seproxyhal_spi_send(UsbIntMessageBuffer, 2);
|
io_seproxyhal_spi_send(G_io_ccid.UsbIntMessageBuffer, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +463,7 @@ void CCID_IntMessage(USBD_HandleTypeDef *pdev)
|
||||||
*/
|
*/
|
||||||
uint8_t CCID_IsIntrTransferComplete (void)
|
uint8_t CCID_IsIntrTransferComplete (void)
|
||||||
{
|
{
|
||||||
return PrevXferComplete_IntrIn;
|
return G_io_ccid.PrevXferComplete_IntrIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -458,8 +474,9 @@ uint8_t CCID_IsIntrTransferComplete (void)
|
||||||
*/
|
*/
|
||||||
void CCID_SetIntrTransferStatus (uint8_t xfer_Status)
|
void CCID_SetIntrTransferStatus (uint8_t xfer_Status)
|
||||||
{
|
{
|
||||||
PrevXferComplete_IntrIn = xfer_Status;
|
G_io_ccid.PrevXferComplete_IntrIn = xfer_Status;
|
||||||
}
|
}
|
||||||
|
#endif // HAVE_CCID_INTERRUPT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -467,12 +484,7 @@ void CCID_SetIntrTransferStatus (uint8_t xfer_Status)
|
||||||
|
|
||||||
|
|
||||||
uint8_t SC_Detect(void) {
|
uint8_t SC_Detect(void) {
|
||||||
return ccid_card_inserted;
|
return G_io_ccid.ccid_card_inserted;
|
||||||
}
|
|
||||||
|
|
||||||
void SC_Poweroff(void) {
|
|
||||||
// nothing to do
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SC_InitParams (void) {
|
void SC_InitParams (void) {
|
||||||
|
@ -480,78 +492,89 @@ void SC_InitParams (void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SC_SetParams (Protocol0_DataStructure_t* pt0) {
|
uint8_t SC_SetParams (Protocol0_DataStructure_t* pt0) {
|
||||||
|
UNUSED(pt0);
|
||||||
return SLOT_NO_ERROR;
|
return SLOT_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SC_ExecuteEscape (uint8_t* escapePtr, uint32_t escapeLen,
|
|
||||||
uint8_t* responseBuff,
|
|
||||||
uint16_t* responseLen) {
|
|
||||||
io_seproxyhal_se_reset();
|
|
||||||
}
|
|
||||||
uint8_t SC_SetClock (uint8_t bClockCommand) {
|
uint8_t SC_SetClock (uint8_t bClockCommand) {
|
||||||
|
UNUSED(bClockCommand);
|
||||||
return SLOT_NO_ERROR;
|
return SLOT_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SC_Request_GetClockFrequencies(uint8_t* pbuf, uint16_t* len);
|
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_Request_GetDataRates(uint8_t* pbuf, uint16_t* len);
|
||||||
uint8_t SC_T0Apdu(uint8_t bmChanges, uint8_t bClassGetResponse,
|
uint8_t SC_T0Apdu(uint8_t bmChanges, uint8_t bClassGetResponse,
|
||||||
uint8_t bClassEnvelope) {
|
uint8_t bClassEnvelope) {
|
||||||
|
UNUSED(bmChanges);
|
||||||
|
UNUSED(bClassGetResponse);
|
||||||
|
UNUSED(bClassEnvelope);
|
||||||
return SLOTERROR_CMD_NOT_SUPPORTED;
|
return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
uint8_t SC_Mechanical(uint8_t bFunction) {
|
uint8_t SC_Mechanical(uint8_t bFunction) {
|
||||||
|
UNUSED(bFunction);
|
||||||
return SLOTERROR_CMD_NOT_SUPPORTED;
|
return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
uint8_t SC_SetDataRateAndClockFrequency(uint32_t dwClockFrequency,
|
uint8_t SC_SetDataRateAndClockFrequency(uint32_t dwClockFrequency,
|
||||||
uint32_t dwDataRate) {
|
uint32_t dwDataRate) {
|
||||||
|
UNUSED(dwClockFrequency);
|
||||||
|
UNUSED(dwDataRate);
|
||||||
return SLOT_NO_ERROR;
|
return SLOT_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
|
uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
|
||||||
uint8_t* pbuf, uint32_t* returnLen ) {
|
uint8_t* pbuf, uint32_t* returnLen ) {
|
||||||
|
UNUSED(bBWI);
|
||||||
|
UNUSED(wLevelParameter);
|
||||||
|
UNUSED(returnLen);
|
||||||
// return SLOTERROR_CMD_NOT_SUPPORTED;
|
// return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||||
uint16_t ret_len,off;
|
uint16_t ret_len,off;
|
||||||
switch(pbuf[0]) {
|
switch(pbuf[0])
|
||||||
case 0: // verify pin
|
{
|
||||||
//ret_len = dwLength - 15;
|
case 0: // verify pin
|
||||||
ret_len = 5;
|
off = 15;
|
||||||
os_memmove(G_io_apdu_buffer, pbuf+15, 5);
|
//ret_len = dwLength - 15;
|
||||||
|
ret_len = 5;
|
||||||
|
break;
|
||||||
|
case 1: // modify pin
|
||||||
|
switch(pbuf[11])
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
off = 20;
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
case 1: // modify pin
|
case 1:
|
||||||
switch(pbuf[11]) {
|
off = 19;
|
||||||
case 3:
|
|
||||||
off = 20;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
case 1:
|
|
||||||
off = 19;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
off = 18;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//ret_len = dwLength - off;
|
|
||||||
ret_len = 5;
|
|
||||||
os_memmove(G_io_apdu_buffer, pbuf+off, 5);
|
|
||||||
break;
|
break;
|
||||||
|
// 0 and 4-0xFF
|
||||||
default: // unsupported
|
default:
|
||||||
Ccid_bulk_data.header.bulkin.dwLength = 0;
|
off = 18;
|
||||||
RDR_to_PC_DataBlock(SLOTERROR_CMD_NOT_SUPPORTED);
|
break;
|
||||||
CCID_Send_Reply(&USBD_Device);
|
}
|
||||||
return SLOTERROR_CMD_NOT_SUPPORTED;
|
//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;
|
||||||
}
|
}
|
||||||
return SC_XferBlock(G_io_apdu_buffer, ret_len, &ret_len);
|
pbuf += off;
|
||||||
|
pbuf[0] = 0xEF;
|
||||||
|
return SC_XferBlock(pbuf, ret_len, &ret_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare the apdu to be processed by the application
|
// prepare the apdu to be processed by the application
|
||||||
uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen, uint16_t* expectedLen) {
|
uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen, uint16_t* expectedLen) {
|
||||||
|
UNUSED(expectedLen);
|
||||||
|
|
||||||
// check for overflow
|
// check for overflow
|
||||||
if (blockLen > IO_APDU_BUFFER_SIZE) {
|
if (blockLen > IO_APDU_BUFFER_SIZE) {
|
||||||
return SLOTERROR_BAD_LENTGH;
|
return SLOTERROR_BAD_LENTGH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy received apdu
|
// copy received apdu // if G_io_ccid_data_buffer is the buffer apdu, then the memmove will do nothing
|
||||||
memmove(G_io_apdu_buffer, ptrBlock, blockLen);
|
os_memmove(G_io_apdu_buffer, ptrBlock, blockLen);
|
||||||
G_io_apdu_length = blockLen;
|
G_io_apdu_length = blockLen;
|
||||||
G_io_apdu_media = IO_APDU_MEDIA_USB_CCID; // for application code
|
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
|
G_io_apdu_state = APDU_USB_CCID; // for next call to io_exchange
|
||||||
|
@ -561,23 +584,26 @@ uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen, uint16_t* expectedLe
|
||||||
|
|
||||||
void io_usb_ccid_reply(unsigned char* buffer, unsigned short length) {
|
void io_usb_ccid_reply(unsigned char* buffer, unsigned short length) {
|
||||||
// avoid memory overflow
|
// avoid memory overflow
|
||||||
if (length > sizeof(Ccid_bulk_data.abData)) {
|
if (length > IO_CCID_DATA_BUFFER_SIZE) {
|
||||||
THROW(EXCEPTION_IO_OVERFLOW);
|
THROW(EXCEPTION_IO_OVERFLOW);
|
||||||
}
|
}
|
||||||
// copy the responde apdu
|
// copy the responde apdu
|
||||||
memmove(Ccid_bulk_data.abData, buffer, length);
|
os_memmove(G_io_ccid_data_buffer, buffer, length);
|
||||||
Ccid_bulk_data.header.bulkin.dwLength = length;
|
G_io_ccid.bulk_header.bulkin.dwLength = length;
|
||||||
// forge reply
|
// forge reply
|
||||||
RDR_to_PC_DataBlock(SLOT_NO_ERROR);
|
RDR_to_PC_DataBlock(SLOT_NO_ERROR);
|
||||||
|
|
||||||
// start sending rpely
|
// start sending rpely
|
||||||
CCID_Send_Reply(&USBD_Device);
|
CCID_Send_Reply(&USBD_Device);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ask for power on
|
// ask for power on
|
||||||
void io_usb_ccid_set_card_inserted(unsigned int inserted) {
|
void io_usb_ccid_set_card_inserted(unsigned int inserted) {
|
||||||
ccid_card_inserted = inserted;
|
G_io_ccid.ccid_card_inserted = inserted;
|
||||||
CCID_UpdSlotChange(1);
|
CCID_UpdSlotChange(1);
|
||||||
|
#ifdef HAVE_CCID_INTERRUPT
|
||||||
CCID_IntMessage(&USBD_Device);
|
CCID_IntMessage(&USBD_Device);
|
||||||
|
#endif // HAVE_CCID_INTERRUPT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -585,6 +611,7 @@ void io_usb_ccid_set_card_inserted(unsigned int inserted) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // HAVE_USB_CLASS_CCID
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
32
src/sdk/usbd_ccid_impl.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef USBD_CCID_IMPL_H
|
||||||
|
#define USBD_CCID_IMPL_H
|
||||||
|
|
||||||
|
#ifdef HAVE_USB_CLASS_CCID
|
||||||
|
|
||||||
|
// ================================================
|
||||||
|
// CCID
|
||||||
|
|
||||||
|
#define TPDU_EXCHANGE 0x01
|
||||||
|
#define SHORT_APDU_EXCHANGE 0x02
|
||||||
|
#define EXTENDED_APDU_EXCHANGE 0x04
|
||||||
|
#define CHARACTER_EXCHANGE 0x00
|
||||||
|
|
||||||
|
#define EXCHANGE_LEVEL_FEATURE SHORT_APDU_EXCHANGE
|
||||||
|
|
||||||
|
#define CCID_INTF 2
|
||||||
|
#define CCID_BULK_IN_EP 0x83
|
||||||
|
#define CCID_BULK_EPIN_SIZE 64
|
||||||
|
#define CCID_BULK_OUT_EP 0x03
|
||||||
|
#define CCID_BULK_EPOUT_SIZE 64
|
||||||
|
|
||||||
|
#ifdef HAVE_CCID_INTERRUPT
|
||||||
|
#define CCID_INTR_IN_EP 0x84
|
||||||
|
#define CCID_INTR_EPIN_SIZE 16
|
||||||
|
#endif // HAVE_CCID_INTERRUPT
|
||||||
|
|
||||||
|
#define IO_CCID_DATA_BUFFER_SIZE IO_APDU_BUFFER_SIZE
|
||||||
|
#define G_io_ccid_data_buffer G_io_apdu_buffer
|
||||||
|
|
||||||
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
|
||||||
|
#endif // USBD_CCID_IMPL_H
|
29
src/sdk/usbd_hid_impl.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef USBD_HID_IMPL_H
|
||||||
|
#define USBD_HID_IMPL_H
|
||||||
|
|
||||||
|
// ================================================
|
||||||
|
// HIDGEN
|
||||||
|
|
||||||
|
#define HID_INTF 0
|
||||||
|
|
||||||
|
#define HID_EPIN_ADDR 0x82
|
||||||
|
#define HID_EPIN_SIZE 0x40
|
||||||
|
|
||||||
|
#define HID_EPOUT_ADDR 0x02
|
||||||
|
#define HID_EPOUT_SIZE 0x40
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
// ================================================
|
||||||
|
// HID U2F
|
||||||
|
|
||||||
|
#define U2F_INTF 1
|
||||||
|
|
||||||
|
#define U2F_EPIN_ADDR 0x81
|
||||||
|
#define U2F_EPIN_SIZE 0x40
|
||||||
|
|
||||||
|
#define U2F_EPOUT_ADDR 0x01
|
||||||
|
#define U2F_EPOUT_SIZE 0x40
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
|
||||||
|
#endif // USBD_HID_IMPL_H
|
||||||
|
|
916
src/sdk/usbd_impl.c
Normal file
|
@ -0,0 +1,916 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file usbd_hid.c
|
||||||
|
* @author MCD Application Team
|
||||||
|
* @version V2.2.0
|
||||||
|
* @date 13-June-2014
|
||||||
|
* @brief This file provides the HID core functions.
|
||||||
|
*
|
||||||
|
* @verbatim
|
||||||
|
*
|
||||||
|
* ===================================================================
|
||||||
|
* HID Class Description
|
||||||
|
* ===================================================================
|
||||||
|
* This module manages the HID class V1.11 following the "Device Class Definition
|
||||||
|
* for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
|
||||||
|
* This driver implements the following aspects of the specification:
|
||||||
|
* - The Boot Interface Subclass
|
||||||
|
* - Usage Page : Generic Desktop
|
||||||
|
* - Usage : Vendor
|
||||||
|
* - Collection : Application
|
||||||
|
*
|
||||||
|
* @note In HS mode and when the DMA is used, all variables and data structures
|
||||||
|
* dealing with the DMA during the transaction process should be 32-bit aligned.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @endverbatim
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* <h2><center>© 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__
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "usbd_hid.h"
|
||||||
|
#include "usbd_hid_impl.h"
|
||||||
|
|
||||||
|
#include "usbd_ctlreq.h"
|
||||||
|
|
||||||
|
#include "usbd_core.h"
|
||||||
|
#include "usbd_conf.h"
|
||||||
|
|
||||||
|
#include "usbd_def.h"
|
||||||
|
#include "os_io_seproxyhal.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
#include "u2f_transport.h"
|
||||||
|
#include "u2f_impl.h"
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
|
||||||
|
#ifdef HAVE_USB_CLASS_CCID
|
||||||
|
#include "usbd_ccid_core.h"
|
||||||
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
|
||||||
|
|
||||||
|
/** @addtogroup STM32_USB_DEVICE_LIBRARY
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @defgroup USBD_HID
|
||||||
|
* @brief usbd core module
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup USBD_HID_Private_TypesDefinitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @defgroup USBD_HID_Private_Defines
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @defgroup USBD_HID_Private_Macros
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
/** @defgroup USBD_HID_Private_FunctionPrototypes
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup USBD_HID_Private_Variables
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HID_EPIN_ADDR 0x82
|
||||||
|
#define HID_EPIN_SIZE 0x40
|
||||||
|
|
||||||
|
#define HID_EPOUT_ADDR 0x02
|
||||||
|
#define HID_EPOUT_SIZE 0x40
|
||||||
|
|
||||||
|
#define USBD_LANGID_STRING 0x409
|
||||||
|
|
||||||
|
#ifdef HAVE_VID_PID_PROBER
|
||||||
|
#define USBD_VID 0x2581
|
||||||
|
#define USBD_PID 0xf1d1
|
||||||
|
#else
|
||||||
|
#define USBD_VID 0x2C97
|
||||||
|
#if defined(TARGET_BLUE) // blue
|
||||||
|
#define USBD_PID 0x0000
|
||||||
|
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
||||||
|
4*2+2,
|
||||||
|
USB_DESC_TYPE_STRING,
|
||||||
|
'B', 0,
|
||||||
|
'l', 0,
|
||||||
|
'u', 0,
|
||||||
|
'e', 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif defined(TARGET_NANOS) // nano s
|
||||||
|
#define USBD_PID 0x0001
|
||||||
|
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
||||||
|
6*2+2,
|
||||||
|
USB_DESC_TYPE_STRING,
|
||||||
|
'N', 0,
|
||||||
|
'a', 0,
|
||||||
|
'n', 0,
|
||||||
|
'o', 0,
|
||||||
|
' ', 0,
|
||||||
|
'S', 0,
|
||||||
|
};
|
||||||
|
#elif defined(TARGET_ARAMIS) // aramis
|
||||||
|
#define USBD_PID 0x0002
|
||||||
|
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
||||||
|
6*2+2,
|
||||||
|
USB_DESC_TYPE_STRING,
|
||||||
|
'A', 0,
|
||||||
|
'r', 0,
|
||||||
|
'a', 0,
|
||||||
|
'm', 0,
|
||||||
|
'i', 0,
|
||||||
|
's', 0,
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#error unknown TARGET_ID
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* USB Standard Device Descriptor */
|
||||||
|
static const uint8_t const USBD_LangIDDesc[]=
|
||||||
|
{
|
||||||
|
USB_LEN_LANGID_STR_DESC,
|
||||||
|
USB_DESC_TYPE_STRING,
|
||||||
|
LOBYTE(USBD_LANGID_STRING),
|
||||||
|
HIBYTE(USBD_LANGID_STRING),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t const USB_SERIAL_STRING[] =
|
||||||
|
{
|
||||||
|
4*2+2,
|
||||||
|
USB_DESC_TYPE_STRING,
|
||||||
|
'0', 0,
|
||||||
|
'0', 0,
|
||||||
|
'0', 0,
|
||||||
|
'1', 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t const USBD_MANUFACTURER_STRING[] = {
|
||||||
|
6*2+2,
|
||||||
|
USB_DESC_TYPE_STRING,
|
||||||
|
'L', 0,
|
||||||
|
'e', 0,
|
||||||
|
'd', 0,
|
||||||
|
'g', 0,
|
||||||
|
'e', 0,
|
||||||
|
'r', 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define USBD_INTERFACE_FS_STRING USBD_PRODUCT_FS_STRING
|
||||||
|
#define USBD_CONFIGURATION_FS_STRING USBD_PRODUCT_FS_STRING
|
||||||
|
|
||||||
|
static const uint8_t const HID_ReportDesc[] = {
|
||||||
|
0x06, 0xA0, 0xFF, // Usage page (vendor defined)
|
||||||
|
0x09, 0x01, // Usage ID (vendor defined)
|
||||||
|
0xA1, 0x01, // Collection (application)
|
||||||
|
|
||||||
|
// The Input report
|
||||||
|
0x09, 0x03, // Usage ID - vendor defined
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
0x75, 0x08, // Report Size (8 bits)
|
||||||
|
0x95, HID_EPIN_SIZE, // Report Count (64 fields)
|
||||||
|
0x81, 0x08, // Input (Data, Variable, Absolute)
|
||||||
|
|
||||||
|
// The Output report
|
||||||
|
0x09, 0x04, // Usage ID - vendor defined
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
0x75, 0x08, // Report Size (8 bits)
|
||||||
|
0x95, HID_EPOUT_SIZE, // Report Count (64 fields)
|
||||||
|
0x91, 0x08, // Output (Data, Variable, Absolute)
|
||||||
|
0xC0
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
static const uint8_t const HID_ReportDesc_fido[] = {
|
||||||
|
0x06, 0xD0, 0xF1, // Usage page (vendor defined)
|
||||||
|
0x09, 0x01, // Usage ID (vendor defined)
|
||||||
|
0xA1, 0x01, // Collection (application)
|
||||||
|
|
||||||
|
// The Input report
|
||||||
|
0x09, 0x03, // Usage ID - vendor defined
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
0x75, 0x08, // Report Size (8 bits)
|
||||||
|
0x95, U2F_EPIN_SIZE, // Report Count (64 fields)
|
||||||
|
0x81, 0x08, // Input (Data, Variable, Absolute)
|
||||||
|
|
||||||
|
// The Output report
|
||||||
|
0x09, 0x04, // Usage ID - vendor defined
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
0x75, 0x08, // Report Size (8 bits)
|
||||||
|
0x95, U2F_EPOUT_SIZE, // Report Count (64 fields)
|
||||||
|
0x91, 0x08, // Output (Data, Variable, Absolute)
|
||||||
|
0xC0
|
||||||
|
};
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
|
||||||
|
#define ARRAY_U2LE(l) (l)&0xFF, (l)>>8
|
||||||
|
|
||||||
|
/* USB HID device Configuration Descriptor */
|
||||||
|
static __ALIGN_BEGIN const uint8_t const N_USBD_CfgDesc[] __ALIGN_END =
|
||||||
|
{
|
||||||
|
0x09, /* bLength: Configuration Descriptor size */
|
||||||
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
||||||
|
ARRAY_U2LE(0x9 /* wTotalLength: Bytes returned */
|
||||||
|
+0x9+0x9+0x7+0x7
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
+0x9+0x9+0x7+0x7
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
#ifdef HAVE_USB_CLASS_CCID
|
||||||
|
+0x9+0x36+0x7+0x7
|
||||||
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
),
|
||||||
|
1
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
+1
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
#ifdef HAVE_USB_CLASS_CCID
|
||||||
|
+1
|
||||||
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
, /*bNumInterfaces */
|
||||||
|
0x01, /*bConfigurationValue: Configuration value*/
|
||||||
|
USBD_IDX_PRODUCT_STR, /*iConfiguration: Index of string descriptor describing the configuration*/
|
||||||
|
0xC0, /*bmAttributes: bus powered */
|
||||||
|
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
|
||||||
|
|
||||||
|
/* HIDGEN ################################################################################################ */
|
||||||
|
|
||||||
|
/************** Descriptor of KBD HID interface ****************/
|
||||||
|
0x09, /*bLength: Interface Descriptor size*/
|
||||||
|
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
|
||||||
|
HID_INTF, /*bInterfaceNumber: Number of Interface*/
|
||||||
|
0x00, /*bAlternateSetting: Alternate setting*/
|
||||||
|
0x02, /*bNumEndpoints*/
|
||||||
|
0x03, /*bInterfaceClass: HID*/
|
||||||
|
0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
|
||||||
|
0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
|
||||||
|
USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/
|
||||||
|
|
||||||
|
/******************** Descriptor of HID *************************/
|
||||||
|
0x09, /*bLength: HID Descriptor size*/
|
||||||
|
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
||||||
|
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
|
||||||
|
0x01,
|
||||||
|
0x00, /*bCountryCode: Hardware target country*/
|
||||||
|
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
||||||
|
0x22, /*bDescriptorType*/
|
||||||
|
sizeof(HID_ReportDesc),/*wItemLength: Total length of Report descriptor*/
|
||||||
|
0x00,
|
||||||
|
|
||||||
|
/******************** Descriptor of Custom HID endpoints ********************/
|
||||||
|
0x07, /*bLength: Endpoint Descriptor size*/
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
||||||
|
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
|
||||||
|
0x03, /*bmAttributes: Interrupt endpoint*/
|
||||||
|
HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
|
||||||
|
0x00,
|
||||||
|
0x01, /*bInterval: Polling Interval (20 ms)*/
|
||||||
|
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||||
|
HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/
|
||||||
|
0x03, /* bmAttributes: Interrupt endpoint */
|
||||||
|
HID_EPOUT_SIZE, /* wMaxPacketSize: 2 Bytes max */
|
||||||
|
0x00,
|
||||||
|
0x01, /* bInterval: Polling Interval (20 ms) */
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
/* HID FIDO ################################################################################################ */
|
||||||
|
|
||||||
|
/************** Descriptor of HID FIDO interface ****************/
|
||||||
|
0x09, /*bLength: Interface Descriptor size*/
|
||||||
|
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
|
||||||
|
U2F_INTF, /*bInterfaceNumber: Number of Interface*/
|
||||||
|
0x00, /*bAlternateSetting: Alternate setting*/
|
||||||
|
0x02, /*bNumEndpoints*/
|
||||||
|
0x03, /*bInterfaceClass: HID*/
|
||||||
|
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
|
||||||
|
0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
|
||||||
|
USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/
|
||||||
|
|
||||||
|
/******************** Descriptor of HID *************************/
|
||||||
|
0x09, /*bLength: HID Descriptor size*/
|
||||||
|
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
||||||
|
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
|
||||||
|
0x01,
|
||||||
|
0x21, /*bCountryCode: Hardware target country*/ // 0x21: US, 0x08: FR, 0x0D: ISO Intl
|
||||||
|
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
||||||
|
0x22, /*bDescriptorType*/
|
||||||
|
sizeof(HID_ReportDesc_fido),/*wItemLength: Total length of Report descriptor*/
|
||||||
|
0x00,
|
||||||
|
/******************** Descriptor of Custom HID endpoints ********************/
|
||||||
|
0x07, /*bLength: Endpoint Descriptor size*/
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
||||||
|
U2F_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
|
||||||
|
0x03, /*bmAttributes: Interrupt endpoint*/
|
||||||
|
U2F_EPIN_SIZE, /*wMaxPacketSize: */
|
||||||
|
0x00,
|
||||||
|
0x01, /*bInterval: Polling Interval */
|
||||||
|
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||||
|
U2F_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/
|
||||||
|
0x03, /* bmAttributes: Interrupt endpoint */
|
||||||
|
U2F_EPOUT_SIZE, /* wMaxPacketSize: */
|
||||||
|
0x00,
|
||||||
|
0x01,/* bInterval: Polling Interval */
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
|
||||||
|
#ifdef HAVE_USB_CLASS_CCID
|
||||||
|
/* CCID ################################################################################################ */
|
||||||
|
|
||||||
|
/******************** CCID **** interface ********************/
|
||||||
|
0x09, /* bLength: Interface Descriptor size */
|
||||||
|
0x04, /* bDescriptorType: */
|
||||||
|
CCID_INTF, /* bInterfaceNumber: Number of Interface */
|
||||||
|
0x00, /* bAlternateSetting: Alternate setting */
|
||||||
|
0x02, /* bNumEndpoints: endpoints used */
|
||||||
|
0x0B, /* bInterfaceClass: user's interface for CCID */
|
||||||
|
0x00, /* bInterfaceSubClass : */
|
||||||
|
0x00, /* nInterfaceProtocol : None */
|
||||||
|
0x05, /* iInterface: */
|
||||||
|
|
||||||
|
/******************* CCID class descriptor ********************/
|
||||||
|
0x36, /* bLength: CCID Descriptor size */
|
||||||
|
0x21, /* bDescriptorType: Functional Descriptor type. */
|
||||||
|
0x10, /* bcdCCID(LSB): CCID Class Spec release number (1.00) */
|
||||||
|
0x01, /* bcdCCID(MSB) */
|
||||||
|
|
||||||
|
0x00, /* bMaxSlotIndex :highest available slot on this device */
|
||||||
|
0x03, /* bVoltageSupport: bit Wise OR for 01h-5.0V 02h-3.0V
|
||||||
|
04h 1.8V*/
|
||||||
|
|
||||||
|
0x01,0x00,0x00,0x00, /* dwProtocols: 0001h = Protocol T=0 */
|
||||||
|
0x10,0x0E,0x00,0x00, /* dwDefaultClock: 3.6Mhz = 3600kHz = 0x0E10,
|
||||||
|
for 4 Mhz the value is (0x00000FA0) :
|
||||||
|
This is used in ETU and waiting time calculations*/
|
||||||
|
0x10,0x0E,0x00,0x00, /* dwMaximumClock: Maximum supported ICC clock frequency
|
||||||
|
in KHz. So, 3.6Mhz = 3600kHz = 0x0E10,
|
||||||
|
4 Mhz (0x00000FA0) : */
|
||||||
|
0x00, /* bNumClockSupported : no setting from PC
|
||||||
|
If the value is 00h, the
|
||||||
|
supported clock frequencies are assumed to be the
|
||||||
|
default clock frequency defined by dwDefaultClock
|
||||||
|
and the maximum clock frequency defined by
|
||||||
|
dwMaximumClock */
|
||||||
|
|
||||||
|
0xCD,0x25,0x00,0x00, /* dwDataRate: Default ICC I/O data rate in bps
|
||||||
|
9677 bps = 0x25CD
|
||||||
|
for example 10752 bps (0x00002A00) */
|
||||||
|
|
||||||
|
0xCD,0x25,0x00,0x00, /* dwMaxDataRate: Maximum supported ICC I/O data
|
||||||
|
rate in bps */
|
||||||
|
0x00, /* bNumDataRatesSupported :
|
||||||
|
The number of data rates that are supported by the CCID
|
||||||
|
If the value is 00h, all data rates between the default
|
||||||
|
data rate dwDataRate and the maximum data rate
|
||||||
|
dwMaxDataRate are supported.
|
||||||
|
Dont support GET_CLOCK_FREQUENCIES
|
||||||
|
*/
|
||||||
|
//46
|
||||||
|
0x00,0x00,0x00,0x00, /* dwMaxIFSD: 0 (T=0 only) */
|
||||||
|
0x00,0x00,0x00,0x00, /* dwSynchProtocols */
|
||||||
|
0x00,0x00,0x00,0x00, /* dwMechanical: no special characteristics */
|
||||||
|
|
||||||
|
0xBA, 0x06, 0x02, 0x00,
|
||||||
|
//0x38,0x00,EXCHANGE_LEVEL_FEATURE,0x00,
|
||||||
|
/* dwFeatures: clk, baud rate, voltage : automatic */
|
||||||
|
/* 00000008h Automatic ICC voltage selection
|
||||||
|
00000010h Automatic ICC clock frequency change
|
||||||
|
00000020h Automatic baud rate change according to
|
||||||
|
active parameters provided by the Host or self
|
||||||
|
determined 00000100h CCID can set
|
||||||
|
ICC in clock stop mode
|
||||||
|
|
||||||
|
Only one of the following values may be present to
|
||||||
|
select a level of exchange:
|
||||||
|
00010000h TPDU level exchanges with CCID
|
||||||
|
00020000h Short APDU level exchange with CCID
|
||||||
|
00040000h Short and Extended APDU level exchange
|
||||||
|
If none of those values : character level of exchange*/
|
||||||
|
0x0F,0x01,0x00,0x00, /* dwMaxCCIDMessageLength: Maximum block size + header*/
|
||||||
|
/* 261 + 10 */
|
||||||
|
|
||||||
|
0x00, /* bClassGetResponse*/
|
||||||
|
0x00, /* bClassEnvelope */
|
||||||
|
0x00,0x00, /* wLcdLayout : 0000h no LCD. */
|
||||||
|
0x00, /* bPINSupport : no PIN verif and modif */
|
||||||
|
0x01, /* bMaxCCIDBusySlots */
|
||||||
|
|
||||||
|
/******************** CCID Endpoints ********************/
|
||||||
|
0x07, /*Endpoint descriptor length = 7*/
|
||||||
|
0x05, /*Endpoint descriptor type */
|
||||||
|
CCID_BULK_IN_EP, /*Endpoint address (IN, address 1) */
|
||||||
|
0x02, /*Bulk endpoint type */
|
||||||
|
LOBYTE(CCID_BULK_EPIN_SIZE),
|
||||||
|
HIBYTE(CCID_BULK_EPIN_SIZE),
|
||||||
|
0x00, /*Polling interval in milliseconds */
|
||||||
|
|
||||||
|
0x07, /*Endpoint descriptor length = 7 */
|
||||||
|
0x05, /*Endpoint descriptor type */
|
||||||
|
CCID_BULK_OUT_EP, /*Endpoint address (OUT, address 1) */
|
||||||
|
0x02, /*Bulk endpoint type */
|
||||||
|
LOBYTE(CCID_BULK_EPOUT_SIZE),
|
||||||
|
HIBYTE(CCID_BULK_EPOUT_SIZE),
|
||||||
|
0x00, /*Polling interval in milliseconds*/
|
||||||
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
} ;
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
/* USB HID device Configuration Descriptor */
|
||||||
|
__ALIGN_BEGIN const uint8_t const USBD_HID_Desc_fido[] __ALIGN_END =
|
||||||
|
{
|
||||||
|
/******************** Descriptor of HID *************************/
|
||||||
|
0x09, /*bLength: HID Descriptor size*/
|
||||||
|
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
||||||
|
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
|
||||||
|
0x01,
|
||||||
|
0x21, /*bCountryCode: Hardware target country*/ // 0x21: US, 0x08: FR, 0x0D: ISO Intl
|
||||||
|
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
||||||
|
0x22, /*bDescriptorType*/
|
||||||
|
sizeof(HID_ReportDesc_fido),/*wItemLength: Total length of Report descriptor*/
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
|
||||||
|
/* USB HID device Configuration Descriptor */
|
||||||
|
__ALIGN_BEGIN const uint8_t const USBD_HID_Desc[] __ALIGN_END =
|
||||||
|
{
|
||||||
|
/* 18 */
|
||||||
|
0x09, /*bLength: HID Descriptor size*/
|
||||||
|
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
||||||
|
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
|
||||||
|
0x01,
|
||||||
|
0x00, /*bCountryCode: Hardware target country*/
|
||||||
|
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
||||||
|
0x22, /*bDescriptorType*/
|
||||||
|
sizeof(HID_ReportDesc),/*wItemLength: Total length of Report descriptor*/
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* USB Standard Device Descriptor */
|
||||||
|
static __ALIGN_BEGIN const uint8_t const USBD_DeviceQualifierDesc[] __ALIGN_END =
|
||||||
|
{
|
||||||
|
USB_LEN_DEV_QUALIFIER_DESC,
|
||||||
|
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x40,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* USB Standard Device Descriptor */
|
||||||
|
static const uint8_t const USBD_DeviceDesc[]= {
|
||||||
|
0x12, /* bLength */
|
||||||
|
USB_DESC_TYPE_DEVICE, /* bDescriptorType */
|
||||||
|
0x00, /* bcdUSB */
|
||||||
|
0x02,
|
||||||
|
0x00, /* bDeviceClass */
|
||||||
|
0x00, /* bDeviceSubClass */
|
||||||
|
0x00, /* bDeviceProtocol */
|
||||||
|
USB_MAX_EP0_SIZE, /* bMaxPacketSize */
|
||||||
|
LOBYTE(USBD_VID), /* idVendor */
|
||||||
|
HIBYTE(USBD_VID), /* idVendor */
|
||||||
|
LOBYTE(USBD_PID), /* idVendor */
|
||||||
|
HIBYTE(USBD_PID), /* idVendor */
|
||||||
|
0x00, /* bcdDevice rel. 2.00 */
|
||||||
|
0x02,
|
||||||
|
USBD_IDX_MFC_STR, /* Index of manufacturer string */
|
||||||
|
USBD_IDX_PRODUCT_STR, /* Index of product string */
|
||||||
|
USBD_IDX_SERIAL_STR, /* Index of serial number string */
|
||||||
|
1 /* bNumConfigurations */
|
||||||
|
}; /* USB_DeviceDescriptor */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the device descriptor.
|
||||||
|
* @param speed: Current device speed
|
||||||
|
* @param length: Pointer to data length variable
|
||||||
|
* @retval Pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||||
|
{
|
||||||
|
UNUSED(speed);
|
||||||
|
*length = sizeof(USBD_DeviceDesc);
|
||||||
|
return (uint8_t*)USBD_DeviceDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the LangID string descriptor.
|
||||||
|
* @param speed: Current device speed
|
||||||
|
* @param length: Pointer to data length variable
|
||||||
|
* @retval Pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||||
|
{
|
||||||
|
UNUSED(speed);
|
||||||
|
*length = sizeof(USBD_LangIDDesc);
|
||||||
|
return (uint8_t*)USBD_LangIDDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the product string descriptor.
|
||||||
|
* @param speed: Current device speed
|
||||||
|
* @param length: Pointer to data length variable
|
||||||
|
* @retval Pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||||
|
{
|
||||||
|
UNUSED(speed);
|
||||||
|
*length = sizeof(USBD_PRODUCT_FS_STRING);
|
||||||
|
return (uint8_t*)USBD_PRODUCT_FS_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the manufacturer string descriptor.
|
||||||
|
* @param speed: Current device speed
|
||||||
|
* @param length: Pointer to data length variable
|
||||||
|
* @retval Pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||||
|
{
|
||||||
|
UNUSED(speed);
|
||||||
|
*length = sizeof(USBD_MANUFACTURER_STRING);
|
||||||
|
return (uint8_t*)USBD_MANUFACTURER_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the serial number string descriptor.
|
||||||
|
* @param speed: Current device speed
|
||||||
|
* @param length: Pointer to data length variable
|
||||||
|
* @retval Pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||||
|
{
|
||||||
|
UNUSED(speed);
|
||||||
|
*length = sizeof(USB_SERIAL_STRING);
|
||||||
|
return (uint8_t*)USB_SERIAL_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the configuration string descriptor.
|
||||||
|
* @param speed: Current device speed
|
||||||
|
* @param length: Pointer to data length variable
|
||||||
|
* @retval Pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||||
|
{
|
||||||
|
UNUSED(speed);
|
||||||
|
*length = sizeof(USBD_CONFIGURATION_FS_STRING);
|
||||||
|
return (uint8_t*)USBD_CONFIGURATION_FS_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the interface string descriptor.
|
||||||
|
* @param speed: Current device speed
|
||||||
|
* @param length: Pointer to data length variable
|
||||||
|
* @retval Pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||||
|
{
|
||||||
|
UNUSED(speed);
|
||||||
|
*length = sizeof(USBD_INTERFACE_FS_STRING);
|
||||||
|
return (uint8_t*)USBD_INTERFACE_FS_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DeviceQualifierDescriptor
|
||||||
|
* return Device Qualifier descriptor
|
||||||
|
* @param length : pointer data length
|
||||||
|
* @retval pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_GetDeviceQualifierDesc_impl (uint16_t *length)
|
||||||
|
{
|
||||||
|
*length = sizeof (USBD_DeviceQualifierDesc);
|
||||||
|
return (uint8_t*)USBD_DeviceQualifierDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USBD_CUSTOM_HID_GetCfgDesc
|
||||||
|
* return configuration descriptor
|
||||||
|
* @param speed : current device speed
|
||||||
|
* @param length : pointer data length
|
||||||
|
* @retval pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
uint8_t *USBD_GetCfgDesc_impl (uint16_t *length)
|
||||||
|
{
|
||||||
|
*length = sizeof (N_USBD_CfgDesc);
|
||||||
|
return (uint8_t*)N_USBD_CfgDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* USBD_HID_GetHidDescriptor_impl(uint16_t* len) {
|
||||||
|
switch (USBD_Device.request.wIndex&0xFF) {
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
case U2F_INTF:
|
||||||
|
*len = sizeof(USBD_HID_Desc_fido);
|
||||||
|
return (uint8_t*)USBD_HID_Desc_fido;
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
case HID_INTF:
|
||||||
|
*len = sizeof(USBD_HID_Desc);
|
||||||
|
return (uint8_t*)USBD_HID_Desc;
|
||||||
|
}
|
||||||
|
*len = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* USBD_HID_GetReportDescriptor_impl(uint16_t* len) {
|
||||||
|
switch (USBD_Device.request.wIndex&0xFF) {
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
case U2F_INTF:
|
||||||
|
|
||||||
|
// very dirty work due to lack of callback when USB_HID_Init is called
|
||||||
|
USBD_LL_OpenEP(&USBD_Device,
|
||||||
|
U2F_EPIN_ADDR,
|
||||||
|
USBD_EP_TYPE_INTR,
|
||||||
|
U2F_EPIN_SIZE);
|
||||||
|
|
||||||
|
USBD_LL_OpenEP(&USBD_Device,
|
||||||
|
U2F_EPOUT_ADDR,
|
||||||
|
USBD_EP_TYPE_INTR,
|
||||||
|
U2F_EPOUT_SIZE);
|
||||||
|
|
||||||
|
/* Prepare Out endpoint to receive 1st packet */
|
||||||
|
USBD_LL_PrepareReceive(&USBD_Device, U2F_EPOUT_ADDR, U2F_EPOUT_SIZE);
|
||||||
|
|
||||||
|
|
||||||
|
*len = sizeof(HID_ReportDesc_fido);
|
||||||
|
return (uint8_t*)HID_ReportDesc_fido;
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
case HID_INTF:
|
||||||
|
*len = sizeof(HID_ReportDesc);
|
||||||
|
return (uint8_t*)HID_ReportDesc;
|
||||||
|
}
|
||||||
|
*len = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USBD_HID_DataOut
|
||||||
|
* handle data OUT Stage
|
||||||
|
* @param pdev: device instance
|
||||||
|
* @param epnum: endpoint index
|
||||||
|
* @retval status
|
||||||
|
*
|
||||||
|
* This function is the default behavior for our implementation when data are sent over the out hid endpoint
|
||||||
|
*/
|
||||||
|
extern volatile unsigned short G_io_apdu_length;
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
uint8_t USBD_U2F_DataIn_impl (USBD_HandleTypeDef *pdev,
|
||||||
|
uint8_t epnum)
|
||||||
|
{
|
||||||
|
UNUSED(pdev);
|
||||||
|
// only the data hid endpoint will receive data
|
||||||
|
switch (epnum) {
|
||||||
|
// FIDO endpoint
|
||||||
|
case (U2F_EPIN_ADDR&0x7F):
|
||||||
|
// advance the u2f sending machine state
|
||||||
|
u2f_transport_sent(&G_io_u2f, U2F_MEDIA_USB);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return USBD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t USBD_U2F_DataOut_impl (USBD_HandleTypeDef *pdev,
|
||||||
|
uint8_t epnum, uint8_t* buffer)
|
||||||
|
{
|
||||||
|
switch (epnum) {
|
||||||
|
// FIDO endpoint
|
||||||
|
case (U2F_EPOUT_ADDR&0x7F):
|
||||||
|
USBD_LL_PrepareReceive(pdev, U2F_EPOUT_ADDR , U2F_EPOUT_SIZE);
|
||||||
|
u2f_transport_received(&G_io_u2f, buffer, io_seproxyhal_get_ep_rx_size(U2F_EPOUT_ADDR), U2F_MEDIA_USB);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return USBD_OK;
|
||||||
|
}
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
|
||||||
|
uint8_t USBD_HID_DataOut_impl (USBD_HandleTypeDef *pdev,
|
||||||
|
uint8_t epnum, uint8_t* buffer)
|
||||||
|
{
|
||||||
|
// only the data hid endpoint will receive data
|
||||||
|
switch (epnum) {
|
||||||
|
|
||||||
|
// HID gen endpoint
|
||||||
|
case (HID_EPOUT_ADDR&0x7F):
|
||||||
|
// prepare receiving the next chunk (masked time)
|
||||||
|
USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR , HID_EPOUT_SIZE);
|
||||||
|
|
||||||
|
// avoid troubles when an apdu has not been replied yet
|
||||||
|
if (G_io_apdu_media == IO_APDU_MEDIA_NONE) {
|
||||||
|
// add to the hid transport
|
||||||
|
switch(io_usb_hid_receive(io_usb_send_apdu_data, buffer, io_seproxyhal_get_ep_rx_size(HID_EPOUT_ADDR))) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_USB_APDU_RECEIVED:
|
||||||
|
G_io_apdu_media = IO_APDU_MEDIA_USB_HID; // for application code
|
||||||
|
G_io_apdu_state = APDU_USB_HID; // for next call to io_exchange
|
||||||
|
G_io_apdu_length = G_io_usb_hid_total_length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return USBD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @defgroup USBD_HID_Private_Functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
// note: how core lib usb calls the hid class
|
||||||
|
const USBD_DescriptorsTypeDef const HID_Desc = {
|
||||||
|
USBD_DeviceDescriptor,
|
||||||
|
USBD_LangIDStrDescriptor,
|
||||||
|
USBD_ManufacturerStrDescriptor,
|
||||||
|
USBD_ProductStrDescriptor,
|
||||||
|
USBD_SerialStrDescriptor,
|
||||||
|
USBD_ConfigStrDescriptor,
|
||||||
|
USBD_InterfaceStrDescriptor,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
static const USBD_ClassTypeDef const USBD_U2F =
|
||||||
|
{
|
||||||
|
USBD_HID_Init,
|
||||||
|
USBD_HID_DeInit,
|
||||||
|
USBD_HID_Setup,
|
||||||
|
NULL, /*EP0_TxSent*/
|
||||||
|
NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */
|
||||||
|
USBD_U2F_DataIn_impl, /*DataIn*/
|
||||||
|
USBD_U2F_DataOut_impl, /*DataOut*/
|
||||||
|
NULL, /*SOF */
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetDeviceQualifierDesc_impl,
|
||||||
|
};
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
|
||||||
|
static const USBD_ClassTypeDef const USBD_HID =
|
||||||
|
{
|
||||||
|
USBD_HID_Init,
|
||||||
|
USBD_HID_DeInit,
|
||||||
|
USBD_HID_Setup,
|
||||||
|
NULL, /*EP0_TxSent*/
|
||||||
|
NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */
|
||||||
|
NULL, /*DataIn*/
|
||||||
|
USBD_HID_DataOut_impl, /*DataOut*/
|
||||||
|
NULL, /*SOF */
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetDeviceQualifierDesc_impl,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_USB_CLASS_CCID
|
||||||
|
static const USBD_ClassTypeDef USBD_CCID =
|
||||||
|
{
|
||||||
|
USBD_CCID_Init,
|
||||||
|
USBD_CCID_DeInit,
|
||||||
|
USBD_CCID_Setup,
|
||||||
|
NULL, /*EP0_TxSent*/
|
||||||
|
NULL, /*EP0_RxReady*/
|
||||||
|
USBD_CCID_DataIn,
|
||||||
|
USBD_CCID_DataOut,
|
||||||
|
NULL, /*SOF */
|
||||||
|
NULL, /*ISOIn*/
|
||||||
|
NULL, /*ISOOut*/
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetCfgDesc_impl,
|
||||||
|
USBD_GetDeviceQualifierDesc_impl,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SC_AnswerToReset (uint8_t voltage, uint8_t* atr_buffer) {
|
||||||
|
UNUSED(voltage);
|
||||||
|
// return the atr length
|
||||||
|
atr_buffer[0] = 0x3B;
|
||||||
|
atr_buffer[1] = 0;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SC_Poweroff(void) {
|
||||||
|
// nothing to do ?
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t SC_ExecuteEscape (uint8_t* escapePtr, uint32_t escapeLen,
|
||||||
|
uint8_t* responseBuff,
|
||||||
|
uint16_t* responseLen) {
|
||||||
|
UNUSED(escapePtr);
|
||||||
|
UNUSED(escapeLen);
|
||||||
|
UNUSED(responseBuff);
|
||||||
|
UNUSED(responseLen);
|
||||||
|
// nothing to do ?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
|
||||||
|
void USB_power(unsigned char enabled) {
|
||||||
|
os_memset(&USBD_Device, 0, sizeof(USBD_Device));
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
os_memset(&USBD_Device, 0, sizeof(USBD_Device));
|
||||||
|
/* Init Device Library */
|
||||||
|
USBD_Init(&USBD_Device, (USBD_DescriptorsTypeDef*)&HID_Desc, 0);
|
||||||
|
|
||||||
|
/* Register the HID class */
|
||||||
|
USBD_RegisterClassForInterface(HID_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_HID);
|
||||||
|
#ifdef HAVE_IO_U2F
|
||||||
|
USBD_RegisterClassForInterface(U2F_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_U2F);
|
||||||
|
// initialize the U2F tunnel transport
|
||||||
|
u2f_transport_init(&G_io_u2f, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE);
|
||||||
|
#endif // HAVE_IO_U2F
|
||||||
|
#ifdef HAVE_USB_CLASS_CCID
|
||||||
|
USBD_RegisterClassForInterface(CCID_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_CCID);
|
||||||
|
#endif // HAVE_USB_CLASS_CCID
|
||||||
|
|
||||||
|
|
||||||
|
/* Start Device Process */
|
||||||
|
USBD_Start(&USBD_Device);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
USBD_DeInit(&USBD_Device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
7
src/sdk/usbd_impl.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef USBD_IMPL_H
|
||||||
|
#define USBD_IMPL_H
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t *USBD_GetCfgDesc_impl (uint16_t *length);
|
||||||
|
|
||||||
|
#endif //USBD_IMPL_H
|
|
@ -1,463 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file usbd_ccid_core.c
|
|
||||||
* @author MCD Application Team
|
|
||||||
* @version V1.0.1
|
|
||||||
* @date 31-January-2014
|
|
||||||
* @brief This file provides all the CCID core functions.
|
|
||||||
*
|
|
||||||
* @verbatim
|
|
||||||
*
|
|
||||||
* ===================================================================
|
|
||||||
* CCID Class Description
|
|
||||||
* ===================================================================
|
|
||||||
* This module manages the Specification for Integrated Circuit(s)
|
|
||||||
* Cards Interface Revision 1.1
|
|
||||||
* This driver implements the following aspects of the specification:
|
|
||||||
* - Bulk Transfers
|
|
||||||
*
|
|
||||||
* @endverbatim
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© 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.
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "usbd_ccid_core.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_USB_CLASS_CCID
|
|
||||||
|
|
||||||
#define USBD_LANGID_STRING 0x409
|
|
||||||
|
|
||||||
#define USBD_VID 0x2C97
|
|
||||||
#if TARGET_ID == 0x31000002 // blue
|
|
||||||
#define USBD_PID 0x0000
|
|
||||||
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
|
||||||
4*2+2,
|
|
||||||
USB_DESC_TYPE_STRING,
|
|
||||||
'B', 0,
|
|
||||||
'l', 0,
|
|
||||||
'u', 0,
|
|
||||||
'e', 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
#elif TARGET_ID == 0x31100002 // nano s
|
|
||||||
#define USBD_PID 0x0001
|
|
||||||
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
|
||||||
6*2+2,
|
|
||||||
USB_DESC_TYPE_STRING,
|
|
||||||
'N', 0,
|
|
||||||
'a', 0,
|
|
||||||
'n', 0,
|
|
||||||
'o', 0,
|
|
||||||
' ', 0,
|
|
||||||
'S', 0,
|
|
||||||
};
|
|
||||||
#elif TARGET_ID == 0x31200002 // aramis
|
|
||||||
#define USBD_PID 0x0002
|
|
||||||
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
|
||||||
6*2+2,
|
|
||||||
USB_DESC_TYPE_STRING,
|
|
||||||
'A', 0,
|
|
||||||
'r', 0,
|
|
||||||
'a', 0,
|
|
||||||
'm', 0,
|
|
||||||
'i', 0,
|
|
||||||
's', 0,
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
#error unknown TARGET_ID
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* USB Standard Device Descriptor */
|
|
||||||
static __ALIGN_BEGIN const uint8_t const USBD_DeviceQualifierDesc[] __ALIGN_END =
|
|
||||||
{
|
|
||||||
USB_LEN_DEV_QUALIFIER_DESC,
|
|
||||||
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
|
||||||
0x00,
|
|
||||||
0x02,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x40,
|
|
||||||
0x01,
|
|
||||||
0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB Standard Device Descriptor */
|
|
||||||
static const uint8_t const USBD_LangIDDesc[]=
|
|
||||||
{
|
|
||||||
USB_LEN_LANGID_STR_DESC,
|
|
||||||
USB_DESC_TYPE_STRING,
|
|
||||||
LOBYTE(USBD_LANGID_STRING),
|
|
||||||
HIBYTE(USBD_LANGID_STRING),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t const USB_SERIAL_STRING[] =
|
|
||||||
{
|
|
||||||
4*2+2,
|
|
||||||
USB_DESC_TYPE_STRING,
|
|
||||||
'0', 0,
|
|
||||||
'0', 0,
|
|
||||||
'0', 0,
|
|
||||||
'1', 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t const USBD_MANUFACTURER_STRING[] = {
|
|
||||||
6*2+2,
|
|
||||||
USB_DESC_TYPE_STRING,
|
|
||||||
'L', 0,
|
|
||||||
'e', 0,
|
|
||||||
'd', 0,
|
|
||||||
'g', 0,
|
|
||||||
'e', 0,
|
|
||||||
'r', 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define USBD_INTERFACE_FS_STRING USBD_PRODUCT_FS_STRING
|
|
||||||
#define USBD_CONFIGURATION_FS_STRING USBD_PRODUCT_FS_STRING
|
|
||||||
|
|
||||||
|
|
||||||
/* USB Standard Device Descriptor */
|
|
||||||
static const uint8_t const USBD_DeviceDesc[]= {
|
|
||||||
0x12, /* bLength */
|
|
||||||
USB_DESC_TYPE_DEVICE, /* bDescriptorType */
|
|
||||||
0x00, /* bcdUSB */
|
|
||||||
0x02,
|
|
||||||
0x00, /* bDeviceClass */
|
|
||||||
0x00, /* bDeviceSubClass */
|
|
||||||
0x00, /* bDeviceProtocol */
|
|
||||||
USB_MAX_EP0_SIZE, /* bMaxPacketSize */
|
|
||||||
LOBYTE(USBD_VID), /* idVendor */
|
|
||||||
HIBYTE(USBD_VID), /* idVendor */
|
|
||||||
LOBYTE(USBD_PID), /* idVendor */
|
|
||||||
HIBYTE(USBD_PID), /* idVendor */
|
|
||||||
0x00, /* bcdDevice rel. 2.00 */
|
|
||||||
0x02,
|
|
||||||
USBD_IDX_MFC_STR, /* Index of manufacturer string */
|
|
||||||
USBD_IDX_PRODUCT_STR, /* Index of product string */
|
|
||||||
USBD_IDX_SERIAL_STR, /* Index of serial number string */
|
|
||||||
USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */
|
|
||||||
}; /* USB_DeviceDescriptor */
|
|
||||||
|
|
||||||
|
|
||||||
/* USB Mass storage device Configuration Descriptor */
|
|
||||||
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
|
|
||||||
#define USBD_OFFSET_CfgDesc_bPINSupport 70
|
|
||||||
const uint8_t N_USBD_CfgDesc[] =
|
|
||||||
{
|
|
||||||
|
|
||||||
0x09, /* bLength: Configuration Descriptor size */
|
|
||||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
||||||
0x9+0x9+0x36+0x7+0x7+0x7,
|
|
||||||
|
|
||||||
0x00,
|
|
||||||
0x01, /* bNumInterfaces: 1 interface */
|
|
||||||
0x01, /* bConfigurationValue: */
|
|
||||||
0x04, /* iConfiguration: */
|
|
||||||
0x80, /*bmAttributes: bus powered */
|
|
||||||
0x32, /* MaxPower 100 mA */
|
|
||||||
|
|
||||||
/******************** CCID **** interface ********************/
|
|
||||||
0x09, /* bLength: Interface Descriptor size */
|
|
||||||
0x04, /* bDescriptorType: */
|
|
||||||
0x00, /* bInterfaceNumber: Number of Interface */
|
|
||||||
0x00, /* bAlternateSetting: Alternate setting */
|
|
||||||
0x03, /* bNumEndpoints: 3 endpoints used */
|
|
||||||
0x0B, /* bInterfaceClass: user's interface for CCID */
|
|
||||||
0x00, /* bInterfaceSubClass : */
|
|
||||||
0x00, /* nInterfaceProtocol : None */
|
|
||||||
0x05, /* iInterface: */
|
|
||||||
|
|
||||||
/******************* CCID class descriptor ********************/
|
|
||||||
0x36, /* bLength: CCID Descriptor size */
|
|
||||||
0x21, /* bDescriptorType: Functional Descriptor type. */
|
|
||||||
0x10, /* bcdCCID(LSB): CCID Class Spec release number (1.00) */
|
|
||||||
0x01, /* bcdCCID(MSB) */
|
|
||||||
|
|
||||||
0x00, /* bMaxSlotIndex :highest available slot on this device */
|
|
||||||
0x03, /* bVoltageSupport: bit Wise OR for 01h-5.0V 02h-3.0V
|
|
||||||
04h 1.8V*/
|
|
||||||
|
|
||||||
0x01,0x00,0x00,0x00, /* dwProtocols: 0001h = Protocol T=0 */
|
|
||||||
0x10,0x0E,0x00,0x00, /* dwDefaultClock: 3.6Mhz = 3600kHz = 0x0E10,
|
|
||||||
for 4 Mhz the value is (0x00000FA0) :
|
|
||||||
This is used in ETU and waiting time calculations*/
|
|
||||||
0x10,0x0E,0x00,0x00, /* dwMaximumClock: Maximum supported ICC clock frequency
|
|
||||||
in KHz. So, 3.6Mhz = 3600kHz = 0x0E10,
|
|
||||||
4 Mhz (0x00000FA0) : */
|
|
||||||
0x00, /* bNumClockSupported : no setting from PC
|
|
||||||
If the value is 00h, the
|
|
||||||
supported clock frequencies are assumed to be the
|
|
||||||
default clock frequency defined by dwDefaultClock
|
|
||||||
and the maximum clock frequency defined by
|
|
||||||
dwMaximumClock */
|
|
||||||
|
|
||||||
0xCD,0x25,0x00,0x00, /* dwDataRate: Default ICC I/O data rate in bps
|
|
||||||
9677 bps = 0x25CD
|
|
||||||
for example 10752 bps (0x00002A00) */
|
|
||||||
|
|
||||||
0xCD,0x25,0x00,0x00, /* dwMaxDataRate: Maximum supported ICC I/O data
|
|
||||||
rate in bps */
|
|
||||||
0x00, /* bNumDataRatesSupported :
|
|
||||||
The number of data rates that are supported by the CCID
|
|
||||||
If the value is 00h, all data rates between the default
|
|
||||||
data rate dwDataRate and the maximum data rate
|
|
||||||
dwMaxDataRate are supported.
|
|
||||||
Dont support GET_CLOCK_FREQUENCIES
|
|
||||||
*/
|
|
||||||
//46
|
|
||||||
0x00,0x00,0x00,0x00, /* dwMaxIFSD: 0 (T=0 only) */
|
|
||||||
0x00,0x00,0x00,0x00, /* dwSynchProtocols */
|
|
||||||
0x00,0x00,0x00,0x00, /* dwMechanical: no special characteristics */
|
|
||||||
|
|
||||||
0x38,0x00,EXCHANGE_LEVEL_FEATURE,0x00,
|
|
||||||
/* dwFeatures: clk, baud rate, voltage : automatic */
|
|
||||||
/* 00000008h Automatic ICC voltage selection
|
|
||||||
00000010h Automatic ICC clock frequency change
|
|
||||||
00000020h Automatic baud rate change according to
|
|
||||||
active parameters provided by the Host or self
|
|
||||||
determined 00000100h CCID can set
|
|
||||||
ICC in clock stop mode
|
|
||||||
|
|
||||||
Only one of the following values may be present to
|
|
||||||
select a level of exchange:
|
|
||||||
00010000h TPDU level exchanges with CCID
|
|
||||||
00020000h Short APDU level exchange with CCID
|
|
||||||
00040000h Short and Extended APDU level exchange
|
|
||||||
If none of those values : character level of exchange*/
|
|
||||||
#if 1
|
|
||||||
0x0F,0x01,0x00,0x00, /* dwMaxCCIDMessageLength: Maximum block size + header*/
|
|
||||||
/* 261 + 10 */
|
|
||||||
#else
|
|
||||||
0xF8,0x00,0x00,0x00, /* dwMaxCCIDMessageLength: Maximum block size + header*/
|
|
||||||
/* EEh + 10 */
|
|
||||||
#endif
|
|
||||||
0x00, /* bClassGetResponse*/
|
|
||||||
0x00, /* bClassEnvelope */
|
|
||||||
0x00,0x00, /* wLcdLayout : 0000h no LCD. */
|
|
||||||
0x03, /* bPINSupport : no PIN verif and modif */ //<= offset: 70
|
|
||||||
0x01, /* bMaxCCIDBusySlots */
|
|
||||||
|
|
||||||
//72
|
|
||||||
/******************** CCID Endpoints ********************/
|
|
||||||
0x07, /*Endpoint descriptor length = 7*/
|
|
||||||
0x05, /*Endpoint descriptor type */
|
|
||||||
CCID_BULK_IN_EP, /*Endpoint address (IN, address 1) */
|
|
||||||
0x02, /*Bulk endpoint type */
|
|
||||||
LOBYTE(CCID_BULK_EPIN_SIZE),
|
|
||||||
HIBYTE(CCID_BULK_EPIN_SIZE),
|
|
||||||
0x00, /*Polling interval in milliseconds */
|
|
||||||
|
|
||||||
0x07, /*Endpoint descriptor length = 7 */
|
|
||||||
0x05, /*Endpoint descriptor type */
|
|
||||||
CCID_BULK_OUT_EP, /*Endpoint address (OUT, address 1) */
|
|
||||||
0x02, /*Bulk endpoint type */
|
|
||||||
LOBYTE(CCID_BULK_EPOUT_SIZE),
|
|
||||||
HIBYTE(CCID_BULK_EPOUT_SIZE),
|
|
||||||
0x00, /*Polling interval in milliseconds*/
|
|
||||||
|
|
||||||
|
|
||||||
0x07, /*bLength: Endpoint Descriptor size*/
|
|
||||||
0x05, /*bDescriptorType:*/
|
|
||||||
CCID_INTR_IN_EP, /*bEndpointAddress: Endpoint Address (IN)*/
|
|
||||||
0x03, /* bmAttributes: Interrupt endpoint */
|
|
||||||
LOBYTE(CCID_INTR_EPIN_SIZE),
|
|
||||||
HIBYTE(CCID_INTR_EPIN_SIZE),
|
|
||||||
0x18 /*Polling interval in milliseconds */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t *USBD_GetCfgDesc_impl (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (N_USBD_CfgDesc);
|
|
||||||
return (uint8_t*)(N_USBD_CfgDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the device descriptor.
|
|
||||||
* @param speed: Current device speed
|
|
||||||
* @param length: Pointer to data length variable
|
|
||||||
* @retval Pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
|
||||||
{
|
|
||||||
UNUSED(speed);
|
|
||||||
*length = sizeof(USBD_DeviceDesc);
|
|
||||||
return (uint8_t*)USBD_DeviceDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the LangID string descriptor.
|
|
||||||
* @param speed: Current device speed
|
|
||||||
* @param length: Pointer to data length variable
|
|
||||||
* @retval Pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
|
||||||
{
|
|
||||||
UNUSED(speed);
|
|
||||||
*length = sizeof(USBD_LangIDDesc);
|
|
||||||
return (uint8_t*)USBD_LangIDDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the product string descriptor.
|
|
||||||
* @param speed: Current device speed
|
|
||||||
* @param length: Pointer to data length variable
|
|
||||||
* @retval Pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
|
||||||
{
|
|
||||||
UNUSED(speed);
|
|
||||||
*length = sizeof(USBD_PRODUCT_FS_STRING);
|
|
||||||
return (uint8_t*)USBD_PRODUCT_FS_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the manufacturer string descriptor.
|
|
||||||
* @param speed: Current device speed
|
|
||||||
* @param length: Pointer to data length variable
|
|
||||||
* @retval Pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
|
||||||
{
|
|
||||||
UNUSED(speed);
|
|
||||||
*length = sizeof(USBD_MANUFACTURER_STRING);
|
|
||||||
return (uint8_t*)USBD_MANUFACTURER_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the serial number string descriptor.
|
|
||||||
* @param speed: Current device speed
|
|
||||||
* @param length: Pointer to data length variable
|
|
||||||
* @retval Pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
|
||||||
{
|
|
||||||
UNUSED(speed);
|
|
||||||
*length = sizeof(USB_SERIAL_STRING);
|
|
||||||
return (uint8_t*)USB_SERIAL_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the configuration string descriptor.
|
|
||||||
* @param speed: Current device speed
|
|
||||||
* @param length: Pointer to data length variable
|
|
||||||
* @retval Pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
|
||||||
{
|
|
||||||
UNUSED(speed);
|
|
||||||
*length = sizeof(USBD_CONFIGURATION_FS_STRING);
|
|
||||||
return (uint8_t*)USBD_CONFIGURATION_FS_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the interface string descriptor.
|
|
||||||
* @param speed: Current device speed
|
|
||||||
* @param length: Pointer to data length variable
|
|
||||||
* @retval Pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
|
||||||
{
|
|
||||||
UNUSED(speed);
|
|
||||||
*length = sizeof(USBD_INTERFACE_FS_STRING);
|
|
||||||
return (uint8_t*)USBD_INTERFACE_FS_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief DeviceQualifierDescriptor
|
|
||||||
* return Device Qualifier descriptor
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_GetDeviceQualifierDesc_impl (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_DeviceQualifierDesc);
|
|
||||||
return (uint8_t*)USBD_DeviceQualifierDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t SC_AnswerToReset (uint8_t voltage, uint8_t* atr_buffer) {
|
|
||||||
// return the atr length
|
|
||||||
atr_buffer[0] = 0x3B;
|
|
||||||
atr_buffer[1] = 0;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// note: how core lib usb calls the hid class
|
|
||||||
static const USBD_DescriptorsTypeDef const CCID_Desc = {
|
|
||||||
USBD_DeviceDescriptor,
|
|
||||||
USBD_LangIDStrDescriptor,
|
|
||||||
USBD_ManufacturerStrDescriptor,
|
|
||||||
USBD_ProductStrDescriptor,
|
|
||||||
USBD_SerialStrDescriptor,
|
|
||||||
USBD_ConfigStrDescriptor,
|
|
||||||
USBD_InterfaceStrDescriptor,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const USBD_ClassTypeDef USBD_CCID =
|
|
||||||
{
|
|
||||||
USBD_CCID_Init,
|
|
||||||
USBD_CCID_DeInit,
|
|
||||||
USBD_CCID_Setup,
|
|
||||||
NULL, /*EP0_TxSent*/
|
|
||||||
NULL, /*EP0_RxReady*/
|
|
||||||
USBD_CCID_DataIn,
|
|
||||||
USBD_CCID_DataOut,
|
|
||||||
NULL, /*SOF */
|
|
||||||
NULL, /*ISOIn*/
|
|
||||||
NULL, /*ISOOut*/
|
|
||||||
USBD_GetCfgDesc_impl,
|
|
||||||
USBD_GetCfgDesc_impl,
|
|
||||||
USBD_GetCfgDesc_impl,
|
|
||||||
USBD_GetDeviceQualifierDesc_impl,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void USBD_CCID_activate_pinpad(int enabled) {
|
|
||||||
unsigned char e;
|
|
||||||
e = enabled?3:0;
|
|
||||||
nvm_write(((char*)PIC(N_USBD_CfgDesc))+USBD_OFFSET_CfgDesc_bPINSupport, &e,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void USB_CCID_power(unsigned char enabled) {
|
|
||||||
os_memset(&USBD_Device, 0, sizeof(USBD_Device));
|
|
||||||
|
|
||||||
if (enabled) {
|
|
||||||
os_memset(&USBD_Device, 0, sizeof(USBD_Device));
|
|
||||||
/* Init Device Library */
|
|
||||||
USBD_Init(&USBD_Device, (USBD_DescriptorsTypeDef*)&CCID_Desc, 0);
|
|
||||||
|
|
||||||
/* Register the HID class */
|
|
||||||
USBD_RegisterClass(&USBD_Device, (USBD_ClassTypeDef*)&USBD_CCID);
|
|
||||||
|
|
||||||
/* Start Device Process */
|
|
||||||
USBD_Start(&USBD_Device);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
USBD_DeInit(&USBD_Device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // HAVE_USB_CLASS_CCID
|
|
|
@ -1,24 +0,0 @@
|
||||||
#ifndef USBD_CCID_IMPL_H
|
|
||||||
#define USBD_CCID_IMPL_H
|
|
||||||
|
|
||||||
#define TPDU_EXCHANGE 0x01
|
|
||||||
#define SHORT_APDU_EXCHANGE 0x02
|
|
||||||
#define EXTENDED_APDU_EXCHANGE 0x04
|
|
||||||
#define CHARACTER_EXCHANGE 0x00
|
|
||||||
|
|
||||||
#define EXCHANGE_LEVEL_FEATURE SHORT_APDU_EXCHANGE
|
|
||||||
|
|
||||||
|
|
||||||
#define CCID_BULK_IN_EP 0x82
|
|
||||||
#define CCID_BULK_EPIN_SIZE 64
|
|
||||||
#define CCID_BULK_OUT_EP 0x02
|
|
||||||
#define CCID_BULK_EPOUT_SIZE 64
|
|
||||||
#define CCID_INTR_IN_EP 0x81
|
|
||||||
#define CCID_INTR_EPIN_SIZE 16
|
|
||||||
|
|
||||||
#define CCID_EP0_BUFF_SIZ 64
|
|
||||||
|
|
||||||
void USB_CCID_power(unsigned char enabled);
|
|
||||||
void USBD_CCID_activate_pinpad(int enabled);
|
|
||||||
|
|
||||||
#endif // USBD_CCID_IMPL_H
|
|