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");
|
||||
# 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.
|
||||
#
|
||||
#*******************************************************************************
|
||||
|
||||
ifeq ($(BOLOS_SDK),)
|
||||
$(error Environment variable BOLOS_SDK is not set)
|
||||
endif
|
||||
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_N=0
|
||||
APPVERSION_P=RC7
|
||||
APPVERSION_N=2
|
||||
APPVERSION_P=1
|
||||
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 #
|
||||
################
|
||||
|
||||
all: default
|
||||
|
||||
############
|
||||
# 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 += $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME)
|
||||
|
||||
##############
|
||||
# Compiler #
|
||||
# Compiler #
|
||||
##############
|
||||
#GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
|
||||
#CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
|
||||
CC := $(CLANGPATH)clang
|
||||
|
||||
#CFLAGS += -O0 -gdwarf-2 -gstrict-dwarf
|
||||
CFLAGS += -O3 -Os
|
||||
CFLAGS += -O3 -Os
|
||||
#CFLAGS += -fno-jump-tables -fno-lookup-tables -fsave-optimization-record
|
||||
#$(info $(CFLAGS))
|
||||
|
||||
AS := $(GCCPATH)arm-none-eabi-gcc
|
||||
|
||||
|
@ -65,9 +88,9 @@ LDLIBS += -lm -lgcc -lc
|
|||
# import rules to compile glyphs(/pone)
|
||||
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
|
||||
SDK_SOURCE_PATH += lib_stusb lib_stusb_impl
|
||||
SDK_SOURCE_PATH += lib_stusb
|
||||
|
||||
|
||||
load: all
|
||||
|
@ -77,8 +100,8 @@ delete:
|
|||
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
|
||||
|
||||
# import generic rules from the sdk
|
||||
include $(BOLOS_SDK)/Makefile.rules
|
||||
include Makefile.rules
|
||||
|
||||
#add dependency on custom makefile filename
|
||||
dep/%.d: %.c Makefile.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
|
||||
|
||||
|
||||
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
|
||||
* Seed mode ON/OFF via apdu
|
||||
|
||||
|
||||
## Installation
|
||||
## Installation and Usage
|
||||
|
||||
### NanoS
|
||||
|
||||
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
|
||||
See the full doc at https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/user/blue-app-openpgp-card.pdf
|
||||
|
||||
|
||||
## Add-on
|
||||
|
@ -79,7 +30,7 @@ The GnuPG application implements the following addon:
|
|||
- 3 independent key slots
|
||||
- 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
|
||||
|
|
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:"):
|
||||
self.token = getDongle(True)
|
||||
self.exchange = self._exchange_ledger
|
||||
self.disconnect = self._disconnect_ledger
|
||||
elif device.startswith("pcsc:"):
|
||||
allreaders = readers()
|
||||
for r in allreaders:
|
||||
|
@ -120,6 +121,7 @@ class GPGCard() :
|
|||
self.connection = r.createConnection()
|
||||
self.connection.connect()
|
||||
self.exchange = self._exchange_pcsc
|
||||
self.disconnect = self._disconnect_pcsc
|
||||
else:
|
||||
#print("No")
|
||||
pass
|
||||
|
@ -127,6 +129,8 @@ class GPGCard() :
|
|||
print("No token")
|
||||
|
||||
|
||||
|
||||
|
||||
### APDU interface ###
|
||||
def _exchange_ledger(self,cmd,sw=0x9000):
|
||||
resp = b''
|
||||
|
@ -160,6 +164,14 @@ class GPGCard() :
|
|||
#print("xch S resp: %s %.04x"%(binascii.hexlify(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):
|
||||
apdu = binascii.unhexlify(b"00A4040006D27600012401")
|
||||
return self.exchange(apdu)
|
||||
|
@ -254,7 +266,7 @@ class GPGCard() :
|
|||
self.sig_date = dates[0:4]
|
||||
self.dec_date = dates[4:8]
|
||||
self.aut_date = dates[8:12]
|
||||
|
||||
|
||||
self.cardholder_cert = self.get_data(0x7f21)
|
||||
|
||||
self.UIF_SIG,sw = self.get_data(0xD6)
|
||||
|
@ -277,13 +289,13 @@ class GPGCard() :
|
|||
self.put_data(0x0102, self.private_02)
|
||||
self.put_data(0x0103, self.private_03)
|
||||
self.put_data(0x0104, self.private_04)
|
||||
|
||||
|
||||
self.put_data(0x5b, self.name)
|
||||
self.put_data(0x5e, self.login)
|
||||
self.put_data(0x5f2d, self.lang)
|
||||
self.put_data(0x5f35, self.sex)
|
||||
self.put_data(0x5f50, self.url)
|
||||
|
||||
|
||||
self.put_data(0xc1, self.sig_attribute)
|
||||
self.put_data(0xc2, self.dec_attribute)
|
||||
self.put_data(0xc3, self.aut_attribute)
|
||||
|
@ -314,13 +326,13 @@ class GPGCard() :
|
|||
self.name, self.login, self.sex, self.url,
|
||||
self.sig_attribute, self.dec_attribute, self.aut_attribute,
|
||||
self.PW_status,
|
||||
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
||||
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
||||
self.sig_date, self.dec_date, self.aut_date,
|
||||
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
||||
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
||||
self.sig_date, self.dec_date, self.aut_date,
|
||||
self.cardholder_cert,
|
||||
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT),
|
||||
f, 2)
|
||||
|
||||
|
||||
|
||||
def restore(self, file_name, seed_key=False):
|
||||
f = open(file_name,mode='r+b')
|
||||
|
@ -329,9 +341,9 @@ class GPGCard() :
|
|||
self.name, self.login, self.sex, self.url,
|
||||
self.sig_attribute, self.dec_attribute, self.aut_attribute,
|
||||
self.status,
|
||||
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
||||
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
||||
self.sig_date, self.dec_date, self.aut_date,
|
||||
self.sig_fingerprints, self.dec_fingerprints, self.aut_fingerprints,
|
||||
self.sig_CA_fingerprints, self.dec_CA_fingerprints, self.aut_CA_fingerprints,
|
||||
self.sig_date, self.dec_date, self.aut_date,
|
||||
self.cardholder_cert,
|
||||
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT) = pickle.load(f)
|
||||
self.set_all()
|
||||
|
|
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
|
||||
#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_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_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_gen(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) ;
|
||||
|
||||
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_set_verified(gpg_pin_t *pin, int verified);
|
||||
int gpg_pin_check(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
|
||||
int gpg_pin_is_verified(int pinID);
|
||||
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_sync12(void) ;
|
||||
|
||||
int gpg_mse_reset();
|
||||
int gpg_apdu_mse();
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* --- IO ---- */
|
||||
|
|
|
@ -44,16 +44,16 @@ int gpg_apdu_get_challenge() {
|
|||
chain[0] = 'r'; chain[1]='n'; chain[2] = 'd';
|
||||
|
||||
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
|
||||
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL);
|
||||
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL);
|
||||
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, 0);
|
||||
hlen=cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256,
|
||||
CX_LAST, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
||||
G_gpg_vstate.work.io_buffer);
|
||||
G_gpg_vstate.work.io_buffer, 32);
|
||||
|
||||
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
|
||||
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3,
|
||||
CX_LAST, G_gpg_vstate.work.io_buffer, hlen,
|
||||
G_gpg_vstate.work.io_buffer);
|
||||
G_gpg_vstate.work.io_buffer,olen);
|
||||
} else {
|
||||
cx_rng(G_gpg_vstate.work.io_buffer, olen);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ int gpg_apdu_get_data(unsigned int ref) {
|
|||
break;
|
||||
/* ----------------- Config RSA exponent ----------------- */
|
||||
case 0x01F8:
|
||||
gpg_io_insert_u32(N_gpg_pstate->default_RSA_exponent);
|
||||
gpg_io_insert(N_gpg_pstate->default_RSA_exponent,4);
|
||||
break;
|
||||
|
||||
/* ----------------- Application ----------------- */
|
||||
|
@ -282,7 +282,7 @@ int gpg_apdu_put_data(unsigned int ref) {
|
|||
if (G_gpg_vstate.io_length != 4) {
|
||||
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);
|
||||
break;
|
||||
|
||||
|
@ -316,7 +316,7 @@ int gpg_apdu_put_data(unsigned int ref) {
|
|||
break;
|
||||
default:
|
||||
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
//fecth 7f78
|
||||
gpg_io_fetch_tl(&t,&l);
|
||||
|
@ -343,6 +343,7 @@ int gpg_apdu_put_data(unsigned int ref) {
|
|||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
case 0x99:
|
||||
break;
|
||||
default:
|
||||
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
||||
|
@ -366,34 +367,25 @@ int gpg_apdu_put_data(unsigned int ref) {
|
|||
//check length
|
||||
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
|
||||
ksz = ksz >> 3;
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa.private;
|
||||
pkey = &keygpg->priv_key.rsa;
|
||||
switch(ksz) {
|
||||
case 1024/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa1024.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa1024.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa1024;
|
||||
pkey_size = sizeof(cx_rsa_1024_private_key_t);
|
||||
pq = G_gpg_vstate.work.rsa1024.public.n;
|
||||
pq = G_gpg_vstate.work.rsa.public1024.n;
|
||||
break;
|
||||
case 2048/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa2048.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa2048.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa2048;
|
||||
pkey_size = sizeof(cx_rsa_2048_private_key_t);
|
||||
pq = G_gpg_vstate.work.rsa2048.public.n;
|
||||
pq = G_gpg_vstate.work.rsa.public2048.n;
|
||||
break;
|
||||
case 3072/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa3072.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa3072.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa3072;
|
||||
pkey_size = sizeof(cx_rsa_3072_private_key_t);
|
||||
pq = G_gpg_vstate.work.rsa3072.public.n;
|
||||
pq = G_gpg_vstate.work.rsa.public3072.n;
|
||||
break;
|
||||
case 4096/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa4096.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa4096.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa4096;
|
||||
pkey_size = sizeof(cx_rsa_4096_private_key_t);
|
||||
pq = G_gpg_vstate.work.rsa4096.public.n;
|
||||
pq = G_gpg_vstate.work.rsa.public4096.n;
|
||||
break;
|
||||
}
|
||||
ksz = ksz>>1;
|
||||
|
@ -432,7 +424,12 @@ int gpg_apdu_put_data(unsigned int ref) {
|
|||
os_memset(pq+ksz, 0, ksz-len_q);
|
||||
|
||||
//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
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
ksz = 32;
|
||||
if (ksz == 32) {
|
||||
G_gpg_vstate.work.ecfp256.private.curve = curve;
|
||||
G_gpg_vstate.work.ecfp256.private.d_len = ksz;
|
||||
os_memmove(G_gpg_vstate.work.ecfp256.private.d, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,ksz);
|
||||
cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp256.public, &G_gpg_vstate.work.ecfp256.private, 1);
|
||||
nvm_write(&keygpg->pub_key.ecfp256, &G_gpg_vstate.work.ecfp256.public, sizeof(cx_ecfp_public_key_t));
|
||||
nvm_write(&keygpg->key.ecfp256, &G_gpg_vstate.work.ecfp256.private, sizeof(cx_ecfp_private_key_t));
|
||||
ksz = gpg_curve2domainlen(curve);
|
||||
if (ksz == len_p) {
|
||||
G_gpg_vstate.work.ecfp.private.curve = curve;
|
||||
G_gpg_vstate.work.ecfp.private.d_len = ksz;
|
||||
os_memmove(G_gpg_vstate.work.ecfp.private.d, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,ksz);
|
||||
cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp.public, &G_gpg_vstate.work.ecfp.private, 1);
|
||||
nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
|
||||
nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
|
||||
if (reset_cnt) {
|
||||
reset_cnt = 0;
|
||||
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
|
||||
|
@ -653,10 +650,27 @@ int gpg_apdu_put_data(unsigned int ref) {
|
|||
}
|
||||
|
||||
/* ----------------- RC ----------------- */
|
||||
case 0xD3:
|
||||
sw = gpg_apdu_change_ref_data();
|
||||
break;
|
||||
case 0xD3: {
|
||||
gpg_pin_t *pin;
|
||||
|
||||
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 ----------------- */
|
||||
case 0xD6:
|
||||
ptr_v = G_gpg_vstate.kslot->sig.UIF;
|
||||
|
|
|
@ -23,12 +23,7 @@
|
|||
|
||||
void gpg_check_access_ins() {
|
||||
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 ;
|
||||
|
||||
switch (G_gpg_vstate.io_ins) {
|
||||
|
@ -45,7 +40,7 @@ void gpg_check_access_ins() {
|
|||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -57,27 +52,30 @@ void gpg_check_access_ins() {
|
|||
if (G_gpg_vstate.io_p1 == 0x81) {
|
||||
return;
|
||||
}
|
||||
if (gpg_pin_is_verified(pin_pw3)) {
|
||||
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case INS_MSE:
|
||||
return ;
|
||||
|
||||
case INS_PSO:
|
||||
if ((ref == 0x9e9a) && gpg_pin_is_verified(pin_pw1)) {
|
||||
//pso:sign
|
||||
if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) {
|
||||
//pso:sign
|
||||
if (N_gpg_pstate->PW_status[0] == 0) {
|
||||
gpg_pin_set_verified(pin_pw1, 0);
|
||||
gpg_pin_set_verified(PIN_ID_PW1, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ((ref == 0x8086 ) && gpg_pin_is_verified(pin_pw2)) {
|
||||
//pso:dec
|
||||
if (((ref == 0x8086 )||(ref == 0x8680)) && gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||
//pso:dec/enc
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case INS_INTERNAL_AUTHENTICATE:
|
||||
if (gpg_pin_is_verified(pin_pw2)) {
|
||||
if (gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -86,7 +84,7 @@ void gpg_check_access_ins() {
|
|||
return;
|
||||
|
||||
case INS_TERMINATE_DF:
|
||||
if (gpg_pin_is_verified(pin_pw3)) {
|
||||
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -99,10 +97,6 @@ void gpg_check_access_ins() {
|
|||
|
||||
void gpg_check_access_read_DO() {
|
||||
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 ;
|
||||
|
||||
|
@ -152,14 +146,14 @@ void gpg_check_access_read_DO() {
|
|||
|
||||
//PW1
|
||||
case 0x0103:
|
||||
if (gpg_pin_is_verified(pin_pw2)) {
|
||||
if (gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
//PW3
|
||||
case 0x0104:
|
||||
if (gpg_pin_is_verified(pin_pw3)) {
|
||||
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -183,7 +177,7 @@ void gpg_check_access_write_DO() {
|
|||
case 0x0101:
|
||||
case 0x0103:
|
||||
case 0x01F2:
|
||||
if (gpg_pin_is_verified(pin_pw2)) {
|
||||
if (gpg_pin_is_verified(PIN_ID_PW2)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -225,7 +219,7 @@ void gpg_check_access_write_DO() {
|
|||
case 0x00D6:
|
||||
case 0x00D7:
|
||||
case 0x00D8:
|
||||
if (gpg_pin_is_verified(pin_pw3)) {
|
||||
if (gpg_pin_is_verified(PIN_ID_PW3)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -242,7 +236,12 @@ int gpg_dispatch() {
|
|||
unsigned int tag,t,l;
|
||||
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 ;
|
||||
|
||||
|
@ -265,7 +264,7 @@ int gpg_dispatch() {
|
|||
|
||||
case INS_TERMINATE_DF:
|
||||
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);
|
||||
return(SW_OK);
|
||||
break;
|
||||
|
@ -274,7 +273,6 @@ int gpg_dispatch() {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Other commands allowed if not terminated */
|
||||
if (N_gpg_pstate->histo[7] != 0x07) {
|
||||
THROW(SW_STATE_TERMINATED);
|
||||
|
@ -361,7 +359,7 @@ int gpg_dispatch() {
|
|||
THROW(SW_INCORRECT_P1P2);
|
||||
|
||||
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 == 2) )
|
||||
) {
|
||||
|
@ -375,10 +373,16 @@ int gpg_dispatch() {
|
|||
sw = gpg_apdu_gen();
|
||||
break;
|
||||
|
||||
/* --- MSE --- */
|
||||
case INS_MSE:
|
||||
sw = gpg_apdu_mse(tag);
|
||||
break;
|
||||
|
||||
/* --- PSO --- */
|
||||
case INS_PSO:
|
||||
sw = gpg_apdu_pso(tag);
|
||||
sw = gpg_apdu_pso();
|
||||
break;
|
||||
|
||||
case INS_INTERNAL_AUTHENTICATE:
|
||||
sw = gpg_apdu_internal_authenticate();
|
||||
break;
|
||||
|
|
|
@ -46,12 +46,12 @@ static void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name,
|
|||
h[1] = idx;
|
||||
|
||||
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, (unsigned char *)key_name, 4, NULL);
|
||||
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, 0, Sn, 32, NULL, 0);
|
||||
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,32);
|
||||
|
||||
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 = ksz >> 3;
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa.private;
|
||||
pkey = &keygpg->priv_key.rsa;
|
||||
switch(ksz) {
|
||||
case 1024/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa1024.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa1024.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa1024;
|
||||
pkey_size = sizeof(cx_rsa_1024_private_key_t);
|
||||
break;
|
||||
case 2048/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa2048.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa2048.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa2048;
|
||||
pkey_size = sizeof(cx_rsa_2048_private_key_t);
|
||||
break;
|
||||
case 3072/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa3072.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa3072.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa3072;
|
||||
pkey_size = sizeof(cx_rsa_3072_private_key_t);
|
||||
break;
|
||||
case 4096/8:
|
||||
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa4096.public;
|
||||
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa4096.private;
|
||||
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa4096;
|
||||
pkey_size = sizeof(cx_rsa_4096_private_key_t);
|
||||
break;
|
||||
}
|
||||
|
@ -153,8 +144,7 @@ int gpg_apdu_gen() {
|
|||
cx_math_next_prime(pq+size,size);
|
||||
}
|
||||
|
||||
|
||||
cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, N_gpg_pstate->default_RSA_exponent, pq);
|
||||
cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, N_gpg_pstate->default_RSA_exponent, 4, pq);
|
||||
|
||||
nvm_write(pkey, rsa_priv, pkey_size);
|
||||
nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4);
|
||||
|
@ -174,19 +164,24 @@ int gpg_apdu_gen() {
|
|||
unsigned int curve,keepprivate;
|
||||
keepprivate = 0;
|
||||
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
|
||||
if (curve == CX_CURVE_NONE) {
|
||||
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||
}
|
||||
if ((G_gpg_vstate.io_p2 == 0x01) | (G_gpg_vstate.seed_mode)) {
|
||||
ksz = gpg_curve2domainlen(curve);
|
||||
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
|
||||
gpg_pso_derive_key_seed(seed, name, 1, seed, 32);
|
||||
cx_ecfp_init_private_key(curve,seed, 32, &G_gpg_vstate.work.ecfp256.private);
|
||||
gpg_pso_derive_key_seed(seed, name, 1, seed, ksz);
|
||||
cx_ecfp_init_private_key(curve,seed, ksz, &G_gpg_vstate.work.ecfp.private);
|
||||
keepprivate = 1;
|
||||
}
|
||||
|
||||
cx_ecfp_generate_pair(curve,
|
||||
&G_gpg_vstate.work.ecfp256.public,
|
||||
&G_gpg_vstate.work.ecfp256.private,
|
||||
&G_gpg_vstate.work.ecfp.public,
|
||||
&G_gpg_vstate.work.ecfp.private,
|
||||
keepprivate);
|
||||
nvm_write(&keygpg->key.ecfp256, &G_gpg_vstate.work.ecfp256.private, sizeof(cx_ecfp_private_key_t));
|
||||
nvm_write(&keygpg->pub_key.ecfp256, &G_gpg_vstate.work.ecfp256.public, sizeof(cx_ecfp_public_key_t));
|
||||
nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
|
||||
nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
|
||||
if (reset_cnt) {
|
||||
reset_cnt = 0;
|
||||
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
|
||||
|
@ -208,32 +203,32 @@ int gpg_apdu_gen() {
|
|||
gpg_io_mark();
|
||||
switch(ksz) {
|
||||
case 1024/8:
|
||||
if (keygpg->key.rsa1024.size == 0) {
|
||||
if (keygpg->priv_key.rsa1024.size == 0) {
|
||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||
}
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa1024.n);
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa1024.n);
|
||||
break;
|
||||
case 2048/8:
|
||||
if (keygpg->key.rsa2048.size == 0) {
|
||||
if (keygpg->priv_key.rsa2048.size == 0) {
|
||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||
}
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa2048.n);
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa2048.n);
|
||||
break;
|
||||
case 3072/8:
|
||||
if (keygpg->key.rsa3072.size == 0) {
|
||||
if (keygpg->priv_key.rsa3072.size == 0) {
|
||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||
}
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa3072.n);
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa3072.n);
|
||||
break;
|
||||
case 4096/8:
|
||||
if (keygpg->key.rsa4096.size == 0) {
|
||||
if (keygpg->priv_key.rsa4096.size == 0) {
|
||||
THROW (SW_REFERENCED_DATA_NOT_FOUND);
|
||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||
}
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa4096.n);
|
||||
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa4096.n);
|
||||
break;
|
||||
}
|
||||
gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa);
|
||||
|
@ -262,7 +257,7 @@ int gpg_apdu_gen() {
|
|||
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1);
|
||||
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);
|
||||
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
|
||||
} else if (curve == CX_CURVE_Curve25519) {
|
||||
unsigned int i,len;
|
||||
|
|
213
src/gpg_init.c
|
@ -18,6 +18,7 @@
|
|||
#include "gpg_types.h"
|
||||
#include "gpg_api.h"
|
||||
#include "gpg_vars.h"
|
||||
#include "usbd_impl.h"
|
||||
|
||||
#define SHORT(x) ((x)>>8)&0xFF, (x)&0xFF
|
||||
/* ----------------------*/
|
||||
|
@ -31,24 +32,47 @@ const unsigned char C_MAGIC[8] = {
|
|||
/* --ECC OID -- */
|
||||
/* ----------------------*/
|
||||
|
||||
/*
|
||||
//brainpool 256t1: 1.3.36.3.3.2.8.1.1.8
|
||||
const unsigned char C_OID_BRAINPOOL256T1[9] = {
|
||||
0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07
|
||||
};
|
||||
*/
|
||||
|
||||
//secp256r1 / NIST P256 /ansi-x9.62 : 1.2.840.10045.3.1.7
|
||||
const unsigned char C_OID_SECP256R1[8] = {
|
||||
0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07
|
||||
};
|
||||
//secp384r1 / NIST P384 /ansi-x9.62 :1.3.132.0.34
|
||||
const unsigned char C_OID_SECP384R1[5] = {
|
||||
0x2B, 0x81, 0x04, 0x00 , 0x22
|
||||
};
|
||||
//secp521r1 / NIST P521 /ansi-x9.62 : 1.3.132.0.35
|
||||
const unsigned char C_OID_SECP521R1[5] = {
|
||||
0x2B, 0x81, 0x04, 0x00, 0x23
|
||||
};
|
||||
|
||||
|
||||
//secp256k1: 1.3.132.0.10
|
||||
const unsigned char C_OID_SECP256K1[5] = {
|
||||
0x2B, 0x81, 0x04, 0x00, 0x0A
|
||||
};
|
||||
|
||||
//secp256r1 / NIST P256 /ansi-x9.62 : 1.2.840.10045.3.1.7
|
||||
const unsigned char C_OID_SECP256R1[8] = {
|
||||
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
|
||||
};
|
||||
|
||||
//brainpool 256r1: 1.3.36.3.3.2.8.1.1.7
|
||||
const unsigned char C_OID_BRAINPOOL256R1[9] = {
|
||||
0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x08
|
||||
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x08
|
||||
};
|
||||
//brainpool 256t1: 1.3.36.3.3.2.8.1.1.8
|
||||
const unsigned char C_OID_BRAINPOOL256T1[9] = {
|
||||
0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07
|
||||
//brainpool 284r1: 1.3.36.3.3.2.8.1.1.11
|
||||
const unsigned char C_OID_BRAINPOOL384R1[9] = {
|
||||
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B
|
||||
};
|
||||
//brainpool 512r1: 1.3.36.3.3.2.8.1.1.13
|
||||
const unsigned char C_OID_BRAINPOOL512R1[9] = {
|
||||
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D
|
||||
};
|
||||
|
||||
|
||||
//Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1
|
||||
const unsigned char C_OID_Ed25519[9] = {
|
||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
|
||||
|
@ -59,10 +83,29 @@ const unsigned char C_OID_cv25519[10] = {
|
|||
0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
|
||||
};
|
||||
|
||||
int gpg_oid2curve(unsigned char* oid, unsigned int len) {
|
||||
unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len) {
|
||||
if ( (len == sizeof(C_OID_SECP256K1)) && (os_memcmp(oid, C_OID_SECP256K1, len)==0) ) {
|
||||
return CX_CURVE_SECP256K1;
|
||||
}
|
||||
|
||||
if ( (len == sizeof(C_OID_SECP256R1)) && (os_memcmp(oid, C_OID_SECP256R1, len)==0) ) {
|
||||
return CX_CURVE_256R1;
|
||||
return CX_CURVE_SECP256R1;
|
||||
}
|
||||
if ( (len == sizeof(C_OID_SECP384R1)) && (os_memcmp(oid, C_OID_SECP384R1, len)==0) ) {
|
||||
return CX_CURVE_SECP384R1;
|
||||
}
|
||||
if ( (len == sizeof(C_OID_SECP521R1)) && (os_memcmp(oid, C_OID_SECP521R1, len)==0) ) {
|
||||
return CX_CURVE_SECP521R1;
|
||||
}
|
||||
|
||||
if ( (len == sizeof(C_OID_BRAINPOOL256R1)) && (os_memcmp(oid, C_OID_BRAINPOOL256R1, len)==0) ) {
|
||||
return CX_CURVE_BrainPoolP256R1;
|
||||
}
|
||||
if ( (len == sizeof(C_OID_BRAINPOOL384R1)) && (os_memcmp(oid, C_OID_BRAINPOOL384R1, len)==0) ) {
|
||||
return CX_CURVE_BrainPoolP384R1;
|
||||
}
|
||||
if ( (len == sizeof(C_OID_BRAINPOOL512R1)) && (os_memcmp(oid, C_OID_BRAINPOOL512R1, len)==0) ) {
|
||||
return CX_CURVE_BrainPoolP512R1;
|
||||
}
|
||||
|
||||
if ( (len == sizeof(C_OID_Ed25519)) && (os_memcmp(oid, C_OID_Ed25519, len)==0) ) {
|
||||
|
@ -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) ) {
|
||||
return CX_CURVE_Curve25519;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if ( (len == sizeof(C_OID_SECP256K1)) && (os_memcmp(oid, C_OID_SECP256K1, len)==0) ) {
|
||||
return CX_CURVE_256K1;
|
||||
}
|
||||
|
||||
if ( (len == sizeof(C_OID_BRAINPOOL256R1)) && (os_memcmp(oid, C_OID_BRAINPOOL256R1, len)==0) ) {
|
||||
return CX_CURVE_BrainPoolP256R1;
|
||||
}
|
||||
|
||||
if ( (len == sizeof(C_OID_BRAINPOOL256T1)) && (os_memcmp(oid, C_OID_BRAINPOOL256T1, len)==0) ) {
|
||||
return CX_CURVE_BrainPoolP256T1;
|
||||
}
|
||||
*/
|
||||
return CX_CURVE_NONE;
|
||||
}
|
||||
|
||||
|
||||
unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
|
||||
switch (cv) {
|
||||
|
||||
case CX_CURVE_SECP256K1:
|
||||
*len = sizeof(C_OID_SECP256K1);
|
||||
return (unsigned char*)PIC(C_OID_SECP256K1);
|
||||
|
||||
case CX_CURVE_SECP256R1:
|
||||
*len = sizeof(C_OID_SECP256R1);
|
||||
return (unsigned char*)PIC(C_OID_SECP256R1);
|
||||
|
||||
case CX_CURVE_SECP384R1:
|
||||
*len = sizeof(C_OID_SECP384R1);
|
||||
return (unsigned char*)PIC(C_OID_SECP384R1);
|
||||
|
||||
case CX_CURVE_SECP521R1:
|
||||
*len = sizeof(C_OID_SECP521R1);
|
||||
return (unsigned char*)PIC(C_OID_SECP521R1);
|
||||
|
||||
case CX_CURVE_BrainPoolP256R1:
|
||||
*len = sizeof(C_OID_SECP256R1);
|
||||
return (unsigned char*)PIC(C_OID_SECP256R1);
|
||||
|
||||
case CX_CURVE_BrainPoolP384R1:
|
||||
*len = sizeof(C_OID_SECP384R1);
|
||||
return (unsigned char*)PIC(C_OID_SECP384R1);
|
||||
|
||||
case CX_CURVE_BrainPoolP512R1:
|
||||
*len = sizeof(C_OID_SECP521R1);
|
||||
return (unsigned char*)PIC(C_OID_SECP521R1);
|
||||
|
||||
case CX_CURVE_Ed25519:
|
||||
*len = sizeof(C_OID_Ed25519);
|
||||
return (unsigned char*)PIC(C_OID_Ed25519);
|
||||
|
||||
case CX_CURVE_Curve25519:
|
||||
*len = sizeof(C_OID_cv25519);
|
||||
return (unsigned char*)PIC(C_OID_cv25519);
|
||||
}
|
||||
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int gpg_curve2domainlen(unsigned int cv) {
|
||||
switch (cv) {
|
||||
|
||||
case CX_CURVE_SECP256K1:
|
||||
case CX_CURVE_SECP256R1:
|
||||
case CX_CURVE_BrainPoolP256R1:
|
||||
case CX_CURVE_Ed25519:
|
||||
case CX_CURVE_Curve25519:
|
||||
return 32;
|
||||
|
||||
case CX_CURVE_SECP384R1:
|
||||
case CX_CURVE_BrainPoolP384R1:
|
||||
return 48;
|
||||
|
||||
case CX_CURVE_BrainPoolP512R1:
|
||||
return 64;
|
||||
|
||||
case CX_CURVE_SECP521R1:
|
||||
return 66;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------*/
|
||||
/* -- Non Mutable Capabilities -- */
|
||||
/* -------------------------------*/
|
||||
|
||||
const unsigned char C_ext_capabilities[10] = {
|
||||
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -RFU
|
||||
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -KDF
|
||||
0x7E,
|
||||
// No SM,
|
||||
0x00,
|
||||
|
@ -104,8 +213,8 @@ const unsigned char C_ext_capabilities[10] = {
|
|||
SHORT(GPG_EXT_PRIVATE_DO_LENGTH),
|
||||
//PIN block formart 2 not supported
|
||||
0x00,
|
||||
//RFU
|
||||
0x00
|
||||
//MSE
|
||||
0x01
|
||||
|
||||
};
|
||||
|
||||
|
@ -122,7 +231,7 @@ const unsigned char C_ext_length[8] = {
|
|||
const unsigned char C_default_AID[] = {
|
||||
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
|
||||
//version
|
||||
0x03, 0x00,
|
||||
0x03, 0x03,
|
||||
//manufacturer
|
||||
0x2C, 0x97,
|
||||
//serial
|
||||
|
@ -154,7 +263,7 @@ const unsigned char C_default_AlgoAttrRSA[] = {
|
|||
0x01
|
||||
};
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
const unsigned char C_default_AlgoAttrECC_sig[] = {
|
||||
// ecdsa
|
||||
0x13,
|
||||
|
@ -167,17 +276,29 @@ const unsigned char C_default_AlgoAttrECC_dec[] = {
|
|||
// NIST-P256
|
||||
0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07
|
||||
};
|
||||
|
||||
#else
|
||||
#elif 0
|
||||
const unsigned char C_default_AlgoAttrECC_sig[] = {
|
||||
// ecdsa
|
||||
0x13,
|
||||
// NIST-P384
|
||||
0x2B, 0x81, 0x04, 0x00 , 0x22
|
||||
};
|
||||
const unsigned char C_default_AlgoAttrECC_dec[] = {
|
||||
// ecdh
|
||||
0x12,
|
||||
// NIST-P384
|
||||
0x2B, 0x81, 0x04, 0x00 , 0x22
|
||||
};
|
||||
#elif 1
|
||||
const unsigned char C_default_AlgoAttrECC_sig[] = {
|
||||
// eddsa
|
||||
22,
|
||||
0x16,
|
||||
// ed25519
|
||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
|
||||
};
|
||||
const unsigned char C_default_AlgoAttrECC_dec[] = {
|
||||
// ecdh
|
||||
18,
|
||||
0x12,
|
||||
//cv25519
|
||||
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));
|
||||
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
|
||||
G_gpg_vstate.slot = N_gpg_pstate->config_slot[1];
|
||||
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
||||
gpg_mse_reset();
|
||||
//pin conf
|
||||
G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0];
|
||||
//ux conf
|
||||
|
@ -260,8 +381,6 @@ int gpg_install(unsigned char app_state) {
|
|||
pin.counter = 3;
|
||||
pin.ref = PIN_ID_PW1;
|
||||
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
|
||||
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);
|
||||
|
||||
//config rsa pub
|
||||
l = GPG_RSA_DEFAULT_PUB;
|
||||
nvm_write(&N_gpg_pstate->default_RSA_exponent, &l, sizeof(unsigned int));
|
||||
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB>>24)&0xFF;
|
||||
G_gpg_vstate.work.io_buffer[1] = (GPG_RSA_DEFAULT_PUB>>16)&0xFF;
|
||||
G_gpg_vstate.work.io_buffer[2] = (GPG_RSA_DEFAULT_PUB>>8)&0xFF;
|
||||
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
|
||||
#if 1
|
||||
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM;
|
||||
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1);
|
||||
|
||||
USBD_CCID_activate_pinpad(3);
|
||||
#else
|
||||
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_HOST;
|
||||
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1);
|
||||
USBD_CCID_activate_pinpad(0);
|
||||
#endif
|
||||
|
||||
//default key template: RSA 2048)
|
||||
|
||||
for (int s = 0; s< GPG_KEYS_SLOTS; s++) {
|
||||
unsigned char uif[2];
|
||||
uif[0] = 0x00;
|
||||
uif[1] = 0x20;
|
||||
#if 1
|
||||
l = sizeof(C_default_AlgoAttrRSA);
|
||||
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.value, (void*)C_default_AlgoAttrRSA, l);
|
||||
|
@ -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.length, &l, sizeof(unsigned int));
|
||||
#endif
|
||||
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.UIF, &uif, 2);
|
||||
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.UIF, &uif, 2);
|
||||
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.UIF, &uif, 2);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#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 */
|
||||
/* ----------------------------------------------------------------------- */
|
||||
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 v32;
|
||||
|
@ -247,7 +244,7 @@ int gpg_io_fetch(unsigned char* buffer, int len) {
|
|||
int gpg_io_do(unsigned int io_flags) {
|
||||
|
||||
//if pending input chaining
|
||||
if (G_gpg_vstate.io_cla & 0x01) {
|
||||
if (G_gpg_vstate.io_cla & 0x10) {
|
||||
goto in_chaining;
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ __attribute__((section(".boot"))) int main(void) {
|
|||
//start communication with MCU
|
||||
io_seproxyhal_init();
|
||||
|
||||
USB_CCID_power(1);
|
||||
USB_power(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"
|
||||
|
||||
gpg_pin_t *gpg_pin_get_pin(int id) {
|
||||
switch (id) {
|
||||
gpg_pin_t *gpg_pin_get_pin(int pinref) {
|
||||
switch (pinref) {
|
||||
case PIN_ID_PW1 :
|
||||
return &N_gpg_pstate->PW1;
|
||||
case PIN_ID_PW2 :
|
||||
return &N_gpg_pstate->PW2;
|
||||
return &N_gpg_pstate->PW1;
|
||||
case PIN_ID_PW3:
|
||||
return &N_gpg_pstate->PW3;
|
||||
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) {
|
||||
switch (id) {
|
||||
static int gpg_pin_get_state_index(unsigned int pinref) {
|
||||
switch (pinref) {
|
||||
case PIN_ID_PW1 :
|
||||
return 1;
|
||||
case PIN_ID_PW2 :
|
||||
|
@ -52,28 +51,10 @@ static int gpg_pin_get_index(unsigned int id) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
void gpg_pin_sync12() {
|
||||
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) {
|
||||
static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int pin_len) {
|
||||
cx_sha256_t sha256;
|
||||
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) {
|
||||
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;
|
||||
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
|
||||
if (brother) {
|
||||
gpg_nvm_write(&(brother->counter), &counter, sizeof(int));
|
||||
}
|
||||
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)) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
counter = 3;
|
||||
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
|
||||
if (brother) {
|
||||
gpg_nvm_write(&(brother->counter), &counter, sizeof(int));
|
||||
}
|
||||
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;
|
||||
gpg_pin_set_verified(pin,0);
|
||||
gpg_pin_set_verified(pinID,0);
|
||||
sw = gpg_pin_check_internal(pin,pin_val,pin_len);
|
||||
if (sw == SW_OK) {
|
||||
gpg_pin_set_verified(pin,1);
|
||||
gpg_pin_set_verified(pinID,1);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
gpg_pin_set_verified(pinID,0);
|
||||
sw = gpg_pin_check_internal(pin,pin_val,pin_len);
|
||||
gpg_pin_set_verified(pin,0);
|
||||
if (sw == SW_OK) {
|
||||
gpg_pin_set_verified(pin,1);
|
||||
gpg_pin_set_verified(pinID,1);
|
||||
}
|
||||
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;
|
||||
|
||||
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.counter = 3;
|
||||
|
||||
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;
|
||||
idx = gpg_pin_get_index(pin->ref);
|
||||
idx = gpg_pin_get_state_index(pinID);
|
||||
if (idx >= 0) {
|
||||
G_gpg_vstate.verified_pin[idx]=verified;
|
||||
return verified;
|
||||
|
@ -143,9 +120,9 @@ int gpg_pin_set_verified(gpg_pin_t *pin, int verified) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int gpg_pin_is_verified(gpg_pin_t *pin) {
|
||||
int gpg_pin_is_verified(int pinID) {
|
||||
int idx;
|
||||
idx = gpg_pin_get_index(pin->ref);
|
||||
idx = gpg_pin_get_state_index(pinID);
|
||||
if (idx >= 0) {
|
||||
return G_gpg_vstate.verified_pin[idx];
|
||||
}
|
||||
|
@ -167,12 +144,13 @@ int gpg_apdu_verify() {
|
|||
return SW_WRONG_DATA;
|
||||
}
|
||||
|
||||
gpg_pin_set_verified(pin,0);
|
||||
if (gpg_pin_is_blocked(pin)) {
|
||||
THROW(SW_PIN_BLOCKED);
|
||||
return SW_PIN_BLOCKED;
|
||||
}
|
||||
if (G_gpg_vstate.io_length == 0) {
|
||||
//PINPAD
|
||||
if (G_gpg_vstate.io_cla == 0xEF) {
|
||||
if (gpg_pin_is_blocked(pin)) {
|
||||
THROW(SW_PIN_BLOCKED);
|
||||
return SW_PIN_BLOCKED;
|
||||
}
|
||||
|
||||
if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) {
|
||||
//Delegate pin check to ui
|
||||
gpg_io_discard(1);
|
||||
|
@ -186,16 +164,46 @@ int gpg_apdu_verify() {
|
|||
return 0;
|
||||
}
|
||||
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);
|
||||
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,
|
||||
G_gpg_vstate.io_length);
|
||||
|
||||
//NORMAL CHECK
|
||||
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);
|
||||
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() {
|
||||
|
@ -208,28 +216,10 @@ int gpg_apdu_change_ref_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 ---
|
||||
if (gpg_pin_is_blocked(pin)) {
|
||||
|
@ -252,7 +242,7 @@ int gpg_apdu_change_ref_data() {
|
|||
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,
|
||||
len);
|
||||
|
||||
|
@ -281,7 +271,7 @@ int gpg_apdu_reset_retry_counter() {
|
|||
pin_rc = gpg_pin_get_pin(PIN_ID_RC);
|
||||
|
||||
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);
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED;
|
||||
}
|
||||
|
@ -296,7 +286,7 @@ int gpg_apdu_reset_retry_counter() {
|
|||
rc_len = pin_rc->length;
|
||||
}
|
||||
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,
|
||||
rc_len);
|
||||
}
|
||||
|
|
157
src/gpg_pso.c
|
@ -18,6 +18,7 @@
|
|||
#include "gpg_types.h"
|
||||
#include "gpg_api.h"
|
||||
#include "gpg_vars.h"
|
||||
#include "gpg_ux_nanos.h"
|
||||
|
||||
const unsigned char gpg_oid_sha256[] = {
|
||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
|
||||
|
@ -28,7 +29,7 @@ const unsigned char gpg_oid_sha512[] = {
|
|||
|
||||
static void gpg_pso_reset_PW1() {
|
||||
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;
|
||||
switch(ksz) {
|
||||
case 1024/8:
|
||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa1024;
|
||||
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa1024;
|
||||
break;
|
||||
case 2048/8:
|
||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa2048;
|
||||
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa2048;
|
||||
break;
|
||||
case 3072/8:
|
||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa3072;
|
||||
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa3072;
|
||||
break;
|
||||
case 4096/8:
|
||||
key = (cx_rsa_private_key_t *)&sigkey->key.rsa4096;
|
||||
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa4096;
|
||||
break;
|
||||
}
|
||||
if (key->size != ksz) {
|
||||
|
@ -86,23 +87,27 @@ static int gpg_sign(gpg_key_t *sigkey) {
|
|||
unsigned int sz,i,rs_len;
|
||||
unsigned char *rs;
|
||||
|
||||
key = &sigkey->key.ecfp256;
|
||||
if (key->d_len != 32) {
|
||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||
return SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
key = &sigkey->priv_key.ecfp;
|
||||
|
||||
//sign
|
||||
#define RS (G_gpg_vstate.work.io_buffer+(GPG_IO_BUFFER_LENGTH-256))
|
||||
if (sigkey->attributes.value[0] == 19) {
|
||||
sz = gpg_curve2domainlen(key->curve);
|
||||
if ((sz == 0) || (key->d_len != sz)) {
|
||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||
return SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
sz = cx_ecdsa_sign(key,
|
||||
CX_RND_TRNG,
|
||||
CX_NONE,
|
||||
G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length,
|
||||
G_gpg_vstate.work.io_buffer);
|
||||
G_gpg_vstate.work.io_buffer, sz,
|
||||
RS, 256,
|
||||
NULL);
|
||||
//reencode r,s in MPI format
|
||||
gpg_io_discard(0);
|
||||
|
||||
rs_len = G_gpg_vstate.work.io_buffer[3];
|
||||
rs = &G_gpg_vstate.work.io_buffer[4];
|
||||
rs_len = RS[3];
|
||||
rs = &RS[4];
|
||||
|
||||
for (i = 0; i<2; i++) {
|
||||
if (*rs == 0) {
|
||||
|
@ -116,15 +121,18 @@ static int gpg_sign(gpg_key_t *sigkey) {
|
|||
rs += 2;
|
||||
}
|
||||
} else{
|
||||
sz = cx_eddsa_sign(key, NULL,
|
||||
sz = cx_eddsa_sign(key,
|
||||
CX_NONE,
|
||||
CX_SHA512,
|
||||
CX_SHA512,
|
||||
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_insert(G_gpg_vstate.work.io_buffer+128, sz);
|
||||
gpg_io_insert(RS, sz);
|
||||
}
|
||||
|
||||
#undef RS
|
||||
|
||||
//send
|
||||
gpg_pso_reset_PW1();
|
||||
return SW_OK;
|
||||
|
@ -134,9 +142,38 @@ static int gpg_sign(gpg_key_t *sigkey) {
|
|||
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
int gpg_apdu_pso(unsigned int pso) {
|
||||
int gpg_apdu_pso() {
|
||||
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) {
|
||||
// --- PSO:CDS ---
|
||||
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));
|
||||
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 ---
|
||||
case 0x8086: {
|
||||
|
@ -159,31 +217,31 @@ int gpg_apdu_pso(unsigned int pso) {
|
|||
// --- PSO:DEC:RSA
|
||||
case 0x00: {
|
||||
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);
|
||||
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;
|
||||
key = NULL;
|
||||
switch(ksz) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
if ((key == NULL) || (key->size != ksz)) {
|
||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||
return 0;
|
||||
return SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
|
||||
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;
|
||||
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.work.io_buffer, GPG_IO_BUFFER_LENGTH);
|
||||
//send
|
||||
gpg_io_discard(0);
|
||||
gpg_io_inserted(sz);
|
||||
|
@ -222,15 +280,11 @@ int gpg_apdu_pso(unsigned int pso) {
|
|||
cx_ecfp_private_key_t *key;
|
||||
unsigned int sz;
|
||||
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);
|
||||
return SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
key = &G_gpg_vstate.kslot->dec.key.ecfp256;
|
||||
if (key->d_len != 32) {
|
||||
THROW(SW_CONDITIONS_NOT_SATISFIED);
|
||||
return SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
key = &G_gpg_vstate.mse_dec->priv_key.ecfp;
|
||||
gpg_io_fetch_l(&l);
|
||||
gpg_io_fetch_tl(&t, &l);
|
||||
if (t != 0x7f49) {
|
||||
|
@ -243,7 +297,11 @@ int gpg_apdu_pso(unsigned int pso) {
|
|||
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) {
|
||||
unsigned int i;
|
||||
|
||||
|
@ -253,8 +311,8 @@ int gpg_apdu_pso(unsigned int pso) {
|
|||
G_gpg_vstate.work.io_buffer[511] = 0x02;
|
||||
sz = cx_ecdh(key,
|
||||
CX_ECDH_X,
|
||||
G_gpg_vstate.work.io_buffer+511,
|
||||
G_gpg_vstate.work.io_buffer+256);
|
||||
G_gpg_vstate.work.io_buffer+511, 65,
|
||||
G_gpg_vstate.work.io_buffer+256, 160);
|
||||
for (i = 0; i <=31; 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 {
|
||||
sz = cx_ecdh(key,
|
||||
CX_ECDH_X,
|
||||
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
|
||||
G_gpg_vstate.work.io_buffer+128);
|
||||
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, 65,
|
||||
G_gpg_vstate.work.io_buffer+128, 160);
|
||||
}
|
||||
//send
|
||||
gpg_io_discard(0);
|
||||
|
@ -276,7 +334,6 @@ int gpg_apdu_pso(unsigned int pso) {
|
|||
THROW(SW_REFERENCED_DATA_NOT_FOUND);
|
||||
return SW_REFERENCED_DATA_NOT_FOUND;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--- PSO:yy NOT SUPPPORTED ---
|
||||
|
@ -290,14 +347,20 @@ int gpg_apdu_pso(unsigned int pso) {
|
|||
|
||||
|
||||
int gpg_apdu_internal_authenticate() {
|
||||
gpg_key_t *sigkey;
|
||||
sigkey = &G_gpg_vstate.kslot->aut;
|
||||
// --- PSO:AUTH ---
|
||||
if (G_gpg_vstate.kslot->aut.UIF[0]) {
|
||||
if ((G_gpg_vstate.UIF_flags)==0) {
|
||||
ui_menu_uifconfirm_display(0);
|
||||
return 0;
|
||||
}
|
||||
G_gpg_vstate.UIF_flags = 0;
|
||||
}
|
||||
|
||||
if (G_gpg_vstate.kslot->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.mse_aut->attributes.value[0] == 1) {
|
||||
if ( G_gpg_vstate.io_length > ((G_gpg_vstate.mse_aut->attributes.value[1]<<8)|G_gpg_vstate.mse_aut->attributes.value[2])*40/100) {
|
||||
THROW(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
|
||||
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
|
||||
ux_state_t ux;
|
||||
|
||||
#else
|
||||
extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
|
||||
int apdu_n;
|
||||
|
|
|
@ -19,10 +19,19 @@
|
|||
#include "gpg_types.h"
|
||||
#include "gpg_api.h"
|
||||
#include "gpg_vars.h"
|
||||
const unsigned char C_MF[] = {0x3F, 0x00};
|
||||
|
||||
int gpg_apdu_select() {
|
||||
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) ) {
|
||||
G_gpg_vstate.DO_current = 0;
|
||||
G_gpg_vstate.DO_reccord = 0;
|
||||
|
@ -36,8 +45,13 @@ int gpg_apdu_select() {
|
|||
}
|
||||
|
||||
gpg_io_discard(0);
|
||||
if (N_gpg_pstate->histo[7] != 0x07) {
|
||||
THROW(SW_STATE_TERMINATED);
|
||||
}
|
||||
sw = SW_OK;
|
||||
} else {
|
||||
}
|
||||
//NOT FOUND
|
||||
else {
|
||||
THROW(SW_FILE_NOT_FOUND);
|
||||
return SW_FILE_NOT_FOUND;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
#define GPG_KEY_ATTRIBUTES_LENGTH 12
|
||||
|
||||
#define GPG_RSA_DEFAULT_PUB 0x010001U
|
||||
#define GPG_RSA_DEFAULT_PUB 0x00010001U
|
||||
|
||||
struct gpg_pin_s {
|
||||
unsigned int ref;
|
||||
|
@ -66,15 +66,25 @@ typedef struct gpg_key_s {
|
|||
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
||||
/* key value */
|
||||
union {
|
||||
cx_rsa_private_key_t rsa;
|
||||
cx_rsa_1024_private_key_t rsa1024;
|
||||
cx_rsa_2048_private_key_t rsa2048;
|
||||
cx_rsa_3072_private_key_t rsa3072;
|
||||
cx_rsa_4096_private_key_t rsa4096;
|
||||
cx_ecfp_private_key_t ecfp256;
|
||||
} key;
|
||||
|
||||
cx_ecfp_private_key_t ecfp;
|
||||
cx_ecfp_256_private_key_t ecfp256;
|
||||
cx_ecfp_384_private_key_t ecfp384;
|
||||
cx_ecfp_512_private_key_t ecfp512;
|
||||
cx_ecfp_640_private_key_t ecfp640;
|
||||
} priv_key;
|
||||
union {
|
||||
unsigned char rsa[4];
|
||||
cx_ecfp_public_key_t ecfp256;
|
||||
unsigned char rsa[4];
|
||||
cx_ecfp_public_key_t ecfp;
|
||||
cx_ecfp_256_public_key_t ecfp256;
|
||||
cx_ecfp_384_public_key_t ecfp384;
|
||||
cx_ecfp_512_public_key_t ecfp512;
|
||||
cx_ecfp_640_public_key_t ecfp640;
|
||||
} pub_key;
|
||||
/* C7 C8 C9 , C5 = C7|C8|C9*/
|
||||
unsigned char fingerprints[20];
|
||||
|
@ -116,7 +126,7 @@ struct gpg_nv_state_s {
|
|||
/* 01F1 (01F2 is volatile)*/
|
||||
unsigned char config_slot[3];
|
||||
/* RSA exponent */
|
||||
unsigned int default_RSA_exponent;
|
||||
unsigned char default_RSA_exponent[4];
|
||||
|
||||
/* 0101 0102 0103 0104 */
|
||||
LV(private_DO1, GPG_EXT_PRIVATE_DO_LENGTH);
|
||||
|
@ -152,7 +162,6 @@ struct gpg_nv_state_s {
|
|||
|
||||
/* PINs */
|
||||
gpg_pin_t PW1;
|
||||
gpg_pin_t PW2;
|
||||
gpg_pin_t PW3;
|
||||
gpg_pin_t RC;
|
||||
|
||||
|
@ -174,10 +183,15 @@ struct gpg_v_state_s {
|
|||
/* app state */
|
||||
unsigned char selected;
|
||||
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 UIF_flags;
|
||||
|
||||
/* io state*/
|
||||
|
||||
unsigned char io_cla;
|
||||
unsigned char io_ins;
|
||||
unsigned char io_p1;
|
||||
|
@ -189,26 +203,41 @@ struct gpg_v_state_s {
|
|||
unsigned short io_mark;
|
||||
union {
|
||||
unsigned char io_buffer[GPG_IO_BUFFER_LENGTH];
|
||||
|
||||
struct {
|
||||
cx_rsa_1024_public_key_t public;
|
||||
cx_rsa_1024_private_key_t private;
|
||||
}rsa1024;
|
||||
union {
|
||||
cx_rsa_public_key_t public;
|
||||
cx_rsa_1024_public_key_t public1024;
|
||||
cx_rsa_2048_public_key_t public2048;
|
||||
cx_rsa_3072_public_key_t public3072;
|
||||
cx_rsa_4096_public_key_t public4096;
|
||||
};
|
||||
union {
|
||||
cx_rsa_private_key_t private;
|
||||
cx_rsa_1024_private_key_t private1024;
|
||||
cx_rsa_2048_private_key_t private2048;
|
||||
cx_rsa_3072_private_key_t private3072;
|
||||
cx_rsa_4096_private_key_t private4096;
|
||||
};
|
||||
} rsa;
|
||||
|
||||
struct {
|
||||
cx_rsa_2048_public_key_t public;
|
||||
cx_rsa_2048_private_key_t private;
|
||||
}rsa2048;
|
||||
struct {
|
||||
cx_rsa_3072_public_key_t public;
|
||||
cx_rsa_3072_private_key_t private;
|
||||
}rsa3072;
|
||||
struct {
|
||||
cx_rsa_4096_public_key_t public;
|
||||
cx_rsa_4096_private_key_t private;
|
||||
}rsa4096;
|
||||
struct {
|
||||
cx_ecfp_public_key_t public;
|
||||
cx_ecfp_private_key_t private;
|
||||
}ecfp256;
|
||||
union{
|
||||
cx_ecfp_public_key_t public;
|
||||
cx_ecfp_256_public_key_t public256;
|
||||
cx_ecfp_384_public_key_t public384;
|
||||
cx_ecfp_512_public_key_t public512;
|
||||
cx_ecfp_640_public_key_t public640;
|
||||
};
|
||||
union {
|
||||
cx_ecfp_private_key_t private;
|
||||
cx_ecfp_256_private_key_t private256;
|
||||
cx_ecfp_384_private_key_t private384;
|
||||
cx_ecfp_512_private_key_t private512;
|
||||
cx_ecfp_640_private_key_t private640;
|
||||
};
|
||||
}ecfp;
|
||||
|
||||
struct {
|
||||
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH-MAX(sizeof(cx_sha3_t),sizeof(cx_sha256_t))];
|
||||
union {
|
||||
|
@ -228,7 +257,7 @@ struct gpg_v_state_s {
|
|||
unsigned char pinmode;
|
||||
|
||||
/* ux menus */
|
||||
char menu[64];
|
||||
char menu[112];
|
||||
unsigned char ux_pinentry[12];
|
||||
unsigned int ux_key;
|
||||
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_VERIFY 0x20
|
||||
#define INS_MSE 0x22
|
||||
#define INS_CHANGE_REFERENCE_DATA 0x24
|
||||
#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_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_UIF_LOCKED;
|
||||
extern const char * const C_UIF_INVALID;
|
||||
|
||||
#define PICSTR(x) ((char*)PIC(x))
|
||||
|
||||
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
|
||||
|
@ -54,5 +57,7 @@ extern const char * const C_DEFAULT_MODE;
|
|||
#define ALLOWED PICSTR(C_ALLOWED)
|
||||
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
|
||||
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
|
||||
#define UIF_LOCKED PICSTR(C_UIF_LOCKED)
|
||||
#define UIF_INVALID PICSTR(C_UIF_INVALID)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
/* ------------------------------ 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 ----------------------------- */
|
||||
|
||||
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;
|
||||
switch(button_mask) {
|
||||
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;
|
||||
break;
|
||||
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
|
@ -240,9 +356,17 @@ unsigned int ui_pinentry_prepro(const bagl_element_t* element) {
|
|||
else if (element->component.userid == 2) {
|
||||
unsigned int i;
|
||||
G_gpg_vstate.menu[0] = ' ';
|
||||
#if 1
|
||||
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++) {
|
||||
G_gpg_vstate.menu[i] = '-';
|
||||
}
|
||||
|
@ -325,15 +449,16 @@ static unsigned int validate_pin() {
|
|||
|
||||
if (G_gpg_vstate.io_ins == 0x20) {
|
||||
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_insert_u16(sw);
|
||||
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 );
|
||||
ui_info(WRONG_PIN, G_gpg_vstate.menu, ui_menu_main_display, 0);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
ui_menu_main_display(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (G_gpg_vstate.io_ins == 0x24) {
|
||||
|
@ -344,7 +469,7 @@ static unsigned int validate_pin() {
|
|||
}
|
||||
if (G_gpg_vstate.io_p1 == 3) {
|
||||
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_insert_u16(SW_CONDITIONS_NOT_SATISFIED);
|
||||
gpg_io_do(IO_RETURN_AFTER_TX);
|
||||
|
@ -381,12 +506,17 @@ static unsigned int validate_pin() {
|
|||
#define LABEL_AUT "Authentication"
|
||||
#define LABEL_DEC "Decryption"
|
||||
|
||||
#define LABEL_RSA2048 "RSA 2048"
|
||||
#define LABEL_RSA3072 "RSA 3072"
|
||||
#define LABEL_RSA4096 "RSA 4096"
|
||||
#define LABEL_NISTP256 "NIST P256"
|
||||
#define LABEL_BPOOLR1 "Brainpool R1"
|
||||
#define LABEL_Ed25519 "Ed25519"
|
||||
#define LABEL_RSA2048 "RSA 2048"
|
||||
#define LABEL_RSA3072 "RSA 3072"
|
||||
#define LABEL_RSA4096 "RSA 4096"
|
||||
#define LABEL_NISTP256 "NIST P256"
|
||||
//#define LABEL_NISTP384 "NIST P384"
|
||||
//#define LABEL_NISTP521 "NIST P521"
|
||||
#define LABEL_SECP256K1 "SEPC 256K1"
|
||||
#define LABEL_BPOOL256R1 "Brainpool 256R1"
|
||||
//#define LABEL_BPOOL384R1 "Brainpool 384R1"
|
||||
//#define LABEL_BPOOL512R1 "Brainpool 512R1"
|
||||
#define LABEL_Ed25519 "Ed25519"
|
||||
|
||||
const ux_menu_entry_t ui_menu_template[] = {
|
||||
{ui_menu_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0},
|
||||
|
@ -430,12 +560,34 @@ const bagl_element_t* ui_menu_template_preprocessor(const ux_menu_entry_t* entry
|
|||
case 4096:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA4096);
|
||||
break;
|
||||
|
||||
case CX_CURVE_SECP256R1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP256);
|
||||
break;
|
||||
case CX_CURVE_BrainPoolP256R1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOLR1);
|
||||
/*
|
||||
case CX_CURVE_SECP384R1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP384);
|
||||
break;
|
||||
case CX_CURVE_SECP521R1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_NISTP521);
|
||||
break;
|
||||
*/
|
||||
case CX_CURVE_SECP256K1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_SECP256K1);
|
||||
break;
|
||||
|
||||
case CX_CURVE_BrainPoolP256R1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOL256R1);
|
||||
break;
|
||||
/*
|
||||
case CX_CURVE_BrainPoolP384R1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOL384R1);
|
||||
break;
|
||||
case CX_CURVE_BrainPoolP512R1:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_BPOOL512R1);
|
||||
break;
|
||||
*/
|
||||
|
||||
case CX_CURVE_Ed25519:
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_Ed25519);
|
||||
break;
|
||||
|
@ -456,7 +608,8 @@ void ui_menu_tmpl_set_action(unsigned int value) {
|
|||
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
|
||||
gpg_key_t* dest;
|
||||
const char* err;
|
||||
|
||||
const unsigned char *oid;
|
||||
unsigned int oid_len;
|
||||
err = NULL;
|
||||
|
||||
os_memset(&attributes, 0, sizeof(attributes));
|
||||
|
@ -473,24 +626,21 @@ void ui_menu_tmpl_set_action(unsigned int value) {
|
|||
attributes.length = 6;
|
||||
break;
|
||||
|
||||
case CX_CURVE_SECP256K1:
|
||||
case CX_CURVE_SECP256R1:
|
||||
if (G_gpg_vstate.ux_key == 2) {
|
||||
attributes.value[0] = 18; //ecdh
|
||||
} else {
|
||||
attributes.value[0] = 19; //ecdsa
|
||||
}
|
||||
os_memmove(attributes.value+1, C_OID_SECP256R1, sizeof(C_OID_SECP256R1));
|
||||
attributes.length = 1+sizeof(C_OID_SECP256R1);
|
||||
break;
|
||||
|
||||
//case CX_CURVE_SECP384R1:
|
||||
//case CX_CURVE_SECP521R1:
|
||||
case CX_CURVE_BrainPoolP256R1:
|
||||
if (G_gpg_vstate.ux_key == 2) {
|
||||
//case CX_CURVE_BrainPoolP384R1:
|
||||
//case CX_CURVE_BrainPoolP512R1:
|
||||
if (G_gpg_vstate.ux_key == 2) {
|
||||
attributes.value[0] = 18; //ecdh
|
||||
} else {
|
||||
attributes.value[0] = 19; //ecdsa
|
||||
}
|
||||
os_memmove(attributes.value+1, C_OID_BRAINPOOL256R1, sizeof(C_OID_BRAINPOOL256R1));
|
||||
attributes.length = 1+sizeof(C_OID_BRAINPOOL256R1);
|
||||
oid = gpg_curve2oid(G_gpg_vstate.ux_type, &oid_len);
|
||||
os_memmove(attributes.value+1, oid, sizeof(oid_len));
|
||||
attributes.length = 1+oid_len;
|
||||
break;
|
||||
|
||||
case CX_CURVE_Ed25519:
|
||||
|
@ -505,7 +655,7 @@ void ui_menu_tmpl_set_action(unsigned int value) {
|
|||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
err = TEMPLATE_TYPE;
|
||||
goto ERROR;
|
||||
}
|
||||
|
@ -552,13 +702,18 @@ void ui_menu_tmpl_key_action(unsigned int value) {
|
|||
|
||||
|
||||
const ux_menu_entry_t ui_menu_tmpl_type[] = {
|
||||
{NULL, ui_menu_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOLR1, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
|
||||
{ui_menu_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
||||
{NULL, ui_menu_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
|
||||
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP384R1, NULL, LABEL_NISTP384, NULL, 0, 0},
|
||||
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP521R1, NULL, LABEL_NISTP521, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, CX_CURVE_SECP256K1, NULL, LABEL_SECP256K1, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOL256R1, NULL, 0, 0},
|
||||
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP384R1, NULL, LABEL_BPOOL384R1, NULL, 0, 0},
|
||||
// {NULL, ui_menu_tmpl_type_action, CX_CURVE_BrainPoolP512R1, NULL, LABEL_BPOOL512R1, NULL, 0, 0},
|
||||
{NULL, ui_menu_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
|
||||
{ui_menu_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
||||
UX_MENU_END
|
||||
};
|
||||
|
||||
|
@ -654,6 +809,7 @@ void ui_menu_pinmode_action(unsigned int value) {
|
|||
} else {
|
||||
s = 3;
|
||||
}
|
||||
//#warning USBD_CCID_activate_pinpad commented
|
||||
USBD_CCID_activate_pinpad(s);
|
||||
}
|
||||
}
|
||||
|
@ -661,15 +817,16 @@ void ui_menu_pinmode_action(unsigned int value) {
|
|||
switch (value) {
|
||||
case PIN_MODE_HOST:
|
||||
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);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIN_MODE_CONFIRM:
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -683,6 +840,84 @@ void ui_menu_pinmode_action(unsigned int value) {
|
|||
// redisplay first entry of the idle menu
|
||||
ui_menu_pinmode_display(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------- UIF MODE UX ------------------------------ */
|
||||
const ux_menu_entry_t ui_menu_uifmode[];
|
||||
void ui_menu_uifmode_display(unsigned int value);
|
||||
const bagl_element_t* ui_menu_uifmode_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
|
||||
void ui_menu_uifmode_action(unsigned int value);
|
||||
|
||||
const ux_menu_entry_t ui_menu_uifmode[] = {
|
||||
{NULL, NULL, -1, NULL, "Activate (+) for:", NULL, 0, 0},
|
||||
{NULL, ui_menu_uifmode_action, 1, NULL, "Signature", NULL, 0, 0},
|
||||
{NULL, ui_menu_uifmode_action, 2, NULL, "Decryption", NULL, 0, 0},
|
||||
{NULL, ui_menu_uifmode_action, 3, NULL, "Authentication", NULL, 0, 0},
|
||||
{ui_menu_settings, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
|
||||
UX_MENU_END
|
||||
};
|
||||
|
||||
void ui_menu_uifmode_display(unsigned int value) {
|
||||
UX_MENU_DISPLAY(value, ui_menu_uifmode, ui_menu_uifmode_preprocessor);
|
||||
}
|
||||
|
||||
const bagl_element_t* ui_menu_uifmode_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
|
||||
if (element->component.userid==0x20) {
|
||||
if ((entry->userid >= 1) && (entry->userid<=3)) {
|
||||
unsigned char uif[2] ;
|
||||
uif[0] = 0;
|
||||
uif[1] = 0;
|
||||
switch (entry->userid) {
|
||||
case 1:
|
||||
*uif = G_gpg_vstate.kslot->sig.UIF[0]?'+':' ';
|
||||
break;
|
||||
case 2:
|
||||
*uif = G_gpg_vstate.kslot->dec.UIF[0]?'+':' ';
|
||||
break;
|
||||
case 3:
|
||||
*uif = G_gpg_vstate.kslot->aut.UIF[0]?'+':' ';
|
||||
break;
|
||||
}
|
||||
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s %s",
|
||||
(char*)PIC(entry->line1), uif);
|
||||
element->text = G_gpg_vstate.menu;
|
||||
element->component.height = 32;
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
void ui_menu_uifmode_action(unsigned int value) {
|
||||
unsigned char *uif;
|
||||
unsigned char new_uif;
|
||||
switch (value) {
|
||||
case 1:
|
||||
uif = &G_gpg_vstate.kslot->sig.UIF[0];
|
||||
break;
|
||||
case 2:
|
||||
uif = &G_gpg_vstate.kslot->dec.UIF[0];
|
||||
break;
|
||||
case 3:
|
||||
uif = &G_gpg_vstate.kslot->aut.UIF[0];
|
||||
break;
|
||||
default:
|
||||
ui_info(INVALID_SELECTION, NULL, ui_menu_uifmode_display,0);
|
||||
return;
|
||||
}
|
||||
if (uif[0] == 0) {
|
||||
new_uif = 1;
|
||||
gpg_nvm_write(&uif[0], &new_uif, 1);
|
||||
} else if (uif[0] == 1) {
|
||||
new_uif = 0;
|
||||
gpg_nvm_write(&uif[0], &new_uif, 1) ;
|
||||
} else /*if (uif[0] == 2 )*/ {
|
||||
ui_info(UIF_LOCKED, NULL, ui_menu_uifmode_display,0);
|
||||
return;
|
||||
}
|
||||
ui_menu_uifmode_display(value);
|
||||
}
|
||||
|
||||
/* -------------------------------- RESET UX --------------------------------- */
|
||||
|
||||
const ux_menu_entry_t ui_menu_reset[] = {
|
||||
|
@ -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_seed_display, 0, NULL, "Seed mode", NULL, 0, 0},
|
||||
{NULL, ui_menu_pinmode_display, 0, NULL, "PIN mode", NULL, 0, 0},
|
||||
{NULL, ui_menu_uifmode_display, 0, NULL, "UIF mode", NULL, 0, 0},
|
||||
{ui_menu_reset, NULL, 0, NULL, "Reset", NULL, 0, 0},
|
||||
{NULL, ui_menu_main_display, 2, &C_badge_back, "Back", NULL, 61, 40},
|
||||
UX_MENU_END
|
||||
|
@ -766,6 +1002,7 @@ void ui_menu_slot_action(unsigned int value) {
|
|||
if (s!= G_gpg_vstate.slot) {
|
||||
G_gpg_vstate.slot = s;
|
||||
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
|
||||
gpg_mse_reset();
|
||||
ui_CCID_reset();
|
||||
}
|
||||
}
|
||||
|
@ -784,7 +1021,7 @@ void ui_menu_slot_action(unsigned int value) {
|
|||
const ux_menu_entry_t ui_menu_info[] = {
|
||||
{NULL, NULL, -1, NULL, "OpenPGP Card", NULL, 0, 0},
|
||||
{NULL, NULL, -1, NULL, "(c) Ledger SAS", NULL, 0, 0},
|
||||
{NULL, NULL, -1, NULL, "Spec 3.0", NULL, 0, 0},
|
||||
{NULL, NULL, -1, NULL, "Spec " XSTR(SPEC_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},
|
||||
UX_MENU_END
|
||||
|
|
|
@ -22,4 +22,5 @@ void ui_init(void);
|
|||
void ui_main_display(unsigned int value);
|
||||
void ui_menu_pinconfirm_display(unsigned int value);
|
||||
void ui_menu_pinentry_display(unsigned int value);
|
||||
void ui_menu_uifconfirm_display(unsigned int value);
|
||||
#endif
|
1057
src/sdk/usbd_ccid_cmd.c
Executable file
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 ------------------------------------------------------------------*/
|
||||
#include "os.h"
|
||||
#include "usbd_ccid_if.h"
|
||||
|
||||
#ifdef HAVE_USB_CLASS_CCID
|
||||
|
||||
#if CCID_BULK_EPIN_SIZE > USB_SEGMENT_SIZE
|
||||
#error configuration error, the USB MAX SEGMENT SIZE does not support the CCID endpoint (CCID_BULK_EPIN_SIZE vs USB_SEGMENT_SIZE)
|
||||
#endif
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
uint8_t Ccid_BulkState;
|
||||
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;
|
||||
usb_class_ccid_t G_io_ccid;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
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)
|
||||
{
|
||||
memset(&Ccid_BulkState, 0, sizeof(Ccid_BulkState));
|
||||
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;
|
||||
memset(&G_io_ccid, 0, sizeof(G_io_ccid));
|
||||
|
||||
/* CCID Related Initialization */
|
||||
#ifdef HAVE_CCID_INTERRUPT
|
||||
CCID_SetIntrTransferStatus(1); /* Transfer Complete Status */
|
||||
#endif // HAVE_CCID_INTERRUPT
|
||||
CCID_UpdSlotChange(1);
|
||||
SC_InitParams();
|
||||
|
||||
/* Prepare Out endpoint to receive 1st packet */
|
||||
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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
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 *****************/
|
||||
|
||||
switch (Ccid_BulkState)
|
||||
switch (G_io_ccid.Ccid_BulkState)
|
||||
{
|
||||
case CCID_STATE_SEND_RESP: {
|
||||
unsigned int remLen = UsbMessageLength;
|
||||
unsigned int remLen = G_io_ccid.UsbMessageLength;
|
||||
|
||||
// advance with acknowledged sent chunk
|
||||
pUsbMessageBuffer += MIN(CCID_BULK_EPIN_SIZE, UsbMessageLength);
|
||||
UsbMessageLength -= MIN(CCID_BULK_EPIN_SIZE, UsbMessageLength);
|
||||
if (G_io_ccid.pUsbMessageBuffer == &G_io_ccid.bulk_header) {
|
||||
// first part of the bulk in sent.
|
||||
// advance in the data buffer to transmit. (mixed source leap)
|
||||
G_io_ccid.pUsbMessageBuffer = G_io_ccid_data_buffer+MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength)-CCID_HEADER_SIZE;
|
||||
}
|
||||
else {
|
||||
G_io_ccid.pUsbMessageBuffer += MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength);
|
||||
}
|
||||
G_io_ccid.UsbMessageLength -= MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength);
|
||||
|
||||
// if remaining length is > EPIN_SIZE: send a filled bulk packet
|
||||
if (UsbMessageLength >= CCID_BULK_EPIN_SIZE) {
|
||||
CCID_Response_SendData(pdev, pUsbMessageBuffer,
|
||||
if (G_io_ccid.UsbMessageLength >= CCID_BULK_EPIN_SIZE) {
|
||||
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
|
||||
// use the header declared size packet must be well formed
|
||||
CCID_BULK_EPIN_SIZE);
|
||||
}
|
||||
|
||||
// if remaining length is 0; send an empty packet and prepare to receive a new command
|
||||
else if (UsbMessageLength == 0 && remLen == CCID_BULK_EPIN_SIZE) {
|
||||
CCID_Response_SendData(pdev, pUsbMessageBuffer,
|
||||
else if (G_io_ccid.UsbMessageLength == 0 && remLen == CCID_BULK_EPIN_SIZE) {
|
||||
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
|
||||
// use the header declared size packet must be well formed
|
||||
0);
|
||||
goto last_xfer; // won't wait ack to avoid missing a command
|
||||
}
|
||||
// else if no more data, then last packet sent, go back to idle (done on transfer ack)
|
||||
else if (UsbMessageLength == 0) { // robustness only
|
||||
else if (G_io_ccid.UsbMessageLength == 0) { // robustness only
|
||||
last_xfer:
|
||||
Ccid_BulkState = CCID_STATE_IDLE;
|
||||
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||
|
||||
/* 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
|
||||
else if (UsbMessageLength < CCID_BULK_EPIN_SIZE) {
|
||||
CCID_Response_SendData(pdev, pUsbMessageBuffer,
|
||||
else if (G_io_ccid.UsbMessageLength < CCID_BULK_EPIN_SIZE) {
|
||||
CCID_Response_SendData(pdev, G_io_ccid.pUsbMessageBuffer,
|
||||
// use the header declared size packet must be well formed
|
||||
UsbMessageLength);
|
||||
G_io_ccid.UsbMessageLength);
|
||||
goto last_xfer; // won't wait ack to avoid missing a command
|
||||
}
|
||||
|
||||
|
@ -157,11 +154,35 @@ void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
|
|||
break;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_CCID_INTERRUPT
|
||||
else if (epnum == (CCID_INTR_IN_EP & 0x7F))
|
||||
{
|
||||
/* Filter the epnum by masking with 0x7f (mask of IN Direction) */
|
||||
CCID_SetIntrTransferStatus(1); /* Transfer Complete Status */
|
||||
}
|
||||
#endif // HAVE_CCID_INTERRUPT
|
||||
}
|
||||
|
||||
void CCID_Send_Reply(USBD_HandleTypeDef *pdev) {
|
||||
/********** Decide for all commands ***************/
|
||||
if (G_io_ccid.Ccid_BulkState == CCID_STATE_SEND_RESP)
|
||||
{
|
||||
G_io_ccid.UsbMessageLength = G_io_ccid.bulk_header.bulkin.dwLength+CCID_HEADER_SIZE; /* Store for future use */
|
||||
|
||||
/* Expected Data Length Packet Received */
|
||||
G_io_ccid.pUsbMessageBuffer = (uint8_t*) &G_io_ccid.bulk_header;
|
||||
|
||||
// send bulk header and first pat of the message at once
|
||||
os_memmove(G_io_usb_ep_buffer, &G_io_ccid.bulk_header, CCID_HEADER_SIZE);
|
||||
if (G_io_ccid.UsbMessageLength>CCID_HEADER_SIZE) {
|
||||
// copy start of data if bigger size than a header
|
||||
os_memmove(G_io_usb_ep_buffer+CCID_HEADER_SIZE, G_io_ccid_data_buffer, MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength)-CCID_HEADER_SIZE);
|
||||
}
|
||||
// send the first mixed source chunk
|
||||
CCID_Response_SendData(pdev, G_io_usb_ep_buffer,
|
||||
// use the header declared size packet must be well formed
|
||||
MIN(CCID_BULK_EPIN_SIZE, G_io_ccid.UsbMessageLength));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,123 +195,113 @@ void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
|
|||
void CCID_BulkMessage_Out (USBD_HandleTypeDef *pdev,
|
||||
uint8_t epnum, uint8_t* buffer, uint16_t dataLen)
|
||||
{
|
||||
|
||||
switch (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)
|
||||
if (epnum == (CCID_BULK_OUT_EP & 0x7F)) {
|
||||
switch (G_io_ccid.Ccid_BulkState)
|
||||
{
|
||||
UsbMessageLength = dataLen; /* Store for future use */
|
||||
|
||||
/* Expected Data Length Packet Received */
|
||||
pUsbMessageBuffer = (uint8_t*) &Ccid_bulk_data;
|
||||
|
||||
/* Fill CCID_BulkOut Data Buffer from USB Buffer */
|
||||
memmove(pUsbMessageBuffer, buffer, dataLen);
|
||||
|
||||
/*
|
||||
Refer : 6 CCID Messages
|
||||
The response messages always contain the exact same slot number,
|
||||
and sequence number fields from the header that was contained in
|
||||
the Bulk-OUT command message.
|
||||
*/
|
||||
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);
|
||||
|
||||
// after a timeout, could be in almost any state :) therefore, clean it and process the newly received command
|
||||
default:
|
||||
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||
// no break is intentional
|
||||
|
||||
case CCID_STATE_IDLE:
|
||||
// prepare to receive another packet later on (to avoid troubles with timeout due to other hid command timeouting the ccid endpoint reply)
|
||||
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
||||
|
||||
if (dataLen == 0x00)
|
||||
{ /* Zero Length Packet Received, end of transfer */
|
||||
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{ /* Long message, receive additional data with command */
|
||||
/* (u8dataLen == CCID_BULK_EPOUT_SIZE) */
|
||||
else if (dataLen >= CCID_HEADER_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 */
|
||||
|
||||
/* 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
|
||||
{ /* Expect more data on OUT EP */
|
||||
Ccid_BulkState = CCID_STATE_RECEIVE_DATA;
|
||||
pUsbMessageBuffer += dataLen; /* Point to new offset */
|
||||
/* Full command is received, process the Command */
|
||||
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
|
||||
CCID_CmdDecode(pdev);
|
||||
}
|
||||
else //if (dataLen == CCID_BULK_EPOUT_SIZE)
|
||||
{
|
||||
if (G_io_ccid.UsbMessageLength < (G_io_ccid.bulk_header.bulkout.dwLength + CCID_HEADER_SIZE))
|
||||
{
|
||||
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
|
||||
G_io_ccid.pUsbMessageBuffer += dataLen;
|
||||
/* Increment the pointer to receive more data */
|
||||
|
||||
/* Prepare EP to Receive next Cmd */
|
||||
USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
||||
|
||||
} /* if (dataLen == CCID_BULK_EPOUT_SIZE) ends */
|
||||
} /* if (dataLen >= CCID_BULK_EPOUT_SIZE) ends */
|
||||
} /* if (dataLen >= CCID_MESSAGE_HEADER_SIZE) ends */
|
||||
break;
|
||||
|
||||
case CCID_STATE_RECEIVE_DATA:
|
||||
|
||||
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 */
|
||||
// not timeout compliant // USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);
|
||||
}
|
||||
else if (G_io_ccid.UsbMessageLength == (G_io_ccid.bulk_header.bulkout.dwLength + CCID_HEADER_SIZE))
|
||||
{
|
||||
/* Full command is received, process the Command */
|
||||
os_memmove(G_io_ccid.pUsbMessageBuffer, buffer, dataLen);
|
||||
CCID_CmdDecode(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Too long data received.... Error ! */
|
||||
G_io_ccid.Ccid_BulkState = CCID_STATE_UNCORRECT_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* Full command is received, process the Command */
|
||||
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;
|
||||
|
||||
break;
|
||||
|
||||
case CCID_STATE_UNCORRECT_LENGTH:
|
||||
Ccid_BulkState = CCID_STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
case CCID_STATE_UNCORRECT_LENGTH:
|
||||
G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
void CCID_Send_Reply(USBD_HandleTypeDef *pdev) {
|
||||
/********** 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));
|
||||
break;
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +315,7 @@ void CCID_CmdDecode(USBD_HandleTypeDef *pdev)
|
|||
{
|
||||
uint8_t errorCode;
|
||||
|
||||
switch (Ccid_bulk_data.header.bulkout.bMessageType)
|
||||
switch (G_io_ccid.bulk_header.bulkout.bMessageType)
|
||||
{
|
||||
case PC_TO_RDR_ICCPOWERON:
|
||||
errorCode = PC_to_RDR_IccPowerOn();
|
||||
|
@ -380,7 +391,7 @@ void CCID_CmdDecode(USBD_HandleTypeDef *pdev)
|
|||
void Transfer_Data_Request(void)
|
||||
{
|
||||
/********** 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,
|
||||
uint16_t len)
|
||||
{
|
||||
UNUSED(pdev);
|
||||
// don't ask the MCU to perform bulk split, we could quickly get into a buffer overflow
|
||||
if (len > CCID_BULK_EPIN_SIZE) {
|
||||
THROW(EXCEPTION_IO_OVERFLOW);
|
||||
|
@ -411,6 +423,7 @@ static void CCID_Response_SendData(USBD_HandleTypeDef *pdev,
|
|||
io_seproxyhal_spi_send(buf, len);
|
||||
}
|
||||
|
||||
#ifdef HAVE_CCID_INTERRUPT
|
||||
/**
|
||||
* @brief CCID_IntMessage
|
||||
* 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)
|
||||
{
|
||||
UNUSED(pdev);
|
||||
/* Check if there us change in Smartcard Slot status */
|
||||
if ( CCID_IsSlotStatusChange() && CCID_IsIntrTransferComplete() )
|
||||
{
|
||||
#ifdef HAVE_CCID_INTERRUPT
|
||||
/* Check Slot Status is changed. Card is Removed/ Fitted */
|
||||
RDR_to_PC_NotifySlotChange();
|
||||
#endif // HAVE_CCID_INTERRUPT
|
||||
|
||||
CCID_SetIntrTransferStatus(0); /* Reset the Status */
|
||||
CCID_UpdSlotChange(0); /* Reset the Status of Slot Change */
|
||||
|
@ -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[5] = 2;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
return ccid_card_inserted;
|
||||
}
|
||||
|
||||
void SC_Poweroff(void) {
|
||||
// nothing to do
|
||||
|
||||
return G_io_ccid.ccid_card_inserted;
|
||||
}
|
||||
|
||||
void SC_InitParams (void) {
|
||||
|
@ -480,78 +492,89 @@ void SC_InitParams (void) {
|
|||
}
|
||||
|
||||
uint8_t SC_SetParams (Protocol0_DataStructure_t* pt0) {
|
||||
UNUSED(pt0);
|
||||
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) {
|
||||
UNUSED(bClockCommand);
|
||||
return SLOT_NO_ERROR;
|
||||
}
|
||||
|
||||
uint8_t SC_Request_GetClockFrequencies(uint8_t* pbuf, uint16_t* len);
|
||||
uint8_t SC_Request_GetDataRates(uint8_t* pbuf, uint16_t* len);
|
||||
uint8_t SC_T0Apdu(uint8_t bmChanges, uint8_t bClassGetResponse,
|
||||
uint8_t bClassEnvelope) {
|
||||
UNUSED(bmChanges);
|
||||
UNUSED(bClassGetResponse);
|
||||
UNUSED(bClassEnvelope);
|
||||
return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||
}
|
||||
uint8_t SC_Mechanical(uint8_t bFunction) {
|
||||
UNUSED(bFunction);
|
||||
return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||
}
|
||||
uint8_t SC_SetDataRateAndClockFrequency(uint32_t dwClockFrequency,
|
||||
uint32_t dwDataRate) {
|
||||
UNUSED(dwClockFrequency);
|
||||
UNUSED(dwDataRate);
|
||||
return SLOT_NO_ERROR;
|
||||
}
|
||||
|
||||
uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
|
||||
uint8_t* pbuf, uint32_t* returnLen ) {
|
||||
UNUSED(bBWI);
|
||||
UNUSED(wLevelParameter);
|
||||
UNUSED(returnLen);
|
||||
// return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||
uint16_t ret_len,off;
|
||||
switch(pbuf[0]) {
|
||||
case 0: // verify pin
|
||||
//ret_len = dwLength - 15;
|
||||
ret_len = 5;
|
||||
os_memmove(G_io_apdu_buffer, pbuf+15, 5);
|
||||
switch(pbuf[0])
|
||||
{
|
||||
case 0: // verify pin
|
||||
off = 15;
|
||||
//ret_len = dwLength - 15;
|
||||
ret_len = 5;
|
||||
break;
|
||||
case 1: // modify pin
|
||||
switch(pbuf[11])
|
||||
{
|
||||
case 3:
|
||||
off = 20;
|
||||
break;
|
||||
|
||||
case 1: // modify pin
|
||||
switch(pbuf[11]) {
|
||||
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);
|
||||
case 2:
|
||||
case 1:
|
||||
off = 19;
|
||||
break;
|
||||
|
||||
default: // unsupported
|
||||
Ccid_bulk_data.header.bulkin.dwLength = 0;
|
||||
RDR_to_PC_DataBlock(SLOTERROR_CMD_NOT_SUPPORTED);
|
||||
CCID_Send_Reply(&USBD_Device);
|
||||
return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||
// 0 and 4-0xFF
|
||||
default:
|
||||
off = 18;
|
||||
break;
|
||||
}
|
||||
//ret_len = dwLength - off;
|
||||
ret_len = 5;
|
||||
break;
|
||||
default: // unsupported
|
||||
G_io_ccid.bulk_header.bulkin.dwLength = 0;
|
||||
RDR_to_PC_DataBlock(SLOTERROR_CMD_NOT_SUPPORTED);
|
||||
CCID_Send_Reply(&USBD_Device);
|
||||
return SLOTERROR_CMD_NOT_SUPPORTED;
|
||||
}
|
||||
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
|
||||
uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen, uint16_t* expectedLen) {
|
||||
UNUSED(expectedLen);
|
||||
|
||||
// check for overflow
|
||||
if (blockLen > IO_APDU_BUFFER_SIZE) {
|
||||
return SLOTERROR_BAD_LENTGH;
|
||||
}
|
||||
|
||||
// copy received apdu
|
||||
memmove(G_io_apdu_buffer, ptrBlock, blockLen);
|
||||
// copy received apdu // if G_io_ccid_data_buffer is the buffer apdu, then the memmove will do nothing
|
||||
os_memmove(G_io_apdu_buffer, ptrBlock, blockLen);
|
||||
G_io_apdu_length = blockLen;
|
||||
G_io_apdu_media = IO_APDU_MEDIA_USB_CCID; // for application code
|
||||
G_io_apdu_state = APDU_USB_CCID; // for next call to io_exchange
|
||||
|
@ -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) {
|
||||
// avoid memory overflow
|
||||
if (length > sizeof(Ccid_bulk_data.abData)) {
|
||||
if (length > IO_CCID_DATA_BUFFER_SIZE) {
|
||||
THROW(EXCEPTION_IO_OVERFLOW);
|
||||
}
|
||||
// copy the responde apdu
|
||||
memmove(Ccid_bulk_data.abData, buffer, length);
|
||||
Ccid_bulk_data.header.bulkin.dwLength = length;
|
||||
os_memmove(G_io_ccid_data_buffer, buffer, length);
|
||||
G_io_ccid.bulk_header.bulkin.dwLength = length;
|
||||
// forge reply
|
||||
RDR_to_PC_DataBlock(SLOT_NO_ERROR);
|
||||
|
||||
// start sending rpely
|
||||
CCID_Send_Reply(&USBD_Device);
|
||||
}
|
||||
|
||||
// ask for power on
|
||||
void io_usb_ccid_set_card_inserted(unsigned int inserted) {
|
||||
ccid_card_inserted = inserted;
|
||||
G_io_ccid.ccid_card_inserted = inserted;
|
||||
CCID_UpdSlotChange(1);
|
||||
#ifdef HAVE_CCID_INTERRUPT
|
||||
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
|
||||
|
||||
/************************ (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
|