Compare commits

...

48 commits

Author SHA1 Message Date
1e23cb6425 More output 2018-07-10 00:32:48 +02:00
27cd81de7a Restauration clé PGP 2018-07-10 00:21:33 +02:00
Cédric
c07cb00cb6 Fix SSH authentication with Ed25519.
When message to sign was too long, it overlayd the signature destination.
2018-06-04 18:50:38 +02:00
Cédric
dfbfb893ef Merge branch 'master' of github.com:LedgerHQ/blue-app-openpgp-card 2018-05-30 12:15:54 +02:00
Cédric
281ea42cbb 1.2.0 code
SDK 1.4.2.x port
Add uif support
Refactor memory layout
Try to add more curve
  gpg 2.2.x handle curves other than ed25519 in a such strange way
  that it is very difficult to do such support.
  So secp256k1, secp256r1 and brainpoolp256 seems works, but according to gpg
  code it works by side effects :-/
Update user documentation for UIF

There is still an issue with ssh authentication with Ed25519. It works with NIST-P256, Brainpool256 curves
2018-05-30 11:44:09 +02:00
Cédric
a0d537dcec Merge branch '1.1.0_fw.1.4.1' 2018-05-28 10:57:14 +02:00
Cédric
b71d2d02d7 port SDK 1.4.2.1 2018-05-28 10:38:04 +02:00
Cédric
81090d3f23 1.4.1 firmware port
Code update for 1.4.1 fw
Fix PUT_DATA[serial] command
2018-03-13 18:47:55 +01:00
Cédric
e6026d5809 intermediate commit 2018-03-05 21:51:57 +01:00
Cédric
2c06e06261
Update blue-app-openpgp-card.rst 2018-02-22 11:00:27 +01:00
Cédric
92cdb83293
Merge pull request #12 from dongcarl/patch-1
Tidy up whitespace in gpgcard.py
2017-11-22 08:52:59 +00:00
Cédric
4fb1610360
Merge pull request #15 from dongcarl/patch-2
gpg_data.c: Clear correct bits for 0x4f tag.
2017-11-22 08:52:23 +00:00
Carl Dong
8c83524536
gpg_data.c: Clear correct bits for 0x4f tag. 2017-11-22 00:11:56 -08:00
Carl Dong
783cf580ab
Tidy up whitespace in gpgcard.py 2017-10-30 00:04:06 -07:00
Cédric Mesnil
77548b1ddd Add quick testing guide 2017-10-05 19:04:27 +02:00
Cédric Mesnil
cf6e295e47 1.1.0 fixes
Fix PIN management
   PINPAD CCID command was in conflict with new PIN get status APDU. Use class CLA=0xEF to
   differenciate both case.

Fix Terminate status management

Fix RC code setting

Add MSE support
Set MSE supported in capabilities
2017-09-05 23:47:16 +02:00
Cédric Mesnil
38e143d248 Reference the new documentation (try 2...) 2017-08-31 17:15:48 +02:00
Cédric Mesnil
f15451f62a Reference the new documentation 2017-08-31 17:13:55 +02:00
Cédric Mesnil
a1c8e7766c On the road to 1.1.0
Fix PIN management

Add 3.3.1 spec addons
  - VERIFY with get status
  - MSE
  - ECC public key import
  - AES PSO:ENC
  - AES multi blcok
2017-08-31 17:03:27 +02:00
Cédric Mesnil
582928a16d reorg some image files 2017-08-30 15:18:36 +02:00
Cédric Mesnil
b049197c02 update logo with correct font 2017-08-30 14:38:17 +02:00
Cédric Mesnil
9fffb46d87 fix Ledger logo 2017-08-30 12:22:09 +02:00
Cédric Mesnil
e80bea28b2 Add User Guide
Reorganize doc section
2017-08-30 12:07:04 +02:00
Cédric Mesnil
8e992a5c63 Merge branch 'master' of github.com:LedgerHQ/blue-app-openpgp-card 2017-08-29 18:02:21 +02:00
Cédric Mesnil
bb745c7cdb more beautiful logo 2017-08-29 17:59:54 +02:00
Cédric
d067dcb144 Update README.md 2017-07-09 08:36:09 +02:00
Cédric
fcf12c5c3f Update README.md
Add on-screen PIN configuration for gnupg
2017-07-09 08:10:31 +02:00
Cédric Mesnil
3f4da471c4 1.0.1 2017-07-07 08:51:11 +02:00
Cédric Mesnil
f8522808b6 BugFix: set ACCESCOND for changing PIN mode tp PW1, not PW2
Allow PIN_CONFIRM switch with USER PIN level
2017-07-06 17:42:26 +02:00
Cédric Mesnil
4733d6f8ba mod it 2017-07-06 16:03:02 +02:00
Cédric Mesnil
2f273469fa add icons 2017-06-27 15:58:09 +02:00
Cédric Mesnil
8f1811313d 1.0.0 2017-06-19 09:30:51 +02:00
Cédric Mesnil
f8f07ec9ba RC7 2017-06-12 14:50:28 +02:00
Cédric Mesnil
d50e45b026 Merge branch 'master' of github.com:LedgerHQ/blue-app-openpgp-card 2017-06-12 14:48:36 +02:00
Cédric Mesnil
9dec68f892 RC7
Fix Signatrure counter:  now incremented
Fix PIN status init: was not correctly initialized
Fix "only once" CDS management: PIN was not invalidated after signing
Change all return 0 by corresponding THROW error code
PIN API refacto
2017-06-12 14:26:10 +02:00
Cédric
a54cc477c2 Update README.md 2017-05-05 16:02:06 +02:00
Cédric Mesnil
2e0d755fb6 RC6
Features:
  "PIN confirm" is now the default PIN input mode.
  Add EF 01F8 for setting default RSA public exponent for key generation. Access control is PW3/Admin.

Bug fixes:
  Fix Issue #2:  Add explicit return after each throw.
2017-05-04 17:30:53 +02:00
Cédric Mesnil
980d24d1e7 Set micro version to RC5 2017-04-25 11:28:23 +02:00
Cédric Mesnil
f3356cb4fe Fix keytocard bug 2017-04-25 11:22:38 +02:00
Cédric Mesnil
bad546edee Merge branch 'gabridome-patch-1' 2017-04-25 10:17:49 +02:00
gabridome
a0abffd38c Mac os adjustments
Mac Os 10.11 protects the files with a set up called SIP that must be disabled 
to be able to modify the .plist file.
Also provided the path for the file in 10.2 MAC OSX systems.
Still the "keytocard" operation doesn't work but the card is visible with
gpg2 --card-status and is editable with gpg2 --card-edit command.
2017-04-24 23:13:19 +02:00
Cédric
27f8e4c48a Update README.md 2017-04-24 14:48:32 +02:00
Cédric
4102128ecc Update README.md 2017-04-24 13:08:18 +02:00
Cédric Mesnil
b6514ff5bd RC4 2017-04-21 15:17:33 +02:00
Cédric Mesnil
de35c7ac78 Add missing decl 2017-04-21 08:14:15 +02:00
Cédric Mesnil
c1efa87a7b Try to fix windows card detection issue 2017-04-20 15:05:43 +02:00
Cédric Mesnil
fc0e37d5f0 Fix onscreen PIN
Add onscreen PIN modification
Fix default PIN mode management
2017-04-13 12:31:13 +02:00
Cédric Mesnil
8430858dfb Async interaction and PIN on screen
Add PIN on screen
Fix strings declarations and usages to avoid PIC fails
Fix IO for Async interaction
Move UX code in dedicated file
2017-04-12 12:11:00 +02:00
50 changed files with 6943 additions and 1447 deletions

View file

@ -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=RC2
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
View file

@ -0,0 +1,29 @@
#*******************************************************************************
# Ledger SDK
# (c) 2017 Ledger
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#*******************************************************************************
#Make the SDK modified SDK sources prioritar to the original ones
SOURCE_PATH += $(dir $(foreach libdir, $(APP_SOURCE_PATH), $(dir $(shell find $(libdir) | grep "\.c$$")))) $(BOLOS_SDK)/src $(foreach libdir, $(SDK_SOURCE_PATH), $(dir $(shell find $(BOLOS_SDK)/$(libdir) | grep "\.c$$")))
SOURCE_FILES := $(foreach path, $(SOURCE_PATH),$(shell find $(path) | grep "\.c$$") ) $(GLYPH_DESTC)
INCLUDES_PATH := $(dir $(foreach libdir, $(APP_SOURCE_PATH), $(dir $(shell find $(libdir) | grep "\.h$$")))) $(dir $(foreach libdir, $(SDK_SOURCE_PATH), $(dir $(shell find $(BOLOS_SDK)/$(libdir) | grep "\.h$$")))) include $(BOLOS_SDK)/include $(BOLOS_SDK)/include/arm
VPATH := $(dir $(SOURCE_FILES))
OBJECT_FILES := $(sort $(addprefix obj/, $(addsuffix .o, $(basename $(notdir $(SOURCE_FILES))))))
DEPEND_FILES := $(sort $(addprefix dep/, $(addsuffix .d, $(basename $(notdir $(SOURCE_FILES))))))
include $(BOLOS_SDK)/Makefile.rules_generic

