Add NanoX support

- embed shake256 as NanoX bug workarround
- replace 'C' by 'C' in PIN Entry
- fix the fact cx_hash does not accept any more NULL as output buff
- add clang formatter
pull/56/head
cslashm 5 years ago
parent f92dd4730c
commit 72df4f7d20

@ -0,0 +1,119 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
#AlignConsecutiveMacros: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
#AllowAllArgumentsOnNextLine: false
#AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
#AllowShortLambdasOnASingleLine: None
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: false
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: BeforeHash
IndentWidth: 2
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
RawStringFormats:
- Delimiter: pb
Language: TextProto
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

@ -21,12 +21,11 @@ $(error Environment variable BOLOS_SDK is not set)
endif endif
include $(BOLOS_SDK)/Makefile.defines include $(BOLOS_SDK)/Makefile.defines
APP_LOAD_PARAMS=--appFlags 0x40 --path "2152157255'" --curve secp256k1 $(COMMON_LOAD_PARAMS) APP_LOAD_PARAMS=--appFlags 0x240 --path "2152157255'" --curve secp256k1 $(COMMON_LOAD_PARAMS)
ifeq ($(MULTISLOT),) ifeq ($(MULTISLOT),)
MULTISLOT := 0 MULTISLOT := 0
endif endif
ifeq ($(MULTISLOT),0) ifeq ($(MULTISLOT),0)
GPG_MULTISLOT:=0 GPG_MULTISLOT:=0
APPNAME:=OpenPGP APPNAME:=OpenPGP
@ -35,22 +34,36 @@ GPG_MULTISLOT:=1
APPNAME:=OpenPGP.XL APPNAME:=OpenPGP.XL
endif endif
APP_LOAD_PARAMS=--appFlags 0x40 --path "2152157255'" --curve secp256k1 $(COMMON_LOAD_PARAMS) ifeq ($(TARGET_NAME),TARGET_BLUE)
ICONNAME = images/icon_monero_blue.gif
SPECVERSION:="3.3.1" else ifeq ($(TARGET_NAME),TARGET_NANOX)
ICONNAME = images/icon_pgp_nanox.gif
else
ICONNAME = images/icon_pgp.gif
endif
APPVERSION_M:=1 APPVERSION_M:=1
APPVERSION_N:=3 APPVERSION_N:=3
APPVERSION_P:=1 APPVERSION_P:=2
APPVERSION:=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APPVERSION:=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
SPECVERSION:="3.3.1"
ifeq ($(TARGET_NAME),TARGET_BLUE) DEFINES += $(OPENPGP_CONFIG)
ICONNAME=images/icon_pgp_blue.gif DEFINES += OPENPGP_VERSION_MAJOR=$(APPVERSION_M) OPENPGP_VERSION_MINOR=$(APPVERSION_N) OPENPGP_VERSION_MICRO=$(APPVERSION_P)
DEFINES += OPENPGP_VERSION=$(APPVERSION)
DEFINES += OPENPGP_NAME=$(APPNAME)
DEFINES += SPEC_VERSION=$(SPECVERSION)
DEFINES += GPG_MULTISLOT=$(GPG_MULTISLOT)
ifeq ($(TARGET_NAME),TARGET_NANOX)
DEFINES += UI_NANO_X
DEFINES += GPG_SHAKE256
else ifeq ($(TARGET_NAME),TARGET_BLUE)
DEFINES += UI_BLUE
else else
ICONNAME=images/icon_pgp.gif DEFINES += UI_NANO_S
endif endif
DEFINES += GPG_MULTISLOT=$(GPG_MULTISLOT) $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME) SPEC_VERSION=$(SPECVERSION)
################ ################
# Default rule # # Default rule #
@ -82,18 +95,51 @@ ifneq ($(NO_CONSENT),)
DEFINES += NO_CONSENT DEFINES += NO_CONSENT
endif endif
DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += OS_IO_SEPROXYHAL
DEFINES += HAVE_BAGL HAVE_SPRINTF 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_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
#DEFINES += HAVE_BLE DEFINES += CUSTOM_IO_APDU_BUFFER_SIZE=\(255+5+64\)
DEFINES += USB_SEGMENT_SIZE=64
DEFINES += U2F_PROXY_MAGIC=\"MOON\"
#DEFINES += HAVE_IO_U2F HAVE_U2F
DEFINES += UNUSED\(x\)=\(void\)x DEFINES += UNUSED\(x\)=\(void\)x
DEFINES += APPVERSION=\"$(APPVERSION)\" DEFINES += APPVERSION=\"$(APPVERSION)\"
DEFINES += CUSTOM_IO_APDU_BUFFER_SIZE=\(255+5+64\)
DEFINES += HAVE_USB_CLASS_CCID DEFINES += HAVE_USB_CLASS_CCID
ifeq ($(TARGET_NAME),TARGET_NANOX)
# DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000
# DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300
DEFINES += HAVE_GLO096
DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64
DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX
DEFINES += HAVE_UX_FLOW
else
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128
endif
# Enabling debug PRINTF
DEBUG = 0
ifneq ($(DEBUG),0)
ifeq ($(TARGET_NAME),TARGET_NANOX)
DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf
else
DEFINES += HAVE_PRINTF PRINTF=screen_printf
endif
else
DEFINES += PRINTF\(...\)=
endif
############## ##############
# Compiler # # Compiler #
############## ##############
@ -118,8 +164,15 @@ include $(BOLOS_SDK)/Makefile.glyphs
### variables processed by the common makefile.rules of the SDK to grab source files and include dirs ### variables processed by the common makefile.rules of the SDK to grab source files and include dirs
APP_SOURCE_PATH += src APP_SOURCE_PATH += src
SDK_SOURCE_PATH += lib_stusb SDK_SOURCE_PATH += lib_stusb lib_stusb_impl
#SDK_SOURCE_PATH += lib_u2f
ifeq ($(TARGET_NAME),TARGET_NANOX)
SDK_SOURCE_PATH += lib_ux
endif
cformat:
clang-format -i src/*.c src/*.h
load: all load: all
cp -a release/$(APPNAME).elf bin/app.elf cp -a release/$(APPNAME).elf bin/app.elf
@ -137,9 +190,12 @@ exit:
delete: delete:
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS) python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
# import generic rules from the sdk # import generic rules from the sdk
include Makefile.rules include Makefile.rules
#add dependency on custom makefile filename #add dependency on custom makefile filename
dep/%.d: %.c Makefile dep/%.d: %.c Makefile

@ -1,14 +1,14 @@
## GnuPG application: blue-app-gnupg ## GnuPG application: blue-app-gnupg
GnuPG application for Ledger Blue and Nano S GnuPG application for Nano S and Nano X
This application implements "The OpenPGP card" specification revision 3.0. This specification is available in *doc* directory and at https://g10code.com/p-card.html . This application implements "The OpenPGP card" specification revision 3.0. This specification is available in *doc* directory and at https://g10code.com/p-card.html .
The application supports: The application supports:
- RSA with key up to 4096 bits - RSA with key up to 4096 bits
- ECDSA with secp256k1, secp256r1, brainpool 256r1 and brainpool 256t1 curves - ECDSA with secp256k1
- EDDSA with Ed25519 curve - EDDSA with Ed25519 curve
- ECDH with secp256k1, secp256r1, brainpool 256r1, brainpool 256t1 and curve25519 curves - ECDH with secp256k1 and curve25519 curves
This release has known missing parts (see also Add-on) : This release has known missing parts (see also Add-on) :

@ -1130,7 +1130,8 @@ using ``--xx-pin`` may compromise your pin codes.
Then you must precise if you want a backup or a restore with ``--backup`` or ``--restore`` Then you must precise if you want a backup or a restore with ``--backup`` or ``--restore``
By default backup is performed without saving keys, assuming you use the seed mode. By default backup is performed without saving keys, assuming you use the seed mode.
If you also want to backup keys you have to pass the ``--backup-keys`` option. If you also want to backup keys you have to pass the ``--backup-keys`` option.
In a general manner it is better to also save your keys with ``--backup-keys`` option.
Note that backup and restore works on current slot, so you have to perform a backup per slot Note that backup and restore works on current slot, so you have to perform a backup per slot
even if some data are shared. You can precise the slot/backup to restore with ``--slot`` even if some data are shared. You can precise the slot/backup to restore with ``--slot``
@ -1140,23 +1141,25 @@ even if some data are shared. You can precise the slot/backup to restore with ``
Backup and Restore example Backup and Restore example
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
First you must have the path of the `ledger-app-openpgp-card/pytools` in your PYTHONPATH.
full backup command: full backup command:
| ``python3 -m gpgcard.gpgcli --backup --pinpad --backup-keys`` | ``python3 -m gpgcard.gpgcli --backup --pinpad --backup-keys --file my_bck_file_name.pickle``
backup command without private keys: backup command without private keys:
| ``python3 -m gpgcard.gpgcli --backup --pinpad `` | ``python3 -m gpgcard.gpgcli --backup --pinpad --file my_bck_file_name.pickle``
full restore command: full restore command:
| ``python3 -m gpgcard.gpgcli --backup --pinpad`` | ``python3 -m gpgcard.gpgcli --backup --pinpad --file my_bck_file_name.pickle``
full restore command with seed key generation: full restore command with seed key generation:
| ``python3 -m gpgcard.gpgcli --backup --pinpad --seed`` | ``python3 -m gpgcard.gpgcli --backup --pinpad --seed --file my_bck_file_name.pickle``
Restore without backup Restore without backup
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

@ -62,6 +62,7 @@ class GPGCardExcpetion(Exception):
class GPGCard() : class GPGCard() :
def __init__(self): def __init__(self):
self.reset() self.reset()
self.log = False
def reset(self): def reset(self):
#token info #token info
@ -158,29 +159,43 @@ class GPGCard() :
cond = False cond = False
return resp,sw return resp,sw
def log_apdu(self,l):
self.log = l
def alog(self, m,dt,sw=0):
if self.log:
print("%s %.04x %s"%(m,sw,''.join(["%.02x"%b for b in dt])))
def _exchange_pcsc(self,apdu, data=None, sw_expected=0x9000, sw_mask=0xFFFF): def _exchange_pcsc(self,apdu, data=None, sw_expected=0x9000, sw_mask=0xFFFF):
if data: if data:
data = [x for x in data] data = [x for x in data]
apdu = [x for x in apdu] apdu = [x for x in apdu]
#send #send
if data: if data:
while len(data) > 0xFE: while len(data) > 0xFE:
apdux = apdu[0:5]+[0xfe]+data[0:0xFE] apdux = apdu[0:5]+[0xfe]+data[0:0xFE]
apdux[0] |= 0x10 apdux[0] |= 0x10
self.alog('send', apdux)
resp, sw1, sw2 = self.connection.transmit(apdux) resp, sw1, sw2 = self.connection.transmit(apdux)
sw = (sw1<<8)|sw2 sw = (sw1<<8)|sw2
self.alog('recv',resp,sw)
if sw != 0x9000: if sw != 0x9000:
return resp,sw return resp,sw
data = data[0xFE:] data = data[0xFE:]
apdu = apdu+[len(data)]+data apdu = apdu+[len(data)]+data
self.alog('send', apdu)
resp, sw1, sw2 = self.connection.transmit(apdu) resp, sw1, sw2 = self.connection.transmit(apdu)
sw = (sw1<<8)|sw2
self.alog('recv', resp, sw)
#receive #receive
while sw1==0x61: while sw1==0x61:
apdu = binascii.unhexlify(b"00c00000%.02x"%sw2) apdu = binascii.unhexlify(b"00c00000%.02x"%sw2)
apdu = [x for x in apdu] apdu = [x for x in apdu]
self.alog('send', apdu)
resp2, sw1, sw2 = self.connection.transmit(apdu) resp2, sw1, sw2 = self.connection.transmit(apdu)
sw = (sw1<<8)|sw2
self.alog('recv', resp2, sw)
resp = resp + resp2 resp = resp + resp2
resp = bytes(resp) resp = bytes(resp)
sw = (sw1<<8)|sw2 sw = (sw1<<8)|sw2
@ -315,6 +330,7 @@ class GPGCard() :
self.dec_key,sw = self.get_data(0x00B8) self.dec_key,sw = self.get_data(0x00B8)
self.aut_key,sw = self.get_data(0x00A4) self.aut_key,sw = self.get_data(0x00A4)
return True return True
def set_all(self): def set_all(self):
@ -353,6 +369,7 @@ class GPGCard() :
self.put_data(0xd8, self.UIF_AUT) self.put_data(0xd8, self.UIF_AUT)
if len(self.sig_key): if len(self.sig_key):
print('COUCOU')
self.put_data(0x00B6, self.sig_key) self.put_data(0x00B6, self.sig_key)
if len(self.dec_key): if len(self.dec_key):
self.put_data(0x00B8, self.dec_key) self.put_data(0x00B8, self.dec_key)
@ -362,7 +379,7 @@ class GPGCard() :
def _backup_file_name(self,file_name): def _backup_file_name(self,file_name):
return file_name+"_slot%d"%(self.slot[0]+1)+".pickle" return file_name #file_name+"_slot%d"%(self.slot[0]+1)+".pickle"
def backup(self, file_name, with_key=False): def backup(self, file_name, with_key=False):
self.get_all(with_key) self.get_all(with_key)
@ -397,7 +414,7 @@ class GPGCard() :
self.sig_date, self.dec_date, self.aut_date, self.sig_date, self.dec_date, self.aut_date,
self.cardholder_cert, self.cardholder_cert,
self.UIF_SIG, self.UIF_DEC, self.UIF_AUT, self.UIF_SIG, self.UIF_DEC, self.UIF_AUT,
self.sig_key, self.dec_key, self.aut_key) = pickle.load(f) self.sig_key, self.dec_key, self.aut_key) = pickle.load(f)
self.set_all() self.set_all()
return True return True

@ -39,7 +39,8 @@ Template identifiers are ed2559, cv25519, rsa2048, rsa3072, rsa4096.
parser.add_argument('--set-fingerprints', metavar='SIG:DEC:AUT', help='sig:dec:aut fingerprints, 20 bytes each in hexa') parser.add_argument('--set-fingerprints', metavar='SIG:DEC:AUT', help='sig:dec:aut fingerprints, 20 bytes each in hexa')
parser.add_argument('--seed-key', help='Regenerate all keys, based on seed mode', action='store_true') parser.add_argument('--seed-key', help='Regenerate all keys, based on seed mode', action='store_true')
parser.add_argument('--slot', metavar='SLOT', help='slot to backup', type=int, default=1) parser.add_argument('--slot', metavar='SLOT', help='slot to backup', type=int, default=1)
parser.add_argument('--user-pin', metavar='PIN', help='User PIN, if pinpad not used') parser.add_argument('--user-pin', metavar='PIN', help='User PIN, if pinpad not used'),
parser.add_argument('--apdu', help='Log APDU exchange', action='store_true')
return parser return parser
def banner(): def banner():
@ -74,6 +75,8 @@ try:
print("Connect to card %s..."%args.reader, end='', flush=True) print("Connect to card %s..."%args.reader, end='', flush=True)
gpgcard = GPGCard() gpgcard = GPGCard()
if args.apdu:
gpgcard.log_apdu(args.apdu)
gpgcard.connect(args.reader) gpgcard.connect(args.reader)
print("OK") print("OK")

@ -1,167 +0,0 @@
/*******************************************************************************
* Ledger Blue - Secure firmware
* (c) 2016, 2017 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
/**
* Global chip memory layout and constants
*
*/
MEMORY
{
DISCARD (rwx) : ORIGIN = 0xd0000000, LENGTH = 1M
FLASH (rx) : ORIGIN = 0xc0d00000, LENGTH = 400K
SRAM (rwx) : ORIGIN = 0x20001800, LENGTH = 4K
}
PAGE_SIZE = 64;
STACK_SIZE = 768;
END_STACK = ORIGIN(SRAM) + LENGTH(SRAM);
SECTIONS
{
ENTRY(main)
/****************************************************************/
/* This section locates the code in FLASH */
/****************************************************************/
/** put text in Flash memory, VMA will be equal to LMA */
.text :
{
/* provide start code symbol, shall be zero */
_text = .;
_nvram = .;
PROVIDE(_setjmp = setjmp); /*thanks clang*/
/* ensure main is always @ 0xC0D00000 */
*(.boot*)
/* place the other code and rodata defined BUT nvram variables that are displaced in a r/w area */
*(.text*)
*(.rodata.[^UN]*) /*.data.rel.ro* not here to detect invalid PIC usage */
*(.rodata.N[^_]*)
. = ALIGN(4);
/* all code placed */
_etext = .;
. = ALIGN(PAGE_SIZE);
_nvram_data = .;
/* NVM data (ex-filesystem) */
*(.rodata.USBD_CfgDesc)
*(.bss.N_* .rodata.N_* .rodata.USBD_CfgDesc)
. = ALIGN(PAGE_SIZE);
_install_parameters = .;
PROVIDE(N_install_parameters = .);
_envram = .;
_nvram_data_size = _envram - _nvram_data;
} > FLASH = 0x00
.data (NOLOAD):
{
. = ALIGN(4);
/**
* Place RAM initialized variables
*/
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > DISCARD /*> SRAM AT>FLASH = 0x00 */
.bss :
{
/**
* Place RAM uninitialized variables
*/
_bss = .;
*(.bss*)
_ebss = .;
/**
* Reserve stack size
*/
. = ALIGN(4);
app_stack_canary = .;
PROVIDE(app_stack_canary = .);
. += 4;
_stack = .;
. = _stack + STACK_SIZE;
PROVIDE( _stack_size = STACK_SIZE );
PROVIDE( _estack = ABSOLUTE(END_STACK) );
} > SRAM = 0x00
/****************************************************************/
/* DEBUG */
/****************************************************************/
/* remove the debugging information from the standard libraries */
DEBUG (NOLOAD) :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

@ -1,30 +0,0 @@
#include "glyphs.h"
unsigned int const C_badge_back_colors[]
= {
0x00000000,
0x00ffffff,
};
unsigned char const C_badge_back_bitmap[] = {
0xe0, 0x01, 0xfe, 0xc1, 0xfd, 0x38, 0x7f, 0x06, 0xdf, 0x81, 0xff, 0xc4, 0x7f, 0xf3, 0xff, 0xbc,
0x1f, 0xe7, 0xe7, 0xf1, 0x3f, 0xf8, 0x07, 0x78, 0x00, };
#ifdef OS_IO_SEPROXYHAL
#include "os_io_seproxyhal.h"
const bagl_icon_details_t C_badge_back = { GLYPH_badge_back_WIDTH, GLYPH_badge_back_HEIGHT, 1, C_badge_back_colors, C_badge_back_bitmap };
#endif // OS_IO_SEPROXYHAL
#include "glyphs.h"
unsigned int const C_icon_dashboard_colors[]
= {
0x00000000,
0x00ffffff,
};
unsigned char const C_icon_dashboard_bitmap[] = {
0xe0, 0x01, 0xfe, 0xc1, 0xff, 0x38, 0x70, 0x06, 0xd8, 0x79, 0x7e, 0x9e, 0x9f, 0xe7, 0xe7, 0xb9,
0x01, 0xe6, 0xc0, 0xf1, 0x3f, 0xf8, 0x07, 0x78, 0x00, };
#ifdef OS_IO_SEPROXYHAL
#include "os_io_seproxyhal.h"
const bagl_icon_details_t C_icon_dashboard = { GLYPH_icon_dashboard_WIDTH, GLYPH_icon_dashboard_HEIGHT, 1, C_icon_dashboard_colors, C_icon_dashboard_bitmap };
#endif // OS_IO_SEPROXYHAL

@ -1,30 +0,0 @@
#ifndef GLYPH_badge_back_BPP
#define GLYPH_badge_back_WIDTH 14
#define GLYPH_badge_back_HEIGHT 14
#define GLYPH_badge_back_BPP 1
extern
unsigned int const C_badge_back_colors[]
;
extern
unsigned char const C_badge_back_bitmap[];
#ifdef OS_IO_SEPROXYHAL
#include "os_io_seproxyhal.h"
extern
const bagl_icon_details_t C_badge_back;
#endif // GLYPH_badge_back_BPP
#endif // OS_IO_SEPROXYHAL
#ifndef GLYPH_icon_dashboard_BPP
#define GLYPH_icon_dashboard_WIDTH 14
#define GLYPH_icon_dashboard_HEIGHT 14
#define GLYPH_icon_dashboard_BPP 1
extern
unsigned int const C_icon_dashboard_colors[]
;
extern
unsigned char const C_icon_dashboard_bitmap[];
#ifdef OS_IO_SEPROXYHAL
#include "os_io_seproxyhal.h"
extern
const bagl_icon_details_t C_icon_dashboard;
#endif // GLYPH_icon_dashboard_BPP
#endif // OS_IO_SEPROXYHAL

@ -14,81 +14,92 @@
*/ */
#ifndef GPG_API_H #ifndef GPG_API_H
#define GPG_API_H #define GPG_API_H
void USBD_CCID_activate_pinpad(int enabled); void USBD_CCID_activate_pinpad(int enabled);
unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len); unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len);
unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len); unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len);
unsigned int gpg_curve2domainlen(unsigned int cv); unsigned int gpg_curve2domainlen(unsigned int cv);
void gpg_init(void); void gpg_init(void);
void gpg_init_ux(void); void gpg_init_ux(void);
int gpg_install(unsigned char app_state) ; int gpg_install(unsigned char app_state);
int gpg_dispatch(void); int gpg_dispatch(void);
int gpg_apdu_select_data(unsigned int ref, int reccord) ; int gpg_apdu_select_data(unsigned int ref, int reccord);
int gpg_apdu_get_data(unsigned int ref) ; int gpg_apdu_get_data(unsigned int ref);
int gpg_apdu_get_next_data(unsigned int ref) ; int gpg_apdu_get_next_data(unsigned int ref);
int gpg_apdu_put_data(unsigned int ref) ; int gpg_apdu_put_data(unsigned int ref);
int gpg_apdu_get_key_data(unsigned int ref); int gpg_apdu_get_key_data(unsigned int ref);
int gpg_apdu_put_key_data(unsigned int ref); int gpg_apdu_put_key_data(unsigned int ref);
void gpg_pso_derive_slot_seed(int slot, unsigned char *seed); void gpg_pso_derive_slot_seed(int slot, unsigned char *seed);
void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx, void gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned char *Ski, unsigned int Ski_len); unsigned char *key_name,
unsigned int idx,
unsigned char *Ski,
unsigned int Ski_len);
int gpg_apdu_pso(void); int gpg_apdu_pso(void);
int gpg_apdu_internal_authenticate(void); int gpg_apdu_internal_authenticate(void);
int gpg_apdu_gen(void ); int gpg_apdu_gen(void);
int gpg_apdu_get_challenge(void) ; int gpg_apdu_get_challenge(void);
int gpg_apdu_select(void) ; int gpg_apdu_select(void);
int gpg_apdu_verify(void) ; int gpg_apdu_verify(void);
int gpg_apdu_change_ref_data(void) ; int gpg_apdu_change_ref_data(void);
int gpg_apdu_reset_retry_counter(void) ; int gpg_apdu_reset_retry_counter(void);
gpg_pin_t *gpg_pin_get_pin(int id); gpg_pin_t *gpg_pin_get_pin(int id);
int gpg_pin_is_blocked(gpg_pin_t *pin); int gpg_pin_is_blocked(gpg_pin_t *pin);
int gpg_pin_is_verified(int pinID); int gpg_pin_is_verified(int pinID);
int gpg_pin_set_verified(int pinID, int verified); 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); int gpg_pin_check(gpg_pin_t *pin, int pinID, unsigned char *pin_val, unsigned int pin_len);
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len); void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
int gpg_mse_reset(); int gpg_mse_reset();
int gpg_apdu_mse(); int gpg_apdu_mse();
#ifdef GPG_SHAKE256
void cx_shake256_init(cx_sha3_t *hash, unsigned int out_length);
void cx_shake256_update(cx_sha3_t *ctx, const uint8_t *data, size_t len);
int cx_shake256_final(cx_sha3_t *hash, uint8_t *digest);
#endif
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- IO ---- */ /* --- IO ---- */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
void gpg_io_discard(int clear) ; void gpg_io_discard(int clear);
void gpg_io_clear(void); void gpg_io_clear(void);
void gpg_io_set_offset(unsigned int offset) ; void gpg_io_set_offset(unsigned int offset);
void gpg_io_mark(void) ; void gpg_io_mark(void);
void gpg_io_rewind(void) ; void gpg_io_rewind(void);
void gpg_io_hole(unsigned int sz) ; void gpg_io_hole(unsigned int sz);
void gpg_io_inserted(unsigned int len); void gpg_io_inserted(unsigned int len);
void gpg_io_insert(unsigned char const * buffer, unsigned int len) ; void gpg_io_insert(unsigned char const *buffer, unsigned int len);
void gpg_io_insert_u32(unsigned int v32) ; void gpg_io_insert_u32(unsigned int v32);
void gpg_io_insert_u24(unsigned int v24) ; void gpg_io_insert_u24(unsigned int v24);
void gpg_io_insert_u16(unsigned int v16) ; void gpg_io_insert_u16(unsigned int v16);
void gpg_io_insert_u8(unsigned int v8) ; void gpg_io_insert_u8(unsigned int v8);
void gpg_io_insert_t(unsigned int T) ; void gpg_io_insert_t(unsigned int T);
void gpg_io_insert_tl(unsigned int T, unsigned int L) ; void gpg_io_insert_tl(unsigned int T, unsigned int L);
void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) ; 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) ; void gpg_io_fetch_buffer(unsigned char *buffer, unsigned int len);
unsigned int gpg_io_fetch_u32(void) ; unsigned int gpg_io_fetch_u32(void);
unsigned int gpg_io_fetch_u24(void) ; unsigned int gpg_io_fetch_u24(void);
unsigned int gpg_io_fetch_u16(void) ; unsigned int gpg_io_fetch_u16(void);
unsigned int gpg_io_fetch_u8(void) ; unsigned int gpg_io_fetch_u8(void);
int gpg_io_fetch_t(unsigned int *T) ; int gpg_io_fetch_t(unsigned int *T);
int gpg_io_fetch_l(unsigned int *L) ; int gpg_io_fetch_l(unsigned int *L);
int gpg_io_fetch_tl(unsigned int *T, unsigned int *L) ; 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_nv(unsigned char *buffer, int len);
int gpg_io_fetch(unsigned char* buffer, int len) ; int gpg_io_fetch(unsigned char *buffer, int len);
int gpg_io_do(unsigned int io_flags) ; int gpg_io_do(unsigned int io_flags);
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- TMP ---- */ /* --- TMP ---- */
@ -99,12 +110,12 @@ void io_usb_ccid_set_card_inserted(unsigned int inserted);
/* --- DEBUG ---- */ /* --- DEBUG ---- */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
#error "UNSUPPORTDED: to be fixed"
#include "gpg_debug.h" #include "gpg_debug.h"
#else #else
#define gpg_nvm_write nvm_write #define gpg_nvm_write nvm_write
#define gpg_io_exchange io_exchange #define gpg_io_exchange io_exchange
#endif #endif

