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
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),)
MULTISLOT := 0
endif
ifeq ($(MULTISLOT),0)
GPG_MULTISLOT:=0
APPNAME:=OpenPGP
@ -35,22 +34,36 @@ GPG_MULTISLOT:=1
APPNAME:=OpenPGP.XL
endif
APP_LOAD_PARAMS=--appFlags 0x40 --path "2152157255'" --curve secp256k1 $(COMMON_LOAD_PARAMS)
SPECVERSION:="3.3.1"
ifeq ($(TARGET_NAME),TARGET_BLUE)
ICONNAME = images/icon_monero_blue.gif
else ifeq ($(TARGET_NAME),TARGET_NANOX)
ICONNAME = images/icon_pgp_nanox.gif
else
ICONNAME = images/icon_pgp.gif
endif
APPVERSION_M:=1
APPVERSION_N:=3
APPVERSION_P:=1
APPVERSION_P:=2
APPVERSION:=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
SPECVERSION:="3.3.1"
ifeq ($(TARGET_NAME),TARGET_BLUE)
ICONNAME=images/icon_pgp_blue.gif
DEFINES += $(OPENPGP_CONFIG)
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
ICONNAME=images/icon_pgp.gif
DEFINES += UI_NANO_S
endif
DEFINES += GPG_MULTISLOT=$(GPG_MULTISLOT) $(GPG_CONFIG) GPG_VERSION=$(APPVERSION) GPG_NAME=$(APPNAME) SPEC_VERSION=$(SPECVERSION)
################
# Default rule #
@ -82,18 +95,51 @@ ifneq ($(NO_CONSENT),)
DEFINES += NO_CONSENT
endif
DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300
DEFINES += OS_IO_SEPROXYHAL
DEFINES += HAVE_BAGL HAVE_SPRINTF
#DEFINES += HAVE_PRINTF PRINTF=screen_printf
DEFINES += PRINTF\(...\)=
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
#DEFINES += HAVE_BLE
DEFINES += 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 += APPVERSION=\"$(APPVERSION)\"
DEFINES += CUSTOM_IO_APDU_BUFFER_SIZE=\(255+5+64\)
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 #
##############
@ -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
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
cp -a release/$(APPNAME).elf bin/app.elf
@ -137,9 +190,12 @@ exit:
delete:
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
# import generic rules from the sdk
include Makefile.rules
#add dependency on custom makefile filename
dep/%.d: %.c Makefile

@ -1,14 +1,14 @@
## 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 .
The application supports:
- RSA with key up to 4096 bits
- ECDSA with secp256k1, secp256r1, brainpool 256r1 and brainpool 256t1 curves
- ECDSA with secp256k1
- 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) :