View file

@ -10,14 +10,18 @@ The application supports:
- EDDSA with Ed25519 curve
- ECDH with secp256k1, secp256r1, brainpool 256r1, brainpool 256t1 and curve25519 curves
To compile it, use at least the Nano S SDK 1.3.1.3 on firmware 1.3.1
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 and Usage
See the full doc at https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/user/blue-app-openpgp-card.pdf
## Add-on
The GnuPG application implements the following addon:
@ -26,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

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -83,6 +83,15 @@ Deterministic key derivation
The deterministic key derivation process relies on the BIP32 scheme.
The master install path of GPG-ledger is set to /0x80'GPG', aka /80475047
Deterministic key derivation maybe activated in:
Settings->Seed Mode->Set on
This activation remains effective until *set off* is selected or the application
ends.
The key management remains the same if seed mode is on or off, i.e. key are stored in memory key containers. So their is no perfomance inpact when using seeded keys.
Seeded keys are generated as follow:
**Step1**:
@ -269,6 +278,6 @@ Other minor add-on
------------------
GnuPG use both fingerprints and serial number to identfy key on card.
So, the put data command accept to modify the AID file with '4F' tag.
So, the put data command is able to modify the AID file with '4F' tag.
In that case the data field shall be four bytes length and shall contain
the new serial number. '4F' is protected by PW3 (admin) PIN.

View 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

Binary file not shown.

File diff suppressed because it is too large Load diff

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

BIN
doc/user/pin_cancel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
doc/user/pin_confirm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
doc/user/pin_entry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
doc/user/pin_validate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

11
images/LICENSE Normal file
View 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,

View file

Before

Width:  |  Height:  |  Size: 88 B

After

Width:  |  Height:  |  Size: 88 B

BIN
images/manager_gnupg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -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()

View 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
View 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) }
}

View file

@ -16,6 +16,11 @@
#ifndef GPG_API_H
#define GPG_API_H
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);
@ -27,22 +32,26 @@ 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) ;
int gpg_apdu_select(void) ;
int gpg_apdu_verify(int id) ;
int gpg_apdu_change_ref_data(int id) ;
int gpg_apdu_verify(void) ;
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_blocked(gpg_pin_t *pin);
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);
int gpg_oid2curve(unsigned char* oid, unsigned int len);
int gpg_is_pin_verified(int id);
int gpg_is_pin_blocked(int id);
void gpg_set_pin_verified(int id, int verified);
int gpg_mse_reset();
int gpg_apdu_mse();
/* ----------------------------------------------------------------------- */
/* --- IO ---- */
@ -65,6 +74,7 @@ void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) ;
void gpg_io_fetch_buffer(unsigned char * buffer, unsigned int len) ;
unsigned int gpg_io_fetch_u32(void) ;
unsigned int gpg_io_fetch_u24(void) ;
unsigned int gpg_io_fetch_u16(void) ;
unsigned int gpg_io_fetch_u8(void) ;
int gpg_io_fetch_t(unsigned int *T) ;
@ -73,8 +83,12 @@ int gpg_io_fetch_tl(unsigned int *T, unsigned int *L) ;
int gpg_io_fetch_nv(unsigned char* buffer, int len) ;
int gpg_io_fetch(unsigned char* buffer, int len) ;
int gpg_io_do(void) ;
int gpg_io_do(unsigned int io_flags) ;
/* ----------------------------------------------------------------------- */
/* --- TMP ---- */
/* ----------------------------------------------------------------------- */
void io_usb_ccid_set_card_inserted(unsigned int inserted);
/* ----------------------------------------------------------------------- */
/* --- DEBUG ---- */

View file

@ -29,6 +29,7 @@ int gpg_apdu_get_challenge() {
}
if (olen > GPG_EXT_CHALLENGE_LENTH) {
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
}
if ((G_gpg_vstate.io_p1&0x82) == 0x82) {
@ -43,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);
}

View file