@ -20,10 +20,10 @@
#include "gpg_vars.h" #include "gpg_vars.h"
int gpg_apdu_get_challenge() { int gpg_apdu_get_challenge() {
unsigned int olen,hlen; unsigned int olen, hlen;
if ((G_gpg_vstate.io_p1&0x80) == 0x80) { if ((G_gpg_vstate.io_p1 & 0x80) == 0x80) {
olen = G_gpg_vstate.io_p2; olen = G_gpg_vstate.io_p2;
} else { } else {
olen = G_gpg_vstate.io_le; olen = G_gpg_vstate.io_le;
} }
@ -31,36 +31,36 @@ int gpg_apdu_get_challenge() {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH; return SW_WRONG_LENGTH;
} }
if ((G_gpg_vstate.io_p1&0x82) == 0x82) {
unsigned int path[2];
unsigned char chain[32];
unsigned char Sr[32];
os_memset(chain, 0, 32); if ((G_gpg_vstate.io_p1 & 0x82) == 0x82) {
unsigned int path[2];
unsigned char chain[32];
unsigned char Sr[32];
os_memset(chain, 0, 32);
path[0] = 0x80475047; path[0] = 0x80475047;
path[1] = 0x0F0F0F0F; path[1] = 0x0F0F0F0F;
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2 , Sr, chain); os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2, Sr, chain);
chain[0] = 'r'; chain[1]='n'; chain[2] = 'd'; chain[0] = 'r';
chain[1] = 'n';
chain[2] = 'd';
cx_sha256_init(&G_gpg_vstate.work.md.sha256); cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL, 0); 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); cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL, 0);
hlen=cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, hlen = cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, CX_LAST, G_gpg_vstate.work.io_buffer,
CX_LAST, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, G_gpg_vstate.io_length, G_gpg_vstate.work.io_buffer, 32);
G_gpg_vstate.work.io_buffer, 32);
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen); cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3, cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3, CX_LAST, G_gpg_vstate.work.io_buffer, hlen,
CX_LAST, G_gpg_vstate.work.io_buffer, hlen, G_gpg_vstate.work.io_buffer, olen);
G_gpg_vstate.work.io_buffer,olen);
} else { } else {
cx_rng(G_gpg_vstate.work.io_buffer, olen); cx_rng(G_gpg_vstate.work.io_buffer, olen);
} }
if ((G_gpg_vstate.io_p1&0x81) == 0x81) { if ((G_gpg_vstate.io_p1 & 0x81) == 0x81) {
cx_math_next_prime(G_gpg_vstate.work.io_buffer,olen); cx_math_next_prime(G_gpg_vstate.work.io_buffer, olen);
} }
gpg_io_discard(0); gpg_io_discard(0);
gpg_io_inserted(olen); gpg_io_inserted(olen);
return SW_OK; return SW_OK;