@ -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``
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
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
~~~~~~~~~~~~~~~~~~~~~~~~~~
First you must have the path of the `ledger-app-openpgp-card/pytools` in your PYTHONPATH.
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:
| ``python3 -m gpgcard.gpgcli --backup --pinpad ``
| ``python3 -m gpgcard.gpgcli --backup --pinpad --file my_bck_file_name.pickle``
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:
| ``python3 -m gpgcard.gpgcli --backup --pinpad --seed``
| ``python3 -m gpgcard.gpgcli --backup --pinpad --seed --file my_bck_file_name.pickle``
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() :
def __init__(self):
self.reset()
self.log = False
def reset(self):
#token info
@ -158,29 +159,43 @@ class GPGCard() :
cond = False
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):
if data:
data = [x for x in data]
apdu = [x for x in apdu]
#send
if data:
while len(data) > 0xFE:
apdux = apdu[0:5]+[0xfe]+data[0:0xFE]
apdux[0] |= 0x10
self.alog('send', apdux)
resp, sw1, sw2 = self.connection.transmit(apdux)
sw = (sw1<<8)|sw2
self.alog('recv',resp,sw)
if sw != 0x9000:
return resp,sw
data = data[0xFE:]
apdu = apdu+[len(data)]+data
self.alog('send', apdu)
resp, sw1, sw2 = self.connection.transmit(apdu)
sw = (sw1<<8)|sw2
self.alog('recv', resp, sw)
#receive
while sw1==0x61:
apdu = binascii.unhexlify(b"00c00000%.02x"%sw2)
apdu = [x for x in apdu]
self.alog('send', apdu)
resp2, sw1, sw2 = self.connection.transmit(apdu)
sw = (sw1<<8)|sw2
self.alog('recv', resp2, sw)
resp = resp + resp2
resp = bytes(resp)
sw = (sw1<<8)|sw2
@ -315,6 +330,7 @@ class GPGCard() :
self.dec_key,sw = self.get_data(0x00B8)
self.aut_key,sw = self.get_data(0x00A4)
return True
def set_all(self):
@ -353,6 +369,7 @@ class GPGCard() :
self.put_data(0xd8, self.UIF_AUT)
if len(self.sig_key):
print('COUCOU')
self.put_data(0x00B6, self.sig_key)
if len(self.dec_key):
self.put_data(0x00B8, self.dec_key)
@ -362,7 +379,7 @@ class GPGCard() :
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):
self.get_all(with_key)
@ -397,7 +414,7 @@ class GPGCard() :
self.sig_date, self.dec_date, self.aut_date,
self.cardholder_cert,
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()
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('--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('--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
def banner():
@ -74,6 +75,8 @@ try:
print("Connect to card %s..."%args.reader, end='', flush=True)
gpgcard = GPGCard()
if args.apdu:
gpgcard.log_apdu(args.apdu)
gpgcard.connect(args.reader)
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
#define GPG_API_H
#define GPG_API_H
void USBD_CCID_activate_pinpad(int enabled);
unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len);
unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len);
unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len);
unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len);
unsigned int gpg_curve2domainlen(unsigned int cv);
void gpg_init(void);
void gpg_init_ux(void);
int gpg_install(unsigned char app_state) ;
int gpg_install(unsigned char app_state);
int gpg_dispatch(void);
int gpg_apdu_select_data(unsigned int ref, int reccord) ;
int gpg_apdu_get_data(unsigned int ref) ;
int gpg_apdu_get_next_data(unsigned int ref) ;
int gpg_apdu_put_data(unsigned int ref) ;
int gpg_apdu_get_key_data(unsigned int ref);
int gpg_apdu_put_key_data(unsigned int ref);
int gpg_apdu_select_data(unsigned int ref, int reccord);
int gpg_apdu_get_data(unsigned int ref);
int gpg_apdu_get_next_data(unsigned int ref);
int gpg_apdu_put_data(unsigned int ref);
int gpg_apdu_get_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_key_seed(unsigned char *Sn, unsigned char* key_name, unsigned int idx,
unsigned char *Ski, unsigned int Ski_len);
void gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned char *key_name,
unsigned int idx,
unsigned char *Ski,
unsigned int Ski_len);
int gpg_apdu_pso(void);
int gpg_apdu_internal_authenticate(void);
int gpg_apdu_gen(void );
int gpg_apdu_get_challenge(void) ;
int gpg_apdu_gen(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_change_ref_data(void) ;
int gpg_apdu_reset_retry_counter(void) ;
int gpg_apdu_verify(void);
int gpg_apdu_change_ref_data(void);
int gpg_apdu_reset_retry_counter(void);
gpg_pin_t *gpg_pin_get_pin(int id);
int gpg_pin_is_blocked(gpg_pin_t *pin);
int gpg_pin_is_verified(int pinID);
int gpg_pin_set_verified(int pinID, int verified);
int gpg_pin_check(gpg_pin_t *pin, int pinID,unsigned char *pin_val, unsigned int pin_len);
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
int gpg_pin_is_blocked(gpg_pin_t *pin);
int gpg_pin_is_verified(int pinID);
int gpg_pin_set_verified(int pinID, int verified);
int gpg_pin_check(gpg_pin_t *pin, int pinID, unsigned char *pin_val, unsigned int pin_len);
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
int gpg_mse_reset();
int gpg_mse_reset();
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 ---- */
/* ----------------------------------------------------------------------- */
void gpg_io_discard(int clear) ;
void gpg_io_discard(int clear);
void gpg_io_clear(void);
void gpg_io_set_offset(unsigned int offset) ;
void gpg_io_mark(void) ;
void gpg_io_rewind(void) ;
void gpg_io_hole(unsigned int sz) ;
void gpg_io_set_offset(unsigned int offset);
void gpg_io_mark(void);
void gpg_io_rewind(void);
void gpg_io_hole(unsigned int sz);
void gpg_io_inserted(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_u24(unsigned int v24) ;
void gpg_io_insert_u16(unsigned int v16) ;
void gpg_io_insert_u8(unsigned int v8) ;
void gpg_io_insert_t(unsigned int T) ;
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_fetch_buffer(unsigned char * buffer, unsigned int len) ;
unsigned int gpg_io_fetch_u32(void) ;
unsigned int gpg_io_fetch_u24(void) ;
unsigned int gpg_io_fetch_u16(void) ;
unsigned int gpg_io_fetch_u8(void) ;
int gpg_io_fetch_t(unsigned int *T) ;
int gpg_io_fetch_l(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(unsigned char* buffer, int len) ;
int gpg_io_do(unsigned int io_flags) ;
void gpg_io_insert(unsigned char const *buffer, unsigned int len);
void gpg_io_insert_u32(unsigned int v32);
void gpg_io_insert_u24(unsigned int v24);
void gpg_io_insert_u16(unsigned int v16);
void gpg_io_insert_u8(unsigned int v8);
void gpg_io_insert_t(unsigned int T);
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_fetch_buffer(unsigned char *buffer, unsigned int len);
unsigned int gpg_io_fetch_u32(void);
unsigned int gpg_io_fetch_u24(void);
unsigned int gpg_io_fetch_u16(void);
unsigned int gpg_io_fetch_u8(void);
int gpg_io_fetch_t(unsigned int *T);
int gpg_io_fetch_l(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(unsigned char *buffer, int len);
int gpg_io_do(unsigned int io_flags);
/* ----------------------------------------------------------------------- */
/* --- TMP ---- */
@ -99,12 +110,12 @@ void io_usb_ccid_set_card_inserted(unsigned int inserted);
/* --- DEBUG ---- */
/* ----------------------------------------------------------------------- */
#ifdef GPG_DEBUG
#error "UNSUPPORTDED: to be fixed"
#include "gpg_debug.h"
#else
#define gpg_nvm_write nvm_write
#define gpg_nvm_write nvm_write
#define gpg_io_exchange io_exchange
#endif

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

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

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

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

@ -20,23 +20,18 @@
#include "gpg_vars.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 -- */
/* ----------------------*/
const unsigned char C_MAGIC[8] = {
'G','P','G','C','A','R','D','3'
};
const unsigned char C_MAGIC[8] = {'G', 'P', 'G', 'C', 'A', 'R', 'D', '3'};
/* ----------------------*/
/* --ECC OID -- */
/* ----------------------*/
//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
};
// secp256r1 / NIST P256 /ansi-x9.62 : 1.2.840.10045.3.1.7
const unsigned char C_OID_SECP256R1[8] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07};
/*
//secp384r1 / NIST P384 /ansi-x9.62 :1.3.132.0.34
const unsigned char C_OID_SECP384R1[5] = {
@ -53,7 +48,6 @@ const unsigned char C_OID_SECP256K1[5] = {
};
*/
/*
//brainpool 256t1: 1.3.36.3.3.2.8.1.1.8
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] = {
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] = {
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) {
if ( (len == sizeof(C_OID_SECP256R1)) && (os_memcmp(oid, C_OID_SECP256R1, len)==0) ) {
unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len) {
if ((len == sizeof(C_OID_SECP256R1)) && (os_memcmp(oid, C_OID_SECP256R1, len) == 0)) {
return CX_CURVE_SECP256R1;
}
/*
@ -112,11 +105,11 @@ unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len) {
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;
}
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;
}
@ -131,12 +124,11 @@ unsigned int gpg_oid2curve(unsigned char* oid, unsigned int len) {
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) {
case CX_CURVE_SECP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1);
return (unsigned char *)PIC(C_OID_SECP256R1);
/*
case CX_CURVE_SECP256K1:
@ -146,7 +138,7 @@ unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
case CX_CURVE_SECP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_SECP521R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
@ -156,22 +148,22 @@ unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
case CX_CURVE_BrainPoolP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1);
case CX_CURVE_BrainPoolP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_BrainPoolP512R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
*/
case CX_CURVE_Ed25519:
*len = sizeof(C_OID_Ed25519);
return (unsigned char*)PIC(C_OID_Ed25519);
return (unsigned char *)PIC(C_OID_Ed25519);
case CX_CURVE_Curve25519:
*len = sizeof(C_OID_cv25519);
return (unsigned char*)PIC(C_OID_cv25519);
return (unsigned char *)PIC(C_OID_cv25519);
}
*len = 0;
@ -181,7 +173,7 @@ unsigned char* gpg_curve2oid(unsigned int cv, unsigned int *len) {
unsigned int gpg_curve2domainlen(unsigned int cv) {
switch (cv) {
case CX_CURVE_SECP256R1:
case CX_CURVE_Ed25519:
case CX_CURVE_Ed25519:
case CX_CURVE_Curve25519:
return 32;
}
@ -193,80 +185,68 @@ unsigned int gpg_curve2domainlen(unsigned int cv) {
/* -------------------------------*/
const unsigned char C_ext_capabilities[10] = {
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -KDF
0x7E,
// No SM,
0x00,
//max challenge
SHORT(GPG_EXT_CHALLENGE_LENTH),
//max cert holder length
SHORT(GPG_EXT_CARD_HOLDER_CERT_LENTH),
//maximum do length
SHORT(GPG_EXT_PRIVATE_DO_LENGTH),
//PIN block formart 2 not supported
0x00,
//MSE
0x01
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -KDF
0x7E,
// No SM,
0x00,
// max challenge
SHORT(GPG_EXT_CHALLENGE_LENTH),
// max cert holder length
SHORT(GPG_EXT_CARD_HOLDER_CERT_LENTH),
// maximum do length
SHORT(GPG_EXT_PRIVATE_DO_LENGTH),
// PIN block formart 2 not supported
0x00,
// MSE
0x01
};
const unsigned char C_ext_length[8] = {
0x02, 0x02, SHORT(GPG_APDU_LENGTH),
0x02, 0x02, SHORT(GPG_APDU_LENGTH)
};
const unsigned char C_ext_length[8] = {0x02, 0x02, SHORT(GPG_APDU_LENGTH), 0x02, 0x02, SHORT(GPG_APDU_LENGTH)};
/* ---------------------*/
/* -- default values -- */
/* ---------------------*/
const unsigned char C_default_AID[] = {
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
//version
0x03, 0x03,
//manufacturer
0x2C, 0x97,
//serial
0x00, 0x00, 0x00, 0x00,
//RFU
0x00,0x00
};
const unsigned char C_default_Histo[] = {
0x00,
0x31,
0xC5, // select method: by DF/partialDF; IO-file:readbinary; RFU???
0x73,
0xC0, // select method: by DF/partialDF ,
0x01, // data coding style: ontime/byte
0x80, // chaining
0x7F, // zero state
0x90, 0x00
};
const unsigned char C_default_AID[] = {0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
// version
0x03, 0x03,
// manufacturer
0x2C, 0x97,
// serial
0x00, 0x00, 0x00, 0x00,
// RFU
0x00, 0x00};
const unsigned char C_default_Histo[] = {0x00, 0x31,
0xC5, // select method: by DF/partialDF; IO-file:readbinary; RFU???
0x73,
0xC0, // select method: by DF/partialDF ,
0x01, // data coding style: ontime/byte
0x80, // chaining
0x7F, // zero state
0x90, 0x00};
// Default template: RSA2048 010800002001 / 010800002001
#if 1
const unsigned char C_default_AlgoAttr_sig[] = {
// RSA
0x01,
// Modulus default length 2048
0x08, 0x00,
// PubExp length 32
0x00, 0x20,
// std: e,p,q with modulus (n)
0x01
};
const unsigned char C_default_AlgoAttr_dec[] = {
// RSA
0x01,
// Modulus default length 2048
0x08, 0x00,
// PubExp length 32
0x00, 0x20,
// std: e,p,q with modulus (n)
0x01
};
const unsigned char C_default_AlgoAttr_sig[] = {
// RSA
0x01,
// Modulus default length 2048
0x08, 0x00,
// PubExp length 32
0x00, 0x20,
// std: e,p,q with modulus (n)
0x01};
const unsigned char C_default_AlgoAttr_dec[] = {
// RSA
0x01,
// Modulus default length 2048
0x08, 0x00,
// PubExp length 32
0x00, 0x20,
// std: e,p,q with modulus (n)
0x01};
#endif
// Default template: NIST P256 132A8648CE3D030107 / 122A8648CE3D030107
@ -285,7 +265,6 @@ const unsigned char C_default_AlgoAttr_dec[] = {
};
#endif
// Default template: Ed/Cv-25519 162B06010401DA470F01 / 122B060104019755010501
#if 0
const unsigned char C_default_AlgoAttr_sig[] = {
@ -304,148 +283,143 @@ const unsigned char C_default_AlgoAttr_dec[] = {
// sha256 0x3132343536
const unsigned char C_sha256_PW1[] = {
0x8d, 0x96, 0x9e, 0xef, 0x6e, 0xca, 0xd3, 0xc2,
0x9a, 0x3a, 0x62, 0x92, 0x80, 0xe6, 0x86, 0xcf,
0x0c, 0x3f, 0x5d, 0x5a, 0x86, 0xaf, 0xf3, 0xca,
0x12, 0x02, 0x0c, 0x92, 0x3a, 0xdc, 0x6c, 0x92,
0x8d, 0x96, 0x9e, 0xef, 0x6e, 0xca, 0xd3, 0xc2, 0x9a, 0x3a, 0x62, 0x92, 0x80, 0xe6, 0x86, 0xcf,
0x0c, 0x3f, 0x5d, 0x5a, 0x86, 0xaf, 0xf3, 0xca, 0x12, 0x02, 0x0c, 0x92, 0x3a, 0xdc, 0x6c, 0x92,
};
// sha256 0x31323435363738
const unsigned char C_sha256_PW2[] = {
0xef, 0x79, 0x7c, 0x81, 0x18, 0xf0, 0x2d, 0xfb,
0x64, 0x96, 0x07, 0xdd, 0x5d, 0x3f, 0x8c, 0x76,
0x23, 0x04, 0x8c, 0x9c, 0x06, 0x3d, 0x53, 0x2c,
0xc9, 0x5c, 0x5e, 0xd7, 0xa8, 0x98, 0xa6, 0x4f,
0xef, 0x79, 0x7c, 0x81, 0x18, 0xf0, 0x2d, 0xfb, 0x64, 0x96, 0x07, 0xdd, 0x5d, 0x3f, 0x8c, 0x76,
0x23, 0x04, 0x8c, 0x9c, 0x06, 0x3d, 0x53, 0x2c, 0xc9, 0x5c, 0x5e, 0xd7, 0xa8, 0x98, 0xa6, 0x4f,
};
/* ----------------------------------------------------------------------- */
/* --- boot init --- */
/* ----------------------------------------------------------------------- */
void gpg_init() {
os_memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
//first init ?
if (os_memcmp(N_gpg_pstate->magic, (void*)C_MAGIC, sizeof(C_MAGIC)) != 0) {
// first init ?
if (os_memcmp((void *)(N_gpg_pstate->magic), (void *)C_MAGIC, sizeof(C_MAGIC)) != 0) {
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));
}
//key conf
// key conf
G_gpg_vstate.slot = N_gpg_pstate->config_slot[1];
G_gpg_vstate.kslot = &N_gpg_pstate->keys[G_gpg_vstate.slot];
gpg_mse_reset();
//pin conf
// pin conf
G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0];
//ux conf
// ux conf
gpg_init_ux();
}
void gpg_init_ux() {
G_gpg_vstate.ux_type = -1;
G_gpg_vstate.ux_key = -1;
G_gpg_vstate.ux_key = -1;
}
/* ----------------------------------------------------------------------- */
/* --- Install/ReInstall GPGapp --- */
/* ----------------------------------------------------------------------- */
int gpg_install(unsigned char app_state) {
gpg_pin_t pin;
gpg_pin_t pin;
unsigned int l;
//full reset data
gpg_nvm_write(N_gpg_pstate, NULL, sizeof(gpg_nv_state_t));
// full reset data
gpg_nvm_write((void *)(N_gpg_pstate), NULL, sizeof(gpg_nv_state_t));
//historical bytes
os_memmove(G_gpg_vstate.work.io_buffer, C_default_Histo, sizeof(C_default_Histo));
// historical bytes
os_memmove(G_gpg_vstate.work.io_buffer, C_default_Histo, sizeof(C_default_Histo));
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));
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
cx_rng(G_gpg_vstate.work.io_buffer, 4*GPG_KEYS_SLOTS);
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);
// Serial
cx_rng(G_gpg_vstate.work.io_buffer, 4 * GPG_KEYS_SLOTS);
for (int s = 0; s < GPG_KEYS_SLOTS; s++) {
gpg_nvm_write((void *)(N_gpg_pstate->keys[s].serial), G_gpg_vstate.work.io_buffer + 4 * s, 4);
}
if (app_state == STATE_ACTIVATE) {
//default sex: none
// default sex: none
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
os_memmove(pin.value, C_sha256_PW1, sizeof(C_sha256_PW1));
// default PW1/PW2: 1 2 3 4 5 6
os_memmove(pin.value, C_sha256_PW1, sizeof(C_sha256_PW1));
pin.length = 6;
pin.counter = 3;
pin.ref = PIN_ID_PW1;
gpg_nvm_write(&N_gpg_pstate->PW1, &pin, sizeof(gpg_pin_t));
pin.ref = PIN_ID_PW1;
gpg_nvm_write((void *)(&N_gpg_pstate->PW1), &pin, sizeof(gpg_pin_t));
//default PW3: 1 2 3 4 5 6 7 8
os_memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2));
// default PW3: 1 2 3 4 5 6 7 8
os_memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2));
pin.length = 8;
pin.counter = 3;
pin.ref = PIN_ID_PW3;
gpg_nvm_write(&N_gpg_pstate->PW3, &pin, sizeof(gpg_pin_t));
pin.ref = PIN_ID_PW3;
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[1] = 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;
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[1] = 0;
G_gpg_vstate.work.io_buffer[2] = 3; // 3: selection by APDU and screen
gpg_nvm_write(&N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer, 3);
//config rsa pub
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB>>24)&0xFF;
G_gpg_vstate.work.io_buffer[1] = (GPG_RSA_DEFAULT_PUB>>16)&0xFF;
G_gpg_vstate.work.io_buffer[2] = (GPG_RSA_DEFAULT_PUB>>8)&0xFF;
G_gpg_vstate.work.io_buffer[3] = (GPG_RSA_DEFAULT_PUB>>0)&0xFF;
nvm_write(&N_gpg_pstate->default_RSA_exponent, G_gpg_vstate.work.io_buffer, 4);
//config pin
G_gpg_vstate.work.io_buffer[2] = 3; // 3: selection by APDU and screen
gpg_nvm_write((void *)(&N_gpg_pstate->config_slot), G_gpg_vstate.work.io_buffer, 3);
// config rsa pub
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB >> 24) & 0xFF;
G_gpg_vstate.work.io_buffer[1] = (GPG_RSA_DEFAULT_PUB >> 16) & 0xFF;
G_gpg_vstate.work.io_buffer[2] = (GPG_RSA_DEFAULT_PUB >> 8) & 0xFF;
G_gpg_vstate.work.io_buffer[3] = (GPG_RSA_DEFAULT_PUB >> 0) & 0xFF;
nvm_write((void *)(&N_gpg_pstate->default_RSA_exponent), G_gpg_vstate.work.io_buffer, 4);
// config pin
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);
//default key template: RSA 2048)
for (int s = 0; s< GPG_KEYS_SLOTS; s++) {
// default key template: RSA 2048)
for (int s = 0; s < GPG_KEYS_SLOTS; s++) {
unsigned char uif[2];
uif[0] = 0x00;
uif[1] = 0x20;
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(&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(&N_gpg_pstate->keys[s].aut.attributes.length, &l, sizeof(unsigned int));
l = sizeof(C_default_AlgoAttr_sig);
gpg_nvm_write((void *)(&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.length), &l, sizeof(unsigned int));
gpg_nvm_write((void *)(&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.length), &l, sizeof(unsigned int));
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(&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(&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].dec.attributes.value), (void *)C_default_AlgoAttr_dec, l);
gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].dec.attributes.length), &l, sizeof(unsigned int));
gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].sig.UIF), &uif, 2);
gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].dec.UIF), &uif, 2);
gpg_nvm_write((void *)(&N_gpg_pstate->keys[s].aut.UIF), &uif, 2);
}
}
return 0;
}
#define USBD_OFFSET_CfgDesc_bPINSupport (sizeof(USBD_CfgDesc)-16)
void USBD_CCID_activate_pinpad(int enabled) {
#define USBD_OFFSET_CfgDesc_bPINSupport (sizeof(USBD_CfgDesc) - 16)
void USBD_CCID_activate_pinpad(int enabled) {
#ifdef HAVE_USB_CLASS_CCID
unsigned short length;
uint8_t *cfgDesc;
unsigned char e;
e = enabled?3:0;
length = 0;
uint8_t * cfgDesc;
unsigned char e;
e = enabled ? 3 : 0;
length = 0;
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_vars.h"
/*
* io_buff: contains current message part
* io_off: offset in current message part
@ -33,25 +32,20 @@
void gpg_io_set_offset(unsigned int offset) {
if (offset == IO_OFFSET_END) {
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;
}
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;
}
else {
} else {
THROW(ERROR_IO_OFFSET);
return ;
return;
}
}
void gpg_io_mark() {
G_gpg_vstate.io_mark = G_gpg_vstate.io_offset;
}
void gpg_io_inserted(unsigned int len) {
G_gpg_vstate.io_offset += len;
G_gpg_vstate.io_length += len;
@ -60,14 +54,14 @@ void gpg_io_inserted(unsigned int len) {
void gpg_io_discard(int clear) {
G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_mark = 0;
G_gpg_vstate.io_mark = 0;
if (clear) {
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) {
if ((G_gpg_vstate.io_length + sz) > GPG_IO_BUFFER_LENGTH) {
THROW(ERROR_IO_FULL);
return ;
return;
}
os_memmove(G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+sz,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
G_gpg_vstate.io_length-G_gpg_vstate.io_offset);
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.io_length - G_gpg_vstate.io_offset);
G_gpg_vstate.io_length += sz;
}
void gpg_io_insert(unsigned char const *buff, unsigned int 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;
}
void gpg_io_insert_u32(unsigned int v32) {
void gpg_io_insert_u32(unsigned int v32) {
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+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+3] = v32>>0;
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 + 2] = v32 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] = v32 >> 0;
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);
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+2] = v24>>0;
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 + 2] = v24 >> 0;
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);
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 + 0] = v16 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v16 >> 0;
G_gpg_vstate.io_offset += 2;
}
void gpg_io_insert_u8(unsigned int v8) {
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;
}
void gpg_io_insert_t(unsigned int T) {
if (T &0xFF00) {
gpg_io_insert_u16(T);
if (T & 0xFF00) {
gpg_io_insert_u16(T);
} 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) {
gpg_io_insert_u8(L);
} else if (L < 256) {
gpg_io_insert_u16(0x8100|L);
gpg_io_insert_u16(0x8100 | L);
} else {
gpg_io_insert_u8(0x82);
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) {
gpg_io_insert_tl(T,L);
gpg_io_insert_tl(T, L);
gpg_io_insert(V, L);
}
/* ----------------------------------------------------------------------- */
/* FECTH data from received buffer */
/* ----------------------------------------------------------------------- */
unsigned int gpg_io_fetch_u32() {
unsigned int v32;
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+2] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+3] << 0) );
unsigned int v32;
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 + 2] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] << 0));
G_gpg_vstate.io_offset += 4;
return v32;
}
unsigned int gpg_io_fetch_u24() {
unsigned int v24;
v24 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+2] << 0) );
unsigned int v24;
v24 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] << 0));
G_gpg_vstate.io_offset += 3;
return v24;
}
unsigned int gpg_io_fetch_u16() {
unsigned int v16;
v16 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] << 0) );
unsigned int v16;
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.io_offset += 2;
return v16;
}
unsigned int gpg_io_fetch_u8() {
unsigned int v8;
v8 = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] ;
unsigned int v8;
v8 = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset += 1;
return v8;
}
@ -201,16 +191,17 @@ int gpg_io_fetch_l(unsigned int *L) {
if ((*L & 0x80) != 0) {
*L &= 0x7F;
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;
} 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] ;
G_gpg_vstate.io_offset += 3 ;
*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];
G_gpg_vstate.io_offset += 3;
} else {
*L = -1;
}
} else {
G_gpg_vstate.io_offset += 1 ;
G_gpg_vstate.io_offset += 1;
}
return 0;
}
@ -221,20 +212,19 @@ int gpg_io_fetch_tl(unsigned int *T, unsigned int *L) {
return 0;
}
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);
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);
G_gpg_vstate.io_offset += len;
return len;
}
int gpg_io_fetch(unsigned char* buffer, int len) {
int gpg_io_fetch(unsigned char *buffer, int len) {
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;
return len;
}
/* ----------------------------------------------------------------------- */
/* REAL IO */
/* ----------------------------------------------------------------------- */
@ -244,125 +234,119 @@ int gpg_io_fetch(unsigned char* buffer, int len) {
int gpg_io_do(unsigned int io_flags) {
unsigned int rx = 0;
//if pending input chaining
// if pending input chaining
if (G_gpg_vstate.io_cla & 0x10) {
goto in_chaining;
}
if (io_flags & IO_ASYNCH_REPLY) {
// if IO_ASYNCH_REPLY has been set,
// gpg_io_exchange will return when IO_RETURN_AFTER_TX will set in ui
// gpg_io_exchange will return when IO_RETURN_AFTER_TX will set in ui
rx = gpg_io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0);
} else {
// --- full out chaining ---
G_gpg_vstate.io_offset = 0;
while(G_gpg_vstate.io_length > MAX_OUT) {
unsigned int tx,xx;
//send chunk
tx = MAX_OUT-2;
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, tx);
while (G_gpg_vstate.io_length > MAX_OUT) {
unsigned int tx, xx;
// send chunk
tx = MAX_OUT - 2;
os_memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, tx);
G_gpg_vstate.io_length -= tx;
G_gpg_vstate.io_offset += tx;
G_io_apdu_buffer[tx] = 0x61;
if (G_gpg_vstate.io_length > MAX_OUT-2) {
xx = MAX_OUT-2;
if (G_gpg_vstate.io_length > MAX_OUT - 2) {
xx = MAX_OUT - 2;
} else {
xx = G_gpg_vstate.io_length-2;
xx = G_gpg_vstate.io_length - 2;
}
G_io_apdu_buffer[tx+1] = xx;
rx = gpg_io_exchange(CHANNEL_APDU, tx+2);
//check get response
if ((G_io_apdu_buffer[0] != 0x00) ||
(G_io_apdu_buffer[1] != 0xc0) ||
(G_io_apdu_buffer[2] != 0x00) ||
(G_io_apdu_buffer[3] != 0x00) ) {
G_io_apdu_buffer[tx + 1] = xx;
rx = gpg_io_exchange(CHANNEL_APDU, tx + 2);
// check get response
if ((G_io_apdu_buffer[0] != 0x00) || (G_io_apdu_buffer[1] != 0xc0) || (G_io_apdu_buffer[2] != 0x00) ||
(G_io_apdu_buffer[3] != 0x00)) {
THROW(SW_COMMAND_NOT_ALLOWED);
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) {
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;
} 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 ---
if (rx < 4) {
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
}
if (rx == 4) {
G_io_apdu_buffer[4]=0;
rx = 4;
G_io_apdu_buffer[4] = 0;
rx = 4;
}
G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_length = 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_p1 = G_io_apdu_buffer[2];
G_gpg_vstate.io_p2 = G_io_apdu_buffer[3];
G_gpg_vstate.io_lc = 0;
G_gpg_vstate.io_le = 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_p1 = G_io_apdu_buffer[2];
G_gpg_vstate.io_p2 = G_io_apdu_buffer[3];
G_gpg_vstate.io_lc = 0;
G_gpg_vstate.io_le = 0;
switch (G_gpg_vstate.io_ins) {
case INS_GET_DATA:
case INS_GET_RESPONSE:
case INS_TERMINATE_DF:
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;
case INS_GET_CHALLENGE:
if (G_gpg_vstate.io_p1 == 0) {
break;
}
case INS_VERIFY:
case INS_CHANGE_REFERENCE_DATA:
if (G_io_apdu_buffer[4] == 0) {
break;
}
goto _default;
case INS_VERIFY:
case INS_CHANGE_REFERENCE_DATA:
if (G_io_apdu_buffer[4] == 0) {
break;
}
goto _default;
default:
_default:
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
os_memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer+5, G_gpg_vstate.io_lc);
G_gpg_vstate.io_length = G_gpg_vstate.io_lc;
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
os_memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer + 5, G_gpg_vstate.io_lc);
G_gpg_vstate.io_length = G_gpg_vstate.io_lc;
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[1] = 0x00;
rx = gpg_io_exchange(CHANNEL_APDU, 2);
rx = gpg_io_exchange(CHANNEL_APDU, 2);
in_chaining:
if ((rx < 4) ||
((G_io_apdu_buffer[0] & 0xEF) != (G_gpg_vstate.io_cla& 0xEF)) ||
(G_io_apdu_buffer[1] != G_gpg_vstate.io_ins) ||
(G_io_apdu_buffer[2] != G_gpg_vstate.io_p1) ||
(G_io_apdu_buffer[3] != G_gpg_vstate.io_p2) ) {
if ((rx < 4) || ((G_io_apdu_buffer[0] & 0xEF) != (G_gpg_vstate.io_cla & 0xEF)) ||
(G_io_apdu_buffer[1] != G_gpg_vstate.io_ins) || (G_io_apdu_buffer[2] != G_gpg_vstate.io_p1) ||
(G_io_apdu_buffer[3] != G_gpg_vstate.io_p2)) {
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
}
if (rx == 4) {
G_io_apdu_buffer[4]=0;
rx = 4;
G_io_apdu_buffer[4] = 0;
rx = 4;
}
G_gpg_vstate.io_cla = G_io_apdu_buffer[0];
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) {
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);
G_gpg_vstate.io_length += 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;
}
return 0;
}

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

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

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

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

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

@ -18,19 +18,21 @@
#include "gpg_types.h"
#include "gpg_api.h"
#include "gpg_vars.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
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
ux_state_t ux;
#else
extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
int apdu_n;
int apdu_n;
#endif
gpg_v_state_t G_gpg_vstate;
gpg_v_state_t G_gpg_vstate;

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

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

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

@ -13,26 +13,25 @@
* limitations under the License.
*/
const char * const C_TEMPLATE_TYPE = "Key type";
const char * const C_TEMPLATE_KEY = "Key";
const char * const C_INVALID_SELECTION = "Invalid selection";
const char *const C_TEMPLATE_TYPE = "Key type";
const char *const C_TEMPLATE_KEY = "Key";
const char *const C_INVALID_SELECTION = "Invalid selection";
const char * const C_OK = "OK";
const char * const C_NOK = "NOK";
const char *const C_OK = "OK";
const char *const C_NOK = "NOK";
const char * const C_WRONG_PIN = "PIN Incorrect";
const char * const C_RIGHT_PIN = "PIN Correct";
const char * const C_PIN_CHANGED = "PIN changed";
const char * const C_PIN_DIFFERS = "2 PINs differs";
const char * const C_PIN_USER = "User PIN";
const char * const C_PIN_ADMIN = "Admin PIN";
const char *const C_WRONG_PIN = "PIN Incorrect";
const char *const C_RIGHT_PIN = "PIN Correct";
const char *const C_PIN_CHANGED = "PIN changed";
const char *const C_PIN_DIFFERS = "2 PINs differs";
const char *const C_PIN_USER = "User PIN";
const char *const C_PIN_ADMIN = "Admin PIN";
const char * const C_VERIFIED = "Verified";
const char * const C_NOT_VERIFIED = "Not Verified";
const char * const C_ALLOWED = "Allowed";
const char * const C_NOT_ALLOWED = "Not Allowed ";
const char *const C_VERIFIED = "Verified";
const char *const C_NOT_VERIFIED = "Not Verified";
const char *const C_ALLOWED = "Allowed";
const char *const C_NOT_ALLOWED = "Not Allowed ";
const char * const C_DEFAULT_MODE = "Default mode";
const char *const C_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
#define GPG_UX_MSG_H
extern const char * const C_TEMPLATE_TYPE;
extern const char * const C_TEMPLATE_KEY;
extern const char * const C_INVALID_SELECTION;
extern const char *const C_TEMPLATE_TYPE;
extern const char *const C_TEMPLATE_KEY;
extern const char *const C_INVALID_SELECTION;
extern const char * const C_OK;
extern const char * const C_NOK;
extern const char *const C_OK;
extern const char *const C_NOK;
extern const char * const C_WRONG_PIN;
extern const char * const C_RIGHT_PIN;
extern const char * const C_PIN_CHANGED;
extern const char * const C_PIN_DIFFERS ;
extern const char * const C_PIN_USER;
extern const char * const C_PIN_ADMIN;
extern const char *const C_WRONG_PIN;
extern const char *const C_RIGHT_PIN;
extern const char *const C_PIN_CHANGED;
extern const char *const C_PIN_DIFFERS;
extern const char *const C_PIN_USER;
extern const char *const C_PIN_ADMIN;
extern const char * const C_VERIFIED;
extern const char * const C_NOT_VERIFIED;
extern const char * const C_NOT_ALLOWED;
extern const char *const C_VERIFIED;
extern const char *const C_NOT_VERIFIED;
extern const char *const C_NOT_ALLOWED;
extern const char * const C_DEFAULT_MODE;
extern const char *const C_DEFAULT_MODE;
extern const char * const C_UIF_LOCKED;
extern const char * const C_UIF_INVALID;
extern const char *const C_UIF_LOCKED;
extern const char *const C_UIF_INVALID;
#define PICSTR(x) ((char*)PIC(x))
#define PICSTR(x) ((char *)PIC(x))
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
#define TEMPLATE_KEY PICSTR(C_TEMPLATE_KEY)
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
#define TEMPLATE_KEY PICSTR(C_TEMPLATE_KEY)
#define INVALID_SELECTION PICSTR(C_INVALID_SELECTION)
#define OK PICSTR(C_OK)
#define NOK PICSTR(C_NOK)
#define WRONG_PIN PICSTR(C_WRONG_PIN)
#define RIGHT_PIN PICSTR(C_RIGHT_PIN)
#define PIN_CHANGED PICSTR(C_PIN_CHANGED)
#define PIN_DIFFERS PICSTR(C_PIN_DIFFERS)
#define PIN_USER PICSTR(C_PIN_USER)
#define PIN_ADMIN PICSTR(C_PIN_ADMIN)
#define VERIFIED PICSTR(C_VERIFIED)
#define NOT_VERIFIED PICSTR(C_NOT_VERIFIED)
#define ALLOWED PICSTR(C_ALLOWED)
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
#define UIF_LOCKED PICSTR(C_UIF_LOCKED)
#define UIF_INVALID PICSTR(C_UIF_INVALID)
#define OK PICSTR(C_OK)
#define NOK PICSTR(C_NOK)
#define WRONG_PIN PICSTR(C_WRONG_PIN)
#define RIGHT_PIN PICSTR(C_RIGHT_PIN)
#define PIN_CHANGED PICSTR(C_PIN_CHANGED)
#define PIN_DIFFERS PICSTR(C_PIN_DIFFERS)
#define PIN_USER PICSTR(C_PIN_USER)
#define PIN_ADMIN PICSTR(C_PIN_ADMIN)
#define VERIFIED PICSTR(C_VERIFIED)
#define NOT_VERIFIED PICSTR(C_NOT_VERIFIED)
#define ALLOWED PICSTR(C_ALLOWED)
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
#define UIF_LOCKED PICSTR(C_UIF_LOCKED)
#define UIF_INVALID PICSTR(C_UIF_INVALID)
#endif

File diff suppressed because it is too large Load Diff

@ -14,7 +14,6 @@
* limitations under the License.
*/
#ifndef 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_cv25519[10];
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))
extern gpg_v_state_t G_gpg_vstate;
#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
extern int apdu_n;

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

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