@ -30,6 +30,7 @@ int gpg_apdu_get_data(unsigned int ref) {
int sw;
if (G_gpg_vstate.DO_current != ref) {
G_gpg_vstate.DO_current = ref;
G_gpg_vstate.DO_reccord = 0;
@ -64,6 +65,10 @@ int gpg_apdu_get_data(unsigned int ref) {
case 0x01F2:
gpg_io_insert_u8(G_gpg_vstate.slot);
break;
/* ----------------- Config RSA exponent ----------------- */
case 0x01F8:
gpg_io_insert(N_gpg_pstate->default_RSA_exponent,4);
break;
/* ----------------- Application ----------------- */
/* Full Application identifier */
@ -176,8 +181,8 @@ int gpg_apdu_get_data(unsigned int ref) {
/* WAT */
default:
sw = SW_REFERENCED_DATA_NOT_FOUND;
break;
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
return sw;
@ -225,6 +230,7 @@ int gpg_apdu_put_data(unsigned int ref) {
WRITE_PRIVATE_DO:
if (G_gpg_vstate.io_length > GPG_EXT_PRIVATE_DO_LENGTH) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_length);
gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int));
@ -234,37 +240,50 @@ int gpg_apdu_put_data(unsigned int ref) {
case 0x01F1:
if (G_gpg_vstate.io_length != 3) {
THROW(SW_WRONG_LENGTH);
return 0;
}
if ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +0] != GPG_KEYS_SLOTS) ||
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +1] >= GPG_KEYS_SLOTS) ||
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +2] > 3)) {
THROW(SW_WRONG_DATA);
return 0;
}
gpg_nvm_write(N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,3);
sw = SW_OK;
break;
case 0x01F2:
if ((N_gpg_pstate->config_slot[2] & 2) == 0) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
if ((G_gpg_vstate.io_length != 1) ||
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS)) {
THROW(SW_WRONG_DATA);
return 0;
}
G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
sw = SW_OK;
break;
/* ----------------- Config RSA exponent ----------------- */
case 0x01F8: {
unsigned int e;
if (G_gpg_vstate.io_length != 4) {
THROW(SW_WRONG_LENGTH);
return 0;
}
e = gpg_io_fetch_u32();
nvm_write(&N_gpg_pstate->default_RSA_exponent, &e, sizeof(unsigned int));
break;
}
/* ----------------- Serial -----------------*/
case 0x4f:
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);
sw = SW_OK;
break;
/* ----------------- Extended Header list -----------------*/
@ -277,6 +296,7 @@ int gpg_apdu_put_data(unsigned int ref) {
gpg_io_fetch_tl(&t,&l);
if (t!=0x4D) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
//fecth B8/B6/A4
gpg_io_fetch_tl(&t,&l);
@ -296,11 +316,13 @@ int gpg_apdu_put_data(unsigned int ref) {
break;
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
//fecth 7f78
gpg_io_fetch_tl(&t,&l);
if (t!=0x7f48) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
len_e = 0; len_p = 0; len_q = 0;
endof = G_gpg_vstate.io_offset+l;
@ -321,15 +343,18 @@ int gpg_apdu_put_data(unsigned int ref) {
case 0x95:
case 0x96:
case 0x97:
case 0x99:
break;
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
}
//fecth 5f78
gpg_io_fetch_tl(&t,&l);
if (t!=0x5f48) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
// --- RSA KEY ---
@ -342,63 +367,69 @@ 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.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.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.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.rsa.public4096.n;
break;
}
ksz = ksz>>1;
if ( (len_e>4)||(len_e==0) ||
(len_p > ksz )||
(len_q > ksz)) {
THROW(SW_WRONG_DATA);
}
//fetch e
e = 0;
switch(len_e) {
case 4:
e = (e<<8) | gpg_io_fetch_u8();
e = gpg_io_fetch_u32();
break;
case 3:
e = (e<<8) | gpg_io_fetch_u8();
e = gpg_io_fetch_u24();
break;
case 2:
e = (e<<8) | gpg_io_fetch_u8();
e = gpg_io_fetch_u16();
break;
case 1:
e = (e<<8) | gpg_io_fetch_u8();
e = gpg_io_fetch_u8();
break;
default:
THROW(SW_WRONG_DATA);
return 0;
}
//move p,q over pub key, this only work because adr<rsa_pub> < adr<p>
if ( (len_p > ksz )|| (len_q > ksz)) {
THROW(SW_WRONG_DATA);
return 0;
}
p = G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset;
q = p + len_p;
pq = (unsigned char*)rsa_pub;
os_memmove(pq+ksz-len_p, p, len_p);
os_memmove(pq+2*ksz-len_q, q, len_q);
os_memset(pq, 0, ksz-len_p);
os_memmove(pq+2*ksz-len_q, q, len_q);
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);
@ -418,15 +449,16 @@ int gpg_apdu_put_data(unsigned int ref) {
curve = gpg_oid2curve(&keygpg->attributes.value[1], keygpg->attributes.length-1);
if (curve == 0) {
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));
@ -437,6 +469,7 @@ int gpg_apdu_put_data(unsigned int ref) {
// --- UNSUPPORTED KEY ---
else {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
break;
} //endof of 3fff
@ -447,45 +480,45 @@ int gpg_apdu_put_data(unsigned int ref) {
case 0x5B:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->name.value)) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(N_gpg_pstate->name.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->name.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* Login data */
case 0x5E:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->login.value)) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(N_gpg_pstate->login.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->login.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* Language preferences */
case 0x5F2D:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->lang.value)) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(N_gpg_pstate->lang.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->lang.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* Sex */
case 0x5F35:
if (G_gpg_vstate.io_length != sizeof(N_gpg_pstate->sex)) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(N_gpg_pstate->sex, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
sw = SW_OK;
break;
/* Uniform resource locator */
case 0x5F50:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->url.value)) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(N_gpg_pstate->url.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->url.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* ----------------- Cardholder certificate ----------------- */
@ -505,8 +538,8 @@ int gpg_apdu_put_data(unsigned int ref) {
ptr_v = G_gpg_vstate.kslot->dec.CA.value;
goto WRITE_CA;
default:
sw = SW_REFERENCED_DATA_NOT_FOUND;
break;
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
WRITE_CA:
if (G_gpg_vstate.io_length > GPG_EXT_CARD_HOLDER_CERT_LENTH) {
@ -514,7 +547,6 @@ int gpg_apdu_put_data(unsigned int ref) {
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* ----------------- Algorithm attributes ----------------- */
@ -533,10 +565,10 @@ int gpg_apdu_put_data(unsigned int ref) {
WRITE_ATTRIBUTES:
if (G_gpg_vstate.io_length > 12) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* ----------------- PWS status ----------------- */
@ -566,9 +598,9 @@ int gpg_apdu_put_data(unsigned int ref) {
WRITE_FINGERPRINTS:
if (G_gpg_vstate.io_length != 20) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 20);
sw = SW_OK;
break;
/* ----------------- Generation date/time ----------------- */
@ -584,9 +616,9 @@ int gpg_apdu_put_data(unsigned int ref) {
WRITE_DATE:
if (G_gpg_vstate.io_length != 4) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 4);
sw = SW_OK;
break;
/* ----------------- AES key ----------------- */
@ -618,10 +650,27 @@ int gpg_apdu_put_data(unsigned int ref) {
}
/* ----------------- RC ----------------- */
case 0xD3:
sw = gpg_apdu_change_ref_data(ID_RC);
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;
@ -635,9 +684,9 @@ int gpg_apdu_put_data(unsigned int ref) {
WRITE_UIF:
if (G_gpg_vstate.io_length != 2) {
THROW(SW_WRONG_LENGTH);
return 0;
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 2);
sw = SW_OK;
break;
/* ----------------- WAT ----------------- */
@ -645,6 +694,7 @@ int gpg_apdu_put_data(unsigned int ref) {
sw = SW_REFERENCED_DATA_NOT_FOUND;
break;
}
gpg_io_discard(1);
return sw;

View file

@ -20,12 +20,10 @@
#include "gpg_vars.h"
int gpg_is_verified(id) {
return G_gpg_vstate.verified_pin[id] ;
}
void gpg_check_access_ins() {
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
switch (G_gpg_vstate.io_ins) {
@ -42,7 +40,7 @@ void gpg_check_access_ins() {
return;
case INS_RESET_RETRY_COUNTER:
if (gpg_is_verified(ID_PW3) || gpg_is_verified(ID_RC)) {
if (gpg_pin_is_verified(PIN_ID_PW3) || gpg_pin_is_verified(PIN_ID_RC)) {
return;
}
@ -54,27 +52,30 @@ void gpg_check_access_ins() {
if (G_gpg_vstate.io_p1 == 0x81) {
return;
}
if (gpg_is_verified(ID_PW3)) {
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
case INS_MSE:
return ;
case INS_PSO:
if ((ref == 0x9e9a) && gpg_is_verified(ID_PW1)) {
//pso:sign
if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) {
//pso:sign
if (N_gpg_pstate->PW_status[0] == 0) {
gpg_set_pin_verified(ID_PW1,0);
gpg_pin_set_verified(PIN_ID_PW1, 0);
}
return;
}
if ((ref == 0x8086 ) && gpg_is_verified(ID_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_is_verified(ID_PW2)) {
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
@ -83,7 +84,7 @@ void gpg_check_access_ins() {
return;
case INS_TERMINATE_DF:
if (gpg_is_pin_verified(ID_PW3) || gpg_is_pin_blocked(ID_PW3)) {
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
@ -96,12 +97,17 @@ void gpg_check_access_ins() {
void gpg_check_access_read_DO() {
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
switch(ref) {
//ALWAYS
case 0x0101:
case 0x0102:
case 0x01F0:
case 0x01F1:
case 0x01F2:
case 0x01F8:
case 0x006E:
case 0x0065:
case 0x0073:
@ -140,14 +146,14 @@ void gpg_check_access_read_DO() {
//PW1
case 0x0103:
if (gpg_is_verified(ID_PW2)) {
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
//PW3
case 0x0104:
if (gpg_is_verified(ID_PW3)) {
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
@ -156,17 +162,22 @@ void gpg_check_access_read_DO() {
THROW(SW_CONDITIONS_NOT_SATISFIED);
}
char debugbuff[5];
void gpg_check_access_write_DO() {
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
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 ;
switch(ref) {
//PW1
case 0x0101:
case 0x0103:
case 0x01F2:
if (gpg_is_verified(ID_PW2)) {
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
@ -177,6 +188,7 @@ void gpg_check_access_write_DO() {
case 0x0102:
case 0x0104:
case 0x01F1:
case 0x01F8:
case 0x005E:
case 0x005B:
case 0x5F2D:
@ -207,7 +219,7 @@ void gpg_check_access_write_DO() {
case 0x00D6:
case 0x00D7:
case 0x00D8:
if (gpg_is_verified(ID_PW3)) {
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
@ -224,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 ;
@ -247,7 +264,7 @@ int gpg_dispatch() {
case INS_TERMINATE_DF:
gpg_io_discard(0);
if (G_gpg_vstate.verified_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;
@ -256,7 +273,6 @@ int gpg_dispatch() {
}
/* Other commands allowed if not terminated */
if (N_gpg_pstate->histo[7] != 0x07) {
THROW(SW_STATE_TERMINATED);
@ -328,7 +344,7 @@ int gpg_dispatch() {
(G_gpg_vstate.io_p2 == 0x82) ||
(G_gpg_vstate.io_p2 == 0x83)
) {
sw = gpg_apdu_verify(G_gpg_vstate.io_p2&0x0F);
sw = gpg_apdu_verify();
break;
}
THROW(SW_INCORRECT_P1P2);
@ -337,13 +353,13 @@ int gpg_dispatch() {
if ((G_gpg_vstate.io_p2 == 0x81) ||
(G_gpg_vstate.io_p2 == 0x83)
) {
sw = gpg_apdu_change_ref_data(G_gpg_vstate.io_p2&0x0F);
sw = gpg_apdu_change_ref_data();
break;
}
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) )
) {
@ -357,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;

View file

@ -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);
}
@ -69,10 +69,12 @@ int gpg_apdu_gen() {
break;
default:
THROW(SW_INCORRECT_P1P2);
return SW_INCORRECT_P1P2;
}
if (G_gpg_vstate.io_lc != 2){
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
}
gpg_io_fetch_tl(&t,&l);
@ -94,6 +96,7 @@ int gpg_apdu_gen() {
break;
default:
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
switch ((G_gpg_vstate.io_p1<<8)|G_gpg_vstate.io_p2) {
@ -102,7 +105,7 @@ int gpg_apdu_gen() {
case 0x8001:
// RSA
if (keygpg->attributes.value[0] == 0x01) {
#define GPG_RSA_DEFAULT_PUB 0x010001U
unsigned char *pq;
cx_rsa_public_key_t *rsa_pub;
cx_rsa_private_key_t *rsa_priv, *pkey;
@ -110,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;
}
@ -150,8 +144,7 @@ int gpg_apdu_gen() {
cx_math_next_prime(pq+size,size);
}
cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, GPG_RSA_DEFAULT_PUB, 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);
@ -162,7 +155,7 @@ int gpg_apdu_gen() {
gpg_io_clear();
goto send_rsa_pub;
#undef GPG_RSA_DEFAULT_PUB
}
// ECC
if ((keygpg->attributes.value[0] == 18) ||
@ -171,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));
@ -205,28 +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);
@ -248,13 +250,14 @@ int gpg_apdu_gen() {
if (keygpg->pub_key.ecfp256.W_len == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
gpg_io_discard(1);
gpg_io_mark();
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;
@ -277,4 +280,5 @@ int gpg_apdu_gen() {
}
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}

View file

@ -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,9 +332,13 @@ 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));
}
//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
gpg_init_ux();
}
@ -229,7 +354,6 @@ void gpg_init_ux() {
int gpg_install(unsigned char app_state) {
gpg_pin_t pin;
unsigned int l;
unsigned char config[4];
//full reset data
gpg_nvm_write(N_gpg_pstate, NULL, sizeof(gpg_nv_state_t));
@ -251,16 +375,18 @@ int gpg_install(unsigned char app_state) {
G_gpg_vstate.work.io_buffer[0] = 0x39;
gpg_nvm_write(&N_gpg_pstate->sex, G_gpg_vstate.work.io_buffer, 1);
//default PW1: 1 2 3 4 5 6
//default PW1/PW2: 1 2 3 4 5 6
os_memmove(pin.value, C_sha256_PW1, sizeof(C_sha256_PW1));
pin.length = 6;
pin.counter = 3;
pin.ref = PIN_ID_PW1;
gpg_nvm_write(&N_gpg_pstate->PW1, &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));
pin.length = 8;
pin.counter = 3;
pin.ref = PIN_ID_PW3;
gpg_nvm_write(&N_gpg_pstate->PW3, &pin, sizeof(gpg_pin_t));
//PWs status
@ -271,13 +397,35 @@ int gpg_install(unsigned char app_state) {
gpg_nvm_write(&N_gpg_pstate->PW_status, G_gpg_vstate.work.io_buffer, 4);
//config slot
config[0] = GPG_KEYS_SLOTS;
config[1] = 0;
config[2] = 3; // 3: selection by APDU and screen
G_gpg_vstate.work.io_buffer[0] = GPG_KEYS_SLOTS;
G_gpg_vstate.work.io_buffer[1] = 0;
G_gpg_vstate.work.io_buffer[2] = 3; // 3: selection by APDU and screen
gpg_nvm_write(&N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer, 3);
//config rsa pub
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);
@ -296,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);
}

View file

@ -42,6 +42,7 @@ void gpg_io_set_offset(unsigned int offset) {
}
else {
THROW(ERROR_IO_OFFSET);
return ;
}
}
@ -76,6 +77,7 @@ void gpg_io_clear() {
void gpg_io_hole(unsigned int sz) {
if ((G_gpg_vstate.io_length + sz) > GPG_IO_BUFFER_LENGTH) {
THROW(ERROR_IO_FULL);
return ;
}
os_memmove(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+sz,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
@ -147,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;
@ -162,6 +161,15 @@ unsigned int gpg_io_fetch_u32() {
return v32;
}
unsigned int gpg_io_fetch_u24() {
unsigned int v24;
v24 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+2] << 0) );
G_gpg_vstate.io_offset += 3;
return v24;
}
unsigned int gpg_io_fetch_u16() {
unsigned int v16;
v16 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 8) |
@ -231,44 +239,56 @@ int gpg_io_fetch(unsigned char* buffer, int len) {
/* REAL IO */
/* ----------------------------------------------------------------------- */
int gpg_io_do() {
#define MAX_OUT GPG_APDU_LENGTH
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;
}
// --- full out chaining ---
G_gpg_vstate.io_offset = 0;
while(G_gpg_vstate.io_length > MAX_OUT) {
unsigned int tx,xx;
//send chunk
tx = MAX_OUT-2;
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, tx);
G_gpg_vstate.io_length -= tx;
G_gpg_vstate.io_offset += tx;
G_io_apdu_buffer[tx] = 0x61;
if (G_gpg_vstate.io_length > MAX_OUT-2) {
xx = MAX_OUT-2;
} else {
xx = G_gpg_vstate.io_length-2;
}
G_io_apdu_buffer[tx+1] = xx;
gpg_io_exchange(CHANNEL_APDU | G_gpg_vstate.io_flags, tx+2);
//check get response
if ((G_io_apdu_buffer[0] != 0x00) ||
if (io_flags & IO_ASYNCH_REPLY) {
// if IO_ASYNCH_REPLY has been set,
// gpg_io_exchange will return when IO_RETURN_AFTER_TX will set in ui
gpg_io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0);
} else {
// --- full out chaining ---
G_gpg_vstate.io_offset = 0;
while(G_gpg_vstate.io_length > MAX_OUT) {
unsigned int tx,xx;
//send chunk
tx = MAX_OUT-2;
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, tx);
G_gpg_vstate.io_length -= tx;
G_gpg_vstate.io_offset += tx;
G_io_apdu_buffer[tx] = 0x61;
if (G_gpg_vstate.io_length > MAX_OUT-2) {
xx = MAX_OUT-2;
} else {
xx = G_gpg_vstate.io_length-2;
}
G_io_apdu_buffer[tx+1] = xx;
gpg_io_exchange(CHANNEL_APDU, tx+2);
//check get response
if ((G_io_apdu_buffer[0] != 0x00) ||
(G_io_apdu_buffer[1] != 0xc0) ||
(G_io_apdu_buffer[2] != 0x00) ||
(G_io_apdu_buffer[3] != 0x00) ) {
THROW(SW_COMMAND_NOT_ALLOWED);
THROW(SW_COMMAND_NOT_ALLOWED);
return 0;
}
}
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_length);
if (io_flags & IO_RETURN_AFTER_TX) {
gpg_io_exchange(CHANNEL_APDU |IO_RETURN_AFTER_TX, G_gpg_vstate.io_length);
return 0;
} else {
gpg_io_exchange(CHANNEL_APDU, G_gpg_vstate.io_length);
}
}
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_length);
gpg_io_exchange(CHANNEL_APDU | G_gpg_vstate.io_flags, G_gpg_vstate.io_length);
//--- full in chaining ---
G_gpg_vstate.io_offset = 0;
@ -292,7 +312,16 @@ int gpg_io_do() {
if (G_gpg_vstate.io_p1 == 0) {
break;
}
case INS_VERIFY:
case INS_CHANGE_REFERENCE_DATA:
if (G_io_apdu_buffer[4] == 0) {
break;
}
goto _default;
default:
_default:
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
os_memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer+5, G_gpg_vstate.io_lc);
G_gpg_vstate.io_length = G_gpg_vstate.io_lc;
@ -303,13 +332,14 @@ int gpg_io_do() {
G_io_apdu_buffer[0] = 0x90;
G_io_apdu_buffer[1] = 0x00;
gpg_io_exchange(CHANNEL_APDU | G_gpg_vstate.io_flags, 2);
gpg_io_exchange(CHANNEL_APDU, 2);
in_chaining:
if (((G_io_apdu_buffer[0] & 0xEF) != (G_gpg_vstate.io_cla& 0xEF)) ||
(G_io_apdu_buffer[1] != G_gpg_vstate.io_ins) ||
(G_io_apdu_buffer[2] != G_gpg_vstate.io_p1) ||
(G_io_apdu_buffer[3] != G_gpg_vstate.io_p2) ) {
THROW(SW_COMMAND_NOT_ALLOWED);
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
}
G_gpg_vstate.io_cla = G_io_apdu_buffer[0];
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];

View file

@ -21,575 +21,26 @@
#include "gpg_api.h"
#include "gpg_vars.h"
#include "gpg_ux_nanos.h"
//#include "gpg_ux_blue.h"
#include "os_io_seproxyhal.h"
#include "string.h"
#include "glyphs.h"
/* ----------------------------------------------------------------------- */
/* --- Blue UI layout --- */
/* ----------------------------------------------------------------------- */
/* screeen size:
blue; 320x480
nanoS: 128x32
*/
#if 0
static const bagl_element_t const ui_idle_blue[] = {
{{BAGL_RECTANGLE, 0x00, 0, 60, 320, 420, 0, 0,
BAGL_FILL, 0xf9f9f9, 0xf9f9f9,
0, 0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_RECTANGLE, 0x00, 0, 0, 320, 60, 0, 0,
BAGL_FILL, 0x1d2028, 0x1d2028,
0, 0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_LABEL, 0x00, 20, 0, 320, 60, 0, 0,
BAGL_FILL, 0xFFFFFF, 0x1d2028,
BAGL_FONT_OPEN_SANS_LIGHT_14px | BAGL_FONT_ALIGNMENT_MIDDLE, 0},
"GPG Card",
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_BUTTON | BAGL_FLAG_TOUCHABLE, 0x00, 190, 215, 120, 40, 0, 6,
BAGL_FILL, 0x41ccb4, 0xF9F9F9,
BAGL_FONT_OPEN_SANS_LIGHT_14px | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE,
0},
"Exit",
0,
0x37ae99,
0xF9F9F9,
gpg_io_seproxyhal_touch_exit,
NULL,
NULL},
#ifdef GPG_DEBUG
{{BAGL_BUTTON | BAGL_FLAG_TOUCHABLE, 0x00, 20, 215, 120, 40, 0, 6,
BAGL_FILL, 0x41ccb4, 0xF9F9F9,
BAGL_FONT_OPEN_SANS_LIGHT_14px | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE,
0},
"Init",
0,
0x37ae99,
0xF9F9F9,
gpg_io_seproxyhal_touch_debug,
NULL,
NULL}
#endif
};
const bagl_element_t ui_idle_nanos[] = {
// type
{{BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0,
BAGL_FILL, 0x000000, 0xFFFFFF,
0,
0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_LABELINE, 0x00, 0, 12, 128, 32, 0, 0,
0 , 0xFFFFFF, 0x000000,
BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER,
0 },
"GPGCard",
0,
0,
0,
NULL,
NULL,
NULL },
//{{BAGL_LABELINE , 0x02, 0, 26, 128, 32, 0, 0, 0 , 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_REGULAR_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Waiting for requests...", 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 },
};
unsigned int gpg_io_seproxyhal_touch_exit(const bagl_element_t *e) {
// Go back to the dashboard
os_sched_exit(0);
return 0; // do not redraw the widget
}
unsigned int ui_idle_blue_button(unsigned int button_mask,
unsigned int button_mask_counter) {
return 0;
}
#endif
/* ----------------------------------------------------------------------- */
/* --- NanoS UI layout --- */
/* ----------------------------------------------------------------------- */
const ux_menu_entry_t ui_idle_sub_template[];
void ui_idle_sub_template_display(unsigned int value);
const bagl_element_t* ui_idle_sub_template_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
void ui_idle_sub_tmpl_set_action(unsigned int value) ;
const ux_menu_entry_t ui_idle_sub_tmpl_key[];
void ui_idle_sub_tmpl_key_action(unsigned int value);
const ux_menu_entry_t ui_idle_sub_tmpl_type[];
void ui_idle_sub_tmpl_type_action(unsigned int value);
const ux_menu_entry_t ui_idle_sub_seed[];
void ui_idle_sub_seed_display(unsigned int value);
const bagl_element_t* ui_idle_sub_seed_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) ;
void ui_idle_sub_seed_action(unsigned int value) ;
const ux_menu_entry_t ui_idle_sub_reset[] ;
void ui_idle_sub_reset_action(unsigned int value);
const ux_menu_entry_t ui_idle_sub_slot[];
void ui_idle_sub_slot_display(unsigned int value);
const bagl_element_t* ui_idle_sub_slot_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
void ui_idle_sub_slot_action(unsigned int value);
const ux_menu_entry_t ui_idle_settings[] ;
const ux_menu_entry_t ui_idle_mainmenu[];
void ui_idle_main_display(unsigned int value) ;
const bagl_element_t* ui_idle_main_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element);
/* ------------------------------- Helpers UX ------------------------------- */
void ui_CCID_reset(void) {
//INSERT CODE HERE TO REMOVE/INSERT THE TOKEN
}
void ui_info(const char* msg1, const char* msg2, const void *menu_display, unsigned int entry) {
ux_menu_entry_t ui_dogsays[2] = {
{NULL, menu_display, 0, NULL, msg1, msg2, 0, 0},
UX_MENU_END
};
UX_MENU_DISPLAY(entry, ui_dogsays, NULL);
};
/* ------------------------------- template UX ------------------------------- */
#define LABEL_SIG "Signature"
#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"
const ux_menu_entry_t ui_idle_sub_template[] = {
{ui_idle_sub_tmpl_key, NULL, -1, NULL, "Choose key...", NULL, 0, 0},
{ui_idle_sub_tmpl_type, NULL, -1, NULL, "Choose type...", NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_set_action, -1, NULL, "Set template", NULL, 0, 0},
{ui_idle_settings, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_template_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_idle_sub_template, ui_idle_sub_template_preprocessor);
}
const bagl_element_t* ui_idle_sub_template_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
if(element->component.userid==0x20) {
if (entry == &ui_idle_sub_template[0]) {
switch(G_gpg_vstate.ux_key) {
case 1:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_SIG);
break;
case 2:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_DEC);
break;
case 3:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "%s", LABEL_AUT);
break;
default:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Choose key...");
break;
}
element->text = G_gpg_vstate.menu;
}
if (entry == &ui_idle_sub_template[1]) {
switch(G_gpg_vstate.ux_type) {
case 2048:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA2048);
break;
case 3072:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_RSA3072);
break;
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);
break;
case CX_CURVE_Ed25519:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu)," %s", LABEL_Ed25519);
break;
default:
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Choose type...");
break;
}
element->text = G_gpg_vstate.menu;
}
}
return element;
}
void ui_idle_sub_tmpl_set_action(unsigned int value) {
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH);
gpg_key_t* dest;
char* err;
err = NULL;
os_memset(&attributes, 0, sizeof(attributes));
switch (G_gpg_vstate.ux_type) {
case 2048:
case 3072:
case 4096:
attributes.value[0] = 0x01;
attributes.value[1] = (G_gpg_vstate.ux_type>>8) &0xFF;
attributes.value[2] = G_gpg_vstate.ux_type&0xFF;
attributes.value[3] = 0x00;
attributes.value[4] = 0x20;
attributes.value[5] = 0x01;
attributes.length = 6;
break;
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_BrainPoolP256R1:
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);
break;
case CX_CURVE_Ed25519:
if (G_gpg_vstate.ux_key == 2) {
attributes.value[0] = 18; //ecdh
os_memmove(attributes.value+1, C_OID_cv25519, sizeof(C_OID_cv25519));
attributes.length = 1+sizeof(C_OID_cv25519);
} else {
attributes.value[0] = 22; //eddsa
os_memmove(attributes.value+1, C_OID_Ed25519, sizeof(C_OID_Ed25519));
attributes.length = 1+sizeof(C_OID_Ed25519);
}
break;
default:
err = "type";
goto ERROR;
}
dest = NULL;
switch(G_gpg_vstate.ux_key) {
case 1:
dest = &G_gpg_vstate.kslot->sig;
break;
case 2:
dest = &G_gpg_vstate.kslot->dec;
break;
case 3:
dest = &G_gpg_vstate.kslot->aut;
break;
default:
err = "key";
goto ERROR;
}
gpg_nvm_write(dest, NULL, sizeof(gpg_key_t));
gpg_nvm_write(&dest->attributes, &attributes, sizeof(attributes));
ui_info("Template set!", NULL, ui_idle_sub_template_display, 0);
return;
ERROR:
ui_info("Invalid selection:", err, ui_idle_sub_template_display, 0);
}
const ux_menu_entry_t ui_idle_sub_tmpl_key[] = {
{NULL, ui_idle_sub_tmpl_key_action, 1, NULL, LABEL_SIG, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_key_action, 2, NULL, LABEL_DEC, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_key_action, 3, NULL, LABEL_AUT, NULL, 0, 0},
{ui_idle_sub_template, NULL, 0, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_tmpl_key_action(unsigned int value) {
G_gpg_vstate.ux_key = value;
ui_idle_sub_template_display(0);
}
const ux_menu_entry_t ui_idle_sub_tmpl_type[] = {
{NULL, ui_idle_sub_tmpl_type_action, 2048, NULL, LABEL_RSA2048, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, 3072, NULL, LABEL_RSA3072, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, 4096, NULL, LABEL_RSA4096, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_SECP256R1, NULL, LABEL_NISTP256, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_BrainPoolP256R1, NULL, LABEL_BPOOLR1, NULL, 0, 0},
{NULL, ui_idle_sub_tmpl_type_action, CX_CURVE_Ed25519, NULL, LABEL_Ed25519, NULL, 0, 0},
{ui_idle_sub_template, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_tmpl_type_action(unsigned int value) {
G_gpg_vstate.ux_type = value;
ui_idle_sub_template_display(1);
}
/* --------------------------------- SEED UX --------------------------------- */
const ux_menu_entry_t ui_idle_sub_seed[] = {
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
{NULL, NULL, 0, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_seed_action, 1, NULL, "Set on", NULL, 0, 0},
{NULL, ui_idle_sub_seed_action, 0, NULL, "Set off", NULL, 0, 0},
{ui_idle_settings, NULL, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_seed_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_idle_sub_seed, ui_idle_sub_seed_preprocessor);
}
const bagl_element_t* ui_idle_sub_seed_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
if(element->component.userid==0x20) {
if (entry == &ui_idle_sub_seed[0]) {
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "< %s >", G_gpg_vstate.seed_mode?"ON":"OFF");
element->text = G_gpg_vstate.menu;
}
}
return element;
}
void ui_idle_sub_seed_action(unsigned int value) {
G_gpg_vstate.seed_mode = value;
ui_idle_sub_seed_display(0);
}
/* -------------------------------- RESET UX --------------------------------- */
const ux_menu_entry_t ui_idle_sub_reset[] = {
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
{NULL, NULL, 0, NULL, "Really Reset ?", NULL, 0, 0},
{NULL, ui_idle_main_display, 0, &C_badge_back, "Oh No!", NULL, 61, 40},
{NULL, ui_idle_sub_reset_action, 0, NULL, "Yes!", NULL, 0, 0},
UX_MENU_END
};
void ui_idle_sub_reset_action(unsigned int value) {
unsigned char magic[4];
magic[0] = 0; magic[1] = 0; magic[2] = 0; magic[3] = 0;
gpg_nvm_write(N_gpg_pstate->magic, magic, 4);
gpg_init();
ui_CCID_reset();
ui_idle_main_display(0);
}
/* ------------------------------- SETTINGS UX ------------------------------- */
const ux_menu_entry_t ui_idle_settings[] = {
{NULL, ui_idle_sub_template_display, 0, NULL, "Key template", NULL, 0, 0},
{NULL, ui_idle_sub_seed_display, 0, NULL, "Seed mode", NULL, 0, 0},
{ui_idle_sub_reset, NULL, 0, NULL, "Reset", NULL, 0, 0},
{NULL, ui_idle_main_display, 2, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
/* --------------------------------- SLOT UX --------------------------------- */
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
const ux_menu_entry_t ui_idle_sub_slot[] = {
{NULL, NULL, -1, NULL, "Choose:", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 1, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 2, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 3, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_slot_action, 128, NULL, "Set Default", NULL, 0, 0},
{NULL, ui_idle_main_display, 1, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
void ui_idle_sub_slot_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_idle_sub_slot, ui_idle_sub_slot_preprocessor);
}
const bagl_element_t* ui_idle_sub_slot_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
unsigned int slot;
if(element->component.userid==0x20) {
for (slot = 1; slot <= 3; slot ++) {
if (entry == &ui_idle_sub_slot[slot]) {
break;
}
}
if (slot != 4) {
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "Slot %d %s %s",
slot,
slot == N_gpg_pstate->config_slot[1]+1?"#":" ", /* default */
slot == G_gpg_vstate.slot+1?"+":" " /* selected*/);
element->text = G_gpg_vstate.menu;
}
}
return element;
}
void ui_idle_sub_slot_action(unsigned int value) {
unsigned char s;
if (value == 128) {
s = G_gpg_vstate.slot;
gpg_nvm_write(&N_gpg_pstate->config_slot[1], &s,1);
value = s+1;
}
else {
s = (unsigned char)(value-1);
if (s!= G_gpg_vstate.slot) {
G_gpg_vstate.slot = s;
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
ui_CCID_reset();
}
}
// redisplay first entry of the idle menu
ui_idle_sub_slot_display(value);
}
/* --------------------------------- INFO UX --------------------------------- */
#if GPG_KEYS_SLOTS != 3
#error menu definition not correct for current value of GPG_KEYS_SLOTS
#endif
#define STR(x) #x
#define XSTR(x) STR(x)
const ux_menu_entry_t ui_idle_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, "App " XSTR(GPG_VERSION), NULL, 0, 0},
{NULL, ui_idle_main_display, 3, &C_badge_back, "Back", NULL, 61, 40},
UX_MENU_END
};
#undef STR
#undef XSTR
/* --------------------------------- MAIN UX --------------------------------- */
const ux_menu_entry_t ui_idle_mainmenu[] = {
{NULL, NULL, 0, NULL, "", NULL, 0, 0},
{NULL, ui_idle_sub_slot_display, 0, NULL, "Select slot", NULL, 0, 0},
{ui_idle_settings, NULL, 0, NULL, "Settings", NULL, 0, 0},
{ui_idle_info, NULL, 0, NULL, "About", NULL, 0, 0},
{NULL, os_sched_exit, 0, &C_icon_dashboard, "Quit app" , NULL, 50, 29},
UX_MENU_END
};
const bagl_element_t* ui_idle_main_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) {
if (entry == &ui_idle_mainmenu[0]) {
if(element->component.userid==0x20) {
unsigned int serial;
char name[20];
serial = MIN(N_gpg_pstate->name.length,19);
os_memset(name, 0, 20);
os_memmove(name, N_gpg_pstate->name.value, serial);
serial = (N_gpg_pstate->AID[10] << 24) |
(N_gpg_pstate->AID[11] << 16) |
(N_gpg_pstate->AID[12] << 8) |
(N_gpg_pstate->AID[13] |(G_gpg_vstate.slot+1));
os_memset(G_gpg_vstate.menu, 0, sizeof(G_gpg_vstate.menu));
snprintf(G_gpg_vstate.menu, sizeof(G_gpg_vstate.menu), "< User: %s / SLOT: %d / Serial: %x >",
name, G_gpg_vstate.slot+1, serial);
element->component.stroke = 10; // 1 second stop in each way
element->component.icon_id = 26; // roundtrip speed in pixel/s
element->text = G_gpg_vstate.menu;
UX_CALLBACK_SET_INTERVAL(bagl_label_roundtrip_duration_ms(element, 7));
}
}
return element;
}
void ui_idle_main_display(unsigned int value) {
UX_MENU_DISPLAY(value, ui_idle_mainmenu, ui_idle_main_preprocessor);
}
void ui_idle_init(void) {
ui_idle_main_display(0);
// setup the first screen changing
UX_CALLBACK_SET_INTERVAL(1000);
}
void io_seproxyhal_display(const bagl_element_t *element) {
io_seproxyhal_display_default((bagl_element_t *)element);
}
/* ----------------------------------------------------------------------- */
/* --- Application Entry --- */
/* ----------------------------------------------------------------------- */
void gpg_main(void) {
unsigned int io_flags;
io_flags = 0;
for (;;) {
volatile unsigned short sw = 0;
BEGIN_TRY {
TRY {
gpg_io_do();
gpg_io_do(io_flags);
sw = gpg_dispatch();
}
CATCH_OTHER(e) {
@ -603,7 +54,12 @@ void gpg_main(void) {
}
}
FINALLY {
gpg_io_insert_u16(sw);
if (sw) {
gpg_io_insert_u16(sw);
io_flags = 0;
} else {
io_flags = IO_ASYNCH_REPLY;
}
}
}
END_TRY;
@ -675,6 +131,7 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
default:
THROW(INVALID_PARAMETER);
return 0;
}
return 0;
}
@ -708,13 +165,15 @@ __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);
//set up
gpg_init();
//set up initial screen
ui_idle_init();
ui_init();

78
src/gpg_mse.c Normal file
View 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;
}

View file

@ -19,15 +19,16 @@
#include "gpg_api.h"
#include "gpg_vars.h"
#include "gpg_ux_nanos.h"
static gpg_pin_t *gpg_get_pin(int id) {
switch (id) {
case ID_PW1 :
case ID_PW2 :
gpg_pin_t *gpg_pin_get_pin(int pinref) {
switch (pinref) {
case PIN_ID_PW1 :
case PIN_ID_PW2 :
return &N_gpg_pstate->PW1;
case ID_PW3:
case PIN_ID_PW3:
return &N_gpg_pstate->PW3;
case ID_RC:
case PIN_ID_RC:
return &N_gpg_pstate->RC;
}
return NULL;
@ -35,152 +36,224 @@ static gpg_pin_t *gpg_get_pin(int id) {
void gpg_set_pin_verified(int id, int verified) {
G_gpg_vstate.verified_pin[id] = verified;
static int gpg_pin_get_state_index(unsigned int pinref) {
switch (pinref) {
case PIN_ID_PW1 :
return 1;
case PIN_ID_PW2 :
return 2;
case PIN_ID_PW3 :
return 3;
case PIN_ID_RC :
return 4;
}
return -1;
}
static void gpg_check_pin(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;
if (pin->counter == 0) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
}
counter = pin->counter-1;
gpg_nvm_write(&(pin->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)) {
THROW(SW_SECURITY_STATUS_NOT_SATISFIED);
return SW_SECURITY_STATUS_NOT_SATISFIED;
}
counter = 3;
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
return SW_OK;
}
static void gpg_set_pin(gpg_pin_t *pin, unsigned char *pin_val, unsigned 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(pinID,0);
sw = gpg_pin_check_internal(pin,pin_val,pin_len);
if (sw == SW_OK) {
gpg_pin_set_verified(pinID,1);
return;
}
THROW(sw);
return;
}
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);
if (sw == SW_OK) {
gpg_pin_set_verified(pinID,1);
}
return sw;
}
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len) {
cx_sha256_t sha256;
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));
}
/*
static void gpg_unblock_pin(int id) {
gpg_pin_t *pin;
int counter;
pin = gpg_get_pin(id);
counter = 3;
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
}
*/
/*
*
*/
int gpg_is_pin_verified(int id) {
return G_gpg_vstate.verified_pin[id] != 0;
int gpg_pin_set_verified(int pinID, int verified) {
int idx;
idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) {
G_gpg_vstate.verified_pin[idx]=verified;
return verified;
}
return 0;
}
/*
*
*/
int gpg_is_pin_blocked(int id) {
gpg_pin_t *pin;
pin = gpg_get_pin(id);
int gpg_pin_is_verified(int pinID) {
int idx;
idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) {
return G_gpg_vstate.verified_pin[idx];
}
return 0;
}
int gpg_pin_is_blocked(gpg_pin_t *pin) {
return pin->counter == 0;
}
/* @return: 1 verified
* 0 not verified
* -1 blocked
*/
int gpg_apdu_verify(int id) {
int gpg_apdu_verify() {
gpg_pin_t *pin;
pin = gpg_get_pin(id);
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
if (pin == NULL) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_set_pin_verified(id,0);
if (gpg_is_pin_blocked(id)) {
THROW(SW_PIN_BLOCKED);
return 0;
}
//PINPAD
if (G_gpg_vstate.io_cla == 0xEF) {
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
}
gpg_check_pin(pin,
G_gpg_vstate.work.io_buffer+ G_gpg_vstate.io_offset,
G_gpg_vstate.io_length);
gpg_set_pin_verified(id,1);
gpg_io_discard(1);
return SW_OK;
}
int gpg_apdu_change_ref_data(int id) {
gpg_pin_t *pin;
int len, newlen;
pin = gpg_get_pin(id);
if (pin == NULL) {
if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) {
//Delegate pin check to ui
gpg_io_discard(1);
ui_menu_pinentry_display(0);
return 0;
}
if (G_gpg_vstate.pinmode == PIN_MODE_CONFIRM) {
//Delegate pin check to ui
gpg_io_discard(1);
ui_menu_pinconfirm_display(0);
return 0;
}
if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) {
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_set_pin_verified(id,0);
// --- RC pin ---
if (id == 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);
} else {
gpg_set_pin(pin,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
newlen);
//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);
//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() {
gpg_pin_t *pin;
int len, newlen;
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
if (pin == NULL) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_pin_set_verified(pin->ref,0);
// --- PW1/PW3 pin ---
if (gpg_is_pin_blocked(id)) {
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return 0;
return SW_PIN_BLOCKED;
}
//avoid any-overflow whitout giving info
if (G_gpg_vstate.io_length == 0) {
if (G_gpg_vstate.pinmode != PIN_MODE_HOST) {
//Delegate pin change to ui
gpg_io_discard(1);
ui_menu_pinentry_display(0);
return 0;
}
}
if (pin->length > G_gpg_vstate.io_length) {
len = G_gpg_vstate.io_length;
} else {
len = pin->length;
}
gpg_check_pin(pin,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
len);
gpg_pin_check_throw(pin, pin->ref,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
len);
newlen = G_gpg_vstate.io_length-len;
if ( (newlen > GPG_MAX_PW_LENGTH) ||
((id == ID_PW1) && (newlen < 6)) ||
((id == ID_PW3) && (newlen < 8)) ) {
((pin->ref == PIN_ID_PW1) && (newlen < 6)) ||
((pin->ref == PIN_ID_PW3) && (newlen < 8)) ) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_set_pin(pin,
gpg_pin_set(pin,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+len,
newlen);
gpg_io_discard(1);
@ -189,19 +262,23 @@ int gpg_apdu_change_ref_data(int id) {
int gpg_apdu_reset_retry_counter() {
gpg_pin_t *pin_pw1;
gpg_pin_t *pin_pw3;
gpg_pin_t *pin_rc;
int rc_len, pw1_len;
pin_pw1 = gpg_get_pin(ID_PW1);
pin_pw1 = gpg_pin_get_pin(PIN_ID_PW1);
pin_pw3 = gpg_pin_get_pin(PIN_ID_PW3);
pin_rc = gpg_pin_get_pin(PIN_ID_RC);
if (G_gpg_vstate.io_p1 == 2) {
if (!G_gpg_vstate.verified_pin[ID_PW3]) {
if (!gpg_pin_is_verified(PIN_ID_PW3)) {
THROW(SW_SECURITY_STATUS_NOT_SATISFIED);
return SW_SECURITY_STATUS_NOT_SATISFIED;
}
rc_len = 0;
pw1_len = G_gpg_vstate.io_length;
} else {
pin_rc = gpg_get_pin(ID_RC);
//avoid any-overflow whitout giving info
if (pin_rc->length > G_gpg_vstate.io_length) {
rc_len = G_gpg_vstate.io_length;
@ -209,15 +286,16 @@ int gpg_apdu_reset_retry_counter() {
rc_len = pin_rc->length;
}
pw1_len = G_gpg_vstate.io_length-rc_len;
gpg_check_pin(pin_rc,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
rc_len);
gpg_pin_check_throw(pin_rc,pin_rc->ref,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
rc_len);
}
if ((pw1_len > GPG_MAX_PW_LENGTH) ||(pw1_len < 6)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_set_pin(pin_pw1,
gpg_pin_set(pin_pw1,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+rc_len,
pw1_len);
gpg_io_discard(1);

View file

@ -18,6 +18,7 @@
#include "gpg_types.h"
#include "gpg_api.h"
#include "gpg_vars.h"
#include "gpg_ux_nanos.h"
const unsigned char gpg_oid_sha256[] = {
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
@ -26,6 +27,11 @@ const unsigned char gpg_oid_sha512[] = {
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40
};
static void gpg_pso_reset_PW1() {
if (N_gpg_pstate->PW_status[0] ==0) {
gpg_pin_set_verified(PIN_ID_PW1,0);
}
}
static int gpg_sign(gpg_key_t *sigkey) {
// --- RSA
@ -36,20 +42,21 @@ 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) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
//sign
@ -70,6 +77,7 @@ static int gpg_sign(gpg_key_t *sigkey) {
//send
gpg_io_discard(0);
gpg_io_inserted(ksz);
gpg_pso_reset_PW1();
return SW_OK;
}
// --- ECDSA/EdDSA
@ -79,22 +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);
}
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) {
@ -108,31 +121,91 @@ 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;
}
// --- PSO:CDS NOT SUPPORTED
THROW(SW_REFERENCED_DATA_NOT_FOUND);
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: {
return gpg_sign(&G_gpg_vstate.kslot->sig);
unsigned int cnt;
int sw;
sw = gpg_sign(&G_gpg_vstate.kslot->sig);
cnt = G_gpg_vstate.kslot->sig_count+1;
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: {
unsigned int msg_len;
@ -141,32 +214,34 @@ int gpg_apdu_pso(unsigned int pso) {
pad_byte = gpg_io_fetch_u8();
switch(pad_byte) {
// --- RSA
// --- 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 SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_rsa_decrypt(key,
@ -179,47 +254,54 @@ int gpg_apdu_pso(unsigned int pso) {
gpg_io_inserted(sz);
return SW_OK;
}
// --- AES
// --- PSO:DEC:AES
case 0x02: {
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_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);
return SW_OK;
}
// --- ECDH
// --- PSO:DEC:ECDH
case 0xA6: {
cx_ecfp_private_key_t *key;
unsigned int sz;
unsigned int curve;
if (G_gpg_vstate.kslot->dec.attributes.value[0] != 18) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
}
key = &G_gpg_vstate.kslot->dec.key.ecfp256;
if (key->d_len != 32) {
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x12) {
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) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x86) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
curve = gpg_oid2curve(G_gpg_vstate.kslot->dec.attributes.value+1, G_gpg_vstate.kslot->dec.attributes.length-1);
curve = gpg_oid2curve(G_gpg_vstate.mse_dec->attributes.value+1, G_gpg_vstate.mse_dec->attributes.length-1);
if (key->curve != curve) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
if (curve == CX_CURVE_Curve25519) {
unsigned int i;
@ -229,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];
}
@ -238,36 +320,47 @@ 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);
gpg_io_insert( G_gpg_vstate.work.io_buffer+128,sz);
return SW_OK;
}
// --- PSO:DEC NOT SUPPORTDED
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
}
//--- PSO NOT SUPPPORTED ---
// --- PSO:DEC:xx NOT SUPPORTDED
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
}
//--- PSO:yy NOT SUPPPORTED ---
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
THROW(SW_WRONG_DATA);
}}
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
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);
}

View file

@ -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;
@ -32,3 +33,4 @@ int apdu_n;
gpg_v_state_t G_gpg_vstate;

View file

@ -19,24 +19,41 @@
#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;
G_gpg_vstate.DO_offset = 0;
if ( G_gpg_vstate.selected == 0) {
G_gpg_vstate.verified_pin[ID_PW1] = 0;
G_gpg_vstate.verified_pin[ID_PW2] = 0;
G_gpg_vstate.verified_pin[ID_PW3] = 0;
G_gpg_vstate.verified_pin[ID_RC] = 0;
G_gpg_vstate.verified_pin[0] = 0;
G_gpg_vstate.verified_pin[1] = 0;
G_gpg_vstate.verified_pin[2] = 0;
G_gpg_vstate.verified_pin[3] = 0;
G_gpg_vstate.verified_pin[4] = 0;
}
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;
}
return sw;
}

View file

@ -16,6 +16,7 @@
#ifndef GPG_TYPES_H
#define GPG_TYPES_H
#include "os_io_seproxyhal.h"
/* cannot send more that F0 bytes in CCID, why? do not know for now
* So set up length to F0 minus 2 bytes for SW
*/
@ -35,11 +36,13 @@
#define GPG_KEY_ATTRIBUTES_LENGTH 12
#define GPG_RSA_DEFAULT_PUB 0x00010001U
struct gpg_pin_s {
unsigned int ref;
//initial pin length, 0 means not set
unsigned int length;
unsigned int counter;
unsigned int length;
unsigned int counter;
//only store sha256 of PIN/RC
unsigned char value[32];
};
@ -63,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];
@ -107,8 +120,13 @@ struct gpg_nv_state_s {
/* magic */
unsigned char magic[8];
/* pin mode */
unsigned char config_pin[1];
/* 01F1 (01F2 is volatile)*/
unsigned char config_slot[3];
/* RSA exponent */
unsigned char default_RSA_exponent[4];
/* 0101 0102 0103 0104 */
LV(private_DO1, GPG_EXT_PRIVATE_DO_LENGTH);
@ -165,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;
@ -178,29 +201,43 @@ struct gpg_v_state_s {
unsigned short io_length;
unsigned short io_offset;
unsigned short io_mark;
unsigned short io_flags;
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 {
@ -217,13 +254,14 @@ struct gpg_v_state_s {
/* PINs state */
unsigned char verified_pin[5];
unsigned char pinmode;
/* ux menus */
char menu[64];
char menu[112];
unsigned char ux_pinentry[12];
unsigned int ux_key;
unsigned int ux_type;
ux_menu_entry_t ui_dogsays[2] ;
#ifdef GPG_DEBUG
unsigned char print;
@ -240,10 +278,6 @@ typedef struct gpg_v_state_s gpg_v_state_t;
/* --- IDentifiers --- */
#define ID_PW1 1
#define ID_PW2 2
#define ID_PW3 3
#define ID_RC 4
#define ID_AUTH 1
#define ID_DEC 2
@ -256,6 +290,17 @@ typedef struct gpg_v_state_s gpg_v_state_t;
#define IO_OFFSET_END (unsigned int)-1
#define IO_OFFSET_MARK (unsigned int)-2
#define PIN_ID_PW1 0x81
#define PIN_ID_PW2 0x82
#define PIN_ID_PW3 0x83
#define PIN_ID_RC 0x84
#define PIN_MODE_HOST 1
#define PIN_MODE_SCREEN 2
#define PIN_MODE_CONFIRM 3
#define PIN_MODE_TRUST 4
/* --- INS --- */
#define INS_SELECT 0xa4
@ -269,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

155
src/gpg_ux_blue.c Normal file
View file

@ -0,0 +1,155 @@
/* 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"
#include "os_io_seproxyhal.h"
#include "string.h"
#include "glyphs.h"
/* ----------------------------------------------------------------------- */
/* --- Blue UI layout --- */
/* ----------------------------------------------------------------------- */
/* screeen size:
blue; 320x480
nanoS: 128x32
*/
#if 0
static const bagl_element_t const ui_idle_blue[] = {
{{BAGL_RECTANGLE, 0x00, 0, 60, 320, 420, 0, 0,
BAGL_FILL, 0xf9f9f9, 0xf9f9f9,
0, 0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_RECTANGLE, 0x00, 0, 0, 320, 60, 0, 0,
BAGL_FILL, 0x1d2028, 0x1d2028,
0, 0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_LABEL, 0x00, 20, 0, 320, 60, 0, 0,
BAGL_FILL, 0xFFFFFF, 0x1d2028,
BAGL_FONT_OPEN_SANS_LIGHT_14px | BAGL_FONT_ALIGNMENT_MIDDLE, 0},
"GPG Card",
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_BUTTON | BAGL_FLAG_TOUCHABLE, 0x00, 190, 215, 120, 40, 0, 6,
BAGL_FILL, 0x41ccb4, 0xF9F9F9,
BAGL_FONT_OPEN_SANS_LIGHT_14px | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE,
0},
"Exit",
0,
0x37ae99,
0xF9F9F9,
gpg_io_seproxyhal_touch_exit,
NULL,
NULL},
#ifdef GPG_DEBUG
{{BAGL_BUTTON | BAGL_FLAG_TOUCHABLE, 0x00, 20, 215, 120, 40, 0, 6,
BAGL_FILL, 0x41ccb4, 0xF9F9F9,
BAGL_FONT_OPEN_SANS_LIGHT_14px | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE,
0},
"Init",
0,
0x37ae99,
0xF9F9F9,
gpg_io_seproxyhal_touch_debug,
NULL,
NULL}
#endif
};
const bagl_element_t ui_idle_nanos[] = {
// type
{{BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0,
BAGL_FILL, 0x000000, 0xFFFFFF,
0,
0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL},
{{BAGL_LABELINE, 0x00, 0, 12, 128, 32, 0, 0,
0 , 0xFFFFFF, 0x000000,
BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER,
0 },
"GPGCard",
0,
0,
0,
NULL,
NULL,
NULL },
//{{BAGL_LABELINE , 0x02, 0, 26, 128, 32, 0, 0, 0 , 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_REGULAR_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Waiting for requests...", 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 },
};
unsigned int gpg_io_seproxyhal_touch_exit(const bagl_element_t *e) {
// Go back to the dashboard
os_sched_exit(0);
return 0; // do not redraw the widget
}
unsigned int ui_idle_blue_button(unsigned int button_mask,
unsigned int button_mask_counter) {
return 0;
}
#endif

38
src/gpg_ux_msg.c Normal file
View file

@ -0,0 +1,38 @@
/* 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.
*/
const char * const C_TEMPLATE_TYPE = "Key type";
const char * const C_TEMPLATE_KEY = "Key";
const char * const C_INVALID_SELECTION = "Invalid selection";
const char * const C_OK = "OK";
const char * const C_NOK = "NOK";
const char * const C_WRONG_PIN = "PIN Incorrect";
const char * const C_RIGHT_PIN = "PIN Correct";
const char * const C_PIN_CHANGED = "PIN changed";
const char * const C_PIN_DIFFERS = "2 PINs differs";
const char * const C_PIN_USER = "User PIN";
const char * const C_PIN_ADMIN = "Admin PIN";
const char * const C_VERIFIED = "Verified";
const char * const C_NOT_VERIFIED = "Not Verified";
const char * const C_ALLOWED = "Allowed";
const char * const C_NOT_ALLOWED = "Not Allowed ";
const char * const C_DEFAULT_MODE = "Default mode";
const char * const C_UIF_LOCKED = "UIF locked";

63
src/gpg_ux_msg.h Normal file
View file

@ -0,0 +1,63 @@
/* 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.
*/
#ifndef GPG_UX_MSG_H
#define GPG_UX_MSG_H
extern const char * const C_TEMPLATE_TYPE;
extern const char * const C_TEMPLATE_KEY;
extern const char * const C_INVALID_SELECTION;
extern const char * const C_OK;
extern const char * const C_NOK;
extern const char * const C_WRONG_PIN;
extern const char * const C_RIGHT_PIN;
extern const char * const C_PIN_CHANGED;
extern const char * const C_PIN_DIFFERS ;
extern const char * const C_PIN_USER;
extern const char * const C_PIN_ADMIN;
extern const char * const C_VERIFIED;
extern const char * const C_NOT_VERIFIED;
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)
#define TEMPLATE_KEY PICSTR(C_TEMPLATE_KEY)
#define INVALID_SELECTION PICSTR(C_INVALID_SELECTION)
#define OK PICSTR(C_OK)
#define NOK PICSTR(C_NOK)
#define WRONG_PIN PICSTR(C_WRONG_PIN)
#define RIGHT_PIN PICSTR(C_RIGHT_PIN)
#define PIN_CHANGED PICSTR(C_PIN_CHANGED)
#define PIN_DIFFERS PICSTR(C_PIN_DIFFERS)
#define PIN_USER PICSTR(C_PIN_USER)
#define PIN_ADMIN PICSTR(C_PIN_ADMIN)
#define VERIFIED PICSTR(C_VERIFIED)
#define NOT_VERIFIED PICSTR(C_NOT_VERIFIED)
#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

1081
src/gpg_ux_nanos.c Normal file

File diff suppressed because it is too large Load diff

26
src/gpg_ux_nanos.h Normal file
View file

@ -0,0 +1,26 @@
/* 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.
*/
#ifndef GPG_UX_NANOS_H
#define GPG_UX_NANOS_H
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

View file

@ -18,6 +18,7 @@
#include "os.h"
#include "cx.h"
#include "os_io_seproxyhal.h"
#include "gpg_types.h"
#include "gpg_api.h"
@ -39,5 +40,5 @@ extern gpg_nv_state_t N_state_pic;
extern int apdu_n;
#endif
extern ux_state_t ux;
#endif

1057
src/sdk/usbd_ccid_cmd.c Executable file

File diff suppressed because it is too large Load diff

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

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

32
src/sdk/usbd_ccid_impl.h Normal file
View 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
View 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
View 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>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
#pragma message "Override SDK source file :" __FILE__
#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
View 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

View file

@ -1,454 +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>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* 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 */
static const uint8_t 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. */
0x01, /* 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*/
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 (USBD_CfgDesc);
return (uint8_t*)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 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

View file

@ -1,22 +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
#endif // USBD_CCID_IMPL_H