@ -19,22 +19,20 @@
#include "gpg_api.h" #include "gpg_api.h"
#include "gpg_vars.h" #include "gpg_vars.h"
int gpg_apdu_select_data(unsigned int ref, int reccord) { int gpg_apdu_select_data(unsigned int ref, int reccord) {
G_gpg_vstate.DO_current = ref; G_gpg_vstate.DO_current = ref;
G_gpg_vstate.DO_reccord = reccord; G_gpg_vstate.DO_reccord = reccord;
G_gpg_vstate.DO_offset = 0; G_gpg_vstate.DO_offset = 0;
return SW_OK; return SW_OK;
} }
int gpg_apdu_get_data(unsigned int ref) { int gpg_apdu_get_data(unsigned int ref) {
int sw; int sw;
if (G_gpg_vstate.DO_current != ref) { if (G_gpg_vstate.DO_current != ref) {
G_gpg_vstate.DO_current = ref; G_gpg_vstate.DO_current = ref;
G_gpg_vstate.DO_reccord = 0; G_gpg_vstate.DO_reccord = 0;
G_gpg_vstate.DO_offset = 0; G_gpg_vstate.DO_offset = 0;
} }
sw = SW_OK; sw = SW_OK;
@ -54,11 +52,11 @@ int gpg_apdu_get_data(unsigned int ref) {
gpg_io_insert(N_gpg_pstate->private_DO4.value, N_gpg_pstate->private_DO4.length); gpg_io_insert(N_gpg_pstate->private_DO4.value, N_gpg_pstate->private_DO4.length);
break; break;
/* ----------------- Config key slot ----------------- */ /* ----------------- Config key slot ----------------- */
case 0x01F0: case 0x01F0:
gpg_io_insert(N_gpg_pstate->config_slot, 3); gpg_io_insert(N_gpg_pstate->config_slot, 3);
gpg_io_insert_u8(G_gpg_vstate.slot); gpg_io_insert_u8(G_gpg_vstate.slot);
break; break;
case 0x01F1: case 0x01F1:
gpg_io_insert(N_gpg_pstate->config_slot, 3); gpg_io_insert(N_gpg_pstate->config_slot, 3);
break; break;
@ -67,10 +65,10 @@ int gpg_apdu_get_data(unsigned int ref) {
break; break;
/* ----------------- Config RSA exponent ----------------- */ /* ----------------- Config RSA exponent ----------------- */
case 0x01F8: case 0x01F8:
gpg_io_insert(N_gpg_pstate->default_RSA_exponent,4); gpg_io_insert(N_gpg_pstate->default_RSA_exponent, 4);
break; break;
/* ----------------- Application ----------------- */ /* ----------------- Application ----------------- */
/* Full Application identifier */ /* Full Application identifier */
case 0x004F: case 0x004F:
gpg_io_insert(N_gpg_pstate->AID, 10); gpg_io_insert(N_gpg_pstate->AID, 10);
@ -97,28 +95,26 @@ int gpg_apdu_get_data(unsigned int ref) {
break; break;
/* Name, Language, Sex */ /* Name, Language, Sex */
case 0x65: case 0x65:
gpg_io_insert_tlv(0x5B, N_gpg_pstate->name.length, N_gpg_pstate->name.value); gpg_io_insert_tlv(0x5B, N_gpg_pstate->name.length, N_gpg_pstate->name.value);
gpg_io_insert_tlv(0x5F2D, N_gpg_pstate->lang.length, N_gpg_pstate->lang.value); gpg_io_insert_tlv(0x5F2D, N_gpg_pstate->lang.length, N_gpg_pstate->lang.value);
gpg_io_insert_tlv(0x5F35, 1, N_gpg_pstate->sex); gpg_io_insert_tlv(0x5F35, 1, N_gpg_pstate->sex);
break; break;
/* ----------------- aid, histo, ext_length, ... ----------------- */ /* ----------------- aid, histo, ext_length, ... ----------------- */
case 0x6E: case 0x6E:
gpg_io_insert_tlv(0x4F, 16, N_gpg_pstate->AID); gpg_io_insert_tlv(0x4F, 16, N_gpg_pstate->AID);
os_memmove(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset-6, G_gpg_vstate.kslot->serial, 4); os_memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset - 6, G_gpg_vstate.kslot->serial, 4);
gpg_io_insert_tlv(0x5F52, 15, N_gpg_pstate->histo); gpg_io_insert_tlv(0x5F52, 15, N_gpg_pstate->histo);
gpg_io_insert_tlv(0x7F66, sizeof(C_ext_length), C_ext_length); gpg_io_insert_tlv(0x7F66, sizeof(C_ext_length), C_ext_length);
gpg_io_mark(); gpg_io_mark();
gpg_io_insert_tlv(0xC0, gpg_io_insert_tlv(0xC0, sizeof(C_ext_capabilities), C_ext_capabilities);
sizeof(C_ext_capabilities),
C_ext_capabilities);
gpg_io_insert_tlv(0xC1, G_gpg_vstate.kslot->sig.attributes.length, G_gpg_vstate.kslot->sig.attributes.value); gpg_io_insert_tlv(0xC1, G_gpg_vstate.kslot->sig.attributes.length, G_gpg_vstate.kslot->sig.attributes.value);
gpg_io_insert_tlv(0xC2, G_gpg_vstate.kslot->dec.attributes.length, G_gpg_vstate.kslot->dec.attributes.value); gpg_io_insert_tlv(0xC2, G_gpg_vstate.kslot->dec.attributes.length, G_gpg_vstate.kslot->dec.attributes.value);
gpg_io_insert_tlv(0xC3, G_gpg_vstate.kslot->aut.attributes.length, G_gpg_vstate.kslot->aut.attributes.value); gpg_io_insert_tlv(0xC3, G_gpg_vstate.kslot->aut.attributes.length, G_gpg_vstate.kslot->aut.attributes.value);
gpg_io_insert_tl(0xC4, 7); gpg_io_insert_tl(0xC4, 7);
gpg_io_insert(N_gpg_pstate->PW_status,4); gpg_io_insert(N_gpg_pstate->PW_status, 4);
gpg_io_insert_u8(N_gpg_pstate->PW1.counter); gpg_io_insert_u8(N_gpg_pstate->PW1.counter);
gpg_io_insert_u8(N_gpg_pstate->RC.counter); gpg_io_insert_u8(N_gpg_pstate->RC.counter);
gpg_io_insert_u8(N_gpg_pstate->PW3.counter); gpg_io_insert_u8(N_gpg_pstate->PW3.counter);
@ -135,7 +131,7 @@ int gpg_apdu_get_data(unsigned int ref) {
gpg_io_insert(G_gpg_vstate.kslot->dec.date, 4); gpg_io_insert(G_gpg_vstate.kslot->dec.date, 4);
gpg_io_insert(G_gpg_vstate.kslot->aut.date, 4); gpg_io_insert(G_gpg_vstate.kslot->aut.date, 4);
gpg_io_set_offset(IO_OFFSET_MARK); gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x73, G_gpg_vstate.io_length- G_gpg_vstate.io_offset); gpg_io_insert_tl(0x73, G_gpg_vstate.io_length - G_gpg_vstate.io_offset);
gpg_io_set_offset(IO_OFFSET_END); gpg_io_set_offset(IO_OFFSET_END);
break; break;
@ -152,7 +148,7 @@ int gpg_apdu_get_data(unsigned int ref) {
/* ----------------- Security support template ----------------- */ /* ----------------- Security support template ----------------- */
case 0x7A: case 0x7A:
gpg_io_insert_tl(0x93,3); gpg_io_insert_tl(0x93, 3);
gpg_io_insert_u24(G_gpg_vstate.kslot->sig_count); gpg_io_insert_u24(G_gpg_vstate.kslot->sig_count);
break; break;
@ -160,22 +156,22 @@ int gpg_apdu_get_data(unsigned int ref) {
case 0x7F21: case 0x7F21:
switch (G_gpg_vstate.DO_reccord) { switch (G_gpg_vstate.DO_reccord) {
case 0: case 0:
gpg_io_insert(G_gpg_vstate.kslot->aut.CA.value,G_gpg_vstate.kslot->aut.CA.length); gpg_io_insert(G_gpg_vstate.kslot->aut.CA.value, G_gpg_vstate.kslot->aut.CA.length);
break; break;
case 1: case 1:
gpg_io_insert(G_gpg_vstate.kslot->dec.CA.value,G_gpg_vstate.kslot->dec.CA.length); gpg_io_insert(G_gpg_vstate.kslot->dec.CA.value, G_gpg_vstate.kslot->dec.CA.length);
break; break;
case 2: case 2:
gpg_io_insert(G_gpg_vstate.kslot->sig.CA.value,G_gpg_vstate.kslot->sig.CA.length); gpg_io_insert(G_gpg_vstate.kslot->sig.CA.value, G_gpg_vstate.kslot->sig.CA.length);
break; break;
default : default:
sw = SW_RECORD_NOT_FOUND; sw = SW_RECORD_NOT_FOUND;
} }
break; break;
/* ----------------- PW Status Bytes ----------------- */ /* ----------------- PW Status Bytes ----------------- */
case 0x00C4: case 0x00C4:
gpg_io_insert(N_gpg_pstate->PW_status,4); gpg_io_insert(N_gpg_pstate->PW_status, 4);
gpg_io_insert_u8(N_gpg_pstate->PW1.counter); gpg_io_insert_u8(N_gpg_pstate->PW1.counter);
gpg_io_insert_u8(N_gpg_pstate->RC.counter); gpg_io_insert_u8(N_gpg_pstate->RC.counter);
gpg_io_insert_u8(N_gpg_pstate->PW3.counter); gpg_io_insert_u8(N_gpg_pstate->PW3.counter);
@ -190,7 +186,7 @@ int gpg_apdu_get_data(unsigned int ref) {
return sw; return sw;
} }
int gpg_apdu_get_next_data(unsigned int ref) { int gpg_apdu_get_next_data(unsigned int ref) {
int sw; int sw;
if ((ref != 0x7F21) || (G_gpg_vstate.DO_current != 0x7F21)) { if ((ref != 0x7F21) || (G_gpg_vstate.DO_current != 0x7F21)) {
@ -204,15 +200,15 @@ int gpg_apdu_get_next_data(unsigned int ref) {
} }
int gpg_apdu_put_data(unsigned int ref) { int gpg_apdu_put_data(unsigned int ref) {
unsigned int t,l,sw; unsigned int t, l, sw;
unsigned int *ptr_l; unsigned int * ptr_l;
unsigned char *ptr_v; unsigned char *ptr_v;
G_gpg_vstate.DO_current = ref; G_gpg_vstate.DO_current = ref;
sw = SW_OK; sw = SW_OK;
switch (ref) { switch (ref) {
/* ----------------- Optional DO for private use ----------------- */ /* ----------------- Optional DO for private use ----------------- */
case 0x0101: case 0x0101:
ptr_l = &N_gpg_pstate->private_DO1.length; ptr_l = &N_gpg_pstate->private_DO1.length;
ptr_v = N_gpg_pstate->private_DO1.value; ptr_v = N_gpg_pstate->private_DO1.value;
@ -234,7 +230,7 @@ int gpg_apdu_put_data(unsigned int ref) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return 0; 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_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)); gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK; sw = SW_OK;
break; break;
@ -244,23 +240,22 @@ int gpg_apdu_put_data(unsigned int ref) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return 0; return 0;
} }
if ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +0] != GPG_KEYS_SLOTS) || 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 + 1] >= GPG_KEYS_SLOTS) ||
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +2] > 3)) { (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] > 3)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return 0; return 0;
} }
gpg_nvm_write(N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,3); gpg_nvm_write(N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, 3);
break; break;
case 0x01F2: case 0x01F2:
if ((N_gpg_pstate->config_slot[2] & 2) == 0) { if ((N_gpg_pstate->config_slot[2] & 2) == 0) {
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
return 0; return 0;
} }
if ((G_gpg_vstate.io_length != 1) || if ((G_gpg_vstate.io_length != 1) || (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS)) {
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS)) { THROW(SW_WRONG_DATA);
THROW(SW_WRONG_DATA);
return 0; return 0;
} }
G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset]; G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
@ -272,12 +267,11 @@ int gpg_apdu_put_data(unsigned int ref) {
if (G_gpg_vstate.io_length != 4) { if (G_gpg_vstate.io_length != 4) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return 0; return 0;
} }
e = gpg_io_fetch_u32(); e = gpg_io_fetch_u32();
nvm_write(&N_gpg_pstate->default_RSA_exponent, &e, sizeof(unsigned int)); nvm_write(&N_gpg_pstate->default_RSA_exponent, &e, sizeof(unsigned int));
break; break;
} }
/* ----------------- Serial -----------------*/ /* ----------------- Serial -----------------*/
case 0x4f: case 0x4f:
@ -289,46 +283,48 @@ int gpg_apdu_put_data(unsigned int ref) {
/* ----------------- Extended Header list -----------------*/ /* ----------------- Extended Header list -----------------*/
case 0x3FFF: { case 0x3FFF: {
unsigned int len_e,len_p,len_q; unsigned int len_e, len_p, len_q;
unsigned int endof,ksz,reset_cnt; unsigned int endof, ksz, reset_cnt;
gpg_key_t *keygpg; gpg_key_t * keygpg;
unsigned int dh; unsigned int dh;
//fecth 4D // fecth 4D
gpg_io_fetch_tl(&t,&l); gpg_io_fetch_tl(&t, &l);
if (t!=0x4D) { if (t != 0x4D) {
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0; return 0;
} }
//fecth B8/B6/A4 // fecth B8/B6/A4
gpg_io_fetch_tl(&t,&l); gpg_io_fetch_tl(&t, &l);
dh = 0; dh = 0;
reset_cnt = 0; reset_cnt = 0;
switch(t) { switch (t) {
case 0xB6: case 0xB6:
keygpg = &G_gpg_vstate.kslot->sig; keygpg = &G_gpg_vstate.kslot->sig;
reset_cnt = 0x11111111; reset_cnt = 0x11111111;
break; break;
case 0xA4: case 0xA4:
keygpg = &G_gpg_vstate.kslot->aut; keygpg = &G_gpg_vstate.kslot->aut;
break; break;
case 0xB8: case 0xB8:
keygpg = &G_gpg_vstate.kslot->dec; keygpg = &G_gpg_vstate.kslot->dec;
dh = 0x11; dh = 0x11;
break; break;
default: default:
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0; return 0;
} }
//fecth 7f78 // fecth 7f78
gpg_io_fetch_tl(&t,&l); gpg_io_fetch_tl(&t, &l);
if (t!=0x7f48) { if (t != 0x7f48) {
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0; return 0;
} }
len_e = 0; len_p = 0; len_q = 0; len_e = 0;
endof = G_gpg_vstate.io_offset+l; len_p = 0;
while (G_gpg_vstate.io_offset<endof) { len_q = 0;
gpg_io_fetch_tl(&t,&l); endof = G_gpg_vstate.io_offset + l;
while (G_gpg_vstate.io_offset < endof) {
gpg_io_fetch_tl(&t, &l);
switch (t) { switch (t) {
case 0x91: case 0x91:
len_e = l; len_e = l;
@ -351,50 +347,49 @@ int gpg_apdu_put_data(unsigned int ref) {
return 0; return 0;
} }
} }
//fecth 5f78 // fecth 5f78
gpg_io_fetch_tl(&t,&l); gpg_io_fetch_tl(&t, &l);
if (t!=0x5f48) { if (t != 0x5f48) {
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0; return 0;
} }
// --- RSA KEY --- // --- RSA KEY ---
if (keygpg->attributes.value[0] == 0x01) { if (keygpg->attributes.value[0] == 0x01) {
unsigned int e; unsigned int e;
unsigned char *p,*q,*pq; unsigned char * p, *q, *pq;
cx_rsa_public_key_t *rsa_pub; cx_rsa_public_key_t * rsa_pub;
cx_rsa_private_key_t *rsa_priv, *pkey; cx_rsa_private_key_t *rsa_priv, *pkey;
unsigned int pkey_size; unsigned int pkey_size;
//check length // check length
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2]; ksz = (keygpg->attributes.value[1] << 8) | keygpg->attributes.value[2];
ksz = ksz >> 3; ksz = ksz >> 3;
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa.public; rsa_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; rsa_priv = (cx_rsa_private_key_t *)&G_gpg_vstate.work.rsa.private;
pkey = &keygpg->priv_key.rsa; pkey = &keygpg->priv_key.rsa;
switch(ksz) { switch (ksz) {
case 1024/8: case 1024 / 8:
pkey_size = sizeof(cx_rsa_1024_private_key_t); pkey_size = sizeof(cx_rsa_1024_private_key_t);
pq = G_gpg_vstate.work.rsa.public1024.n; pq = G_gpg_vstate.work.rsa.public1024.n;
break; break;
case 2048/8: case 2048 / 8:
pkey_size = sizeof(cx_rsa_2048_private_key_t); pkey_size = sizeof(cx_rsa_2048_private_key_t);
pq = G_gpg_vstate.work.rsa.public2048.n; pq = G_gpg_vstate.work.rsa.public2048.n;
break; break;
case 3072/8: case 3072 / 8:
pkey_size = sizeof(cx_rsa_3072_private_key_t); pkey_size = sizeof(cx_rsa_3072_private_key_t);
pq = G_gpg_vstate.work.rsa.public3072.n; pq = G_gpg_vstate.work.rsa.public3072.n;
break; break;
case 4096/8: case 4096 / 8:
pkey_size = sizeof(cx_rsa_4096_private_key_t); pkey_size = sizeof(cx_rsa_4096_private_key_t);
pq = G_gpg_vstate.work.rsa.public4096.n; pq = G_gpg_vstate.work.rsa.public4096.n;
break; break;
} }
ksz = ksz>>1; ksz = ksz >> 1;
// fetch e
//fetch e
e = 0; e = 0;
switch(len_e) { switch (len_e) {
case 4: case 4:
e = gpg_io_fetch_u32(); e = gpg_io_fetch_u32();
break; break;
@ -404,65 +399,64 @@ int gpg_apdu_put_data(unsigned int ref) {
case 2: case 2:
e = gpg_io_fetch_u16(); e = gpg_io_fetch_u16();
break; break;
case 1: case 1:
e = gpg_io_fetch_u8(); e = gpg_io_fetch_u8();
break; break;
default: default:
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return 0; return 0;
} }
//move p,q over pub key, this only work because adr<rsa_pub> < adr<p> // move p,q over pub key, this only work because adr<rsa_pub> < adr<p>
if ( (len_p > ksz )|| (len_q > ksz)) { if ((len_p > ksz) || (len_q > ksz)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return 0; return 0;
} }
p = G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset; p = G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset;
q = p + len_p; q = p + len_p;
os_memmove(pq+ksz-len_p, p, len_p); os_memmove(pq + ksz - len_p, p, len_p);
os_memset(pq, 0, ksz-len_p); os_memset(pq, 0, ksz - len_p);
os_memmove(pq+2*ksz-len_q, q, len_q); os_memmove(pq + 2 * ksz - len_q, q, len_q);
os_memset(pq+ksz, 0, ksz-len_q); os_memset(pq + ksz, 0, ksz - len_q);
//regenerate RSA private key // regenerate RSA private key
unsigned char _e[4]; unsigned char _e[4];
_e[0] = e>>24; _e[0] = e >> 24;
_e[1] = e>>16; _e[1] = e >> 16;
_e[2] = e>>8; _e[2] = e >> 8;
_e[3] = e>>0; _e[3] = e >> 0;
cx_rsa_generate_pair(ksz<<1, rsa_pub, rsa_priv, _e, 4, pq); cx_rsa_generate_pair(ksz << 1, rsa_pub, rsa_priv, _e, 4, pq);
//write keys // write keys
nvm_write(&keygpg->pub_key.rsa, rsa_pub->e, 4); nvm_write(&keygpg->pub_key.rsa, rsa_pub->e, 4);
nvm_write(pkey, rsa_priv, pkey_size); nvm_write(pkey, rsa_priv, pkey_size);
if (reset_cnt) { if (reset_cnt) {
reset_cnt = 0; reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int)); nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
} }
} }
// --- ECC KEY --- // --- ECC KEY ---
else if ((keygpg->attributes.value[0] == 19) || else if ((keygpg->attributes.value[0] == 19) || (keygpg->attributes.value[0] == 18) ||
(keygpg->attributes.value[0] == 18) || (keygpg->attributes.value[0] == 22)) {
(keygpg->attributes.value[0] == 22) ) {
unsigned int curve; unsigned int curve;
ksz = 0; ksz = 0;
curve = gpg_oid2curve(&keygpg->attributes.value[1], keygpg->attributes.length-1); curve = gpg_oid2curve(&keygpg->attributes.value[1], keygpg->attributes.length - 1);
if (curve == 0) { if (curve == 0) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return 0; return 0;
} }
ksz = gpg_curve2domainlen(curve); ksz = gpg_curve2domainlen(curve);
if (ksz == len_p) { if (ksz == len_p) {
G_gpg_vstate.work.ecfp.private.curve = curve; G_gpg_vstate.work.ecfp.private.curve = curve;
G_gpg_vstate.work.ecfp.private.d_len = ksz; 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); 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); 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->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)); nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
if (reset_cnt) { if (reset_cnt) {
reset_cnt = 0; reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int)); nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
} }
} }
@ -473,10 +467,9 @@ int gpg_apdu_put_data(unsigned int ref) {
return 0; return 0;
} }
break; break;
} //endof of 3fff } // endof of 3fff
/* ----------------- User -----------------*/ /* ----------------- User -----------------*/
/* Name */ /* Name */
case 0x5B: case 0x5B:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->name.value)) { if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->name.value)) {
@ -495,7 +488,7 @@ int gpg_apdu_put_data(unsigned int ref) {
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.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)); gpg_nvm_write(&N_gpg_pstate->login.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
break; break;
/* Language preferences */ /* Language preferences */
case 0x5F2D: case 0x5F2D:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->lang.value)) { if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->lang.value)) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
@ -514,7 +507,7 @@ int gpg_apdu_put_data(unsigned int ref) {
break; break;
/* Uniform resource locator */ /* Uniform resource locator */
case 0x5F50: case 0x5F50:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->url.value)) { if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->url.value)) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return 0; return 0;
} }
@ -524,26 +517,26 @@ int gpg_apdu_put_data(unsigned int ref) {
/* ----------------- Cardholder certificate ----------------- */ /* ----------------- Cardholder certificate ----------------- */
case 0x7F21: case 0x7F21:
ptr_v = NULL; ptr_v = NULL;
switch ( G_gpg_vstate.DO_reccord) { switch (G_gpg_vstate.DO_reccord) {
case 0: case 0:
ptr_l = &G_gpg_vstate.kslot->aut.CA.length; ptr_l = &G_gpg_vstate.kslot->aut.CA.length;
ptr_v = G_gpg_vstate.kslot->aut.CA.value; ptr_v = G_gpg_vstate.kslot->aut.CA.value;
goto WRITE_CA; goto WRITE_CA;
case 1: case 1:
ptr_l = &G_gpg_vstate.kslot->sig.CA.length; ptr_l = &G_gpg_vstate.kslot->sig.CA.length;
ptr_v = G_gpg_vstate.kslot->sig.CA.value; ptr_v = G_gpg_vstate.kslot->sig.CA.value;
goto WRITE_CA; goto WRITE_CA;
case 2: case 2:
ptr_l = &G_gpg_vstate.kslot->dec.CA.length; ptr_l = &G_gpg_vstate.kslot->dec.CA.length;
ptr_v = G_gpg_vstate.kslot->dec.CA.value; ptr_v = G_gpg_vstate.kslot->dec.CA.value;
goto WRITE_CA; goto WRITE_CA;
default: default:
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0; return 0;
} }
WRITE_CA: WRITE_CA:
if (G_gpg_vstate.io_length > GPG_EXT_CARD_HOLDER_CERT_LENTH) { if (G_gpg_vstate.io_length > GPG_EXT_CARD_HOLDER_CERT_LENTH) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
} }
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
@ -564,7 +557,7 @@ int gpg_apdu_put_data(unsigned int ref) {
ptr_v = G_gpg_vstate.kslot->aut.attributes.value; ptr_v = G_gpg_vstate.kslot->aut.attributes.value;
goto WRITE_ATTRIBUTES; goto WRITE_ATTRIBUTES;
WRITE_ATTRIBUTES: WRITE_ATTRIBUTES:
if (G_gpg_vstate.io_length > 12) { if (G_gpg_vstate.io_length > 12) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return 0; return 0;
} }
@ -585,7 +578,7 @@ int gpg_apdu_put_data(unsigned int ref) {
ptr_v = G_gpg_vstate.kslot->dec.fingerprints; ptr_v = G_gpg_vstate.kslot->dec.fingerprints;
goto WRITE_FINGERPRINTS; goto WRITE_FINGERPRINTS;
case 0xC9: case 0xC9:
ptr_v =G_gpg_vstate.kslot->aut.fingerprints; ptr_v = G_gpg_vstate.kslot->aut.fingerprints;
goto WRITE_FINGERPRINTS; goto WRITE_FINGERPRINTS;
case 0xCA: case 0xCA:
ptr_v = G_gpg_vstate.kslot->sig.CA_fingerprints; ptr_v = G_gpg_vstate.kslot->sig.CA_fingerprints;
@ -624,30 +617,29 @@ int gpg_apdu_put_data(unsigned int ref) {
/* ----------------- AES key ----------------- */ /* ----------------- AES key ----------------- */
{ {
void *pkey; void * pkey;
cx_aes_key_t aes_key; cx_aes_key_t aes_key;
case 0xD1: case 0xD1:
pkey = &N_gpg_pstate->SM_enc; pkey = &N_gpg_pstate->SM_enc;
goto init_aes_key; goto init_aes_key;
case 0xD2: case 0xD2:
pkey = &N_gpg_pstate->SM_mac; pkey = &N_gpg_pstate->SM_mac;
goto init_aes_key; goto init_aes_key;
case 0xD5: case 0xD5:
pkey = &G_gpg_vstate.kslot->AES_dec; pkey = &G_gpg_vstate.kslot->AES_dec;
goto init_aes_key; goto init_aes_key;
init_aes_key: init_aes_key:
cx_aes_init_key(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, &aes_key); cx_aes_init_key(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, &aes_key);
gpg_nvm_write(pkey, &aes_key, sizeof(cx_aes_key_t)); gpg_nvm_write(pkey, &aes_key, sizeof(cx_aes_key_t));
break; break;
/* AES key: one shot */ /* AES key: one shot */
case 0xF4: case 0xF4:
cx_aes_init_key(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, &aes_key); cx_aes_init_key(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, &aes_key);
gpg_nvm_write(&N_gpg_pstate->SM_enc, &aes_key, sizeof(cx_aes_key_t)); gpg_nvm_write(&N_gpg_pstate->SM_enc, &aes_key, sizeof(cx_aes_key_t));
cx_aes_init_key(G_gpg_vstate.work.io_buffer+16, G_gpg_vstate.io_length, &aes_key); cx_aes_init_key(G_gpg_vstate.work.io_buffer + 16, G_gpg_vstate.io_length, &aes_key);
gpg_nvm_write(&N_gpg_pstate->SM_mac, &aes_key, sizeof(cx_aes_key_t)); gpg_nvm_write(&N_gpg_pstate->SM_mac, &aes_key, sizeof(cx_aes_key_t));
break; break;
} }
/* ----------------- RC ----------------- */ /* ----------------- RC ----------------- */
@ -658,20 +650,16 @@ int gpg_apdu_put_data(unsigned int ref) {
if (G_gpg_vstate.io_length == 0) { if (G_gpg_vstate.io_length == 0) {
gpg_nvm_write(pin, NULL, sizeof(gpg_pin_t)); 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)) {
else if ((G_gpg_vstate.io_length > GPG_MAX_PW_LENGTH) ||
(G_gpg_vstate.io_length < 8)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} else { } else {
gpg_pin_set(pin, gpg_pin_set(pin, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, G_gpg_vstate.io_length);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
G_gpg_vstate.io_length);
} }
sw = SW_OK; sw = SW_OK;
break; break;
} }
/* ----------------- UIF ----------------- */ /* ----------------- UIF ----------------- */
case 0xD6: case 0xD6:
ptr_v = G_gpg_vstate.kslot->sig.UIF; ptr_v = G_gpg_vstate.kslot->sig.UIF;
@ -679,10 +667,10 @@ int gpg_apdu_put_data(unsigned int ref) {
case 0xD7: case 0xD7:
ptr_v = G_gpg_vstate.kslot->dec.UIF; ptr_v = G_gpg_vstate.kslot->dec.UIF;
goto WRITE_UIF; goto WRITE_UIF;
case 0xD8: case 0xD8:
ptr_v = G_gpg_vstate.kslot->aut.UIF; ptr_v = G_gpg_vstate.kslot->aut.UIF;
goto WRITE_UIF; goto WRITE_UIF;
WRITE_UIF: WRITE_UIF:
if (G_gpg_vstate.io_length != 2) { if (G_gpg_vstate.io_length != 2) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return 0; return 0;
@ -690,7 +678,7 @@ int gpg_apdu_put_data(unsigned int ref) {
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 2); gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 2);
break; break;
/* ----------------- WAT ----------------- */ /* ----------------- WAT ----------------- */
default: default:
sw = SW_REFERENCED_DATA_NOT_FOUND; sw = SW_REFERENCED_DATA_NOT_FOUND;
break; break;
@ -698,27 +686,25 @@ int gpg_apdu_put_data(unsigned int ref) {
gpg_io_discard(1); gpg_io_discard(1);
return sw; return sw;
} }
static void gpg_init_keyenc(cx_aes_key_t *keyenc) { static void gpg_init_keyenc(cx_aes_key_t *keyenc) {
unsigned char seed[32]; unsigned char seed[32];
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed); gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, (unsigned char*)PIC("key "), 1, seed, 16); gpg_pso_derive_key_seed(seed, (unsigned char *)PIC("key "), 1, seed, 16);
cx_aes_init_key(seed, 16, keyenc); cx_aes_init_key(seed, 16, keyenc);
} }
//cmd // cmd
//resp TID API COMPAT len_pub len_priv priv // resp TID API COMPAT len_pub len_priv priv
int gpg_apdu_get_key_data(unsigned int ref) { int gpg_apdu_get_key_data(unsigned int ref) {
cx_aes_key_t keyenc; cx_aes_key_t keyenc;
gpg_key_t *keygpg; gpg_key_t * keygpg;
unsigned int len = 0; unsigned int len = 0;
gpg_init_keyenc(&keyenc); gpg_init_keyenc(&keyenc);
switch(ref) { switch (ref) {
case 0x00B6: case 0x00B6:
keygpg = &G_gpg_vstate.kslot->sig; keygpg = &G_gpg_vstate.kslot->sig;
break; break;
@ -734,43 +720,40 @@ int gpg_apdu_get_key_data(unsigned int ref) {
} }
gpg_io_discard(1); gpg_io_discard(1);
//clear part // clear part
gpg_io_insert_u32(TARGET_ID); gpg_io_insert_u32(TARGET_ID);
gpg_io_insert_u32(CX_APILEVEL); gpg_io_insert_u32(CX_APILEVEL);
gpg_io_insert_u32(CX_COMPAT_APILEVEL); gpg_io_insert_u32(CX_COMPAT_APILEVEL);
// encrypted part
//encrypted part switch (keygpg->attributes.value[0]) {
switch(keygpg->attributes.value[0]) { case 0x01: // RSA
case 0x01: //RSA // insert pubkey;
//insert pubkey;
gpg_io_insert_u32(4); gpg_io_insert_u32(4);
gpg_io_insert(keygpg->pub_key.rsa, 4); gpg_io_insert(keygpg->pub_key.rsa, 4);
//insert privkey // insert privkey
gpg_io_mark(); gpg_io_mark();
len = cx_aes(&keyenc, len = cx_aes(&keyenc, CX_ENCRYPT | CX_CHAIN_CBC | CX_PAD_ISO9797M2 | CX_LAST,
CX_ENCRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST, (unsigned char *)&keygpg->priv_key.rsa4096, sizeof(cx_rsa_4096_private_key_t),
(unsigned char*)&keygpg->priv_key.rsa4096, sizeof(cx_rsa_4096_private_key_t), G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, GPG_IO_BUFFER_LENGTH - G_gpg_vstate.io_offset);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, GPG_IO_BUFFER_LENGTH-G_gpg_vstate.io_offset);
gpg_io_inserted(len); gpg_io_inserted(len);
gpg_io_set_offset(IO_OFFSET_MARK); gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_u32(len); gpg_io_insert_u32(len);
gpg_io_set_offset(IO_OFFSET_END); gpg_io_set_offset(IO_OFFSET_END);
break; break;
case 18: //ECC case 18: // ECC
case 19: case 19:
case 22: case 22:
//insert pubkey; // insert pubkey;
gpg_io_insert_u32(sizeof(cx_ecfp_640_public_key_t)); gpg_io_insert_u32(sizeof(cx_ecfp_640_public_key_t));
gpg_io_insert((unsigned char*)&keygpg->pub_key.ecfp640, sizeof(cx_ecfp_640_public_key_t)); gpg_io_insert((unsigned char *)&keygpg->pub_key.ecfp640, sizeof(cx_ecfp_640_public_key_t));
//insert privkey // insert privkey
gpg_io_mark(); gpg_io_mark();
len = cx_aes(&keyenc, len = cx_aes(&keyenc, CX_ENCRYPT | CX_CHAIN_CBC | CX_PAD_ISO9797M2 | CX_LAST,
CX_ENCRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST, (unsigned char *)&keygpg->priv_key.ecfp640, sizeof(cx_ecfp_640_private_key_t),
(unsigned char*)&keygpg->priv_key.ecfp640, sizeof(cx_ecfp_640_private_key_t), G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, GPG_IO_BUFFER_LENGTH - G_gpg_vstate.io_offset);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, GPG_IO_BUFFER_LENGTH-G_gpg_vstate.io_offset);
gpg_io_inserted(len); gpg_io_inserted(len);
gpg_io_set_offset(IO_OFFSET_MARK); gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_u32(len); gpg_io_insert_u32(len);
@ -778,23 +761,22 @@ int gpg_apdu_get_key_data(unsigned int ref) {
break; break;
default: default:
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
return SW_OK; return SW_OK;
} }
//cmd TID API COMPAT len_pub len_priv priv // cmd TID API COMPAT len_pub len_priv priv
//resp - // resp -
int gpg_apdu_put_key_data(unsigned int ref) { int gpg_apdu_put_key_data(unsigned int ref) {
cx_aes_key_t keyenc; cx_aes_key_t keyenc;
gpg_key_t *keygpg; gpg_key_t * keygpg;
unsigned int len; unsigned int len;
unsigned int offset; unsigned int offset;
gpg_init_keyenc(&keyenc); gpg_init_keyenc(&keyenc);
switch(ref) { switch (ref) {
case 0xB6: case 0xB6:
keygpg = &G_gpg_vstate.kslot->sig; keygpg = &G_gpg_vstate.kslot->sig;
break; break;
@ -809,16 +791,17 @@ int gpg_apdu_put_key_data(unsigned int ref) {
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
/* unsigned int target_id = */ /* unsigned int target_id = */
gpg_io_fetch_u32(); gpg_io_fetch_u32();
/* unsigned int cx_apilevel = */ /* unsigned int cx_apilevel = */
gpg_io_fetch_u32(); gpg_io_fetch_u32();
/* unsigned int cx_compat_apilevel = */ /* unsigned int cx_compat_apilevel = */
gpg_io_fetch_u32(); gpg_io_fetch_u32();
switch(keygpg->attributes.value[0]) { switch (keygpg->attributes.value[0]) {
case 0x01: //RSA // RSA
//insert pubkey; case 0x01:
// insert pubkey;
len = gpg_io_fetch_u32(); len = gpg_io_fetch_u32();
if (len != 4) { if (len != 4) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
@ -826,55 +809,53 @@ int gpg_apdu_put_key_data(unsigned int ref) {
} }
gpg_io_fetch_nv(keygpg->pub_key.rsa, len); gpg_io_fetch_nv(keygpg->pub_key.rsa, len);
//insert privkey // insert privkey
len = gpg_io_fetch_u32(); len = gpg_io_fetch_u32();
if (len > (G_gpg_vstate.io_length-G_gpg_vstate.io_offset)) { if (len > (G_gpg_vstate.io_length - G_gpg_vstate.io_offset)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
} }
offset = G_gpg_vstate.io_offset; offset = G_gpg_vstate.io_offset;
gpg_io_discard(0); gpg_io_discard(0);
len = cx_aes(&keyenc, len = cx_aes(&keyenc, CX_DECRYPT | CX_CHAIN_CBC | CX_PAD_ISO9797M2 | CX_LAST, G_gpg_vstate.work.io_buffer + offset,
CX_DECRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST, len, G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
G_gpg_vstate.work.io_buffer+offset, len,
G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
if (len != sizeof(cx_rsa_4096_private_key_t)) { if (len != sizeof(cx_rsa_4096_private_key_t)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
} }
gpg_nvm_write((unsigned char*)&keygpg->priv_key.rsa4096, G_gpg_vstate.work.io_buffer, len); gpg_nvm_write((unsigned char *)&keygpg->priv_key.rsa4096, G_gpg_vstate.work.io_buffer, len);
break; break;
case 18: //ECC // ECC
case 19: case 18: /* 12h */
case 22: case 19: /* 13h */
//insert pubkey; case 22: /* 16h */
// insert pubkey;
len = gpg_io_fetch_u32(); len = gpg_io_fetch_u32();
if (len != sizeof(cx_ecfp_640_public_key_t)) { if (len != sizeof(cx_ecfp_640_public_key_t)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
gpg_io_fetch_nv((unsigned char*)&keygpg->pub_key.ecfp640, len); gpg_io_fetch_nv((unsigned char *)&keygpg->pub_key.ecfp640, len);
//insert privkey // insert privkey
len = gpg_io_fetch_u32(); len = gpg_io_fetch_u32();
if (len > (G_gpg_vstate.io_length-G_gpg_vstate.io_offset)) { if (len > (G_gpg_vstate.io_length - G_gpg_vstate.io_offset)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
} }
offset = G_gpg_vstate.io_offset; offset = G_gpg_vstate.io_offset;
gpg_io_discard(0); gpg_io_discard(0);
len = cx_aes(&keyenc,
CX_DECRYPT|CX_CHAIN_CBC|CX_PAD_ISO9797M2|CX_LAST, len = cx_aes(&keyenc, CX_DECRYPT | CX_CHAIN_CBC | CX_PAD_ISO9797M2 | CX_LAST, G_gpg_vstate.work.io_buffer + offset,
G_gpg_vstate.work.io_buffer+offset, len, len, G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
if (len != sizeof(cx_ecfp_640_private_key_t)) { if (len != sizeof(cx_ecfp_640_private_key_t)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
gpg_nvm_write((unsigned char*)&keygpg->priv_key.ecfp640, G_gpg_vstate.work.io_buffer, len); gpg_nvm_write((unsigned char *)&keygpg->priv_key.ecfp640, G_gpg_vstate.work.io_buffer, len);
break; break;
default: default:
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
gpg_io_discard(1); gpg_io_discard(1);
return SW_OK; return SW_OK;

@ -19,12 +19,10 @@
#include "gpg_api.h" #include "gpg_api.h"
#include "gpg_vars.h" #include "gpg_vars.h"
void gpg_check_access_ins() { void gpg_check_access_ins() {
unsigned int ref; unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ; ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (G_gpg_vstate.io_ins) { switch (G_gpg_vstate.io_ins) {
case INS_EXIT: case INS_EXIT:
@ -42,7 +40,7 @@ void gpg_check_access_ins() {
case INS_VERIFY: case INS_VERIFY:
return; return;
case INS_CHANGE_REFERENCE_DATA: case INS_CHANGE_REFERENCE_DATA:
return; return;
case INS_RESET_RETRY_COUNTER: case INS_RESET_RETRY_COUNTER:
@ -61,22 +59,22 @@ void gpg_check_access_ins() {
} }
if (gpg_pin_is_verified(PIN_ID_PW3)) { if (gpg_pin_is_verified(PIN_ID_PW3)) {
return; return;
} }
break; break;
case INS_MSE: case INS_MSE:
return ; return;
case INS_PSO: case INS_PSO:
if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) { if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) {
//pso:sign // pso:sign
if (N_gpg_pstate->PW_status[0] == 0) { if (N_gpg_pstate->PW_status[0] == 0) {
gpg_pin_set_verified(PIN_ID_PW1, 0); gpg_pin_set_verified(PIN_ID_PW1, 0);
} }
return; return;
} }
if (((ref == 0x8086 )||(ref == 0x8680)) && gpg_pin_is_verified(PIN_ID_PW2)) { if (((ref == 0x8086) || (ref == 0x8680)) && gpg_pin_is_verified(PIN_ID_PW2)) {
//pso:dec/enc // pso:dec/enc
return; return;
} }
break; break;
@ -85,7 +83,7 @@ void gpg_check_access_ins() {
if (gpg_pin_is_verified(PIN_ID_PW2)) { if (gpg_pin_is_verified(PIN_ID_PW2)) {
return; return;
} }
break; break;
case INS_GET_CHALLENGE: case INS_GET_CHALLENGE:
return; return;
@ -108,11 +106,11 @@ void gpg_check_access_ins() {
void gpg_check_access_read_DO() { void gpg_check_access_read_DO() {
unsigned int ref; unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ;
switch(ref) { ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
//ALWAYS
switch (ref) {
// ALWAYS
case 0x0101: case 0x0101:
case 0x0102: case 0x0102:
case 0x01F0: case 0x01F0:
@ -155,23 +153,23 @@ void gpg_check_access_read_DO() {
case 0x00D8: case 0x00D8:
return; return;
//PW2 // PW2
case 0x0103: case 0x0103:
if (gpg_pin_is_verified(PIN_ID_PW2)) { if (gpg_pin_is_verified(PIN_ID_PW2)) {
return; return;
} }
break; break;
//PW3 // PW3
case 0x00B6: case 0x00B6:
case 0x00A4: case 0x00A4:
case 0x00B8: case 0x00B8:
case 0x0104: case 0x0104:
if (gpg_pin_is_verified(PIN_ID_PW3)) { if (gpg_pin_is_verified(PIN_ID_PW3)) {
return; return;
} }
break; break;
} }
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
} }
@ -180,24 +178,24 @@ char debugbuff[5];
void gpg_check_access_write_DO() { void gpg_check_access_write_DO() {
unsigned int ref; unsigned int ref;
gpg_pin_t *pin_pw2, *pin_pw3; gpg_pin_t * pin_pw2, *pin_pw3;
pin_pw2 = gpg_pin_get_pin(PIN_ID_PW2); pin_pw2 = gpg_pin_get_pin(PIN_ID_PW2);
pin_pw3 = gpg_pin_get_pin(PIN_ID_PW3); pin_pw3 = gpg_pin_get_pin(PIN_ID_PW3);
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ; ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch(ref) { switch (ref) {
//PW2 // PW2
case 0x0101: case 0x0101:
case 0x0103: case 0x0103:
case 0x01F2: case 0x01F2:
if (gpg_pin_is_verified(PIN_ID_PW2)) { if (gpg_pin_is_verified(PIN_ID_PW2)) {
return; return;
} }
break; break;
//PW3 // PW3
case 0x3FFF: //only used for putkey under PW3 control case 0x3FFF: // only used for putkey under PW3 control
case 0x4f: case 0x4f:
case 0x0102: case 0x0102:
case 0x0104: case 0x0104:
@ -240,26 +238,22 @@ void gpg_check_access_write_DO() {
if (gpg_pin_is_verified(PIN_ID_PW3)) { if (gpg_pin_is_verified(PIN_ID_PW3)) {
return; return;
} }
break; break;
} }
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
} }
/* assume command is fully received */ /* assume command is fully received */
int gpg_dispatch() { int gpg_dispatch() {
unsigned int tag,t,l; unsigned int tag, t, l;
int sw; int sw;
if ((G_gpg_vstate.io_cla != 0x00) && if ((G_gpg_vstate.io_cla != 0x00) && (G_gpg_vstate.io_cla != 0x10) && (G_gpg_vstate.io_cla != 0xEF)) {
(G_gpg_vstate.io_cla != 0x10) &&
(G_gpg_vstate.io_cla != 0xEF)) {
THROW(SW_CLA_NOT_SUPPORTED); THROW(SW_CLA_NOT_SUPPORTED);
return SW_CLA_NOT_SUPPORTED; return SW_CLA_NOT_SUPPORTED;
} }
tag = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ; tag = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (G_gpg_vstate.io_ins) { switch (G_gpg_vstate.io_ins) {
/* --- SELECT --- */ /* --- SELECT --- */
@ -274,21 +268,20 @@ int gpg_dispatch() {
if (N_gpg_pstate->histo[7] == STATE_TERMINATE) { if (N_gpg_pstate->histo[7] == STATE_TERMINATE) {
gpg_install(STATE_ACTIVATE); gpg_install(STATE_ACTIVATE);
} }
return(SW_OK); return (SW_OK);
break; break;
case INS_TERMINATE_DF: case INS_TERMINATE_DF:
gpg_io_discard(0); gpg_io_discard(0);
if (gpg_pin_is_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); gpg_install(STATE_TERMINATE);
return(SW_OK); return (SW_OK);
break; break;
} }
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
break; break;
} }
/* Other commands allowed if not terminated */ /* Other commands allowed if not terminated */
if (N_gpg_pstate->histo[7] != 0x07) { if (N_gpg_pstate->histo[7] != 0x07) {
THROW(SW_STATE_TERMINATED); THROW(SW_STATE_TERMINATED);
@ -298,8 +291,6 @@ int gpg_dispatch() {
gpg_check_access_ins(); gpg_check_access_ins();
switch (G_gpg_vstate.io_ins) { switch (G_gpg_vstate.io_ins) {
#ifdef GPG_DEBUG_APDU #ifdef GPG_DEBUG_APDU
case 0x42: case 0x42:
sw = debug_apdu(); sw = debug_apdu();
@ -322,19 +313,19 @@ int gpg_dispatch() {
if ((G_gpg_vstate.io_p1 > 2) || (G_gpg_vstate.io_p2 != 0x04)) { if ((G_gpg_vstate.io_p1 > 2) || (G_gpg_vstate.io_p2 != 0x04)) {
THROW(SW_WRONG_P1P2); THROW(SW_WRONG_P1P2);
} }
gpg_io_fetch_tl(&t,&l); gpg_io_fetch_tl(&t, &l);
if (t != 0x60) { if (t != 0x60) {
//TODO add l check // TODO add l check
THROW(SW_DATA_INVALID); THROW(SW_DATA_INVALID);
} }
gpg_io_fetch_tl(&t,&l); gpg_io_fetch_tl(&t, &l);
if (t != 0x5C) { if (t != 0x5C) {
//TODO add l check // TODO add l check
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
} }
if (l == 1) { if (l == 1) {
tag = gpg_io_fetch_u8(); tag = gpg_io_fetch_u8();
} else if (l == 2) { } else if (l == 2) {
tag = gpg_io_fetch_u16(); tag = gpg_io_fetch_u16();
} else { } else {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
@ -344,10 +335,10 @@ int gpg_dispatch() {
case INS_GET_DATA: case INS_GET_DATA:
gpg_check_access_read_DO(); gpg_check_access_read_DO();
switch(tag) { switch (tag) {
case 0x00B6: case 0x00B6:
case 0x00A4: case 0x00A4:
case 0x00B8: case 0x00B8:
sw = gpg_apdu_get_key_data(tag); sw = gpg_apdu_get_key_data(tag);
break; break;
default: default:
@ -361,14 +352,13 @@ int gpg_dispatch() {
sw = gpg_apdu_get_next_data(tag); sw = gpg_apdu_get_next_data(tag);
break; break;
case INS_PUT_DATA_ODD:
case INS_PUT_DATA_ODD: case INS_PUT_DATA:
case INS_PUT_DATA:
gpg_check_access_write_DO(); gpg_check_access_write_DO();
switch(tag) { switch (tag) {
case 0x00B6: case 0x00B6:
case 0x00A4: case 0x00A4:
case 0x00B8: case 0x00B8:
sw = gpg_apdu_put_key_data(tag); sw = gpg_apdu_put_key_data(tag);
break; break;
default: default:
@ -379,55 +369,47 @@ int gpg_dispatch() {
/* --- PIN -- */ /* --- PIN -- */
case INS_VERIFY: case INS_VERIFY:
if ((G_gpg_vstate.io_p2 == 0x81) || if ((G_gpg_vstate.io_p2 == 0x81) || (G_gpg_vstate.io_p2 == 0x82) || (G_gpg_vstate.io_p2 == 0x83)) {
(G_gpg_vstate.io_p2 == 0x82) ||
(G_gpg_vstate.io_p2 == 0x83)
) {
sw = gpg_apdu_verify(); sw = gpg_apdu_verify();
break; break;
} }
THROW(SW_INCORRECT_P1P2); THROW(SW_INCORRECT_P1P2);
case INS_CHANGE_REFERENCE_DATA: case INS_CHANGE_REFERENCE_DATA:
if ((G_gpg_vstate.io_p2 == 0x81) || if ((G_gpg_vstate.io_p2 == 0x81) || (G_gpg_vstate.io_p2 == 0x83)) {
(G_gpg_vstate.io_p2 == 0x83) sw = gpg_apdu_change_ref_data();
) { break;
sw = gpg_apdu_change_ref_data(); }
break; THROW(SW_INCORRECT_P1P2);
}
THROW(SW_INCORRECT_P1P2);
case INS_RESET_RETRY_COUNTER: case INS_RESET_RETRY_COUNTER:
if ((G_gpg_vstate.io_p2 == 0x81) && if ((G_gpg_vstate.io_p2 == 0x81) && ((G_gpg_vstate.io_p1 == 0) || (G_gpg_vstate.io_p1 == 2))) {
( (G_gpg_vstate.io_p1 == 0) || sw = gpg_apdu_reset_retry_counter();
(G_gpg_vstate.io_p1 == 2) ) break;
) { }
sw = gpg_apdu_reset_retry_counter(); THROW(SW_INCORRECT_P1P2);
break;
} /* --- Key Management --- */
THROW(SW_INCORRECT_P1P2);
/* --- Key Management --- */
case INS_GEN_ASYM_KEYPAIR: case INS_GEN_ASYM_KEYPAIR:
sw = gpg_apdu_gen(); sw = gpg_apdu_gen();
break; break;
/* --- MSE --- */ /* --- MSE --- */
case INS_MSE: case INS_MSE:
sw = gpg_apdu_mse(tag); sw = gpg_apdu_mse(tag);
break; break;
/* --- PSO --- */ /* --- PSO --- */
case INS_PSO: case INS_PSO:
sw = gpg_apdu_pso(); sw = gpg_apdu_pso();
break; break;
case INS_INTERNAL_AUTHENTICATE: case INS_INTERNAL_AUTHENTICATE:
sw = gpg_apdu_internal_authenticate(); sw = gpg_apdu_internal_authenticate();
break; break;
default: default:
THROW( SW_INS_NOT_SUPPORTED); THROW(SW_INS_NOT_SUPPORTED);
break; break;
} }

@ -22,15 +22,15 @@
/* @in slot slot num [0 ; GPG_KEYS_SLOTS[ /* @in slot slot num [0 ; GPG_KEYS_SLOTS[
* @out seed 32 bytes master seed for given slot * @out seed 32 bytes master seed for given slot
*/ */
void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) { void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
unsigned int path[2]; unsigned int path[2];
unsigned char chain[32]; unsigned char chain[32];
os_memset(chain, 0, 32); os_memset(chain, 0, 32);
path[0] = 0x80475047; path[0] = 0x80475047;
path[1] = slot+1; path[1] = slot + 1;
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2 , seed, chain); os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2, seed, chain);
} }
/* @in Sn master seed slot number /* @in Sn master seed slot number
* @in key_name key name: 'sig ', 'auth ', 'dec ' * @in key_name key name: 'sig ', 'auth ', 'dec '
@ -38,31 +38,37 @@ void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
* @out Ski generated sub_seed * @out Ski generated sub_seed
* @in Ski_len sub-seed length * @in Ski_len sub-seed length
*/ */
void gpg_pso_derive_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx, void gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned char *Ski, unsigned int Ski_len) { unsigned char *key_name,
unsigned int idx,
unsigned char *Ski,
unsigned int Ski_len) {
unsigned char h[32]; unsigned char h[32];
h[0] = idx >>8; h[0] = idx >> 8;
h[1] = idx; h[1] = idx;
cx_sha256_init(&G_gpg_vstate.work.md.sha256); cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL, 0); 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, 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_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, CX_LAST, h, 2, h, 32);
#ifdef GPG_SHAKE256
cx_shake256_init(&G_gpg_vstate.work.md.sha3, Ski_len);
cx_shake256_update(&G_gpg_vstate.work.md.sha3, h, 32);
cx_shake256_final(&G_gpg_vstate.work.md.sha3, Ski);
#else
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len); cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len);
cx_hash((cx_hash_t*)&G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski, Ski_len); cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski, Ski_len);
#endif
} }
/* assume command is fully received */ /* assume command is fully received */
int gpg_apdu_gen() { int gpg_apdu_gen() {
unsigned int t,l,ksz,reset_cnt; unsigned int t, l, ksz, reset_cnt;
gpg_key_t *keygpg; gpg_key_t * keygpg;
unsigned char seed[66]; unsigned char seed[66];
unsigned char* name; unsigned char *name;
switch ((G_gpg_vstate.io_p1<<8)|G_gpg_vstate.io_p2) { switch ((G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2) {
case 0x8000: case 0x8000:
case 0x8001: case 0x8001:
case 0x8100: case 0x8100:
@ -72,76 +78,75 @@ int gpg_apdu_gen() {
return SW_INCORRECT_P1P2; return SW_INCORRECT_P1P2;
} }
if (G_gpg_vstate.io_lc != 2){ if (G_gpg_vstate.io_lc != 2) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH; return SW_WRONG_LENGTH;
} }
gpg_io_fetch_tl(&t,&l); gpg_io_fetch_tl(&t, &l);
gpg_io_discard(1); gpg_io_discard(1);
reset_cnt = 0; reset_cnt = 0;
switch(t) { switch (t) {
case 0xB6: case 0xB6:
keygpg = &G_gpg_vstate.kslot->sig; keygpg = &G_gpg_vstate.kslot->sig;
name = (unsigned char*)PIC("sig "); name = (unsigned char *)PIC("sig ");
reset_cnt = 0; reset_cnt = 0;
break; break;
case 0xA4: case 0xA4:
keygpg = &G_gpg_vstate.kslot->aut; keygpg = &G_gpg_vstate.kslot->aut;
name = (unsigned char*)PIC("aut "); name = (unsigned char *)PIC("aut ");
break; break;
case 0xB8: case 0xB8:
keygpg = &G_gpg_vstate.kslot->dec; keygpg = &G_gpg_vstate.kslot->dec;
name = (unsigned char*)PIC("dec "); name = (unsigned char *)PIC("dec ");
break; break;
default: default:
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
switch ((G_gpg_vstate.io_p1<<8)|G_gpg_vstate.io_p2) { switch ((G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2) {
// -- generate keypair --- // -- generate keypair ---
case 0x8000: case 0x8000:
case 0x8001: case 0x8001:
// RSA // RSA
if (keygpg->attributes.value[0] == 0x01) { if (keygpg->attributes.value[0] == 0x01) {
unsigned char * pq;
unsigned char *pq; cx_rsa_public_key_t * rsa_pub;
cx_rsa_public_key_t *rsa_pub;
cx_rsa_private_key_t *rsa_priv, *pkey; cx_rsa_private_key_t *rsa_priv, *pkey;
unsigned int pkey_size; unsigned int pkey_size;
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2]; ksz = (keygpg->attributes.value[1] << 8) | keygpg->attributes.value[2];
ksz = ksz >> 3; ksz = ksz >> 3;
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa.public; rsa_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; rsa_priv = (cx_rsa_private_key_t *)&G_gpg_vstate.work.rsa.private;
pkey = &keygpg->priv_key.rsa; pkey = &keygpg->priv_key.rsa;
switch(ksz) { switch (ksz) {
case 1024/8: case 1024 / 8:
pkey_size = sizeof(cx_rsa_1024_private_key_t); pkey_size = sizeof(cx_rsa_1024_private_key_t);
break; break;
case 2048/8: case 2048 / 8:
pkey_size = sizeof(cx_rsa_2048_private_key_t); pkey_size = sizeof(cx_rsa_2048_private_key_t);
break; break;
case 3072/8: case 3072 / 8:
pkey_size = sizeof(cx_rsa_3072_private_key_t); pkey_size = sizeof(cx_rsa_3072_private_key_t);
break; break;
case 4096/8: case 4096 / 8:
pkey_size = sizeof(cx_rsa_4096_private_key_t); pkey_size = sizeof(cx_rsa_4096_private_key_t);
break; break;
} }
pq = NULL; pq = NULL;
if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)){ if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) {
pq = &rsa_pub->n[0]; pq = &rsa_pub->n[0];
unsigned int size; unsigned int size;
size = ksz>>1; size = ksz >> 1;
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed); gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, pq, size); gpg_pso_derive_key_seed(seed, name, 1, pq, size);
gpg_pso_derive_key_seed(seed, name, 2, pq+size, size); gpg_pso_derive_key_seed(seed, name, 2, pq + size, size);
*pq |= 0x80; *pq |= 0x80;
*(pq+size) |= 0x80; *(pq + size) |= 0x80;
cx_math_next_prime(pq,size); cx_math_next_prime(pq, size);
cx_math_next_prime(pq+size,size); cx_math_next_prime(pq + size, size);
} }
cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, N_gpg_pstate->default_RSA_exponent, 4, pq); cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, N_gpg_pstate->default_RSA_exponent, 4, pq);
@ -150,41 +155,36 @@ int gpg_apdu_gen() {
nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4); nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4);
if (reset_cnt) { if (reset_cnt) {
reset_cnt = 0; reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int)); nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
} }
gpg_io_clear(); gpg_io_clear();
goto send_rsa_pub; goto send_rsa_pub;
} }
// ECC // ECC
if ((keygpg->attributes.value[0] == 18) || if ((keygpg->attributes.value[0] == 18) || (keygpg->attributes.value[0] == 19) ||
(keygpg->attributes.value[0] == 19) || (keygpg->attributes.value[0] == 22)) {
(keygpg->attributes.value[0] == 22) ){ unsigned int curve, keepprivate;
unsigned int curve,keepprivate;
keepprivate = 0; keepprivate = 0;
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1); curve = gpg_oid2curve(keygpg->attributes.value + 1, keygpg->attributes.length - 1);
if (curve == CX_CURVE_NONE) { if (curve == CX_CURVE_NONE) {
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) { if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) {
ksz = gpg_curve2domainlen(curve); ksz = gpg_curve2domainlen(curve);
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed); gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, seed, ksz); gpg_pso_derive_key_seed(seed, name, 1, seed, ksz);
cx_ecfp_init_private_key(curve,seed, ksz, &G_gpg_vstate.work.ecfp.private); cx_ecfp_init_private_key(curve, seed, ksz, &G_gpg_vstate.work.ecfp.private);
keepprivate = 1; keepprivate = 1;
} }
cx_ecfp_generate_pair(curve, cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp.public, &G_gpg_vstate.work.ecfp.private, keepprivate);
&G_gpg_vstate.work.ecfp.public, nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
&G_gpg_vstate.work.ecfp.private,
keepprivate);
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)); nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
if (reset_cnt) { if (reset_cnt) {
reset_cnt = 0; reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int)); nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
} }
gpg_io_clear(); gpg_io_clear();
goto send_ecc_pub; goto send_ecc_pub;
@ -197,88 +197,86 @@ int gpg_apdu_gen() {
/// read RSA /// read RSA
send_rsa_pub: send_rsa_pub:
gpg_io_discard(1); gpg_io_discard(1);
//check length // check length
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2]; ksz = (keygpg->attributes.value[1] << 8) | keygpg->attributes.value[2];
ksz = ksz>>3; ksz = ksz >> 3;
gpg_io_mark(); gpg_io_mark();
switch(ksz) { switch (ksz) {
case 1024/8: case 1024 / 8:
if (keygpg->priv_key.rsa1024.size == 0) { if (keygpg->priv_key.rsa1024.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa1024.n); gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa1024.n);
break; break;
case 2048/8: case 2048 / 8:
if (keygpg->priv_key.rsa2048.size == 0) { if (keygpg->priv_key.rsa2048.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa2048.n); gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa2048.n);
break; break;
case 3072/8: case 3072 / 8:
if (keygpg->priv_key.rsa3072.size == 0) { if (keygpg->priv_key.rsa3072.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa3072.n); gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa3072.n);
break; break;
case 4096/8: case 4096 / 8:
if (keygpg->priv_key.rsa4096.size == 0) { if (keygpg->priv_key.rsa4096.size == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->priv_key.rsa4096.n); gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa4096.n);
break; break;
} }
gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa); gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa);
l = G_gpg_vstate.io_length; l = G_gpg_vstate.io_length;
gpg_io_set_offset(IO_OFFSET_MARK); gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x7f49,l); gpg_io_insert_tl(0x7f49, l);
gpg_io_set_offset(IO_OFFSET_END); gpg_io_set_offset(IO_OFFSET_END);
return SW_OK; return SW_OK;
} }
if ((keygpg->attributes.value[0] == 18) || if ((keygpg->attributes.value[0] == 18) || (keygpg->attributes.value[0] == 19) ||
(keygpg->attributes.value[0] == 19) || (keygpg->attributes.value[0] == 22)) {
(keygpg->attributes.value[0] == 22) ){
unsigned int curve; unsigned int curve;
/// read ECC /// read ECC
send_ecc_pub: send_ecc_pub:
if (keygpg->pub_key.ecfp256.W_len == 0) { if (keygpg->pub_key.ecfp256.W_len == 0) {
THROW (SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0; return 0;
} }
gpg_io_discard(1); gpg_io_discard(1);
gpg_io_mark(); gpg_io_mark();
curve = gpg_oid2curve(keygpg->attributes.value+1, keygpg->attributes.length-1); curve = gpg_oid2curve(keygpg->attributes.value + 1, keygpg->attributes.length - 1);
if (curve == CX_CURVE_Ed25519) { if (curve == CX_CURVE_Ed25519) {
os_memmove(G_gpg_vstate.work.io_buffer+128, keygpg->pub_key.ecfp256.W,keygpg->pub_key.ecfp256.W_len); os_memmove(G_gpg_vstate.work.io_buffer + 128, keygpg->pub_key.ecfp256.W, keygpg->pub_key.ecfp256.W_len);
cx_edward_compress_point(CX_CURVE_Ed25519, G_gpg_vstate.work.io_buffer+128, 65); cx_edward_compress_point(CX_CURVE_Ed25519, G_gpg_vstate.work.io_buffer + 128, 65);
gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer+129); //129: discard 02 gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer + 129); // 129: discard 02
} else if (curve == CX_CURVE_Curve25519) { } else if (curve == CX_CURVE_Curve25519) {
unsigned int i,len; unsigned int i, len;
len = keygpg->pub_key.ecfp256.W_len-1; len = keygpg->pub_key.ecfp256.W_len - 1;
for (i = 0; i <=len; i++) { for (i = 0; i <= len; i++) {
G_gpg_vstate.work.io_buffer[128+i] = keygpg->pub_key.ecfp256.W[len-i]; G_gpg_vstate.work.io_buffer[128 + i] = keygpg->pub_key.ecfp256.W[len - i];
} }
gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer+128); gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer + 128);
} else { } else {
gpg_io_insert_tlv(0x86, keygpg->pub_key.ecfp256.W_len, (unsigned char*)&keygpg->pub_key.ecfp256.W ); gpg_io_insert_tlv(0x86, keygpg->pub_key.ecfp256.W_len, (unsigned char *)&keygpg->pub_key.ecfp256.W);
} }
l = G_gpg_vstate.io_length; l = G_gpg_vstate.io_length;
gpg_io_set_offset(IO_OFFSET_MARK); gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x7f49,l); gpg_io_insert_tl(0x7f49, l);
gpg_io_set_offset(IO_OFFSET_END); gpg_io_set_offset(IO_OFFSET_END);
return SW_OK; return SW_OK;
} }
break; break;
} }
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }

@ -20,23 +20,18 @@
#include "gpg_vars.h" #include "gpg_vars.h"
#include "usbd_impl.h" #include "usbd_impl.h"
#define SHORT(x) ((x)>>8)&0xFF, (x)&0xFF #define SHORT(x) ((x) >> 8) & 0xFF, (x)&0xFF
/* ----------------------*/ /* ----------------------*/
/* -- A Kind of Magic -- */ /* -- A Kind of Magic -- */
/* ----------------------*/ /* ----------------------*/
const unsigned char C_MAGIC[8] = { const unsigned char C_MAGIC[8] = {'G', 'P', 'G', 'C', 'A', 'R', 'D', '3'};
'G','P','G','C','A','R','D','3'
};
/* ----------------------*/ /* ----------------------*/
/* --ECC OID -- */ /* --ECC OID -- */
/* ----------------------*/ /* ----------------------*/
// secp256r1 / NIST P256 /ansi-x9.62 : 1.2.840.10045.3.1.7
//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};
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 //secp384r1 / NIST P384 /ansi-x9.62 :1.3.132.0.34
const unsigned char C_OID_SECP384R1[5] = { const unsigned char C_OID_SECP384R1[5] = {
@ -53,7 +48,6 @@ const unsigned char C_OID_SECP256K1[5] = {
}; };
*/ */
/* /*
//brainpool 256t1: 1.3.36.3.3.2.8.1.1.8 //brainpool 256t1: 1.3.36.3.3.2.8.1.1.8
const unsigned char C_OID_BRAINPOOL256T1[9] = { const unsigned char C_OID_BRAINPOOL256T1[9] = {
@ -73,19 +67,18 @@ const unsigned char C_OID_BRAINPOOL512R1[9] = {
}; };
*/ */
//Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1 // Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1
const unsigned char C_OID_Ed25519[9] = { const unsigned char C_OID_Ed25519[9] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
}; };
//Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1 // Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1
const unsigned char C_OID_cv25519[10] = { const unsigned char C_OID_cv25519[10] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
}; };
unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len) { unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len) {
if ((len == sizeof(C_OID_SECP256R1)) && (os_memcmp(oid, C_OID_SECP256R1, len) == 0)) {
if ( (len == sizeof(C_OID_SECP256R1)) && (os_memcmp(oid, C_OID_SECP256R1, len)==0) ) {
return CX_CURVE_SECP256R1; return CX_CURVE_SECP256R1;
} }
/* /*
@ -112,11 +105,11 @@ unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len) {
return CX_CURVE_BrainPoolP512R1; return CX_CURVE_BrainPoolP512R1;
} }
*/ */
if ( (len == sizeof(C_OID_Ed25519)) && (os_memcmp(oid, C_OID_Ed25519, len)==0) ) { if ((len == sizeof(C_OID_Ed25519)) && (os_memcmp(oid, C_OID_Ed25519, len) == 0)) {
return CX_CURVE_Ed25519; return CX_CURVE_Ed25519;
} }
if ( (len == sizeof(C_OID_cv25519)) && (os_memcmp(oid, C_OID_cv25519, len)==0) ) { if ((len == sizeof(C_OID_cv25519)) && (os_memcmp(oid, C_OID_cv25519, len) == 0)) {
return CX_CURVE_Curve25519; return CX_CURVE_Curve25519;
} }
@ -131,12 +124,11 @@ unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len) {
return CX_CURVE_NONE; return CX_CURVE_NONE;
} }
unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len) {
unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
switch (cv) { switch (cv) {
case CX_CURVE_SECP256R1: case CX_CURVE_SECP256R1:
*len = sizeof(C_OID_SECP256R1); *len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1); return (unsigned char *)PIC(C_OID_SECP256R1);
/* /*
case CX_CURVE_SECP256K1: case CX_CURVE_SECP256K1:
@ -146,7 +138,7 @@ unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
case CX_CURVE_SECP384R1: case CX_CURVE_SECP384R1:
*len = sizeof(C_OID_SECP384R1); *len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1); return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_SECP521R1: case CX_CURVE_SECP521R1:
*len = sizeof(C_OID_SECP521R1); *len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1); return (unsigned char*)PIC(C_OID_SECP521R1);
@ -156,22 +148,22 @@ unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
case CX_CURVE_BrainPoolP256R1: case CX_CURVE_BrainPoolP256R1:
*len = sizeof(C_OID_SECP256R1); *len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1); return (unsigned char*)PIC(C_OID_SECP256R1);
case CX_CURVE_BrainPoolP384R1: case CX_CURVE_BrainPoolP384R1:
*len = sizeof(C_OID_SECP384R1); *len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1); return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_BrainPoolP512R1: case CX_CURVE_BrainPoolP512R1:
*len = sizeof(C_OID_SECP521R1); *len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1); return (unsigned char*)PIC(C_OID_SECP521R1);
*/ */
case CX_CURVE_Ed25519: case CX_CURVE_Ed25519:
*len = sizeof(C_OID_Ed25519); *len = sizeof(C_OID_Ed25519);
return (unsigned char*)PIC(C_OID_Ed25519); return (unsigned char *)PIC(C_OID_Ed25519);
case CX_CURVE_Curve25519: case CX_CURVE_Curve25519:
*len = sizeof(C_OID_cv25519); *len = sizeof(C_OID_cv25519);
return (unsigned char*)PIC(C_OID_cv25519); return (unsigned char *)PIC(C_OID_cv25519);
} }
*len = 0; *len = 0;
@ -181,7 +173,7 @@ unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
unsigned int gpg_curve2domainlen(unsigned int cv) { unsigned int gpg_curve2domainlen(unsigned int cv) {
switch (cv) { switch (cv) {
case CX_CURVE_SECP256R1: case CX_CURVE_SECP256R1:
case CX_CURVE_Ed25519: case CX_CURVE_Ed25519:
case CX_CURVE_Curve25519: case CX_CURVE_Curve25519:
return 32; return 32;
} }
@ -193,80 +185,68 @@ unsigned int gpg_curve2domainlen(unsigned int cv) {
/* -------------------------------*/ /* -------------------------------*/
const unsigned char C_ext_capabilities[10] = { const unsigned char C_ext_capabilities[10] = {
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -KDF //-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -KDF
0x7E, 0x7E,
// No SM, // No SM,
0x00, 0x00,
//max challenge // max challenge
SHORT(GPG_EXT_CHALLENGE_LENTH), SHORT(GPG_EXT_CHALLENGE_LENTH),
//max cert holder length // max cert holder length
SHORT(GPG_EXT_CARD_HOLDER_CERT_LENTH), SHORT(GPG_EXT_CARD_HOLDER_CERT_LENTH),
//maximum do length // maximum do length
SHORT(GPG_EXT_PRIVATE_DO_LENGTH), SHORT(GPG_EXT_PRIVATE_DO_LENGTH),
//PIN block formart 2 not supported // PIN block formart 2 not supported
0x00, 0x00,
//MSE // MSE
0x01 0x01
}; };
const unsigned char C_ext_length[8] = { const unsigned char C_ext_length[8] = {0x02, 0x02, SHORT(GPG_APDU_LENGTH), 0x02, 0x02, SHORT(GPG_APDU_LENGTH)};
0x02, 0x02, SHORT(GPG_APDU_LENGTH),
0x02, 0x02, SHORT(GPG_APDU_LENGTH)
};
/* ---------------------*/ /* ---------------------*/
/* -- default values -- */ /* -- default values -- */
/* ---------------------*/ /* ---------------------*/
const unsigned char C_default_AID[] = { const unsigned char C_default_AID[] = {0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01, // version
//version 0x03, 0x03,
0x03, 0x03, // manufacturer
//manufacturer 0x2C, 0x97,
0x2C, 0x97, // serial
//serial 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // RFU
//RFU 0x00, 0x00};
0x00,0x00
}; const unsigned char C_default_Histo[] = {0x00, 0x31,
0xC5, // select method: by DF/partialDF; IO-file:readbinary; RFU???
const unsigned char C_default_Histo[] = { 0x73,
0x00, 0xC0, // select method: by DF/partialDF ,
0x31, 0x01, // data coding style: ontime/byte
0xC5, // select method: by DF/partialDF; IO-file:readbinary; RFU??? 0x80, // chaining
0x73, 0x7F, // zero state
0xC0, // select method: by DF/partialDF , 0x90, 0x00};
0x01, // data coding style: ontime/byte
0x80, // chaining
0x7F, // zero state
0x90, 0x00
};
// Default template: RSA2048 010800002001 / 010800002001 // Default template: RSA2048 010800002001 / 010800002001
#if 1 #if 1
const unsigned char C_default_AlgoAttr_sig[] = { const unsigned char C_default_AlgoAttr_sig[] = {
// RSA // RSA
0x01, 0x01,
// Modulus default length 2048 // Modulus default length 2048
0x08, 0x00, 0x08, 0x00,
// PubExp length 32 // PubExp length 32
0x00, 0x20, 0x00, 0x20,
// std: e,p,q with modulus (n) // std: e,p,q with modulus (n)
0x01 0x01};
}; const unsigned char C_default_AlgoAttr_dec[] = {
const unsigned char C_default_AlgoAttr_dec[] = { // RSA
// RSA 0x01,
0x01, // Modulus default length 2048
// Modulus default length 2048 0x08, 0x00,
0x08, 0x00, // PubExp length 32
// PubExp length 32 0x00, 0x20,
0x00, 0x20, // std: e,p,q with modulus (n)
// std: e,p,q with modulus (n) 0x01};
0x01
};
#endif #endif
// Default template: NIST P256 132A8648CE3D030107 / 122A8648CE3D030107 // Default template: NIST P256 132A8648CE3D030107 / 122A8648CE3D030107
@ -285,7 +265,6 @@ const unsigned char C_default_AlgoAttr_dec[] = {
}; };
#endif #endif
// Default template: Ed/Cv-25519 162B06010401DA470F01 / 122B060104019755010501 // Default template: Ed/Cv-25519 162B06010401DA470F01 / 122B060104019755010501
#if 0 #if 0
const unsigned char C_default_AlgoAttr_sig[] = { const unsigned char C_default_AlgoAttr_sig[] = {
@ -304,148 +283,143 @@ const unsigned char C_default_AlgoAttr_dec[] = {
// sha256 0x3132343536 // sha256 0x3132343536
const unsigned char C_sha256_PW1[] = { const unsigned char C_sha256_PW1[] = {
0x8d, 0x96, 0x9e, 0xef, 0x6e, 0xca, 0xd3, 0xc2, 0x8d, 0x96, 0x9e, 0xef, 0x6e, 0xca, 0xd3, 0xc2, 0x9a, 0x3a, 0x62, 0x92, 0x80, 0xe6, 0x86, 0xcf,
0x9a, 0x3a, 0x62, 0x92, 0x80, 0xe6, 0x86, 0xcf, 0x0c, 0x3f, 0x5d, 0x5a, 0x86, 0xaf, 0xf3, 0xca, 0x12, 0x02, 0x0c, 0x92, 0x3a, 0xdc, 0x6c, 0x92,
0x0c, 0x3f, 0x5d, 0x5a, 0x86, 0xaf, 0xf3, 0xca,
0x12, 0x02, 0x0c, 0x92, 0x3a, 0xdc, 0x6c, 0x92,
}; };
// sha256 0x31323435363738 // sha256 0x31323435363738
const unsigned char C_sha256_PW2[] = { const unsigned char C_sha256_PW2[] = {
0xef, 0x79, 0x7c, 0x81, 0x18, 0xf0, 0x2d, 0xfb, 0xef, 0x79, 0x7c, 0x81, 0x18, 0xf0, 0x2d, 0xfb, 0x64, 0x96, 0x07, 0xdd, 0x5d, 0x3f, 0x8c, 0x76,
0x64, 0x96, 0x07, 0xdd, 0x5d, 0x3f, 0x8c, 0x76, 0x23, 0x04, 0x8c, 0x9c, 0x06, 0x3d, 0x53, 0x2c, 0xc9, 0x5c, 0x5e, 0xd7, 0xa8, 0x98, 0xa6, 0x4f,
0x23, 0x04, 0x8c, 0x9c, 0x06, 0x3d, 0x53, 0x2c,
0xc9, 0x5c, 0x5e, 0xd7, 0xa8, 0x98, 0xa6, 0x4f,
}; };
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- boot init --- */ /* --- boot init --- */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
void gpg_init() { void gpg_init() {
os_memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t)); os_memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
//first init ? // first init ?
if (os_memcmp(N_gpg_pstate->magic, (void*)C_MAGIC, sizeof(C_MAGIC)) != 0) { if (os_memcmp((void *)(N_gpg_pstate->magic), (void *)C_MAGIC, sizeof(C_MAGIC)) != 0) {
gpg_install(STATE_ACTIVATE); gpg_install(STATE_ACTIVATE);
gpg_nvm_write(N_gpg_pstate->magic, (void*)C_MAGIC, sizeof(C_MAGIC)); gpg_nvm_write((void *)(N_gpg_pstate->magic), (void *)C_MAGIC, sizeof(C_MAGIC));
os_memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t)); os_memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
} }
//key conf // key conf
G_gpg_vstate.slot = N_gpg_pstate->config_slot[1]; G_gpg_vstate.slot = N_gpg_pstate->config_slot[1];
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot]; G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
gpg_mse_reset(); gpg_mse_reset();
//pin conf // pin conf
G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0]; G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0];
//ux conf // ux conf
gpg_init_ux(); gpg_init_ux();
} }
void gpg_init_ux() { void gpg_init_ux() {
G_gpg_vstate.ux_type = -1; G_gpg_vstate.ux_type = -1;
G_gpg_vstate.ux_key = -1; G_gpg_vstate.ux_key = -1;
} }
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- Install/ReInstall GPGapp --- */ /* --- Install/ReInstall GPGapp --- */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
int gpg_install(unsigned char app_state) { int gpg_install(unsigned char app_state) {
gpg_pin_t pin; gpg_pin_t pin;
unsigned int l; unsigned int l;
//full reset data // full reset data
gpg_nvm_write(N_gpg_pstate, NULL, sizeof(gpg_nv_state_t)); gpg_nvm_write((void *)(N_gpg_pstate), NULL, sizeof(gpg_nv_state_t));
//historical bytes // historical bytes
os_memmove(G_gpg_vstate.work.io_buffer, C_default_Histo, sizeof(C_default_Histo)); os_memmove(G_gpg_vstate.work.io_buffer, C_default_Histo, sizeof(C_default_Histo));
G_gpg_vstate.work.io_buffer[7] = app_state; G_gpg_vstate.work.io_buffer[7] = app_state;
gpg_nvm_write(N_gpg_pstate->histo, G_gpg_vstate.work.io_buffer, sizeof(C_default_Histo)); gpg_nvm_write((void *)(N_gpg_pstate->histo), G_gpg_vstate.work.io_buffer, sizeof(C_default_Histo));
//AID // AID
os_memmove(G_gpg_vstate.work.io_buffer, C_default_AID, sizeof(C_default_AID)); os_memmove(G_gpg_vstate.work.io_buffer, C_default_AID, sizeof(C_default_AID));
gpg_nvm_write(N_gpg_pstate->AID, &G_gpg_vstate.work.io_buffer, sizeof(C_default_AID)); gpg_nvm_write((void *)(N_gpg_pstate->AID), &G_gpg_vstate.work.io_buffer, sizeof(C_default_AID));
//Serial // Serial
cx_rng(G_gpg_vstate.work.io_buffer, 4*GPG_KEYS_SLOTS); cx_rng(G_gpg_vstate.work.io_buffer, 4 * GPG_KEYS_SLOTS);
for (int s=0; s<GPG_KEYS_SLOTS; s++) { for (int s = 0; s < GPG_KEYS_SLOTS; s++) {
gpg_nvm_write(N_gpg_pstate->keys[s].serial, G_gpg_vstate.work.io_buffer+4*s, 4); gpg_nvm_write((void *)(N_gpg_pstate->keys[s].serial), G_gpg_vstate.work.io_buffer + 4 * s, 4);
} }
if (app_state == STATE_ACTIVATE) { if (app_state == STATE_ACTIVATE) {
// default sex: none
//default sex: none
G_gpg_vstate.work.io_buffer[0] = 0x39; G_gpg_vstate.work.io_buffer[0] = 0x39;
gpg_nvm_write(&N_gpg_pstate->sex, G_gpg_vstate.work.io_buffer, 1); gpg_nvm_write((void *)(&N_gpg_pstate->sex), G_gpg_vstate.work.io_buffer, 1);
//default PW1/PW2: 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)); os_memmove(pin.value, C_sha256_PW1, sizeof(C_sha256_PW1));
pin.length = 6; pin.length = 6;
pin.counter = 3; pin.counter = 3;
pin.ref = PIN_ID_PW1; pin.ref = PIN_ID_PW1;
gpg_nvm_write(&N_gpg_pstate->PW1, &pin, sizeof(gpg_pin_t)); gpg_nvm_write((void *)(&N_gpg_pstate->PW1), &pin, sizeof(gpg_pin_t));
//default PW3: 1 2 3 4 5 6 7 8 // default PW3: 1 2 3 4 5 6 7 8
os_memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2)); os_memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2));
pin.length = 8; pin.length = 8;
pin.counter = 3; pin.counter = 3;
pin.ref = PIN_ID_PW3; pin.ref = PIN_ID_PW3;
gpg_nvm_write(&N_gpg_pstate->PW3, &pin, sizeof(gpg_pin_t)); gpg_nvm_write((void *)(&N_gpg_pstate->PW3), &pin, sizeof(gpg_pin_t));
//PWs status // PWs status
G_gpg_vstate.work.io_buffer[0] = 1; G_gpg_vstate.work.io_buffer[0] = 1;
G_gpg_vstate.work.io_buffer[1] = GPG_MAX_PW_LENGTH; G_gpg_vstate.work.io_buffer[1] = GPG_MAX_PW_LENGTH;
G_gpg_vstate.work.io_buffer[2] = GPG_MAX_PW_LENGTH; G_gpg_vstate.work.io_buffer[2] = GPG_MAX_PW_LENGTH;
G_gpg_vstate.work.io_buffer[3] = GPG_MAX_PW_LENGTH; G_gpg_vstate.work.io_buffer[3] = GPG_MAX_PW_LENGTH;
gpg_nvm_write(&N_gpg_pstate->PW_status, G_gpg_vstate.work.io_buffer, 4); gpg_nvm_write((void *)(&N_gpg_pstate->PW_status), G_gpg_vstate.work.io_buffer, 4);
//config slot // config slot
G_gpg_vstate.work.io_buffer[0] = GPG_KEYS_SLOTS; G_gpg_vstate.work.io_buffer[0] = GPG_KEYS_SLOTS;
G_gpg_vstate.work.io_buffer[1] = 0; G_gpg_vstate.work.io_buffer[1] = 0;
G_gpg_vstate.work.io_buffer[2] = 3; // 3: selection by APDU and screen 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); gpg_nvm_write((void *)(&N_gpg_pstate->config_slot), G_gpg_vstate.work.io_buffer, 3);
//config rsa pub // config rsa pub
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB>>24)&0xFF; 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[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[2] = (GPG_RSA_DEFAULT_PUB >> 8) & 0xFF;
G_gpg_vstate.work.io_buffer[3] = (GPG_RSA_DEFAULT_PUB>>0)&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); nvm_write((void *)(&N_gpg_pstate->default_RSA_exponent), G_gpg_vstate.work.io_buffer, 4);
//config pin // config pin
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM; G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM;
gpg_nvm_write(&N_gpg_pstate->config_pin, G_gpg_vstate.work.io_buffer, 1); gpg_nvm_write((void *)(&N_gpg_pstate->config_pin), G_gpg_vstate.work.io_buffer, 1);
USBD_CCID_activate_pinpad(3); USBD_CCID_activate_pinpad(3);
//default key template: RSA 2048) // default key template: RSA 2048)
for (int s = 0; s< GPG_KEYS_SLOTS; s++) { for (int s = 0; s < GPG_KEYS_SLOTS; s++) {
unsigned char uif[2]; unsigned char uif[2];
uif[0] = 0x00; uif[0] = 0x00;
uif[1] = 0x20; uif[1] = 0x20;
l = sizeof(C_default_AlgoAttr_sig); l = sizeof(C_default_AlgoAttr_sig);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.value, (void*)C_default_AlgoAttr_sig, l); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].sig.attributes.value), (void *)C_default_AlgoAttr_sig, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.attributes.length, &l, sizeof(unsigned int)); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].sig.attributes.length), &l, sizeof(unsigned int));
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.attributes.value, (void*)C_default_AlgoAttr_sig, l); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].aut.attributes.value), (void *)C_default_AlgoAttr_sig, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.attributes.length, &l, sizeof(unsigned int)); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].aut.attributes.length), &l, sizeof(unsigned int));
l = sizeof(C_default_AlgoAttr_dec); l = sizeof(C_default_AlgoAttr_dec);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.value, (void*)C_default_AlgoAttr_dec, l); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].dec.attributes.value), (void *)C_default_AlgoAttr_dec, l);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.attributes.length, &l, sizeof(unsigned int)); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].dec.attributes.length), &l, sizeof(unsigned int));
gpg_nvm_write(&N_gpg_pstate->keys[s].sig.UIF, &uif, 2); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].sig.UIF), &uif, 2);
gpg_nvm_write(&N_gpg_pstate->keys[s].dec.UIF, &uif, 2); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].dec.UIF), &uif, 2);
gpg_nvm_write(&N_gpg_pstate->keys[s].aut.UIF, &uif, 2); gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].aut.UIF), &uif, 2);
} }
} }
return 0; return 0;
} }
#define USBD_OFFSET_CfgDesc_bPINSupport (sizeof(USBD_CfgDesc) - 16)
#define USBD_OFFSET_CfgDesc_bPINSupport (sizeof(USBD_CfgDesc)-16) void USBD_CCID_activate_pinpad(int enabled) {
void USBD_CCID_activate_pinpad(int enabled) { #ifdef HAVE_USB_CLASS_CCID
unsigned short length; unsigned short length;
uint8_t *cfgDesc; uint8_t * cfgDesc;
unsigned char e; unsigned char e;
e = enabled?3:0; e = enabled ? 3 : 0;
length = 0; length = 0;
cfgDesc = USBD_GetCfgDesc_impl(&length); cfgDesc = USBD_GetCfgDesc_impl(&length);
nvm_write(cfgDesc+(length-16), &e,1); nvm_write(cfgDesc + (length - 16), &e, 1);
#endif
} }