@ -25,5 +25,23 @@
#define U2F_EPOUT_SIZE 0x40
#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

@ -47,6 +47,7 @@
#pragma message "Override SDK source file :" __FILE__
#include "os.h"
#include "sdk_compat.h"
/* 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
#ifdef HAVE_VID_PID_PROBER
@ -131,9 +126,9 @@
#define USBD_PID 0xf1d1
#else
#define USBD_VID 0x2C97
#if defined(TARGET_BLUE) // blue
#if defined(TARGET_BLUE)
#define USBD_PID 0x0000
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
static uint8_t const USBD_PRODUCT_FS_STRING[] = {
4*2+2,
USB_DESC_TYPE_STRING,
'B', 0,
@ -142,9 +137,9 @@ static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
'e', 0,
};
#elif defined(TARGET_NANOS) // nano s
#elif defined(TARGET_NANOS)
#define USBD_PID 0x0001
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
static uint8_t const USBD_PRODUCT_FS_STRING[] = {
6*2+2,
USB_DESC_TYPE_STRING,
'N', 0,
@ -154,9 +149,9 @@ static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
' ', 0,
'S', 0,
};
#elif defined(TARGET_ARAMIS) // aramis
#elif defined(TARGET_ARAMIS)
#define USBD_PID 0x0002
static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
static uint8_t const USBD_PRODUCT_FS_STRING[] = {
6*2+2,
USB_DESC_TYPE_STRING,
'A', 0,
@ -166,13 +161,34 @@ static const uint8_t const USBD_PRODUCT_FS_STRING[] = {
'i', 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
#error unknown TARGET_ID
#endif
#endif
/* USB Standard Device Descriptor */
static const uint8_t const USBD_LangIDDesc[]=
static uint8_t const USBD_LangIDDesc[]=
{
USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING,
@ -180,7 +196,7 @@ static const uint8_t const USBD_LangIDDesc[]=
HIBYTE(USBD_LANGID_STRING),
};
static const uint8_t const USB_SERIAL_STRING[] =
static uint8_t const USB_SERIAL_STRING[] =
{
4*2+2,
USB_DESC_TYPE_STRING,
@ -190,7 +206,7 @@ static const uint8_t const USB_SERIAL_STRING[] =
'1', 0,
};
static const uint8_t const USBD_MANUFACTURER_STRING[] = {
static uint8_t const USBD_MANUFACTURER_STRING[] = {
6*2+2,
USB_DESC_TYPE_STRING,
'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_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)
0x09, 0x01, // Usage ID (vendor defined)
0xA1, 0x01, // Collection (application)
@ -228,7 +244,7 @@ static const uint8_t const HID_ReportDesc[] = {
};
#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)
0x09, 0x01, // Usage ID (vendor defined)
0xA1, 0x01, // Collection (application)
@ -255,7 +271,7 @@ static const uint8_t const HID_ReportDesc_fido[] = {
#define ARRAY_U2LE(l) (l)&0xFF, (l)>>8
/* USB HID device Configuration Descriptor */
static __ALIGN_BEGIN const uint8_t const N_USBD_CfgDesc[] __ALIGN_END =
static __ALIGN_BEGIN uint8_t const N_USBD_CfgDesc[] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
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
+0x9+0x36+0x7+0x7
#endif // HAVE_USB_CLASS_CCID
#ifdef HAVE_WEBUSB
+0x9+0x7+0x7
#endif // HAVE_WEBUSB
),
1
#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
+1
#endif // HAVE_USB_CLASS_CCID
#ifdef HAVE_WEBUSB
+1
#endif // HAVE_WEBUSB
, /*bNumInterfaces */
0x01, /*bConfigurationValue: Configuration value*/
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),
0x00, /*Polling interval in milliseconds*/
#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
/* 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 *************************/
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
/* 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 */
0x09, /*bLength: HID Descriptor size*/
@ -497,7 +551,7 @@ __ALIGN_BEGIN const uint8_t const USBD_HID_Desc[] __ALIGN_END =
};
/* 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_DESC_TYPE_DEVICE_QUALIFIER,
@ -512,7 +566,7 @@ static __ALIGN_BEGIN const uint8_t const USBD_DeviceQualifierDesc[] __ALIGN_END
};
/* USB Standard Device Descriptor */
static const uint8_t const USBD_DeviceDesc[]= {
static uint8_t const USBD_DeviceDesc[]= {
0x12, /* bLength */
USB_DESC_TYPE_DEVICE, /* bDescriptorType */
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
*/
extern volatile unsigned short G_io_apdu_length;
#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 epnum)
{
@ -743,6 +827,20 @@ uint8_t USBD_U2F_DataOut_impl (USBD_HandleTypeDef *pdev,
}
#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 epnum, uint8_t* buffer)
{
@ -774,12 +872,97 @@ uint8_t USBD_HID_DataOut_impl (USBD_HandleTypeDef *pdev,
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
* @{
*/
// note: how core lib usb calls the hid class
const USBD_DescriptorsTypeDef const HID_Desc = {
USBD_DescriptorsTypeDef const HID_Desc = {
USBD_DeviceDescriptor,
USBD_LangIDStrDescriptor,
USBD_ManufacturerStrDescriptor,
@ -791,9 +974,9 @@ const USBD_DescriptorsTypeDef const HID_Desc = {
};
#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_Setup,
NULL, /*EP0_TxSent*/
@ -810,14 +993,14 @@ static const USBD_ClassTypeDef const USBD_U2F =
};
#endif // HAVE_IO_U2F
static const USBD_ClassTypeDef const USBD_HID =
static USBD_ClassTypeDef const USBD_HID =
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */
NULL, /*DataIn*/
USBD_HID_DataIn_impl, /*DataIn*/
USBD_HID_DataOut_impl, /*DataOut*/
NULL, /*SOF */
NULL,
@ -828,6 +1011,102 @@ static const USBD_ClassTypeDef const USBD_HID =
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
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) {
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) {
os_memset(&USBD_Device, 0, sizeof(USBD_Device));
/* Init Device Library */
@ -890,6 +1175,10 @@ void USB_power(unsigned char enabled) {
USBD_RegisterClassForInterface(CCID_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_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 */
USBD_Start(&USBD_Device);

Loading…
Cancel
Save