@ -19,7 +19,6 @@
#include "gpg_api.h" #include "gpg_api.h"
#include "gpg_vars.h" #include "gpg_vars.h"
/* /*
* io_buff: contains current message part * io_buff: contains current message part
* io_off: offset in current message part * io_off: offset in current message part
@ -33,25 +32,20 @@
void gpg_io_set_offset(unsigned int offset) { void gpg_io_set_offset(unsigned int offset) {
if (offset == IO_OFFSET_END) { if (offset == IO_OFFSET_END) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_length; G_gpg_vstate.io_offset = G_gpg_vstate.io_length;
} } else if (offset == IO_OFFSET_MARK) {
else if (offset == IO_OFFSET_MARK) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_mark; G_gpg_vstate.io_offset = G_gpg_vstate.io_mark;
} } else if (offset < G_gpg_vstate.io_length) {
else if (offset < G_gpg_vstate.io_length) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_length; G_gpg_vstate.io_offset = G_gpg_vstate.io_length;
} } else {
else {
THROW(ERROR_IO_OFFSET); THROW(ERROR_IO_OFFSET);
return ; return;
} }
} }
void gpg_io_mark() { void gpg_io_mark() {
G_gpg_vstate.io_mark = G_gpg_vstate.io_offset; G_gpg_vstate.io_mark = G_gpg_vstate.io_offset;
} }
void gpg_io_inserted(unsigned int len) { void gpg_io_inserted(unsigned int len) {
G_gpg_vstate.io_offset += len; G_gpg_vstate.io_offset += len;
G_gpg_vstate.io_length += len; G_gpg_vstate.io_length += len;
@ -60,14 +54,14 @@ void gpg_io_inserted(unsigned int len) {
void gpg_io_discard(int clear) { void gpg_io_discard(int clear) {
G_gpg_vstate.io_length = 0; G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_offset = 0; G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_mark = 0; G_gpg_vstate.io_mark = 0;
if (clear) { if (clear) {
gpg_io_clear(); gpg_io_clear();
} }
} }
void gpg_io_clear() { void gpg_io_clear() {
os_memset(G_gpg_vstate.work.io_buffer, 0 , GPG_IO_BUFFER_LENGTH); os_memset(G_gpg_vstate.work.io_buffer, 0, GPG_IO_BUFFER_LENGTH);
} }
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
@ -77,54 +71,52 @@ void gpg_io_clear() {
void gpg_io_hole(unsigned int sz) { void gpg_io_hole(unsigned int sz) {
if ((G_gpg_vstate.io_length + sz) > GPG_IO_BUFFER_LENGTH) { if ((G_gpg_vstate.io_length + sz) > GPG_IO_BUFFER_LENGTH) {
THROW(ERROR_IO_FULL); THROW(ERROR_IO_FULL);
return ; return;
} }
os_memmove(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+sz, 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, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, G_gpg_vstate.io_length - G_gpg_vstate.io_offset);
G_gpg_vstate.io_length-G_gpg_vstate.io_offset);
G_gpg_vstate.io_length += sz; G_gpg_vstate.io_length += sz;
} }
void gpg_io_insert(unsigned char const *buff, unsigned int len) { void gpg_io_insert(unsigned char const *buff, unsigned int len) {
gpg_io_hole(len); gpg_io_hole(len);
os_memmove(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, buff, len); os_memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, buff, len);
G_gpg_vstate.io_offset += len; G_gpg_vstate.io_offset += len;
} }
void gpg_io_insert_u32(unsigned int v32) { void gpg_io_insert_u32(unsigned int v32) {
gpg_io_hole(4); gpg_io_hole(4);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] = v32>>24; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v32 >> 24;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] = v32>>16; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v32 >> 16;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+2] = v32>>8; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] = v32 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+3] = v32>>0; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] = v32 >> 0;
G_gpg_vstate.io_offset += 4; G_gpg_vstate.io_offset += 4;
} }
void gpg_io_insert_u24(unsigned int v24) { void gpg_io_insert_u24(unsigned int v24) {
gpg_io_hole(3); gpg_io_hole(3);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] = v24>>16; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v24 >> 16;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] = v24>>8; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v24 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+2] = v24>>0; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] = v24 >> 0;
G_gpg_vstate.io_offset += 3; G_gpg_vstate.io_offset += 3;
} }
void gpg_io_insert_u16(unsigned int v16) { void gpg_io_insert_u16(unsigned int v16) {
gpg_io_hole(2); gpg_io_hole(2);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] = v16>>8; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v16 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] = v16>>0; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v16 >> 0;
G_gpg_vstate.io_offset += 2; G_gpg_vstate.io_offset += 2;
} }
void gpg_io_insert_u8(unsigned int v8) { void gpg_io_insert_u8(unsigned int v8) {
gpg_io_hole(1); gpg_io_hole(1);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] = v8; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v8;
G_gpg_vstate.io_offset += 1; G_gpg_vstate.io_offset += 1;
} }
void gpg_io_insert_t(unsigned int T) { void gpg_io_insert_t(unsigned int T) {
if (T &0xFF00) { if (T & 0xFF00) {
gpg_io_insert_u16(T); gpg_io_insert_u16(T);
} else { } else {
gpg_io_insert_u8(T); gpg_io_insert_u8(T);
} }
} }
@ -133,7 +125,7 @@ void gpg_io_insert_tl(unsigned int T, unsigned int L) {
if (L < 128) { if (L < 128) {
gpg_io_insert_u8(L); gpg_io_insert_u8(L);
} else if (L < 256) { } else if (L < 256) {
gpg_io_insert_u16(0x8100|L); gpg_io_insert_u16(0x8100 | L);
} else { } else {
gpg_io_insert_u8(0x82); gpg_io_insert_u8(0x82);
gpg_io_insert_u16(L); gpg_io_insert_u16(L);
@ -141,46 +133,44 @@ void gpg_io_insert_tl(unsigned int T, unsigned int L) {
} }
void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) { void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) {
gpg_io_insert_tl(T,L); gpg_io_insert_tl(T, L);
gpg_io_insert(V, L); gpg_io_insert(V, L);
} }
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* FECTH data from received buffer */ /* FECTH data from received buffer */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
unsigned int gpg_io_fetch_u32() { unsigned int gpg_io_fetch_u32() {
unsigned int v32; unsigned int v32;
v32 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 24) | v32 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 24) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] << 16) | (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+2] << 8) | (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+3] << 0) ); (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] << 0));
G_gpg_vstate.io_offset += 4; G_gpg_vstate.io_offset += 4;
return v32; return v32;
} }
unsigned int gpg_io_fetch_u24() { unsigned int gpg_io_fetch_u24() {
unsigned int v24; unsigned int v24;
v24 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 16) | 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 + 1] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+2] << 0) ); (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] << 0));
G_gpg_vstate.io_offset += 3; G_gpg_vstate.io_offset += 3;
return v24; return v24;
} }
unsigned int gpg_io_fetch_u16() { unsigned int gpg_io_fetch_u16() {
unsigned int v16; unsigned int v16;
v16 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 8) | v16 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] << 0) ); (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 0));
G_gpg_vstate.io_offset += 2; G_gpg_vstate.io_offset += 2;
return v16; return v16;
} }
unsigned int gpg_io_fetch_u8() { unsigned int gpg_io_fetch_u8() {
unsigned int v8; unsigned int v8;
v8 = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] ; v8 = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset += 1; G_gpg_vstate.io_offset += 1;
return v8; return v8;
} }
@ -201,16 +191,17 @@ int gpg_io_fetch_l(unsigned int *L) {
if ((*L & 0x80) != 0) { if ((*L & 0x80) != 0) {
*L &= 0x7F; *L &= 0x7F;
if (*L == 1) { if (*L == 1) {
*L = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1]; *L = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1];
G_gpg_vstate.io_offset += 2; G_gpg_vstate.io_offset += 2;
} else if (*L == 2) { } else if (*L == 2) {
*L = (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] ; *L = (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 8) |
G_gpg_vstate.io_offset += 3 ; G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2];
G_gpg_vstate.io_offset += 3;
} else { } else {
*L = -1; *L = -1;
} }
} else { } else {
G_gpg_vstate.io_offset += 1 ; G_gpg_vstate.io_offset += 1;
} }
return 0; return 0;
} }
@ -221,20 +212,19 @@ int gpg_io_fetch_tl(unsigned int *T, unsigned int *L) {
return 0; return 0;
} }
int gpg_io_fetch_nv(unsigned char* buffer, int len) { int gpg_io_fetch_nv(unsigned char *buffer, int len) {
gpg_nvm_write(buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, len); gpg_nvm_write(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
G_gpg_vstate.io_offset += len; G_gpg_vstate.io_offset += len;
return len; return len;
} }
int gpg_io_fetch(unsigned char* buffer, int len) { int gpg_io_fetch(unsigned char *buffer, int len) {
if (buffer) { if (buffer) {
os_memmove(buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, len); os_memmove(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
} }
G_gpg_vstate.io_offset += len; G_gpg_vstate.io_offset += len;
return len; return len;
} }
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* REAL IO */ /* REAL IO */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
@ -244,125 +234,119 @@ int gpg_io_fetch(unsigned char* buffer, int len) {
int gpg_io_do(unsigned int io_flags) { int gpg_io_do(unsigned int io_flags) {
unsigned int rx = 0; unsigned int rx = 0;
//if pending input chaining // if pending input chaining
if (G_gpg_vstate.io_cla & 0x10) { if (G_gpg_vstate.io_cla & 0x10) {
goto in_chaining; goto in_chaining;
} }
if (io_flags & IO_ASYNCH_REPLY) { if (io_flags & IO_ASYNCH_REPLY) {
// if IO_ASYNCH_REPLY has been set, // if IO_ASYNCH_REPLY has been set,
// gpg_io_exchange will return when IO_RETURN_AFTER_TX will set in ui // gpg_io_exchange will return when IO_RETURN_AFTER_TX will set in ui
rx = gpg_io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0); rx = gpg_io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0);
} else { } else {
// --- full out chaining --- // --- full out chaining ---
G_gpg_vstate.io_offset = 0; G_gpg_vstate.io_offset = 0;
while(G_gpg_vstate.io_length > MAX_OUT) { while (G_gpg_vstate.io_length > MAX_OUT) {
unsigned int tx,xx; unsigned int tx, xx;
//send chunk // send chunk
tx = MAX_OUT-2; tx = MAX_OUT - 2;
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, tx); 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_length -= tx;
G_gpg_vstate.io_offset += tx; G_gpg_vstate.io_offset += tx;
G_io_apdu_buffer[tx] = 0x61; G_io_apdu_buffer[tx] = 0x61;
if (G_gpg_vstate.io_length > MAX_OUT-2) { if (G_gpg_vstate.io_length > MAX_OUT - 2) {
xx = MAX_OUT-2; xx = MAX_OUT - 2;
} else { } else {
xx = G_gpg_vstate.io_length-2; xx = G_gpg_vstate.io_length - 2;
} }
G_io_apdu_buffer[tx+1] = xx; G_io_apdu_buffer[tx + 1] = xx;
rx = gpg_io_exchange(CHANNEL_APDU, tx+2); rx = gpg_io_exchange(CHANNEL_APDU, tx + 2);
//check get response // check get response
if ((G_io_apdu_buffer[0] != 0x00) || if ((G_io_apdu_buffer[0] != 0x00) || (G_io_apdu_buffer[1] != 0xc0) || (G_io_apdu_buffer[2] != 0x00) ||
(G_io_apdu_buffer[1] != 0xc0) || (G_io_apdu_buffer[3] != 0x00)) {
(G_io_apdu_buffer[2] != 0x00) ||
(G_io_apdu_buffer[3] != 0x00) ) {
THROW(SW_COMMAND_NOT_ALLOWED); THROW(SW_COMMAND_NOT_ALLOWED);
return 0; return 0;
} }
} }
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, 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);
if (io_flags & IO_RETURN_AFTER_TX) { if (io_flags & IO_RETURN_AFTER_TX) {
rx = gpg_io_exchange(CHANNEL_APDU |IO_RETURN_AFTER_TX, G_gpg_vstate.io_length); rx = gpg_io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_gpg_vstate.io_length);
return 0; return 0;
} else { } else {
rx = gpg_io_exchange(CHANNEL_APDU, G_gpg_vstate.io_length); rx = gpg_io_exchange(CHANNEL_APDU, G_gpg_vstate.io_length);
} }
} }
//--- full in chaining --- //--- full in chaining ---
if (rx < 4) { if (rx < 4) {
THROW(SW_COMMAND_NOT_ALLOWED); THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED; return SW_COMMAND_NOT_ALLOWED;
} }
if (rx == 4) { if (rx == 4) {
G_io_apdu_buffer[4]=0; G_io_apdu_buffer[4] = 0;
rx = 4; rx = 4;
} }
G_gpg_vstate.io_offset = 0; G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_length = 0; G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_cla = G_io_apdu_buffer[0]; G_gpg_vstate.io_cla = G_io_apdu_buffer[0];
G_gpg_vstate.io_ins = G_io_apdu_buffer[1]; G_gpg_vstate.io_ins = G_io_apdu_buffer[1];
G_gpg_vstate.io_p1 = G_io_apdu_buffer[2]; G_gpg_vstate.io_p1 = G_io_apdu_buffer[2];
G_gpg_vstate.io_p2 = G_io_apdu_buffer[3]; G_gpg_vstate.io_p2 = G_io_apdu_buffer[3];
G_gpg_vstate.io_lc = 0; G_gpg_vstate.io_lc = 0;
G_gpg_vstate.io_le = 0; G_gpg_vstate.io_le = 0;
switch (G_gpg_vstate.io_ins) { switch (G_gpg_vstate.io_ins) {
case INS_GET_DATA: case INS_GET_DATA:
case INS_GET_RESPONSE: case INS_GET_RESPONSE:
case INS_TERMINATE_DF: case INS_TERMINATE_DF:
case INS_ACTIVATE_FILE: case INS_ACTIVATE_FILE:
G_gpg_vstate.io_le = G_io_apdu_buffer[4]; G_gpg_vstate.io_le = G_io_apdu_buffer[4];
break; break;
case INS_GET_CHALLENGE: case INS_GET_CHALLENGE:
if (G_gpg_vstate.io_p1 == 0) { if (G_gpg_vstate.io_p1 == 0) {
break; break;
} }
case INS_VERIFY: case INS_VERIFY:
case INS_CHANGE_REFERENCE_DATA: case INS_CHANGE_REFERENCE_DATA:
if (G_io_apdu_buffer[4] == 0) { if (G_io_apdu_buffer[4] == 0) {
break; break;
} }
goto _default; goto _default;
default: default:
_default: _default:
G_gpg_vstate.io_lc = G_io_apdu_buffer[4]; 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); 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; G_gpg_vstate.io_length = G_gpg_vstate.io_lc;
break; break;
} }
while(G_gpg_vstate.io_cla & 0x10) { while (G_gpg_vstate.io_cla & 0x10) {
G_io_apdu_buffer[0] = 0x90; G_io_apdu_buffer[0] = 0x90;
G_io_apdu_buffer[1] = 0x00; G_io_apdu_buffer[1] = 0x00;
rx = gpg_io_exchange(CHANNEL_APDU, 2); rx = gpg_io_exchange(CHANNEL_APDU, 2);
in_chaining: in_chaining:
if ((rx < 4) || if ((rx < 4) || ((G_io_apdu_buffer[0] & 0xEF) != (G_gpg_vstate.io_cla & 0xEF)) ||
((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[1] != G_gpg_vstate.io_ins) || (G_io_apdu_buffer[3] != G_gpg_vstate.io_p2)) {
(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; return SW_COMMAND_NOT_ALLOWED;
} }
if (rx == 4) { if (rx == 4) {
G_io_apdu_buffer[4]=0; G_io_apdu_buffer[4] = 0;
rx = 4; rx = 4;
} }
G_gpg_vstate.io_cla = G_io_apdu_buffer[0]; G_gpg_vstate.io_cla = G_io_apdu_buffer[0];
G_gpg_vstate.io_lc = G_io_apdu_buffer[4]; G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
if ((G_gpg_vstate.io_length + G_gpg_vstate.io_lc) > GPG_IO_BUFFER_LENGTH) { if ((G_gpg_vstate.io_length + G_gpg_vstate.io_lc) > GPG_IO_BUFFER_LENGTH) {
return 1; return 1;
} }
os_memmove(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_length, G_io_apdu_buffer+5, G_gpg_vstate.io_lc); os_memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_length, G_io_apdu_buffer + 5, G_gpg_vstate.io_lc);
G_gpg_vstate.io_length += G_gpg_vstate.io_lc; G_gpg_vstate.io_length += G_gpg_vstate.io_lc;
} }
return 0; return 0;
} }

@ -28,7 +28,6 @@
#include "string.h" #include "string.h"
#include "glyphs.h" #include "glyphs.h"
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- Application Entry --- */ /* --- Application Entry --- */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
@ -45,8 +44,7 @@ void gpg_main(void) {
} }
CATCH_OTHER(e) { CATCH_OTHER(e) {
gpg_io_discard(1); gpg_io_discard(1);
if ( (e & 0xFFFF0000) || if ((e & 0xFFFF0000) || (((e & 0xF000) != 0x6000) && ((e & 0xF000) != 0x9000))) {
( ((e&0xF000)!=0x6000) && ((e&0xF000)!=0x9000) ) ) {
gpg_io_insert_u32(e); gpg_io_insert_u32(e);
sw = 0x6f42; sw = 0x6f42;
} else { } else {
@ -64,10 +62,8 @@ void gpg_main(void) {
} }
END_TRY; END_TRY;
} }
} }
unsigned char io_event(unsigned char channel) { unsigned char io_event(unsigned char channel) {
// nothing done with the event, throw an error on the transport layer if // nothing done with the event, throw an error on the transport layer if
// needed // needed
@ -81,7 +77,6 @@ unsigned char io_event(unsigned char channel) {
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break; break;
// other events are propagated to the UX just in case // other events are propagated to the UX just in case
default: default:
UX_DEFAULT_EVENT(); UX_DEFAULT_EVENT();
@ -91,11 +86,10 @@ unsigned char io_event(unsigned char channel) {
UX_DISPLAYED_EVENT({}); UX_DISPLAYED_EVENT({});
break; break;
case SEPROXYHAL_TAG_TICKER_EVENT: case SEPROXYHAL_TAG_TICKER_EVENT:
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {
{ // only allow display when not locked of overlayed by an OS UX.
// only allow display when not locked of overlayed by an OS UX. if (UX_ALLOWED) {
if (UX_ALLOWED ) { UX_REDISPLAY();
UX_REDISPLAY();
} }
}); });
break; break;
@ -125,8 +119,7 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
return 0; // nothing received from the master so far (it's a tx return 0; // nothing received from the master so far (it's a tx
// transaction) // transaction)
} else { } else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer, return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
sizeof(G_io_apdu_buffer), 0);
} }
default: default:
@ -153,39 +146,36 @@ __attribute__((section(".boot"))) int main(void) {
// exit critical section // exit critical section
__asm volatile("cpsie i"); __asm volatile("cpsie i");
// ensure exception will work as planned // ensure exception will work as planned
os_boot(); os_boot();
for(;;) { for (;;) {
UX_INIT(); UX_INIT();
BEGIN_TRY { BEGIN_TRY {
TRY { TRY {
// start communication with MCU
//start communication with MCU
io_seproxyhal_init(); io_seproxyhal_init();
USB_power(1); USB_power(1);
#if HAVE_USB_CLASS_CCID
io_usb_ccid_set_card_inserted(1); io_usb_ccid_set_card_inserted(1);
#endif
//set up // set up
gpg_init(); gpg_init();
//set up initial screen
ui_init();
// set up initial screen
ui_init();
//start the application // start the application
//the first exchange will: // the first exchange will:
// - display the initial screen // - display the initial screen
// - send the ATR // - send the ATR
// - receive the first command // - receive the first command
gpg_main(); gpg_main();
} }
CATCH(EXCEPTION_IO_RESET) { CATCH(EXCEPTION_IO_RESET) {
// reset IO and UX // reset IO and UX
continue; continue;
} }
CATCH_ALL { CATCH_ALL {

@ -20,29 +20,26 @@
#include "gpg_vars.h" #include "gpg_vars.h"
static int gpg_mse_set(int crt, int ref) { static int gpg_mse_set(int crt, int ref) {
if (crt == 0xA4) { if (crt == 0xA4) {
if (ref == 0x02) { if (ref == 0x02) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->dec; G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->dec;
} }
if (ref == 0x03) { if (ref == 0x03) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->aut; G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->aut;
} }
} }
if (crt == 0xB8) { if (crt == 0xB8) {
if (ref == 0x02) { if (ref == 0x02) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->dec; G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->dec;
} }
if (ref == 0x03) { if (ref == 0x03) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->aut; G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->aut;
} }
} }
return 0; return 0;
} }
int gpg_mse_reset() { int gpg_mse_reset() {
gpg_mse_set(0xA4, 0x03); gpg_mse_set(0xA4, 0x03);
gpg_mse_set(0xB8, 0x02); gpg_mse_set(0xB8, 0x02);
@ -50,29 +47,26 @@ int gpg_mse_reset() {
} }
int gpg_apdu_mse() { int gpg_apdu_mse() {
int crt,ref; int crt, ref;
if ((G_gpg_vstate.io_p1 != 0x41) || if ((G_gpg_vstate.io_p1 != 0x41) || ((G_gpg_vstate.io_p2 != 0xA4) && (G_gpg_vstate.io_p2 != 0xB8))) {
((G_gpg_vstate.io_p2 != 0xA4)&&(G_gpg_vstate.io_p2 != 0xB8))) {
THROW(SW_INCORRECT_P1P2); THROW(SW_INCORRECT_P1P2);
return SW_INCORRECT_P1P2; return SW_INCORRECT_P1P2;
} }
crt = gpg_io_fetch_u16(); crt = gpg_io_fetch_u16();
if (crt != 0x8301) { if (crt != 0x8301) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
ref = gpg_io_fetch_u8(); ref = gpg_io_fetch_u8();
if ((ref != 0x02) && (ref != 0x03)) { if ((ref != 0x02) && (ref != 0x03)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
gpg_mse_set(crt,ref); gpg_mse_set(crt, ref);
gpg_io_discard(1); gpg_io_discard(1);
return SW_OK; return SW_OK;
} }

@ -19,4 +19,8 @@
#include "gpg_api.h" #include "gpg_api.h"
#include "gpg_vars.h" #include "gpg_vars.h"
#ifdef TARGET_NANOX
const gpg_nv_state_t N_state_pic;
#else
gpg_nv_state_t N_state_pic; gpg_nv_state_t N_state_pic;
#endif

@ -23,8 +23,8 @@
gpg_pin_t *gpg_pin_get_pin(int pinref) { gpg_pin_t *gpg_pin_get_pin(int pinref) {
switch (pinref) { switch (pinref) {
case PIN_ID_PW1 : case PIN_ID_PW1:
case PIN_ID_PW2 : case PIN_ID_PW2:
return &N_gpg_pstate->PW1; return &N_gpg_pstate->PW1;
case PIN_ID_PW3: case PIN_ID_PW3:
return &N_gpg_pstate->PW3; return &N_gpg_pstate->PW3;
@ -34,37 +34,33 @@ gpg_pin_t *gpg_pin_get_pin(int pinref) {
return NULL; return NULL;
} }
static int gpg_pin_get_state_index(unsigned int pinref) {
static int gpg_pin_get_state_index(unsigned int pinref) {
switch (pinref) { switch (pinref) {
case PIN_ID_PW1 : case PIN_ID_PW1:
return 1; return 1;
case PIN_ID_PW2 : case PIN_ID_PW2:
return 2; return 2;
case PIN_ID_PW3 : case PIN_ID_PW3:
return 3; return 3;
case PIN_ID_RC : case PIN_ID_RC:
return 4; return 4;
} }
return -1; return -1;
} }
static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int pin_len) { static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int pin_len) {
cx_sha256_t sha256;
unsigned int counter; unsigned int counter;
if (pin->counter == 0) { if (pin->counter == 0) {
return SW_PIN_BLOCKED; return SW_PIN_BLOCKED;
} }
counter = pin->counter-1; counter = pin->counter - 1;
gpg_nvm_write(&(pin->counter), &counter, sizeof(int)); gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
cx_sha256_init(&sha256); cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t*)&sha256, CX_LAST, pin_val, pin_len, NULL, 0); cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, CX_LAST, pin_val, pin_len, G_gpg_vstate.work.md.H,
if (os_memcmp(sha256.acc, pin->value, 32)) { sizeof(G_gpg_vstate.work.md.H));
if (os_memcmp(G_gpg_vstate.work.md.H, pin->value, 32)) {
return SW_SECURITY_STATUS_NOT_SATISFIED; return SW_SECURITY_STATUS_NOT_SATISFIED;
} }
@ -73,26 +69,24 @@ static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int p
return SW_OK; return SW_OK;
} }
static void gpg_pin_check_throw(gpg_pin_t *pin, int pinID, static void gpg_pin_check_throw(gpg_pin_t *pin, int pinID, unsigned char *pin_val, int pin_len) {
unsigned char *pin_val, int pin_len) {
int sw; int sw;
gpg_pin_set_verified(pinID,0); gpg_pin_set_verified(pinID, 0);
sw = gpg_pin_check_internal(pin,pin_val,pin_len); sw = gpg_pin_check_internal(pin, pin_val, pin_len);
if (sw == SW_OK) { if (sw == SW_OK) {
gpg_pin_set_verified(pinID,1); gpg_pin_set_verified(pinID, 1);
return; return;
} }
THROW(sw); THROW(sw);
return; return;
} }
int gpg_pin_check(gpg_pin_t *pin, int pinID, int gpg_pin_check(gpg_pin_t *pin, int pinID, unsigned char *pin_val, unsigned int pin_len) {
unsigned char *pin_val, unsigned int pin_len) {
int sw; int sw;
gpg_pin_set_verified(pinID,0); gpg_pin_set_verified(pinID, 0);
sw = gpg_pin_check_internal(pin,pin_val,pin_len); sw = gpg_pin_check_internal(pin, pin_val, pin_len);
if (sw == SW_OK) { if (sw == SW_OK) {
gpg_pin_set_verified(pinID,1); gpg_pin_set_verified(pinID, 1);
} }
return sw; return sw;
} }
@ -103,8 +97,8 @@ void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len) {
gpg_pin_t newpin; gpg_pin_t newpin;
cx_sha256_init(&sha256); cx_sha256_init(&sha256);
cx_hash((cx_hash_t*)&sha256, CX_LAST, pin_val, pin_len, newpin.value, 32); cx_hash((cx_hash_t *)&sha256, CX_LAST, pin_val, pin_len, newpin.value, 32);
newpin.length = pin_len; newpin.length = pin_len;
newpin.counter = 3; newpin.counter = 3;
gpg_nvm_write(pin, &newpin, sizeof(gpg_pin_t)); gpg_nvm_write(pin, &newpin, sizeof(gpg_pin_t));
@ -114,27 +108,25 @@ int gpg_pin_set_verified(int pinID, int verified) {
int idx; int idx;
idx = gpg_pin_get_state_index(pinID); idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) { if (idx >= 0) {
G_gpg_vstate.verified_pin[idx]=verified; G_gpg_vstate.verified_pin[idx] = verified;
return verified; return verified;
} }
return 0; return 0;
} }
int gpg_pin_is_verified(int pinID) { int gpg_pin_is_verified(int pinID) {
int idx; int idx;
idx = gpg_pin_get_state_index(pinID); idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) { if (idx >= 0) {
return G_gpg_vstate.verified_pin[idx]; return G_gpg_vstate.verified_pin[idx];
} }
return 0; return 0;
} }
int gpg_pin_is_blocked(gpg_pin_t *pin) { int gpg_pin_is_blocked(gpg_pin_t *pin) {
return pin->counter == 0; return pin->counter == 0;
} }
int gpg_apdu_verify() { int gpg_apdu_verify() {
gpg_pin_t *pin; gpg_pin_t *pin;
@ -143,8 +135,8 @@ int gpg_apdu_verify() {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
//PINPAD // PINPAD
if (G_gpg_vstate.io_cla == 0xEF) { if (G_gpg_vstate.io_cla == 0xEF) {
if (gpg_pin_is_blocked(pin)) { if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED); THROW(SW_PIN_BLOCKED);
@ -152,34 +144,33 @@ int gpg_apdu_verify() {
} }
if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) { if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) {
//Delegate pin check to ui // Delegate pin check to ui
gpg_io_discard(1); gpg_io_discard(1);
ui_menu_pinentry_display(0); ui_menu_pinentry_display(0);
return 0; return 0;
} }
if (G_gpg_vstate.pinmode == PIN_MODE_CONFIRM) { if (G_gpg_vstate.pinmode == PIN_MODE_CONFIRM) {
//Delegate pin check to ui // Delegate pin check to ui
gpg_io_discard(1); gpg_io_discard(1);
ui_menu_pinconfirm_display(0); ui_menu_pinconfirm_display(0);
return 0; return 0;
} }
if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) { if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) {
gpg_pin_set_verified(G_gpg_vstate.io_p2,1); gpg_pin_set_verified(G_gpg_vstate.io_p2, 1);
gpg_io_discard(1); gpg_io_discard(1);
return SW_OK; return SW_OK;
} }
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
//NORMAL CHECK // NORMAL CHECK
if ((G_gpg_vstate.io_p1==0) && G_gpg_vstate.io_length) { if ((G_gpg_vstate.io_p1 == 0) && G_gpg_vstate.io_length) {
if (gpg_pin_is_blocked(pin)) { if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED); THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED; return SW_PIN_BLOCKED;
} }
gpg_pin_check_throw(pin, G_gpg_vstate.io_p2, gpg_pin_check_throw(pin, G_gpg_vstate.io_p2, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
G_gpg_vstate.work.io_buffer+ G_gpg_vstate.io_offset,
G_gpg_vstate.io_length); G_gpg_vstate.io_length);
gpg_io_discard(1); gpg_io_discard(1);
return SW_OK; return SW_OK;
@ -187,75 +178,66 @@ int gpg_apdu_verify() {
gpg_io_discard(1); gpg_io_discard(1);
//STATUS REQUEST // STATUS REQUEST
if ((G_gpg_vstate.io_p1==0) && G_gpg_vstate.io_length==0) { if ((G_gpg_vstate.io_p1 == 0) && G_gpg_vstate.io_length == 0) {
if (gpg_pin_is_verified(G_gpg_vstate.io_p2)) { if (gpg_pin_is_verified(G_gpg_vstate.io_p2)) {
return SW_OK; return SW_OK;
} }
return 0x63C0 | pin->counter; return 0x63C0 | pin->counter;
} }
//RESET REQUEST // RESET REQUEST
if ((G_gpg_vstate.io_p1==0xFF) && G_gpg_vstate.io_length==0) { if ((G_gpg_vstate.io_p1 == 0xFF) && G_gpg_vstate.io_length == 0) {
gpg_pin_set_verified(G_gpg_vstate.io_p2,0); gpg_pin_set_verified(G_gpg_vstate.io_p2, 0);
return SW_OK; return SW_OK;
} }
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
int gpg_apdu_change_ref_data() { int gpg_apdu_change_ref_data() {
gpg_pin_t *pin; gpg_pin_t *pin;
int len, newlen; int len, newlen;
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2); pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
if (pin == NULL) { if (pin == NULL) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
gpg_pin_set_verified(pin->ref,0); gpg_pin_set_verified(pin->ref, 0);
// --- PW1/PW3 pin --- // --- PW1/PW3 pin ---
if (gpg_pin_is_blocked(pin)) { if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED); THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED; return SW_PIN_BLOCKED;
} }
//avoid any-overflow whitout giving info // avoid any-overflow whitout giving info
if (G_gpg_vstate.io_length == 0) { if (G_gpg_vstate.io_length == 0) {
if (G_gpg_vstate.pinmode != PIN_MODE_HOST) { if (G_gpg_vstate.pinmode != PIN_MODE_HOST) {
//Delegate pin change to ui // Delegate pin change to ui
gpg_io_discard(1); gpg_io_discard(1);
ui_menu_pinentry_display(0); ui_menu_pinentry_display(0);
return 0; return 0;
} }
} }
if (pin->length > G_gpg_vstate.io_length) { if (pin->length > G_gpg_vstate.io_length) {
len = G_gpg_vstate.io_length; len = G_gpg_vstate.io_length;
} else { } else {
len = pin->length; len = pin->length;
} }
gpg_pin_check_throw(pin, pin->ref, gpg_pin_check_throw(pin, pin->ref, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
len);
newlen = G_gpg_vstate.io_length-len; newlen = G_gpg_vstate.io_length - len;
if ( (newlen > GPG_MAX_PW_LENGTH) || if ((newlen > GPG_MAX_PW_LENGTH) || ((pin->ref == PIN_ID_PW1) && (newlen < 6)) ||
((pin->ref == PIN_ID_PW1) && (newlen < 6)) || ((pin->ref == PIN_ID_PW3) && (newlen < 8))) {
((pin->ref == PIN_ID_PW3) && (newlen < 8)) ) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
gpg_pin_set(pin, gpg_pin_set(pin, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + len, newlen);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+len,
newlen);
gpg_io_discard(1); gpg_io_discard(1);
return SW_OK; return SW_OK;
} }
@ -264,40 +246,35 @@ int gpg_apdu_reset_retry_counter() {
gpg_pin_t *pin_pw1; gpg_pin_t *pin_pw1;
gpg_pin_t *pin_pw3; gpg_pin_t *pin_pw3;
gpg_pin_t *pin_rc; gpg_pin_t *pin_rc;
int rc_len, pw1_len; int rc_len, pw1_len;
pin_pw1 = gpg_pin_get_pin(PIN_ID_PW1); pin_pw1 = gpg_pin_get_pin(PIN_ID_PW1);
pin_pw3 = gpg_pin_get_pin(PIN_ID_PW3); pin_pw3 = gpg_pin_get_pin(PIN_ID_PW3);
pin_rc = gpg_pin_get_pin(PIN_ID_RC); pin_rc = gpg_pin_get_pin(PIN_ID_RC);
if (G_gpg_vstate.io_p1 == 2) { if (G_gpg_vstate.io_p1 == 2) {
if (!gpg_pin_is_verified(PIN_ID_PW3)) { if (!gpg_pin_is_verified(PIN_ID_PW3)) {
THROW(SW_SECURITY_STATUS_NOT_SATISFIED); THROW(SW_SECURITY_STATUS_NOT_SATISFIED);
return SW_SECURITY_STATUS_NOT_SATISFIED; return SW_SECURITY_STATUS_NOT_SATISFIED;
} }
rc_len = 0; rc_len = 0;
pw1_len = G_gpg_vstate.io_length; pw1_len = G_gpg_vstate.io_length;
} else { } else {
// avoid any-overflow whitout giving info
//avoid any-overflow whitout giving info
if (pin_rc->length > G_gpg_vstate.io_length) { if (pin_rc->length > G_gpg_vstate.io_length) {
rc_len = G_gpg_vstate.io_length; rc_len = G_gpg_vstate.io_length;
} else { } else {
rc_len = pin_rc->length; rc_len = pin_rc->length;
} }
pw1_len = G_gpg_vstate.io_length-rc_len; pw1_len = G_gpg_vstate.io_length - rc_len;
gpg_pin_check_throw(pin_rc,pin_rc->ref, gpg_pin_check_throw(pin_rc, pin_rc->ref, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, rc_len);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
rc_len);
} }
if ((pw1_len > GPG_MAX_PW_LENGTH) ||(pw1_len < 6)) { if ((pw1_len > GPG_MAX_PW_LENGTH) || (pw1_len < 6)) {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
gpg_pin_set(pin_pw1, gpg_pin_set(pin_pw1, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + rc_len, pw1_len);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+rc_len,
pw1_len);
gpg_io_discard(1); gpg_io_discard(1);
return SW_OK; return SW_OK;
} }

@ -20,152 +20,133 @@
#include "gpg_vars.h" #include "gpg_vars.h"
#include "gpg_ux_nanos.h" #include "gpg_ux_nanos.h"
const unsigned char gpg_oid_sha256[] = { const unsigned char gpg_oid_sha256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
}; const unsigned char gpg_oid_sha512[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
const unsigned char gpg_oid_sha512[] = { 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
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() { static void gpg_pso_reset_PW1() {
if (N_gpg_pstate->PW_status[0] ==0) { if (N_gpg_pstate->PW_status[0] == 0) {
gpg_pin_set_verified(PIN_ID_PW1,0); gpg_pin_set_verified(PIN_ID_PW1, 0);
} }
} }
static int gpg_sign(gpg_key_t *sigkey) { static int gpg_sign(gpg_key_t *sigkey) {
// --- RSA // --- RSA
if (sigkey->attributes.value[0] == 1) { if (sigkey->attributes.value[0] == 1) {
cx_rsa_private_key_t *key; cx_rsa_private_key_t *key;
unsigned int ksz,l; unsigned int ksz, l;
ksz = (sigkey->attributes.value[1]<<8) | sigkey->attributes.value[2]; ksz = (sigkey->attributes.value[1] << 8) | sigkey->attributes.value[2];
ksz = ksz>>3; ksz = ksz >> 3;
switch(ksz) { switch (ksz) {
case 1024/8: case 1024 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa1024; key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa1024;
break; break;
case 2048/8: case 2048 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa2048; key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa2048;
break; break;
case 3072/8: case 3072 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa3072; key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa3072;
break; break;
case 4096/8: case 4096 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa4096; key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa4096;
break; break;
} }
if (key->size != ksz) { if (key->size != ksz) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
// sign
l = ksz - G_gpg_vstate.io_length;
os_memmove(G_gpg_vstate.work.io_buffer + l, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
os_memset(G_gpg_vstate.work.io_buffer, 0xFF, l);
G_gpg_vstate.work.io_buffer[0] = 0;
G_gpg_vstate.work.io_buffer[1] = 1;
G_gpg_vstate.work.io_buffer[l - 1] = 0;
ksz = cx_rsa_decrypt(key, CX_PAD_NONE, CX_NONE, G_gpg_vstate.work.io_buffer, ksz, G_gpg_vstate.work.io_buffer, ksz);
// send
gpg_io_discard(0);
gpg_io_inserted(ksz);
gpg_pso_reset_PW1();
return SW_OK;
}
// --- ECDSA/EdDSA
if ((sigkey->attributes.value[0] == 19) || (sigkey->attributes.value[0] == 22)) {
cx_ecfp_private_key_t *key;
unsigned int sz, i, rs_len;
unsigned char * rs;
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); THROW(SW_CONDITIONS_NOT_SATISFIED);
return 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, sz, RS, 256, NULL);
//sign // reencode r,s in MPI format
l = ksz - G_gpg_vstate.io_length;
os_memmove(G_gpg_vstate.work.io_buffer+l,
G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length);
os_memset(G_gpg_vstate.work.io_buffer, 0xFF, l);
G_gpg_vstate.work.io_buffer[0] = 0;
G_gpg_vstate.work.io_buffer[1] = 1;
G_gpg_vstate.work.io_buffer[l-1] = 0;
ksz = cx_rsa_decrypt(key,
CX_PAD_NONE,
CX_NONE,
G_gpg_vstate.work.io_buffer, ksz,
G_gpg_vstate.work.io_buffer, ksz);
//send
gpg_io_discard(0); gpg_io_discard(0);
gpg_io_inserted(ksz);
gpg_pso_reset_PW1();
return SW_OK;
}
// --- ECDSA/EdDSA
if ((sigkey->attributes.value[0] == 19) ||
(sigkey->attributes.value[0] == 22)) {
cx_ecfp_private_key_t *key;
unsigned int sz,i,rs_len;
unsigned char *rs;
key = &sigkey->priv_key.ecfp; rs_len = RS[3];
rs = &RS[4];
//sign for (i = 0; i < 2; i++) {
#define RS (G_gpg_vstate.work.io_buffer+(GPG_IO_BUFFER_LENGTH-256)) if (*rs == 0) {
if (sigkey->attributes.value[0] == 19) { rs++;
sz = gpg_curve2domainlen(key->curve); rs_len--;
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, sz,
RS, 256,
NULL);
//reencode r,s in MPI format
gpg_io_discard(0);
rs_len = RS[3];
rs = &RS[4];
for (i = 0; i<2; i++) {
if (*rs == 0) {
rs++;
rs_len--;
}
gpg_io_insert_u8(0);
gpg_io_insert(rs,rs_len);
rs = rs+rs_len;
rs_len = rs[1];
rs += 2;
} }
} else{ gpg_io_insert_u8(0);
sz = cx_eddsa_sign(key, gpg_io_insert(rs, rs_len);
CX_NONE, rs = rs + rs_len;
CX_SHA512, rs_len = rs[1];
G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, rs += 2;
NULL, 0,
RS, 256,
NULL);
gpg_io_discard(0);
gpg_io_insert(RS, sz);
} }
#undef RS } else {
sz = cx_eddsa_sign(key, CX_NONE, CX_SHA512, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, NULL, 0, RS, 256,
//send NULL);
gpg_pso_reset_PW1(); gpg_io_discard(0);
return SW_OK; gpg_io_insert(RS, sz);
} }
// --- PSO:CDS NOT SUPPORTED #undef RS
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; // 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() { int gpg_apdu_pso() {
unsigned int t,l,ksz; unsigned int t, l, ksz;
unsigned int pso; unsigned int pso;
pso = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2 ; pso = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
//UIF HANDLE // UIF HANDLE
switch(pso) { switch (pso) {
// --- PSO:CDS --- // --- PSO:CDS ---
case 0x9e9a: case 0x9e9a:
if (G_gpg_vstate.kslot->sig.UIF[0]) { if (G_gpg_vstate.kslot->sig.UIF[0]) {
if ((G_gpg_vstate.UIF_flags)==0) { if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0); ui_menu_uifconfirm_display(0);
return 0; return 0;
} }
G_gpg_vstate.UIF_flags = 0; G_gpg_vstate.UIF_flags = 0;
} }
break; break;
// --- PSO:DEC --- // --- PSO:DEC ---
case 0x8086: case 0x8086:
case 0x8680: case 0x8680:
if (G_gpg_vstate.kslot->dec.UIF[0]) { if (G_gpg_vstate.kslot->dec.UIF[0]) {
if ((G_gpg_vstate.UIF_flags)==0) { if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0); ui_menu_uifconfirm_display(0);
return 0; return 0;
} }
@ -175,35 +156,33 @@ int gpg_apdu_pso() {
} }
// --- PSO:ENC --- // --- PSO:ENC ---
switch(pso) { switch (pso) {
// --- PSO:CDS --- // --- PSO:CDS ---
case 0x9e9a: { case 0x9e9a: {
unsigned int cnt; unsigned int cnt;
int sw; int sw;
sw = gpg_sign(&G_gpg_vstate.kslot->sig); sw = gpg_sign(&G_gpg_vstate.kslot->sig);
cnt = G_gpg_vstate.kslot->sig_count+1; cnt = G_gpg_vstate.kslot->sig_count + 1;
nvm_write(&G_gpg_vstate.kslot->sig_count,&cnt,sizeof(unsigned int)); nvm_write(&G_gpg_vstate.kslot->sig_count, &cnt, sizeof(unsigned int));
return sw; return sw;
} }
// --- PSO:ENC --- // --- PSO:ENC ---
case 0x8680: { case 0x8680: {
unsigned int msg_len; unsigned int msg_len;
cx_aes_key_t *key; cx_aes_key_t *key;
unsigned int sz; unsigned int sz;
key = &G_gpg_vstate.kslot->AES_dec; key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != 16)) { if (!(key->size != 16)) {
THROW(SW_CONDITIONS_NOT_SATISFIED+5); THROW(SW_CONDITIONS_NOT_SATISFIED + 5);
return SW_CONDITIONS_NOT_SATISFIED; return SW_CONDITIONS_NOT_SATISFIED;
} }
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset; msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_aes(key, sz = cx_aes(key, CX_ENCRYPT | CX_CHAIN_CBC | CX_LAST, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, msg_len,
CX_ENCRYPT|CX_CHAIN_CBC|CX_LAST, G_gpg_vstate.work.io_buffer + 1, GPG_IO_BUFFER_LENGTH - 1);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, msg_len, // send
G_gpg_vstate.work.io_buffer+1, GPG_IO_BUFFER_LENGTH-1);
//send
gpg_io_discard(0); gpg_io_discard(0);
G_gpg_vstate.work.io_buffer[0] = 0x02; G_gpg_vstate.work.io_buffer[0] = 0x02;
gpg_io_inserted(1+sz); gpg_io_inserted(1 + sz);
return SW_OK; return SW_OK;
} }
@ -214,7 +193,7 @@ int gpg_apdu_pso() {
unsigned int sz; unsigned int sz;
pad_byte = gpg_io_fetch_u8(); pad_byte = gpg_io_fetch_u8();
switch(pad_byte) { switch (pad_byte) {
// --- PSO:DEC:RSA // --- PSO:DEC:RSA
case 0x00: { case 0x00: {
cx_rsa_private_key_t *key; cx_rsa_private_key_t *key;
@ -222,35 +201,32 @@ int gpg_apdu_pso() {
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED; return SW_CONDITIONS_NOT_SATISFIED;
} }
ksz = (G_gpg_vstate.mse_dec->attributes.value[1]<<8) | G_gpg_vstate.mse_dec->attributes.value[2]; ksz = (G_gpg_vstate.mse_dec->attributes.value[1] << 8) | G_gpg_vstate.mse_dec->attributes.value[2];
ksz = ksz>>3; ksz = ksz >> 3;
key = NULL; key = NULL;
switch(ksz) { switch (ksz) {
case 1024/8: case 1024 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa1024; key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa1024;
break; break;
case 2048/8: case 2048 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa2048; key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa2048;
break; break;
case 3072/8: case 3072 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa3072; key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa3072;
break; break;
case 4096/8: case 4096 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa4096; key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa4096;
break; break;
} }
if ((key == NULL) || (key->size != ksz)) { if ((key == NULL) || (key->size != ksz)) {
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED; return SW_CONDITIONS_NOT_SATISFIED;
} }
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset; msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_rsa_decrypt(key, sz = cx_rsa_decrypt(key, CX_PAD_PKCS1_1o5, CX_NONE, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, msg_len,
CX_PAD_PKCS1_1o5, G_gpg_vstate.work.io_buffer, ksz);
CX_NONE, // send
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, msg_len,
G_gpg_vstate.work.io_buffer,ksz);
//send
gpg_io_discard(0); gpg_io_discard(0);
gpg_io_inserted(sz); gpg_io_inserted(sz);
return SW_OK; return SW_OK;
@ -259,18 +235,16 @@ int gpg_apdu_pso() {
// --- PSO:DEC:AES // --- PSO:DEC:AES
case 0x02: { case 0x02: {
cx_aes_key_t *key; cx_aes_key_t *key;
unsigned int sz; unsigned int sz;
key = &G_gpg_vstate.kslot->AES_dec; key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != 16)) { if (!(key->size != 16)) {
THROW(SW_CONDITIONS_NOT_SATISFIED+5); THROW(SW_CONDITIONS_NOT_SATISFIED + 5);
return SW_CONDITIONS_NOT_SATISFIED; return SW_CONDITIONS_NOT_SATISFIED;
} }
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset; msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_aes(key, sz = cx_aes(key, CX_DECRYPT | CX_CHAIN_CBC | CX_LAST, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
CX_DECRYPT|CX_CHAIN_CBC|CX_LAST, msg_len, G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, msg_len, // send
G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
//send
gpg_io_discard(0); gpg_io_discard(0);
gpg_io_inserted(sz); gpg_io_inserted(sz);
return SW_OK; return SW_OK;
@ -279,8 +253,8 @@ int gpg_apdu_pso() {
// --- PSO:DEC:ECDH // --- PSO:DEC:ECDH
case 0xA6: { case 0xA6: {
cx_ecfp_private_key_t *key; cx_ecfp_private_key_t *key;
unsigned int sz; unsigned int sz;
unsigned int curve; unsigned int curve;
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x12) { if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x12) {
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED; return SW_CONDITIONS_NOT_SATISFIED;
@ -297,46 +271,41 @@ int gpg_apdu_pso() {
THROW(SW_WRONG_DATA); THROW(SW_WRONG_DATA);
return SW_WRONG_DATA; return SW_WRONG_DATA;
} }
curve = gpg_oid2curve(G_gpg_vstate.mse_dec->attributes.value+1, G_gpg_vstate.mse_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) { if (key->curve != curve) {
THROW(SW_CONDITIONS_NOT_SATISFIED); THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED; return SW_CONDITIONS_NOT_SATISFIED;
} }
if (curve == CX_CURVE_Curve25519) { if (curve == CX_CURVE_Curve25519) {
unsigned int i; unsigned int i;
for (i = 0; i <=31; i++) { for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer[512+i] = (G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset)[31-i]; G_gpg_vstate.work.io_buffer[512 + i] = (G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset)[31 - i];
} }
G_gpg_vstate.work.io_buffer[511] = 0x02; G_gpg_vstate.work.io_buffer[511] = 0x02;
sz = cx_ecdh(key, sz = cx_ecdh(key, CX_ECDH_X, G_gpg_vstate.work.io_buffer + 511, 65, G_gpg_vstate.work.io_buffer + 256, 160);
CX_ECDH_X, for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer+511, 65, G_gpg_vstate.work.io_buffer[128 + i] = G_gpg_vstate.work.io_buffer[287 - i];
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];
} }
sz = 32; sz = 32;
} else { } else {
sz = cx_ecdh(key, sz = cx_ecdh(key, CX_ECDH_X, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, 65,
CX_ECDH_X, G_gpg_vstate.work.io_buffer + 128, 160);
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, 65,
G_gpg_vstate.work.io_buffer+128, 160);
} }
//send // send
gpg_io_discard(0); gpg_io_discard(0);
gpg_io_insert( G_gpg_vstate.work.io_buffer+128,sz); gpg_io_insert(G_gpg_vstate.work.io_buffer + 128, sz);
return SW_OK; return SW_OK;
} }
// --- PSO:DEC:xx NOT SUPPORTDED // --- PSO:DEC:xx NOT SUPPORTDED
default: default:
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
} }
//--- PSO:yy NOT SUPPPORTED --- //--- PSO:yy NOT SUPPPORTED ---
default: default:
THROW(SW_REFERENCED_DATA_NOT_FOUND); THROW(SW_REFERENCED_DATA_NOT_FOUND);
@ -346,11 +315,10 @@ int gpg_apdu_pso() {
return SW_REFERENCED_DATA_NOT_FOUND; return SW_REFERENCED_DATA_NOT_FOUND;
} }
int gpg_apdu_internal_authenticate() { int gpg_apdu_internal_authenticate() {
// --- PSO:AUTH --- // --- PSO:AUTH ---
if (G_gpg_vstate.kslot->aut.UIF[0]) { if (G_gpg_vstate.kslot->aut.UIF[0]) {
if ((G_gpg_vstate.UIF_flags)==0) { if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0); ui_menu_uifconfirm_display(0);
return 0; return 0;
} }
@ -358,10 +326,11 @@ int gpg_apdu_internal_authenticate() {
} }
if (G_gpg_vstate.mse_aut->attributes.value[0] == 1) { 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) { if (G_gpg_vstate.io_length >
((G_gpg_vstate.mse_aut->attributes.value[1] << 8) | G_gpg_vstate.mse_aut->attributes.value[2]) * 40 / 100) {
THROW(SW_WRONG_LENGTH); THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH; return SW_WRONG_LENGTH;
} }
} }
return gpg_sign(G_gpg_vstate.mse_aut); return gpg_sign(G_gpg_vstate.mse_aut);
} }

@ -18,19 +18,21 @@
#include "gpg_types.h" #include "gpg_types.h"
#include "gpg_api.h" #include "gpg_api.h"
#include "gpg_vars.h" #include "gpg_vars.h"
#include "os_io_seproxyhal.h" #include "os_io_seproxyhal.h"
#ifdef TARGET_NANOX
#include "ux.h"
ux_state_t G_ux;
bolos_ux_params_t G_ux_params;
#else
ux_state_t ux;
#endif
#ifndef GPG_DEBUG_MAIN #ifndef GPG_DEBUG_MAIN
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
ux_state_t ux;
#else #else
extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
int apdu_n; int apdu_n;
#endif #endif
gpg_v_state_t G_gpg_vstate;
gpg_v_state_t G_gpg_vstate;

@ -13,7 +13,6 @@
* limitations under the License. * limitations under the License.
*/ */
#include "os.h" #include "os.h"
#include "cx.h" #include "cx.h"
#include "gpg_types.h" #include "gpg_types.h"
@ -24,24 +23,23 @@ const unsigned char C_MF[] = {0x3F, 0x00};
int gpg_apdu_select() { int gpg_apdu_select() {
int sw; int sw;
//MF // MF
if ( (G_gpg_vstate.io_length == 2) && if ((G_gpg_vstate.io_length == 2) && (os_memcmp(G_gpg_vstate.work.io_buffer, C_MF, G_gpg_vstate.io_length) == 0)) {
(os_memcmp(G_gpg_vstate.work.io_buffer, C_MF, G_gpg_vstate.io_length) == 0) ) {
gpg_io_discard(0); gpg_io_discard(0);
sw = SW_OK; sw = SW_OK;
} }
//AID APP // AID APP
else if ( (G_gpg_vstate.io_length == 6) && else if ((G_gpg_vstate.io_length == 6) &&
(os_memcmp(G_gpg_vstate.work.io_buffer, N_gpg_pstate->AID, G_gpg_vstate.io_length) == 0) ) { (os_memcmp(G_gpg_vstate.work.io_buffer, N_gpg_pstate->AID, G_gpg_vstate.io_length) == 0)) {
G_gpg_vstate.DO_current = 0; G_gpg_vstate.DO_current = 0;
G_gpg_vstate.DO_reccord = 0; G_gpg_vstate.DO_reccord = 0;
G_gpg_vstate.DO_offset = 0; G_gpg_vstate.DO_offset = 0;
if ( G_gpg_vstate.selected == 0) { if (G_gpg_vstate.selected == 0) {
G_gpg_vstate.verified_pin[0] = 0; G_gpg_vstate.verified_pin[0] = 0;
G_gpg_vstate.verified_pin[1] = 0; G_gpg_vstate.verified_pin[1] = 0;
G_gpg_vstate.verified_pin[2] = 0; G_gpg_vstate.verified_pin[2] = 0;
G_gpg_vstate.verified_pin[3] = 0; G_gpg_vstate.verified_pin[3] = 0;
G_gpg_vstate.verified_pin[4] = 0; G_gpg_vstate.verified_pin[4] = 0;
} }
gpg_io_discard(0); gpg_io_discard(0);
@ -49,8 +47,8 @@ int gpg_apdu_select() {
THROW(SW_STATE_TERMINATED); THROW(SW_STATE_TERMINATED);
} }
sw = SW_OK; sw = SW_OK;
} }
//NOT FOUND // NOT FOUND
else { else {
THROW(SW_FILE_NOT_FOUND); THROW(SW_FILE_NOT_FOUND);
return SW_FILE_NOT_FOUND; return SW_FILE_NOT_FOUND;

@ -17,96 +17,96 @@
#define GPG_TYPES_H #define GPG_TYPES_H
#include "os_io_seproxyhal.h" #include "os_io_seproxyhal.h"
#ifdef TARGET_NANOX
#include "ux.h"
#endif
/* cannot send more that F0 bytes in CCID, why? do not know for now /* 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 * So set up length to F0 minus 2 bytes for SW
*/ */
#define GPG_APDU_LENGTH 0xFE #define GPG_APDU_LENGTH 0xFE
/* big private DO */ /* big private DO */
#define GPG_EXT_PRIVATE_DO_LENGTH 512 #define GPG_EXT_PRIVATE_DO_LENGTH 512
/* will be fixed..1024 is not enougth */ /* will be fixed..1024 is not enougth */
#define GPG_EXT_CARD_HOLDER_CERT_LENTH 2560 #define GPG_EXT_CARD_HOLDER_CERT_LENTH 2560
/* random choice */ /* random choice */
#define GPG_EXT_CHALLENGE_LENTH 254 #define GPG_EXT_CHALLENGE_LENTH 254
/* accpet long PW, but less than one sha256 block */ /* accpet long PW, but less than one sha256 block */
#define GPG_MAX_PW_LENGTH 12 #define GPG_MAX_PW_LENGTH 12
#if GPG_MULTISLOT #if GPG_MULTISLOT
#define GPG_KEYS_SLOTS 3 #define GPG_KEYS_SLOTS 3
#else #else
#define GPG_KEYS_SLOTS 1 #define GPG_KEYS_SLOTS 1
#endif #endif
#define GPG_KEY_ATTRIBUTES_LENGTH 12 #define GPG_KEY_ATTRIBUTES_LENGTH 12
#define GPG_RSA_DEFAULT_PUB 0x00010001U #define GPG_RSA_DEFAULT_PUB 0x00010001U
struct gpg_pin_s { struct gpg_pin_s {
unsigned int ref; unsigned int ref;
//initial pin length, 0 means not set // initial pin length, 0 means not set
unsigned int length; unsigned int length;
unsigned int counter; unsigned int counter;
//only store sha256 of PIN/RC // only store sha256 of PIN/RC
unsigned char value[32]; unsigned char value[32];
}; };
typedef struct gpg_pin_s gpg_pin_t; typedef struct gpg_pin_s gpg_pin_t;
#define LV(name, maxlen) \
struct { \
#define LV(name,maxlen) \ unsigned int length; \
struct { \ unsigned char value[maxlen]; \
unsigned int length; \
unsigned char value[maxlen]; \
} name } name
typedef struct gpg_lv_s { typedef struct gpg_lv_s {
unsigned int length; unsigned int length;
unsigned char value[]; unsigned char value[];
} gpg_lv_t; } gpg_lv_t;
typedef struct gpg_key_s { typedef struct gpg_key_s {
/* C1 C2 C3 */ /* C1 C2 C3 */
LV(attributes,GPG_KEY_ATTRIBUTES_LENGTH); LV(attributes, GPG_KEY_ATTRIBUTES_LENGTH);
/* key value */ /* key value */
/* WARN: changing the cx_<key>_t structures breaks backup/restore. Adapt backup/restore code /* WARN: changing the cx_<key>_t structures breaks backup/restore. Adapt backup/restore code
* to ensure backward compatibility. * to ensure backward compatibility.
*/ */
union { union {
cx_rsa_private_key_t rsa; cx_rsa_private_key_t rsa;
cx_rsa_1024_private_key_t rsa1024; cx_rsa_1024_private_key_t rsa1024;
cx_rsa_2048_private_key_t rsa2048; cx_rsa_2048_private_key_t rsa2048;
cx_rsa_3072_private_key_t rsa3072; cx_rsa_3072_private_key_t rsa3072;
cx_rsa_4096_private_key_t rsa4096; cx_rsa_4096_private_key_t rsa4096;
cx_ecfp_private_key_t ecfp; cx_ecfp_private_key_t ecfp;
cx_ecfp_256_private_key_t ecfp256; cx_ecfp_256_private_key_t ecfp256;
cx_ecfp_384_private_key_t ecfp384; cx_ecfp_384_private_key_t ecfp384;
cx_ecfp_512_private_key_t ecfp512; cx_ecfp_512_private_key_t ecfp512;
cx_ecfp_640_private_key_t ecfp640; cx_ecfp_640_private_key_t ecfp640;
} priv_key; } priv_key;
union { union {
unsigned char rsa[4]; unsigned char rsa[4];
cx_ecfp_public_key_t ecfp; cx_ecfp_public_key_t ecfp;
cx_ecfp_256_public_key_t ecfp256; cx_ecfp_256_public_key_t ecfp256;
cx_ecfp_384_public_key_t ecfp384; cx_ecfp_384_public_key_t ecfp384;
cx_ecfp_512_public_key_t ecfp512; cx_ecfp_512_public_key_t ecfp512;
cx_ecfp_640_public_key_t ecfp640; cx_ecfp_640_public_key_t ecfp640;
} pub_key; } pub_key;
/* C7 C8 C9 , C5 = C7|C8|C9*/ /* C7 C8 C9 , C5 = C7|C8|C9*/
unsigned char fingerprints[20]; unsigned char fingerprints[20];
/* 7F21 */ /* 7F21 */
LV(CA,GPG_EXT_CARD_HOLDER_CERT_LENTH); LV(CA, GPG_EXT_CARD_HOLDER_CERT_LENTH);
/* C7 C8 C9, C6 = C7|C8|C9*/ /* C7 C8 C9, C6 = C7|C8|C9*/
unsigned char CA_fingerprints[20]; unsigned char CA_fingerprints[20];
/* CE CF D0, CD = CE|CF|D0 */ /* CE CF D0, CD = CE|CF|D0 */
unsigned char date[4]; unsigned char date[4];
/* D6/D7/D8- */ /* D6/D7/D8- */
unsigned char UIF[2]; unsigned char UIF[2];
} gpg_key_t; } gpg_key_t;
typedef struct gpg_key_slot_s {
typedef struct gpg_key_slot_s{
unsigned char serial[4]; unsigned char serial[4];
/* */ /* */
gpg_key_t sig; gpg_key_t sig;
@ -120,7 +120,6 @@ typedef struct gpg_key_slot_s{
} gpg_key_slot_t; } gpg_key_slot_t;
struct gpg_nv_state_s { struct gpg_nv_state_s {
/* magic */ /* magic */
unsigned char magic[8]; unsigned char magic[8];
@ -146,21 +145,21 @@ struct gpg_nv_state_s {
/* -- Cardholder Related Data -- */ /* -- Cardholder Related Data -- */
/* 5B */ /* 5B */
LV(name,39); LV(name, 39);
/* 5F2D */ /* 5F2D */
LV(lang, 8); LV(lang, 8);
/* 5F35 */ /* 5F35 */
unsigned char sex[1]; unsigned char sex[1];
/* -- Application Related Data -- */ /* -- Application Related Data -- */
/* 4F */ /* 4F */
unsigned char AID[16]; unsigned char AID[16];
/* 5F52 */ /* 5F52 */
unsigned char histo[15]; unsigned char histo[15];
/* 7f66 */ /* 7f66 */
//unsigned char ext_length_info[8]; // unsigned char ext_length_info[8];
/* C0 */ /* C0 */
//unsigned char ext_capabilities[10]; // unsigned char ext_capabilities[10];
/* C4 */ /* C4 */
unsigned char PW_status[4]; unsigned char PW_status[4];
@ -178,7 +177,7 @@ struct gpg_nv_state_s {
cx_aes_key_t SM_enc; cx_aes_key_t SM_enc;
/* D2 */ /* D2 */
cx_aes_key_t SM_mac; cx_aes_key_t SM_mac;
} ; };
typedef struct gpg_nv_state_s gpg_nv_state_t; typedef struct gpg_nv_state_s gpg_nv_state_t;
@ -188,37 +187,37 @@ struct gpg_v_state_s {
/* app state */ /* app state */
unsigned char selected; unsigned char selected;
unsigned char slot; /* DO 01F2 */ unsigned char slot; /* DO 01F2 */
gpg_key_slot_t *kslot; gpg_key_slot_t *kslot;
gpg_key_t *mse_aut; gpg_key_t * mse_aut;
gpg_key_t *mse_dec; gpg_key_t * mse_dec;
unsigned char seed_mode; unsigned char seed_mode;
unsigned char UIF_flags; unsigned char UIF_flags;
/* io state*/ /* io state*/
unsigned char io_cla; unsigned char io_cla;
unsigned char io_ins; unsigned char io_ins;
unsigned char io_p1; unsigned char io_p1;
unsigned char io_p2; unsigned char io_p2;
unsigned char io_lc; unsigned char io_lc;
unsigned char io_le; unsigned char io_le;
unsigned short io_length; unsigned short io_length;
unsigned short io_offset; unsigned short io_offset;
unsigned short io_mark; unsigned short io_mark;
union { union {
unsigned char io_buffer[GPG_IO_BUFFER_LENGTH]; unsigned char io_buffer[GPG_IO_BUFFER_LENGTH];
struct { struct {
union { union {
cx_rsa_public_key_t public; cx_rsa_public_key_t public;
cx_rsa_1024_public_key_t public1024; cx_rsa_1024_public_key_t public1024;
cx_rsa_2048_public_key_t public2048; cx_rsa_2048_public_key_t public2048;
cx_rsa_3072_public_key_t public3072; cx_rsa_3072_public_key_t public3072;
cx_rsa_4096_public_key_t public4096; cx_rsa_4096_public_key_t public4096;
}; };
union { union {
cx_rsa_private_key_t private; cx_rsa_private_key_t private;
cx_rsa_1024_private_key_t private1024; cx_rsa_1024_private_key_t private1024;
cx_rsa_2048_private_key_t private2048; cx_rsa_2048_private_key_t private2048;
cx_rsa_3072_private_key_t private3072; cx_rsa_3072_private_key_t private3072;
@ -227,26 +226,27 @@ struct gpg_v_state_s {
} rsa; } rsa;
struct { struct {
union{ union {
cx_ecfp_public_key_t public; cx_ecfp_public_key_t public;
cx_ecfp_256_public_key_t public256; cx_ecfp_256_public_key_t public256;
cx_ecfp_384_public_key_t public384; cx_ecfp_384_public_key_t public384;
cx_ecfp_512_public_key_t public512; cx_ecfp_512_public_key_t public512;
cx_ecfp_640_public_key_t public640; cx_ecfp_640_public_key_t public640;
}; };
union { union {
cx_ecfp_private_key_t private; cx_ecfp_private_key_t private;
cx_ecfp_256_private_key_t private256; cx_ecfp_256_private_key_t private256;
cx_ecfp_384_private_key_t private384; cx_ecfp_384_private_key_t private384;
cx_ecfp_512_private_key_t private512; cx_ecfp_512_private_key_t private512;
cx_ecfp_640_private_key_t private640; cx_ecfp_640_private_key_t private640;
}; };
}ecfp; } ecfp;
struct { struct {
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH-MAX(sizeof(cx_sha3_t),sizeof(cx_sha256_t))]; unsigned char md_buffer[GPG_IO_BUFFER_LENGTH - (32 + MAX(sizeof(cx_sha3_t), sizeof(cx_sha256_t)))];
unsigned char H[32];
union { union {
cx_sha3_t sha3; cx_sha3_t sha3;
cx_sha256_t sha256; cx_sha256_t sha256;
}; };
} md; } md;
@ -266,124 +266,128 @@ struct gpg_v_state_s {
unsigned char ux_pinentry[12]; unsigned char ux_pinentry[12];
unsigned int ux_key; unsigned int ux_key;
unsigned int ux_type; unsigned int ux_type;
ux_menu_entry_t ui_dogsays[2] ;
#ifdef UI_NANO_S
ux_menu_entry_t ui_dogsays[2];
#endif
#ifdef UI_NANO_X
char ux_buff1[32];
char ux_buff2[32];
char ux_buff3[32];
char ux_buff4[32];
char ux_buff5[32];
#endif
#ifdef GPG_DEBUG #ifdef GPG_DEBUG
unsigned char print; unsigned char print;
#endif #endif
} ; };
typedef struct gpg_v_state_s gpg_v_state_t; typedef struct gpg_v_state_s gpg_v_state_t;
/* --- Errors --- */ /* --- Errors --- */
#define ERROR(x) ((x)<<16) #define ERROR(x) ((x) << 16)
#define ERROR_IO_OFFSET ERROR(1) #define ERROR_IO_OFFSET ERROR(1)
#define ERROR_IO_FULL ERROR(2) #define ERROR_IO_FULL ERROR(2)
/* --- IDentifiers --- */ /* --- IDentifiers --- */
#define ID_AUTH 1
#define ID_DEC 2
#define ID_SIG 3
#define ID_AUTH 1 #define STATE_ACTIVATE 0x07
#define ID_DEC 2 #define STATE_TERMINATE 0x03
#define ID_SIG 3
#define STATE_ACTIVATE 0x07 #define IO_OFFSET_END (unsigned int)-1
#define STATE_TERMINATE 0x03 #define IO_OFFSET_MARK (unsigned int)-2
#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
#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 --- */ /* --- INS --- */
#define INS_EXIT 0x02 #define INS_EXIT 0x02
#define INS_SELECT 0xa4 #define INS_SELECT 0xa4
#define INS_TERMINATE_DF 0xe6 #define INS_TERMINATE_DF 0xe6
#define INS_ACTIVATE_FILE 0x44 #define INS_ACTIVATE_FILE 0x44
#define INS_SELECT_DATA 0xa5 #define INS_SELECT_DATA 0xa5
#define INS_GET_DATA 0xca #define INS_GET_DATA 0xca
#define INS_GET_NEXT_DATA 0xcc #define INS_GET_NEXT_DATA 0xcc
#define INS_PUT_DATA 0xda #define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb #define INS_PUT_DATA_ODD 0xdb
#define INS_VERIFY 0x20 #define INS_VERIFY 0x20
#define INS_MSE 0x22 #define INS_MSE 0x22
#define INS_CHANGE_REFERENCE_DATA 0x24 #define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_RESET_RETRY_COUNTER 0x2c #define INS_RESET_RETRY_COUNTER 0x2c
#define INS_GEN_ASYM_KEYPAIR 0x47 #define INS_GEN_ASYM_KEYPAIR 0x47
#define INS_PSO 0x2a #define INS_PSO 0x2a
//#define INS_COMPUTEDIGSIG 0x2a //#define INS_COMPUTEDIGSIG 0x2a
//#define INS_DECIPHER 0x2a //#define INS_DECIPHER 0x2a
#define INS_INTERNAL_AUTHENTICATE 0x88 #define INS_INTERNAL_AUTHENTICATE 0x88
#define INS_GET_CHALLENGE 0x84
#define INS_GET_RESPONSE 0xc0
#define INS_GET_CHALLENGE 0x84
#define INS_GET_RESPONSE 0xc0
/* --- IO constants --- */ /* --- IO constants --- */
#define OFFSET_CLA 0 #define OFFSET_CLA 0
#define OFFSET_INS 1 #define OFFSET_INS 1
#define OFFSET_P1 2 #define OFFSET_P1 2
#define OFFSET_P2 3 #define OFFSET_P2 3
#define OFFSET_P3 4 #define OFFSET_P3 4
#define OFFSET_CDATA 5 #define OFFSET_CDATA 5
#define OFFSET_EXT_CDATA 7 #define OFFSET_EXT_CDATA 7
#define SW_OK 0x9000
#define SW_OK 0x9000 #define SW_ALGORITHM_UNSUPPORTED 0x9484
#define SW_ALGORITHM_UNSUPPORTED 0x9484
#define SW_BYTES_REMAINING_00 0x6100
#define SW_BYTES_REMAINING_00 0x6100
#define SW_WARNING_STATE_UNCHANGED 0x6200
#define SW_WARNING_STATE_UNCHANGED 0x6200 #define SW_STATE_TERMINATED 0x6285
#define SW_STATE_TERMINATED 0x6285
#define SW_MORE_DATA_AVAILABLE 0x6310
#define SW_MORE_DATA_AVAILABLE 0x6310
#define SW_WRONG_LENGTH 0x6700
#define SW_WRONG_LENGTH 0x6700
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881 #define SW_SECURE_MESSAGING_NOT_SUPPORTED 0x6882
#define SW_SECURE_MESSAGING_NOT_SUPPORTED 0x6882 #define SW_LAST_COMMAND_EXPECTED 0x6883
#define SW_LAST_COMMAND_EXPECTED 0x6883 #define SW_COMMAND_CHAINING_NOT_SUPPORTED 0x6884
#define SW_COMMAND_CHAINING_NOT_SUPPORTED 0x6884
#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982
#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 #define SW_FILE_INVALID 0x6983
#define SW_FILE_INVALID 0x6983 #define SW_PIN_BLOCKED 0x6983
#define SW_PIN_BLOCKED 0x6983 #define SW_DATA_INVALID 0x6984
#define SW_DATA_INVALID 0x6984 #define SW_CONDITIONS_NOT_SATISFIED 0x6985
#define SW_CONDITIONS_NOT_SATISFIED 0x6985 #define SW_COMMAND_NOT_ALLOWED 0x6986
#define SW_COMMAND_NOT_ALLOWED 0x6986 #define SW_APPLET_SELECT_FAILED 0x6999
#define SW_APPLET_SELECT_FAILED 0x6999
#define SW_WRONG_DATA 0x6a80
#define SW_WRONG_DATA 0x6a80 #define SW_FUNC_NOT_SUPPORTED 0x6a81
#define SW_FUNC_NOT_SUPPORTED 0x6a81 #define SW_FILE_NOT_FOUND 0x6a82
#define SW_FILE_NOT_FOUND 0x6a82 #define SW_RECORD_NOT_FOUND 0x6a83
#define SW_RECORD_NOT_FOUND 0x6a83 #define SW_FILE_FULL 0x6a84
#define SW_FILE_FULL 0x6a84 #define SW_INCORRECT_P1P2 0x6a86
#define SW_INCORRECT_P1P2 0x6a86 #define SW_REFERENCED_DATA_NOT_FOUND 0x6a88
#define SW_REFERENCED_DATA_NOT_FOUND 0x6a88
#define SW_WRONG_P1P2 0x6b00
#define SW_WRONG_P1P2 0x6b00 #define SW_CORRECT_LENGTH_00 0x6c00
#define SW_CORRECT_LENGTH_00 0x6c00 #define SW_INS_NOT_SUPPORTED 0x6d00
#define SW_INS_NOT_SUPPORTED 0x6d00 #define SW_CLA_NOT_SUPPORTED 0x6e00
#define SW_CLA_NOT_SUPPORTED 0x6e00
#define SW_UNKNOWN 0x6f00
#define SW_UNKNOWN 0x6f00
#endif #endif

@ -14,25 +14,21 @@
* limitations under the License. * limitations under the License.
*/ */
#include "os.h" #include "os.h"
#include "cx.h" #include "cx.h"
#include "gpg_types.h" #include "gpg_types.h"
#include "gpg_api.h" #include "gpg_api.h"
#include "gpg_vars.h" #include "gpg_vars.h"
#include "os_io_seproxyhal.h" #include "os_io_seproxyhal.h"
#include "string.h" #include "string.h"
#include "glyphs.h" #include "glyphs.h"
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* --- Blue UI layout --- */ /* --- Blue UI layout --- */
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* screeen size: /* screeen size:
blue; 320x480 blue; 320x480
nanoS: 128x32 nanoS: 128x32
*/ */
#if 0 #if 0

@ -13,26 +13,25 @@
* limitations under the License. * limitations under the License.
*/ */
const char * const C_TEMPLATE_TYPE = "Key type"; const char *const C_TEMPLATE_TYPE = "Key type";
const char * const C_TEMPLATE_KEY = "Key"; const char *const C_TEMPLATE_KEY = "Key";
const char * const C_INVALID_SELECTION = "Invalid selection"; const char *const C_INVALID_SELECTION = "Invalid selection";
const char * const C_OK = "OK"; const char *const C_OK = "OK";
const char * const C_NOK = "NOK"; const char *const C_NOK = "NOK";
const char * const C_WRONG_PIN = "PIN Incorrect"; const char *const C_WRONG_PIN = "PIN Incorrect";
const char * const C_RIGHT_PIN = "PIN Correct"; const char *const C_RIGHT_PIN = "PIN Correct";
const char * const C_PIN_CHANGED = "PIN changed"; const char *const C_PIN_CHANGED = "PIN changed";
const char * const C_PIN_DIFFERS = "2 PINs differs"; const char *const C_PIN_DIFFERS = "2 PINs differs";
const char * const C_PIN_USER = "User PIN"; const char *const C_PIN_USER = "User PIN";
const char * const C_PIN_ADMIN = "Admin PIN"; const char *const C_PIN_ADMIN = "Admin PIN";
const char * const C_VERIFIED = "Verified"; const char *const C_VERIFIED = "Verified";
const char * const C_NOT_VERIFIED = "Not Verified"; const char *const C_NOT_VERIFIED = "Not Verified";
const char * const C_ALLOWED = "Allowed"; const char *const C_ALLOWED = "Allowed";
const char * const C_NOT_ALLOWED = "Not Allowed "; const char *const C_NOT_ALLOWED = "Not Allowed ";
const char * const C_DEFAULT_MODE = "Default mode"; const char *const C_DEFAULT_MODE = "Default mode";
const char *const C_UIF_LOCKED = "UIF locked";
const char * const C_UIF_LOCKED = "UIF locked";

@ -16,48 +16,48 @@
#ifndef GPG_UX_MSG_H #ifndef GPG_UX_MSG_H
#define GPG_UX_MSG_H #define GPG_UX_MSG_H
extern const char * const C_TEMPLATE_TYPE; extern const char *const C_TEMPLATE_TYPE;
extern const char * const C_TEMPLATE_KEY; extern const char *const C_TEMPLATE_KEY;
extern const char * const C_INVALID_SELECTION; extern const char *const C_INVALID_SELECTION;
extern const char * const C_OK; extern const char *const C_OK;
extern const char * const C_NOK; extern const char *const C_NOK;
extern const char * const C_WRONG_PIN; extern const char *const C_WRONG_PIN;
extern const char * const C_RIGHT_PIN; extern const char *const C_RIGHT_PIN;
extern const char * const C_PIN_CHANGED; extern const char *const C_PIN_CHANGED;
extern const char * const C_PIN_DIFFERS ; extern const char *const C_PIN_DIFFERS;
extern const char * const C_PIN_USER; extern const char *const C_PIN_USER;
extern const char * const C_PIN_ADMIN; extern const char *const C_PIN_ADMIN;
extern const char * const C_VERIFIED; extern const char *const C_VERIFIED;
extern const char * const C_NOT_VERIFIED; extern const char *const C_NOT_VERIFIED;
extern const char * const C_NOT_ALLOWED; extern const char *const C_NOT_ALLOWED;
extern const char * const C_DEFAULT_MODE; extern const char *const C_DEFAULT_MODE;
extern const char * const C_UIF_LOCKED; extern const char *const C_UIF_LOCKED;
extern const char * const C_UIF_INVALID; extern const char *const C_UIF_INVALID;
#define PICSTR(x) ((char*)PIC(x)) #define PICSTR(x) ((char *)PIC(x))
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE) #define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
#define TEMPLATE_KEY PICSTR(C_TEMPLATE_KEY) #define TEMPLATE_KEY PICSTR(C_TEMPLATE_KEY)
#define INVALID_SELECTION PICSTR(C_INVALID_SELECTION) #define INVALID_SELECTION PICSTR(C_INVALID_SELECTION)
#define OK PICSTR(C_OK) #define OK PICSTR(C_OK)
#define NOK PICSTR(C_NOK) #define NOK PICSTR(C_NOK)
#define WRONG_PIN PICSTR(C_WRONG_PIN) #define WRONG_PIN PICSTR(C_WRONG_PIN)
#define RIGHT_PIN PICSTR(C_RIGHT_PIN) #define RIGHT_PIN PICSTR(C_RIGHT_PIN)
#define PIN_CHANGED PICSTR(C_PIN_CHANGED) #define PIN_CHANGED PICSTR(C_PIN_CHANGED)
#define PIN_DIFFERS PICSTR(C_PIN_DIFFERS) #define PIN_DIFFERS PICSTR(C_PIN_DIFFERS)
#define PIN_USER PICSTR(C_PIN_USER) #define PIN_USER PICSTR(C_PIN_USER)
#define PIN_ADMIN PICSTR(C_PIN_ADMIN) #define PIN_ADMIN PICSTR(C_PIN_ADMIN)
#define VERIFIED PICSTR(C_VERIFIED) #define VERIFIED PICSTR(C_VERIFIED)
#define NOT_VERIFIED PICSTR(C_NOT_VERIFIED) #define NOT_VERIFIED PICSTR(C_NOT_VERIFIED)
#define ALLOWED PICSTR(C_ALLOWED) #define ALLOWED PICSTR(C_ALLOWED)
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED) #define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE) #define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
#define UIF_LOCKED PICSTR(C_UIF_LOCKED) #define UIF_LOCKED PICSTR(C_UIF_LOCKED)
#define UIF_INVALID PICSTR(C_UIF_INVALID) #define UIF_INVALID PICSTR(C_UIF_INVALID)
#endif #endif

File diff suppressed because it is too large Load Diff

@ -14,7 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef GPG_UX_NANOS_H #ifndef GPG_UX_NANOS_H
#define GPG_UX_NANOS_H #define GPG_UX_NANOS_H

File diff suppressed because it is too large Load Diff

@ -31,10 +31,15 @@ extern const unsigned char C_OID_BRAINPOOL256T1[9];
extern const unsigned char C_OID_Ed25519[9]; extern const unsigned char C_OID_Ed25519[9];
extern const unsigned char C_OID_cv25519[10]; extern const unsigned char C_OID_cv25519[10];
extern gpg_v_state_t G_gpg_vstate; extern gpg_v_state_t G_gpg_vstate;
extern gpg_nv_state_t N_state_pic;
#define N_gpg_pstate ((WIDE gpg_nv_state_t *)PIC(&N_state_pic))
#ifdef TARGET_NANOX
extern const gpg_nv_state_t N_state_pic;
#define N_gpg_pstate ((volatile gpg_nv_state_t *)PIC(&N_state_pic))
#else
extern gpg_nv_state_t N_state_pic;
#define N_gpg_pstate ((WIDE gpg_nv_state_t *)PIC(&N_state_pic))
#endif
#ifdef GPG_DEBUG_MAIN #ifdef GPG_DEBUG_MAIN
extern int apdu_n; extern int apdu_n;

@ -27,12 +27,13 @@
#pragma message "Override SDK source file :" __FILE__ #pragma message "Override SDK source file :" __FILE__
#ifdef HAVE_USB_CLASS_CCID
#include "sdk_compat.h"
/* Includes ------------------------------------------------------------------*/ /* Includes ------------------------------------------------------------------*/
#include "usbd_ccid_cmd.h" #include "usbd_ccid_cmd.h"
#ifdef HAVE_USB_CLASS_CCID
/* Private typedef -----------------------------------------------------------*/ /* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/

@ -29,10 +29,12 @@
/* Includes ------------------------------------------------------------------*/ /* Includes ------------------------------------------------------------------*/
#include "os.h" #include "os.h"
#include "usbd_ccid_if.h" #include "sdk_compat.h"
#ifdef HAVE_USB_CLASS_CCID #ifdef HAVE_USB_CLASS_CCID
#include "usbd_ccid_if.h"
#if CCID_BULK_EPIN_SIZE > USB_SEGMENT_SIZE #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) #error configuration error, the USB MAX SEGMENT SIZE does not support the CCID endpoint (CCID_BULK_EPIN_SIZE vs USB_SEGMENT_SIZE)
#endif #endif
@ -531,16 +533,14 @@ uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
UNUSED(returnLen); UNUSED(returnLen);
// return SLOTERROR_CMD_NOT_SUPPORTED; // return SLOTERROR_CMD_NOT_SUPPORTED;
uint16_t ret_len,off; uint16_t ret_len,off;
switch(pbuf[0]) switch(pbuf[0]) {
{
case 0: // verify pin case 0: // verify pin
off = 15; off = 15;
//ret_len = dwLength - 15; //ret_len = dwLength - 15;
ret_len = 5; ret_len = 5;
break; break;
case 1: // modify pin case 1: // modify pin
switch(pbuf[11]) switch(pbuf[11]) {
{
case 3: case 3:
off = 20; off = 20;
break; break;

@ -25,5 +25,23 @@
#define U2F_EPOUT_SIZE 0x40 #define U2F_EPOUT_SIZE 0x40
#endif // HAVE_IO_U2F #endif // HAVE_IO_U2F
#ifdef HAVE_WEBUSB
#define WEBUSB_EPIN_ADDR 0x83
#define WEBUSB_EPIN_SIZE 0x40
#define WEBUSB_EPOUT_ADDR 0x03
#define WEBUSB_EPOUT_SIZE 0x40
#ifdef HAVE_USB_CLASS_CCID
#error Unsupported CCID+WEBUSB, not enough endpoints
#endif // HAVE_USB_CLASS_CCID
#ifdef HAVE_IO_U2F
#define WEBUSB_INTF 2
#else // HAVE_IO_U2F
#define WEBUSB_INTF 1
#endif // HAVE_IO_U2F
#endif // HAVE_WEBUSB
#endif // USBD_HID_IMPL_H #endif // USBD_HID_IMPL_H

@ -47,6 +47,7 @@
#pragma message "Override SDK source file :" __FILE__ #pragma message "Override SDK source file :" __FILE__
#include "os.h" #include "os.h"
#include "sdk_compat.h"
/* Includes ------------------------------------------------------------------*/ /* Includes ------------------------------------------------------------------*/
@ -118,12 +119,6 @@
* @{ * @{
*/ */
#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 #define USBD_LANGID_STRING 0x409
#ifdef HAVE_VID_PID_PROBER #ifdef HAVE_VID_PID_PROBER
@ -131,9 +126,9 @@
#define USBD_PID 0xf1d1 #define USBD_PID 0xf1d1
#else #else
#define USBD_VID 0x2C97 #define USBD_VID 0x2C97
#if defined(TARGET_BLUE) // blue #if defined(TARGET_BLUE)
#define USBD_PID 0x0000 #define USBD_PID 0x0000
static const uint8_t const USBD_PRODUCT_FS_STRING[] = { static uint8_t const USBD_PRODUCT_FS_STRING[] = {
4*2+2, 4*2+2,
USB_DESC_TYPE_STRING, USB_DESC_TYPE_STRING,
'B', 0, 'B', 0,
@ -142,9 +137,9 @@ static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
'e', 0, 'e', 0,
}; };
#elif defined(TARGET_NANOS) // nano s #elif defined(TARGET_NANOS)
#define USBD_PID 0x0001 #define USBD_PID 0x0001
static const uint8_t const USBD_PRODUCT_FS_STRING[] = { static uint8_t const USBD_PRODUCT_FS_STRING[] = {
6*2+2, 6*2+2,
USB_DESC_TYPE_STRING, USB_DESC_TYPE_STRING,
'N', 0, 'N', 0,
@ -154,9 +149,9 @@ static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
' ', 0, ' ', 0,
'S', 0, 'S', 0,
}; };
#elif defined(TARGET_ARAMIS) // aramis #elif defined(TARGET_ARAMIS)
#define USBD_PID 0x0002 #define USBD_PID 0x0002
static const uint8_t const USBD_PRODUCT_FS_STRING[] = { static uint8_t const USBD_PRODUCT_FS_STRING[] = {
6*2+2, 6*2+2,
USB_DESC_TYPE_STRING, USB_DESC_TYPE_STRING,
'A', 0, 'A', 0,
@ -166,13 +161,34 @@ static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
'i', 0, 'i', 0,
's', 0, 's', 0,
}; };
#elif defined(TARGET_HW2)
#define USBD_PID 0x0003
static uint8_t const USBD_PRODUCT_FS_STRING[] = {
3*2+2,
USB_DESC_TYPE_STRING,
'H', 0,
'W', 0,
'2', 0,
};
#elif defined(TARGET_NANOX)
#define USBD_PID 0x0004
static uint8_t const USBD_PRODUCT_FS_STRING[] = {
6*2+2,
USB_DESC_TYPE_STRING,
'N', 0,
'a', 0,
'n', 0,
'o', 0,
' ', 0,
'X', 0,
};
#else #else
#error unknown TARGET_ID #error unknown TARGET_ID
#endif #endif
#endif #endif
/* USB Standard Device Descriptor */ /* USB Standard Device Descriptor */
static const uint8_t const USBD_LangIDDesc[]= static uint8_t const USBD_LangIDDesc[]=
{ {
USB_LEN_LANGID_STR_DESC, USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING, USB_DESC_TYPE_STRING,
@ -180,7 +196,7 @@ static const uint8_t const USBD_LangIDDesc[]=
HIBYTE(USBD_LANGID_STRING), HIBYTE(USBD_LANGID_STRING),
}; };
static const uint8_t const USB_SERIAL_STRING[] = static uint8_t const USB_SERIAL_STRING[] =
{ {
4*2+2, 4*2+2,
USB_DESC_TYPE_STRING, USB_DESC_TYPE_STRING,
@ -190,7 +206,7 @@ static const uint8_t const USB_SERIAL_STRING[] =
'1', 0, '1', 0,
}; };
static const uint8_t const USBD_MANUFACTURER_STRING[] = { static uint8_t const USBD_MANUFACTURER_STRING[] = {
6*2+2, 6*2+2,
USB_DESC_TYPE_STRING, USB_DESC_TYPE_STRING,
'L', 0, 'L', 0,
@ -204,7 +220,7 @@ static const uint8_t const USBD_MANUFACTURER_STRING[] = {
#define USBD_INTERFACE_FS_STRING USBD_PRODUCT_FS_STRING #define USBD_INTERFACE_FS_STRING USBD_PRODUCT_FS_STRING
#define USBD_CONFIGURATION_FS_STRING USBD_PRODUCT_FS_STRING #define USBD_CONFIGURATION_FS_STRING USBD_PRODUCT_FS_STRING
static const uint8_t const HID_ReportDesc[] = { static uint8_t const HID_ReportDesc[] = {
0x06, 0xA0, 0xFF, // Usage page (vendor defined) 0x06, 0xA0, 0xFF, // Usage page (vendor defined)
0x09, 0x01, // Usage ID (vendor defined) 0x09, 0x01, // Usage ID (vendor defined)
0xA1, 0x01, // Collection (application) 0xA1, 0x01, // Collection (application)
@ -228,7 +244,7 @@ static const uint8_t const HID_ReportDesc[] = {
}; };
#ifdef HAVE_IO_U2F #ifdef HAVE_IO_U2F
static const uint8_t const HID_ReportDesc_fido[] = { static uint8_t const HID_ReportDesc_fido[] = {
0x06, 0xD0, 0xF1, // Usage page (vendor defined) 0x06, 0xD0, 0xF1, // Usage page (vendor defined)
0x09, 0x01, // Usage ID (vendor defined) 0x09, 0x01, // Usage ID (vendor defined)
0xA1, 0x01, // Collection (application) 0xA1, 0x01, // Collection (application)
@ -255,7 +271,7 @@ static const uint8_t const HID_ReportDesc_fido[] = {
#define ARRAY_U2LE(l) (l)&0xFF, (l)>>8 #define ARRAY_U2LE(l) (l)&0xFF, (l)>>8
/* USB HID device Configuration Descriptor */ /* USB HID device Configuration Descriptor */
static __ALIGN_BEGIN const uint8_t const N_USBD_CfgDesc[] __ALIGN_END = static __ALIGN_BEGIN uint8_t const N_USBD_CfgDesc[] __ALIGN_END =
{ {
0x09, /* bLength: Configuration Descriptor size */ 0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
@ -267,6 +283,9 @@ static __ALIGN_BEGIN const uint8_t const N_USBD_CfgDesc[] __ALIGN_END =
#ifdef HAVE_USB_CLASS_CCID #ifdef HAVE_USB_CLASS_CCID
+0x9+0x36+0x7+0x7 +0x9+0x36+0x7+0x7
#endif // HAVE_USB_CLASS_CCID #endif // HAVE_USB_CLASS_CCID
#ifdef HAVE_WEBUSB
+0x9+0x7+0x7
#endif // HAVE_WEBUSB
), ),
1 1
#ifdef HAVE_IO_U2F #ifdef HAVE_IO_U2F
@ -275,6 +294,9 @@ static __ALIGN_BEGIN const uint8_t const N_USBD_CfgDesc[] __ALIGN_END =
#ifdef HAVE_USB_CLASS_CCID #ifdef HAVE_USB_CLASS_CCID
+1 +1
#endif // HAVE_USB_CLASS_CCID #endif // HAVE_USB_CLASS_CCID
#ifdef HAVE_WEBUSB
+1
#endif // HAVE_WEBUSB
, /*bNumInterfaces */ , /*bNumInterfaces */
0x01, /*bConfigurationValue: Configuration value*/ 0x01, /*bConfigurationValue: Configuration value*/
USBD_IDX_PRODUCT_STR, /*iConfiguration: Index of string descriptor describing the configuration*/ USBD_IDX_PRODUCT_STR, /*iConfiguration: Index of string descriptor describing the configuration*/
@ -462,11 +484,43 @@ static __ALIGN_BEGIN const uint8_t const N_USBD_CfgDesc[] __ALIGN_END =
HIBYTE(CCID_BULK_EPOUT_SIZE), HIBYTE(CCID_BULK_EPOUT_SIZE),
0x00, /*Polling interval in milliseconds*/ 0x00, /*Polling interval in milliseconds*/
#endif // HAVE_USB_CLASS_CCID #endif // HAVE_USB_CLASS_CCID
#ifdef HAVE_WEBUSB
/* WEBUSB ################################################################################################ */
/************** Descriptor of WEBUSB interface ****************/
0x09, /*bLength: Interface Descriptor size*/
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
WEBUSB_INTF, /*bInterfaceNumber: Number of Interface*/
0x00, /*bAlternateSetting: Alternate setting*/
0x02, /*bNumEndpoints*/
0xFF, /*bInterfaceClass: WINUSB*/
0xFF, /*bInterfaceSubClass : WINUSB*/
0xFF, /*nInterfaceProtocol : WINUSB*/
USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/
/******************** Descriptor of endpoints ********************/
0x07, /*bLength: Endpoint Descriptor size*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
WEBUSB_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
WEBUSB_EPIN_SIZE, /*wMaxPacketSize: */
0x00,
0x01, /*bInterval: Polling Interval */
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */
WEBUSB_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/
0x03, /* bmAttributes: Interrupt endpoint */
WEBUSB_EPOUT_SIZE, /* wMaxPacketSize: */
0x00,
0x01,/* bInterval: Polling Interval */
#endif // HAVE_WEBUSB
} ; } ;
#ifdef HAVE_IO_U2F #ifdef HAVE_IO_U2F
/* USB HID device Configuration Descriptor */ /* USB HID device Configuration Descriptor */
__ALIGN_BEGIN const uint8_t const USBD_HID_Desc_fido[] __ALIGN_END = __ALIGN_BEGIN uint8_t const USBD_HID_Desc_fido[] __ALIGN_END =
{ {
/******************** Descriptor of HID *************************/ /******************** Descriptor of HID *************************/
0x09, /*bLength: HID Descriptor size*/ 0x09, /*bLength: HID Descriptor size*/
@ -482,7 +536,7 @@ __ALIGN_BEGIN const uint8_t const USBD_HID_Desc_fido[] __ALIGN_END =
#endif // HAVE_IO_U2F #endif // HAVE_IO_U2F
/* USB HID device Configuration Descriptor */ /* USB HID device Configuration Descriptor */
__ALIGN_BEGIN const uint8_t const USBD_HID_Desc[] __ALIGN_END = __ALIGN_BEGIN uint8_t const USBD_HID_Desc[] __ALIGN_END =
{ {
/* 18 */ /* 18 */
0x09, /*bLength: HID Descriptor size*/ 0x09, /*bLength: HID Descriptor size*/
@ -497,7 +551,7 @@ __ALIGN_BEGIN const uint8_t const USBD_HID_Desc[] __ALIGN_END =
}; };
/* USB Standard Device Descriptor */ /* USB Standard Device Descriptor */
static __ALIGN_BEGIN const uint8_t const USBD_DeviceQualifierDesc[] __ALIGN_END = static __ALIGN_BEGIN uint8_t const USBD_DeviceQualifierDesc[] __ALIGN_END =
{ {
USB_LEN_DEV_QUALIFIER_DESC, USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER, USB_DESC_TYPE_DEVICE_QUALIFIER,
@ -512,7 +566,7 @@ static __ALIGN_BEGIN const uint8_t const USBD_DeviceQualifierDesc[] __ALIGN_END
}; };
/* USB Standard Device Descriptor */ /* USB Standard Device Descriptor */
static const uint8_t const USBD_DeviceDesc[]= { static uint8_t const USBD_DeviceDesc[]= {
0x12, /* bLength */ 0x12, /* bLength */
USB_DESC_TYPE_DEVICE, /* bDescriptorType */ USB_DESC_TYPE_DEVICE, /* bDescriptorType */
0x00, /* bcdUSB */ 0x00, /* bcdUSB */
@ -710,9 +764,39 @@ uint8_t* USBD_HID_GetReportDescriptor_impl(uint16_t* len) {
* *
* This function is the default behavior for our implementation when data are sent over the out hid endpoint * 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 #ifdef HAVE_IO_U2F
/**
* @brief USBD_HID_Init
* Initialize the HID interface
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
uint8_t USBD_U2F_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
UNUSED(cfgidx);
/* Open EP IN */
USBD_LL_OpenEP(pdev,
U2F_EPIN_ADDR,
USBD_EP_TYPE_INTR,
U2F_EPIN_SIZE);
/* Open EP OUT */
USBD_LL_OpenEP(pdev,
U2F_EPOUT_ADDR,
USBD_EP_TYPE_INTR,
U2F_EPOUT_SIZE);
/* Prepare Out endpoint to receive 1st packet */
USBD_LL_PrepareReceive(pdev, U2F_EPOUT_ADDR, U2F_EPOUT_SIZE);
return USBD_OK;
}
uint8_t USBD_U2F_DataIn_impl (USBD_HandleTypeDef *pdev, uint8_t USBD_U2F_DataIn_impl (USBD_HandleTypeDef *pdev,
uint8_t epnum) uint8_t epnum)
{ {
@ -743,6 +827,20 @@ uint8_t USBD_U2F_DataOut_impl (USBD_HandleTypeDef *pdev,
} }
#endif // HAVE_IO_U2F #endif // HAVE_IO_U2F
uint8_t USBD_HID_DataIn_impl (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
UNUSED(pdev);
switch (epnum) {
// HID gen endpoint
case (HID_EPIN_ADDR&0x7F):
io_usb_hid_sent(io_usb_send_apdu_data);
break;
}
return USBD_OK;
}
uint8_t USBD_HID_DataOut_impl (USBD_HandleTypeDef *pdev, uint8_t USBD_HID_DataOut_impl (USBD_HandleTypeDef *pdev,
uint8_t epnum, uint8_t* buffer) uint8_t epnum, uint8_t* buffer)
{ {
@ -774,12 +872,97 @@ uint8_t USBD_HID_DataOut_impl (USBD_HandleTypeDef *pdev,
return USBD_OK; return USBD_OK;
} }
#ifdef HAVE_WEBUSB
uint8_t USBD_WEBUSB_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
UNUSED(cfgidx);
/* Open EP IN */
USBD_LL_OpenEP(pdev,
WEBUSB_EPIN_ADDR,
USBD_EP_TYPE_INTR,
WEBUSB_EPIN_SIZE);
/* Open EP OUT */
USBD_LL_OpenEP(pdev,
WEBUSB_EPOUT_ADDR,
USBD_EP_TYPE_INTR,
WEBUSB_EPOUT_SIZE);
/* Prepare Out endpoint to receive 1st packet */
USBD_LL_PrepareReceive(pdev, WEBUSB_EPOUT_ADDR, WEBUSB_EPOUT_SIZE);
return USBD_OK;
}
uint8_t USBD_WEBUSB_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx) {
UNUSED(pdev);
UNUSED(cfgidx);
return USBD_OK;
}
uint8_t USBD_WEBUSB_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
UNUSED(pdev);
UNUSED(req);
return USBD_OK;
}
uint8_t USBD_WEBUSB_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
UNUSED(pdev);
switch (epnum) {
// HID gen endpoint
case (WEBUSB_EPIN_ADDR&0x7F):
io_usb_hid_sent(io_usb_send_apdu_data_ep0x83);
break;
}
return USBD_OK;
}
uint8_t USBD_WEBUSB_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum, uint8_t* buffer)
{
// only the data hid endpoint will receive data
switch (epnum) {
// HID gen endpoint
case (WEBUSB_EPOUT_ADDR&0x7F):
// prepare receiving the next chunk (masked time)
USBD_LL_PrepareReceive(pdev, WEBUSB_EPOUT_ADDR, WEBUSB_EPOUT_SIZE);
// avoid troubles when an apdu has not been replied yet
if (G_io_app.apdu_media == IO_APDU_MEDIA_NONE) {
// add to the hid transport
switch(io_usb_hid_receive(io_usb_send_apdu_data_ep0x83, buffer, io_seproxyhal_get_ep_rx_size(WEBUSB_EPOUT_ADDR))) {
default:
break;
case IO_USB_APDU_RECEIVED:
G_io_app.apdu_media = IO_APDU_MEDIA_USB_WEBUSB; // for application code
G_io_app.apdu_state = APDU_USB_WEBUSB; // for next call to io_exchange
G_io_app.apdu_length = G_io_usb_hid_total_length;
break;
}
}
break;
}
return USBD_OK;
}
#endif // HAVE_WEBUSB
/** @defgroup USBD_HID_Private_Functions /** @defgroup USBD_HID_Private_Functions
* @{ * @{
*/ */
// note: how core lib usb calls the hid class // note: how core lib usb calls the hid class
const USBD_DescriptorsTypeDef const HID_Desc = { USBD_DescriptorsTypeDef const HID_Desc = {
USBD_DeviceDescriptor, USBD_DeviceDescriptor,
USBD_LangIDStrDescriptor, USBD_LangIDStrDescriptor,
USBD_ManufacturerStrDescriptor, USBD_ManufacturerStrDescriptor,
@ -791,9 +974,9 @@ const USBD_DescriptorsTypeDef const HID_Desc = {
}; };
#ifdef HAVE_IO_U2F #ifdef HAVE_IO_U2F
static const USBD_ClassTypeDef const USBD_U2F = static USBD_ClassTypeDef const USBD_U2F =
{ {
USBD_HID_Init, USBD_U2F_Init,
USBD_HID_DeInit, USBD_HID_DeInit,
USBD_HID_Setup, USBD_HID_Setup,
NULL, /*EP0_TxSent*/ NULL, /*EP0_TxSent*/
@ -810,14 +993,14 @@ static const USBD_ClassTypeDef const USBD_U2F =
}; };
#endif // HAVE_IO_U2F #endif // HAVE_IO_U2F
static const USBD_ClassTypeDef const USBD_HID = static USBD_ClassTypeDef const USBD_HID =
{ {
USBD_HID_Init, USBD_HID_Init,
USBD_HID_DeInit, USBD_HID_DeInit,
USBD_HID_Setup, USBD_HID_Setup,
NULL, /*EP0_TxSent*/ NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */ NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */
NULL, /*DataIn*/ USBD_HID_DataIn_impl, /*DataIn*/
USBD_HID_DataOut_impl, /*DataOut*/ USBD_HID_DataOut_impl, /*DataOut*/
NULL, /*SOF */ NULL, /*SOF */
NULL, NULL,
@ -828,6 +1011,102 @@ static const USBD_ClassTypeDef const USBD_HID =
USBD_GetDeviceQualifierDesc_impl, USBD_GetDeviceQualifierDesc_impl,
}; };
#ifdef HAVE_WEBUSB
// arbitrary vendor choosen
#define WEBUSB_VENDOR_CODE 0x1E
// from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
// see also this (for endianness explanation)
// https://github.com/WICG/webusb/issues/115#issuecomment-352206549
#define WEBUSB_UUID 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65
#define WEBUSB_REQ_GET_URL 0x02
#define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0
#define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1
#define WEBUSB_DT_FUNCTION_SUBSET_HEADER 2
#define WEBUSB_DT_URL 3
#define WEBUSB_URL_SCHEME_HTTP 0
#define WEBUSB_URL_SCHEME_HTTPS 1
#define WEBUSB_URL_SCHEME_CUSTOM 255
unsigned char const C_webusb_url_descriptor[] = {
// bLength
3 + WEBUSB_URL_SIZE_B,
// bDescriptorType
WEBUSB_DT_URL,
// bScheme
WEBUSB_URL_SCHEME_HTTPS,
// URL
WEBUSB_URL
};
/* USB 3.1 Descriptor Types - Table 9-6 */
#define USB_DT_BOS 15
#define USB_DT_DEVICE_CAPABILITY 16
#define USB_DT_BOS_SIZE 5
/* USB Device Capability Types - USB 3.1 Table 9-14 */
#define USB_DC_PLATFORM 5
unsigned char const C_usb_bos[] = {
USB_DT_BOS_SIZE, // bLength (5)
USB_DT_BOS, // bDescriptorType
(5+8+16), // wTotalLength
(5+8+16)>>8,
1, //bNumberDeviceCapabilities
// capability descriptor
8+16, // bLength
USB_DT_DEVICE_CAPABILITY, // bDescriptorType
USB_DC_PLATFORM, // bDevCapability
0, // bReserved
WEBUSB_UUID, // UUID[16]
0x00, // bcdVersion
0x01,
WEBUSB_VENDOR_CODE, // bVencordCode
1 // iLanding
};
// upon unsupported request, check for webusb request
void USBD_CtlError( USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) {
if ((req->bmRequest & 0x80) && req->bRequest == WEBUSB_VENDOR_CODE && req->wIndex == WEBUSB_REQ_GET_URL
// HTTPS url
&& req->wValue == 1) {
// return the URL descriptor
USBD_CtlSendData (pdev, (unsigned char*)C_webusb_url_descriptor, sizeof(C_webusb_url_descriptor));
}
else if ((req->bmRequest & 0x80) && req->bRequest == USB_REQ_GET_DESCRIPTOR && (req->wValue>>8) == USB_DT_BOS) {
USBD_CtlSendData(pdev, (unsigned char*)C_usb_bos, sizeof(C_usb_bos));
}
else {
USBD_CtlStall(pdev);
}
}
static const USBD_ClassTypeDef USBD_WEBUSB =
{
USBD_WEBUSB_Init,
USBD_WEBUSB_DeInit,
USBD_WEBUSB_Setup,
NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/
USBD_WEBUSB_DataIn,
USBD_WEBUSB_DataOut,
NULL, /*SOF */
NULL, /*ISOIn*/
NULL, /*ISOOut*/
USBD_GetCfgDesc_impl,
USBD_GetCfgDesc_impl,
USBD_GetCfgDesc_impl,
USBD_GetDeviceQualifierDesc_impl,
};
#endif // HAVE_WEBUSB
#ifdef HAVE_USB_CLASS_CCID #ifdef HAVE_USB_CLASS_CCID
static const USBD_ClassTypeDef USBD_CCID = static const USBD_ClassTypeDef USBD_CCID =
{ {
@ -874,6 +1153,12 @@ uint8_t SC_ExecuteEscape (uint8_t* escapePtr, uint32_t escapeLen,
void USB_power(unsigned char enabled) { void USB_power(unsigned char enabled) {
os_memset(&USBD_Device, 0, sizeof(USBD_Device)); os_memset(&USBD_Device, 0, sizeof(USBD_Device));
#if TARGET_ID == 0x33000004
// init timeouts and other global fields
os_memset(G_io_app.usb_ep_xfer_len, 0, sizeof(G_io_app.usb_ep_xfer_len));
os_memset(G_io_app.usb_ep_timeouts, 0, sizeof(G_io_app.usb_ep_timeouts));
#endif
if (enabled) { if (enabled) {
os_memset(&USBD_Device, 0, sizeof(USBD_Device)); os_memset(&USBD_Device, 0, sizeof(USBD_Device));
/* Init Device Library */ /* Init Device Library */
@ -890,6 +1175,10 @@ void USB_power(unsigned char enabled) {
USBD_RegisterClassForInterface(CCID_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_CCID); USBD_RegisterClassForInterface(CCID_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_CCID);
#endif // HAVE_USB_CLASS_CCID #endif // HAVE_USB_CLASS_CCID
#ifdef HAVE_WEBUSB
USBD_RegisterClassForInterface(WEBUSB_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_WEBUSB);
USBD_LL_PrepareReceive(&USBD_Device, WEBUSB_EPOUT_ADDR , WEBUSB_EPOUT_SIZE);
#endif // HAVE_WEBUSB
/* Start Device Process */ /* Start Device Process */
USBD_Start(&USBD_Device); USBD_Start(&USBD_Device);

Loading…
Cancel
Save