From 2e0d755fb6644892aae1158397597ec10001145d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Mesnil?= Date: Thu, 4 May 2017 17:30:53 +0200 Subject: [PATCH] RC6 Features: "PIN confirm" is now the default PIN input mode. Add EF 01F8 for setting default RSA public exponent for key generation. Access control is PW3/Admin. Bug fixes: Fix Issue #2: Add explicit return after each throw. --- Makefile | 2 +- README.md | 9 +- doc/gpgcard3.0-addon.rst | 11 ++- sdk/usbd_ccid_if.h | 209 +++++++++++++++++++++++++++++++++++++++ src/gpg_api.h | 1 + src/gpg_challenge.c | 1 + src/gpg_data.c | 91 +++++++++++------ src/gpg_dispatch.c | 5 + src/gpg_gen.c | 15 ++- src/gpg_init.c | 8 +- src/gpg_io.c | 13 ++- src/gpg_main.c | 1 + src/gpg_pin.c | 8 +- src/gpg_pso.c | 44 ++++++--- src/gpg_select.c | 1 + src/gpg_types.h | 3 + 16 files changed, 369 insertions(+), 53 deletions(-) create mode 100755 sdk/usbd_ccid_if.h diff --git a/Makefile b/Makefile index 8c9cfd6..cb333e9 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ APP_LOAD_PARAMS=--appFlags 0x40 --path "2152157255" --curve secp256k1 $(COMMON_ APPVERSION_M=1 APPVERSION_N=0 -APPVERSION_P=RC5 +APPVERSION_P=RC6 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) ICONNAME=icon_pgp.gif diff --git a/README.md b/README.md index f5abb16..eaaa526 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,13 @@ This release is in beta stage with known missing parts (see also Add-on) : #### From source - - use at least the Nano S SDK 1.3.1.4 on firmware 1.3.1 - - replace lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c by the one provided in sdk/ directory +Building from sources requires the the Nano S SDK 1.3.1.4 on firmware 1.3.1. See +https://github.com/LedgerHQ/nanos-secure-sdk + +The SDK must be slightly modified: + + - replace lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c and - replace lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/usbd_ccid_if.h by the one provided in sdk/ directory + - edit script.ld and modify the stack size : STACK_SIZE = 832; #### From Binary diff --git a/doc/gpgcard3.0-addon.rst b/doc/gpgcard3.0-addon.rst index 1e0c95b..a501b0d 100644 --- a/doc/gpgcard3.0-addon.rst +++ b/doc/gpgcard3.0-addon.rst @@ -83,6 +83,15 @@ Deterministic key derivation The deterministic key derivation process relies on the BIP32 scheme. The master install path of GPG-ledger is set to /0x80'GPG', aka /80475047 +Deterministic key derivation maybe activated in: + Settings->Seed Mode->Set on + +This activation remains effective until *set off* is selected or the application +ends. + +The key management remains the same if seed mode is on or off, i.e. key are stored in memory key containers. So their is no perfomance inpact when using seeded keys. + +Seeded keys are generated as follow: **Step1**: @@ -269,6 +278,6 @@ Other minor add-on ------------------ GnuPG use both fingerprints and serial number to identfy key on card. -So, the put data command accept to modify the AID file with '4F' tag. +So, the put data command is able to modify the AID file with '4F' tag. In that case the data field shall be four bytes length and shall contain the new serial number. '4F' is protected by PW3 (admin) PIN. diff --git a/sdk/usbd_ccid_if.h b/sdk/usbd_ccid_if.h new file mode 100755 index 0000000..78e042f --- /dev/null +++ b/sdk/usbd_ccid_if.h @@ -0,0 +1,209 @@ +/** + ****************************************************************************** + * @file usbd_ccid_if.h + * @author MCD Application Team + * @version V1.0.1 + * @date 31-January-2014 + * @brief This file provides all the functions prototypes for USB CCID + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CCID_IF_H +#define __USBD_CCID_IF_H + +#include "usbd_core.h" + +#ifdef HAVE_USB_CLASS_CCID + + +/* Exported defines ----------------------------------------------------------*/ +/* Bulk-only Command Block Wrapper */ +#define ABDATA_SIZE 261 +#define CCID_CMD_HEADER_SIZE 10 +#define CCID_RESPONSE_HEADER_SIZE 10 + + +#define CCID_INT_BUFF_SIZ 2 + +#define CARD_SLOT_FITTED 1 +#define CARD_SLOT_REMOVED 0 + +#define BULK_MAX_PACKET_SIZE 0x40 +#define CCID_IN_EP_SIZE 0x40 +#define INTR_MAX_PACKET_SIZE 8 +#define CCID_MESSAGE_HEADER_SIZE 10 +#define CCID_NUMBER_OF_SLOTS 1 + /* Number of SLOTS. For single card, this value is 1 */ + +/* Following Parameters used in PC_to_RDR_IccPowerOn */ +#define VOLTAGE_SELECTION_AUTOMATIC 0xFF +#define VOLTAGE_SELECTION_3V 0x02 +#define VOLTAGE_SELECTION_5V 0x01 +#define VOLTAGE_SELECTION_1V8 0x03 + +#define PC_TO_RDR_ICCPOWERON 0x62 +#define PC_TO_RDR_ICCPOWEROFF 0x63 +#define PC_TO_RDR_GETSLOTSTATUS 0x65 +#define PC_TO_RDR_XFRBLOCK 0x6F +#define PC_TO_RDR_GETPARAMETERS 0x6C +#define PC_TO_RDR_RESETPARAMETERS 0x6D +#define PC_TO_RDR_SETPARAMETERS 0x61 +#define PC_TO_RDR_ESCAPE 0x6B +#define PC_TO_RDR_ICCCLOCK 0x6E +#define PC_TO_RDR_T0APDU 0x6A +#define PC_TO_RDR_SECURE 0x69 +#define PC_TO_RDR_MECHANICAL 0x71 +#define PC_TO_RDR_ABORT 0x72 +#define PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY 0x73 + +#define RDR_TO_PC_DATABLOCK 0x80 +#define RDR_TO_PC_SLOTSTATUS 0x81 +#define RDR_TO_PC_PARAMETERS 0x82 +#define RDR_TO_PC_ESCAPE 0x83 +#define RDR_TO_PC_DATARATEANDCLOCKFREQUENCY 0x84 + +#define RDR_TO_PC_NOTIFYSLOTCHANGE 0x50 +#define RDR_TO_PC_HARDWAREERROR 0x51 + +#define OFFSET_INT_BMESSAGETYPE 0 +#define OFFSET_INT_BMSLOTICCSTATE 1 +#define SLOT_ICC_PRESENT 0x01 + /* LSb : (0b = no ICC present, 1b = ICC present) */ + +#define SLOT_ICC_CHANGE 0x02 /* MSb : (0b = no change, 1b = change) */ +/*****************************************************************************/ +/*********************** CCID Bulk Transfer State machine ********************/ +/*****************************************************************************/ +#define CCID_STATE_IDLE 0 /* Idle state */ +#define CCID_STATE_DATA_OUT 1 /* Data Out state */ +#define CCID_STATE_RECEIVE_DATA 2 +#define CCID_STATE_SEND_RESP 3 +#define CCID_STATE_DATAIN 4 +#define CCID_STATE_UNCORRECT_LENGTH 5 + +#define DIR_IN 0 +#define DIR_OUT 1 +#define BOTH_DIR 2 + +/* Exported types ------------------------------------------------------------*/ +#pragma pack(1) +typedef struct +{ + #pragma pack(1) + union { + #pragma pack(1) + struct { + uint8_t bMessageType; /* Offset = 0*/ + uint32_t dwLength; /* Offset = 1, The length field (dwLength) is the length + of the message not including the 10-byte header.*/ + uint8_t bSlot; /* Offset = 5*/ + uint8_t bSeq; /* Offset = 6*/ + uint8_t bSpecific_0; /* Offset = 7*/ + uint8_t bSpecific_1; /* Offset = 8*/ + uint8_t bSpecific_2; /* Offset = 9*/ + } bulkout; + #pragma pack(1) + struct { + uint8_t bMessageType; /* Offset = 0*/ + uint32_t dwLength; /* Offset = 1*/ + uint8_t bSlot; /* Offset = 5, Same as Bulk-OUT message */ + uint8_t bSeq; /* Offset = 6, Same as Bulk-OUT message */ + uint8_t bStatus; /* Offset = 7, Slot status as defined in § 6.2.6*/ + uint8_t bError; /* Offset = 8, Slot error as defined in § 6.2.6*/ + uint8_t bSpecific; /* Offset = 9*/ + } bulkin; + } header; + uint8_t abData [ABDATA_SIZE]; /* Offset = 10, For reference, the absolute + maximum block size for a TPDU T=0 block is 260 bytes + (5 bytes command; 255 bytes data), + or for a TPDU T=1 block is 259 bytes, + or for a short APDU T=1 block is 261 bytes, + or for an extended APDU T=1 block is 65544 bytes.*/ +} Ccid_bulk_data_t; +#pragma pack() + + +#pragma pack() + +typedef struct +{ + __IO uint8_t SlotStatus; + __IO uint8_t SlotStatusChange; +} Ccid_SlotStatus_t; + + +typedef struct +{ + __IO uint8_t bAbortRequestFlag; + __IO uint8_t bSeq; + __IO uint8_t bSlot; +} usb_ccid_param_t; + + +#pragma pack(1) +typedef struct _Protocol0_DataStructure_t +{ + uint8_t bmFindexDindex; + uint8_t bmTCCKST0; + uint8_t bGuardTimeT0; + uint8_t bWaitingIntegerT0; + uint8_t bClockStop; +} Protocol0_DataStructure_t; +#pragma pack() + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ccid_core.h" + +extern usb_ccid_param_t usb_ccid_param; +extern Ccid_bulk_data_t Ccid_bulk_data; /* Buffer for the Out Data */ +extern Ccid_SlotStatus_t Ccid_SlotStatus; +extern uint8_t UsbIntMessageBuffer[]; + +extern Protocol0_DataStructure_t Protocol0_DataStructure; + +/* Exported macros -----------------------------------------------------------*/ +/* Exported variables --------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev, + uint8_t epnum); + +void CCID_BulkMessage_Out (USBD_HandleTypeDef *pdev, + uint8_t epnum, uint8_t* buffer, uint16_t buflen); + +void CCID_ReceiveCmdHeader(uint8_t* pDst, uint8_t u8length); +void CCID_CmdDecode(USBD_HandleTypeDef *pdev); + +void CCID_IntMessage(USBD_HandleTypeDef *pdev); +void CCID_Init(USBD_HandleTypeDef *pdev); +void CCID_DeInit(USBD_HandleTypeDef *pdev); + +uint8_t CCID_IsIntrTransferComplete(void); +void CCID_SetIntrTransferStatus (uint8_t ); +void Transfer_Data_Request(void); +void Set_CSW (uint8_t CSW_Status, uint8_t Send_Permission); + +void io_usb_ccid_set_card_inserted(unsigned int inserted); + +#endif // HAVE_USB_CLASS_CCID + +#endif /* __USBD_CCID_IF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/gpg_api.h b/src/gpg_api.h index 142a0d3..4bfb092 100644 --- a/src/gpg_api.h +++ b/src/gpg_api.h @@ -67,6 +67,7 @@ void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) ; void gpg_io_fetch_buffer(unsigned char * buffer, unsigned int len) ; unsigned int gpg_io_fetch_u32(void) ; +unsigned int gpg_io_fetch_u24(void) ; unsigned int gpg_io_fetch_u16(void) ; unsigned int gpg_io_fetch_u8(void) ; int gpg_io_fetch_t(unsigned int *T) ; diff --git a/src/gpg_challenge.c b/src/gpg_challenge.c index f156920..dab7b0b 100644 --- a/src/gpg_challenge.c +++ b/src/gpg_challenge.c @@ -29,6 +29,7 @@ int gpg_apdu_get_challenge() { } if (olen > GPG_EXT_CHALLENGE_LENTH) { THROW(SW_WRONG_LENGTH); + return 0; } if ((G_gpg_vstate.io_p1&0x82) == 0x82) { diff --git a/src/gpg_data.c b/src/gpg_data.c index 85a84cd..071a2cc 100644 --- a/src/gpg_data.c +++ b/src/gpg_data.c @@ -30,6 +30,7 @@ int gpg_apdu_get_data(unsigned int ref) { int sw; + if (G_gpg_vstate.DO_current != ref) { G_gpg_vstate.DO_current = ref; G_gpg_vstate.DO_reccord = 0; @@ -64,6 +65,10 @@ int gpg_apdu_get_data(unsigned int ref) { case 0x01F2: gpg_io_insert_u8(G_gpg_vstate.slot); break; + /* ----------------- Config RSA exponent ----------------- */ + case 0x01F8: + gpg_io_insert_u32(N_gpg_pstate->default_RSA_exponent); + break; /* ----------------- Application ----------------- */ /* Full Application identifier */ @@ -176,8 +181,8 @@ int gpg_apdu_get_data(unsigned int ref) { /* WAT */ default: - sw = SW_REFERENCED_DATA_NOT_FOUND; - break; + THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; } return sw; @@ -225,6 +230,7 @@ int gpg_apdu_put_data(unsigned int ref) { WRITE_PRIVATE_DO: if (G_gpg_vstate.io_length > GPG_EXT_PRIVATE_DO_LENGTH) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_length); gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int)); @@ -234,29 +240,43 @@ int gpg_apdu_put_data(unsigned int ref) { case 0x01F1: if (G_gpg_vstate.io_length != 3) { THROW(SW_WRONG_LENGTH); + return 0; } if ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +0] != GPG_KEYS_SLOTS) || (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +1] >= GPG_KEYS_SLOTS) || (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +2] > 3)) { THROW(SW_WRONG_DATA); + return 0; } gpg_nvm_write(N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,3); - sw = SW_OK; break; case 0x01F2: if ((N_gpg_pstate->config_slot[2] & 2) == 0) { THROW(SW_CONDITIONS_NOT_SATISFIED); + return 0; } if ((G_gpg_vstate.io_length != 1) || (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS)) { THROW(SW_WRONG_DATA); + return 0; } G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset]; - - sw = SW_OK; break; + /* ----------------- Config RSA exponent ----------------- */ + case 0x01F8: { + unsigned int e; + if (G_gpg_vstate.io_length != 4) { + THROW(SW_WRONG_LENGTH); + return 0; + } + e = gpg_io_fetch_u32(); + nvm_write(&N_gpg_pstate->default_RSA_exponent, &e, sizeof(unsigned int)); + break; + } + + /* ----------------- Serial -----------------*/ case 0x4f: if (G_gpg_vstate.io_length != 4) { @@ -264,7 +284,6 @@ int gpg_apdu_put_data(unsigned int ref) { } G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] &= ~0x07; nvm_write(&N_gpg_pstate->AID[10], &G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset], 4); - sw = SW_OK; break; /* ----------------- Extended Header list -----------------*/ @@ -277,6 +296,7 @@ int gpg_apdu_put_data(unsigned int ref) { gpg_io_fetch_tl(&t,&l); if (t!=0x4D) { THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; } //fecth B8/B6/A4 gpg_io_fetch_tl(&t,&l); @@ -296,11 +316,13 @@ int gpg_apdu_put_data(unsigned int ref) { break; default: THROW(SW_REFERENCED_DATA_NOT_FOUND); + break; } //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; @@ -324,12 +346,14 @@ int gpg_apdu_put_data(unsigned int ref) { break; default: THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; } } //fecth 5f78 gpg_io_fetch_tl(&t,&l); if (t!=0x5f48) { THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; } // --- RSA KEY --- @@ -373,33 +397,40 @@ int gpg_apdu_put_data(unsigned int ref) { break; } ksz = ksz>>1; - if ( (len_e>4)||(len_e==0) || - (len_p > ksz )|| - (len_q > ksz)) { - THROW(SW_WRONG_DATA); - } + //fetch e e = 0; switch(len_e) { case 4: - e = (e<<8) | gpg_io_fetch_u8(); + e = gpg_io_fetch_u32(); + break; case 3: - e = (e<<8) | gpg_io_fetch_u8(); + e = gpg_io_fetch_u24(); + break; case 2: - e = (e<<8) | gpg_io_fetch_u8(); + e = gpg_io_fetch_u16(); + break; case 1: - e = (e<<8) | gpg_io_fetch_u8(); + e = gpg_io_fetch_u8(); + break; + default: + THROW(SW_WRONG_DATA); + return 0; } //move p,q over pub key, this only work because adr < adr

+ 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_memmove(pq+2*ksz-len_q, q, len_q); os_memset(pq, 0, ksz-len_p); + os_memmove(pq+2*ksz-len_q, q, len_q); os_memset(pq+ksz, 0, ksz-len_q); + //regenerate RSA private key cx_rsa_generate_pair(ksz<<1, rsa_pub, rsa_priv, e, pq); @@ -421,6 +452,7 @@ int gpg_apdu_put_data(unsigned int ref) { curve = gpg_oid2curve(&keygpg->attributes.value[1], keygpg->attributes.length-1); if (curve == 0) { THROW(SW_WRONG_DATA); + return 0; } ksz = 32; if (ksz == 32) { @@ -440,6 +472,7 @@ int gpg_apdu_put_data(unsigned int ref) { // --- UNSUPPORTED KEY --- else { THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; } break; } //endof of 3fff @@ -450,45 +483,45 @@ int gpg_apdu_put_data(unsigned int ref) { case 0x5B: if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->name.value)) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(N_gpg_pstate->name.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); gpg_nvm_write(&N_gpg_pstate->name.length, &G_gpg_vstate.io_length, sizeof(unsigned int)); - sw = SW_OK; break; /* Login data */ case 0x5E: if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->login.value)) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(N_gpg_pstate->login.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); gpg_nvm_write(&N_gpg_pstate->login.length, &G_gpg_vstate.io_length, sizeof(unsigned int)); - sw = SW_OK; break; /* Language preferences */ case 0x5F2D: if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->lang.value)) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(N_gpg_pstate->lang.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); gpg_nvm_write(&N_gpg_pstate->lang.length, &G_gpg_vstate.io_length, sizeof(unsigned int)); - sw = SW_OK; break; /* Sex */ case 0x5F35: if (G_gpg_vstate.io_length != sizeof(N_gpg_pstate->sex)) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(N_gpg_pstate->sex, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); - sw = SW_OK; break; /* Uniform resource locator */ case 0x5F50: if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->url.value)) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(N_gpg_pstate->url.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); gpg_nvm_write(&N_gpg_pstate->url.length, &G_gpg_vstate.io_length, sizeof(unsigned int)); - sw = SW_OK; break; /* ----------------- Cardholder certificate ----------------- */ @@ -508,8 +541,8 @@ int gpg_apdu_put_data(unsigned int ref) { ptr_v = G_gpg_vstate.kslot->dec.CA.value; goto WRITE_CA; default: - sw = SW_REFERENCED_DATA_NOT_FOUND; - break; + THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; } WRITE_CA: if (G_gpg_vstate.io_length > GPG_EXT_CARD_HOLDER_CERT_LENTH) { @@ -517,7 +550,6 @@ int gpg_apdu_put_data(unsigned int ref) { } gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int)); - sw = SW_OK; break; /* ----------------- Algorithm attributes ----------------- */ @@ -536,10 +568,10 @@ int gpg_apdu_put_data(unsigned int ref) { WRITE_ATTRIBUTES: if (G_gpg_vstate.io_length > 12) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length); gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int)); - sw = SW_OK; break; /* ----------------- PWS status ----------------- */ @@ -569,9 +601,9 @@ int gpg_apdu_put_data(unsigned int ref) { WRITE_FINGERPRINTS: if (G_gpg_vstate.io_length != 20) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 20); - sw = SW_OK; break; /* ----------------- Generation date/time ----------------- */ @@ -587,9 +619,9 @@ int gpg_apdu_put_data(unsigned int ref) { WRITE_DATE: if (G_gpg_vstate.io_length != 4) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 4); - sw = SW_OK; break; /* ----------------- AES key ----------------- */ @@ -638,9 +670,9 @@ int gpg_apdu_put_data(unsigned int ref) { WRITE_UIF: if (G_gpg_vstate.io_length != 2) { THROW(SW_WRONG_LENGTH); + return 0; } gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 2); - sw = SW_OK; break; /* ----------------- WAT ----------------- */ @@ -648,6 +680,7 @@ int gpg_apdu_put_data(unsigned int ref) { sw = SW_REFERENCED_DATA_NOT_FOUND; break; } + gpg_io_discard(1); return sw; diff --git a/src/gpg_dispatch.c b/src/gpg_dispatch.c index 23a4614..c58e9fd 100644 --- a/src/gpg_dispatch.c +++ b/src/gpg_dispatch.c @@ -102,6 +102,10 @@ void gpg_check_access_read_DO() { //ALWAYS case 0x0101: case 0x0102: + case 0x01F0: + case 0x01F1: + case 0x01F2: + case 0x01F8: case 0x006E: case 0x0065: case 0x0073: @@ -179,6 +183,7 @@ void gpg_check_access_write_DO() { case 0x0102: case 0x0104: case 0x01F1: + case 0x01F8: case 0x005E: case 0x005B: case 0x5F2D: diff --git a/src/gpg_gen.c b/src/gpg_gen.c index 703d27f..9bca64d 100644 --- a/src/gpg_gen.c +++ b/src/gpg_gen.c @@ -69,10 +69,12 @@ int gpg_apdu_gen() { break; default: THROW(SW_INCORRECT_P1P2); + return 0; } if (G_gpg_vstate.io_lc != 2){ THROW(SW_WRONG_LENGTH); + return 0; } gpg_io_fetch_tl(&t,&l); @@ -94,6 +96,7 @@ int gpg_apdu_gen() { break; default: THROW(SW_WRONG_DATA); + return 0; } switch ((G_gpg_vstate.io_p1<<8)|G_gpg_vstate.io_p2) { @@ -102,7 +105,7 @@ int gpg_apdu_gen() { case 0x8001: // RSA if (keygpg->attributes.value[0] == 0x01) { -#define GPG_RSA_DEFAULT_PUB 0x010001U + unsigned char *pq; cx_rsa_public_key_t *rsa_pub; cx_rsa_private_key_t *rsa_priv, *pkey; @@ -151,7 +154,7 @@ int gpg_apdu_gen() { } - cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, GPG_RSA_DEFAULT_PUB, pq); + cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, N_gpg_pstate->default_RSA_exponent, pq); nvm_write(pkey, rsa_priv, pkey_size); nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4); @@ -162,7 +165,7 @@ int gpg_apdu_gen() { gpg_io_clear(); goto send_rsa_pub; -#undef GPG_RSA_DEFAULT_PUB + } // ECC if ((keygpg->attributes.value[0] == 18) || @@ -207,24 +210,28 @@ int gpg_apdu_gen() { case 1024/8: if (keygpg->key.rsa1024.size == 0) { THROW (SW_REFERENCED_DATA_NOT_FOUND); + return 0; } gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa1024.n); break; case 2048/8: if (keygpg->key.rsa2048.size == 0) { THROW (SW_REFERENCED_DATA_NOT_FOUND); + return 0; } gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa2048.n); break; case 3072/8: if (keygpg->key.rsa3072.size == 0) { THROW (SW_REFERENCED_DATA_NOT_FOUND); + return 0; } gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa3072.n); break; case 4096/8: if (keygpg->key.rsa4096.size == 0) { THROW (SW_REFERENCED_DATA_NOT_FOUND); + return 0; } gpg_io_insert_tlv(0x81,ksz,(unsigned char*)&keygpg->key.rsa4096.n); break; @@ -248,6 +255,7 @@ int gpg_apdu_gen() { if (keygpg->pub_key.ecfp256.W_len == 0) { THROW (SW_REFERENCED_DATA_NOT_FOUND); + return 0; } gpg_io_discard(1); gpg_io_mark(); @@ -277,4 +285,5 @@ int gpg_apdu_gen() { } THROW(SW_WRONG_DATA); + return 0; } diff --git a/src/gpg_init.c b/src/gpg_init.c index d56ff27..28d73eb 100644 --- a/src/gpg_init.c +++ b/src/gpg_init.c @@ -276,9 +276,13 @@ int gpg_install(unsigned char app_state) { 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 + l = GPG_RSA_DEFAULT_PUB; + nvm_write(&N_gpg_pstate->default_RSA_exponent, &l, sizeof(unsigned int)); + //config pin - G_gpg_vstate.work.io_buffer[0] = PIN_MODE_SCREEN; + 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); //default key template: RSA 2048) diff --git a/src/gpg_io.c b/src/gpg_io.c index 21f2582..c50623b 100644 --- a/src/gpg_io.c +++ b/src/gpg_io.c @@ -162,6 +162,15 @@ unsigned int gpg_io_fetch_u32() { return v32; } +unsigned int gpg_io_fetch_u24() { + unsigned int v24; + v24 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 16) | + (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+1] << 8) | + (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+2] << 0) ); + G_gpg_vstate.io_offset += 3; + return v24; +} + unsigned int gpg_io_fetch_u16() { unsigned int v16; v16 = ( (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset+0] << 8) | @@ -269,6 +278,7 @@ int gpg_io_do(unsigned int io_flags) { (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); @@ -329,7 +339,8 @@ int gpg_io_do(unsigned int io_flags) { (G_io_apdu_buffer[1] != G_gpg_vstate.io_ins) || (G_io_apdu_buffer[2] != G_gpg_vstate.io_p1) || (G_io_apdu_buffer[3] != G_gpg_vstate.io_p2) ) { - THROW(SW_COMMAND_NOT_ALLOWED); + THROW(SW_COMMAND_NOT_ALLOWED); + return 0; } G_gpg_vstate.io_cla = G_io_apdu_buffer[0]; G_gpg_vstate.io_lc = G_io_apdu_buffer[4]; diff --git a/src/gpg_main.c b/src/gpg_main.c index 40a84c5..9390543 100644 --- a/src/gpg_main.c +++ b/src/gpg_main.c @@ -131,6 +131,7 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { default: THROW(INVALID_PARAMETER); + return 0; } return 0; } diff --git a/src/gpg_pin.c b/src/gpg_pin.c index 421ea45..2d810ef 100644 --- a/src/gpg_pin.c +++ b/src/gpg_pin.c @@ -139,6 +139,7 @@ int gpg_apdu_verify(int id) { pin = gpg_get_pin(id); if (pin == NULL) { THROW(SW_WRONG_DATA); + return 0; } gpg_set_pin_verified(id,0); @@ -168,7 +169,7 @@ int gpg_apdu_verify(int id) { gpg_checkthrow_pin(pin, G_gpg_vstate.work.io_buffer+ G_gpg_vstate.io_offset, G_gpg_vstate.io_length); - gpg_set_pin_verified(id,1); + gpg_set_pin_verified(id,1); gpg_io_discard(1); return SW_OK; } @@ -180,6 +181,7 @@ int gpg_apdu_change_ref_data(int id) { pin = gpg_get_pin(id); if (pin == NULL) { THROW(SW_WRONG_DATA); + return 0; } gpg_set_pin_verified(id,0); @@ -195,6 +197,7 @@ int gpg_apdu_change_ref_data(int id) { else if ((newlen > GPG_MAX_PW_LENGTH) || (newlen < 8)) { THROW(SW_WRONG_DATA); + return 0; } else { gpg_set_pin(pin, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, @@ -234,6 +237,7 @@ int gpg_apdu_change_ref_data(int id) { ((id == PIN_ID_PW1) && (newlen < 6)) || ((id == PIN_ID_PW3) && (newlen < 8)) ) { THROW(SW_WRONG_DATA); + return 0; } gpg_set_pin(pin, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+len, @@ -252,6 +256,7 @@ int gpg_apdu_reset_retry_counter() { if (G_gpg_vstate.io_p1 == 2) { if (!G_gpg_vstate.verified_pin[PIN_ID_PW3]) { THROW(SW_SECURITY_STATUS_NOT_SATISFIED); + return 0; } rc_len = 0; pw1_len = G_gpg_vstate.io_length; @@ -271,6 +276,7 @@ int gpg_apdu_reset_retry_counter() { if ((pw1_len > GPG_MAX_PW_LENGTH) ||(pw1_len < 6)) { THROW(SW_WRONG_DATA); + return 0; } gpg_set_pin(pin_pw1, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset+rc_len, diff --git a/src/gpg_pso.c b/src/gpg_pso.c index 916dc44..470d5fd 100644 --- a/src/gpg_pso.c +++ b/src/gpg_pso.c @@ -50,6 +50,7 @@ static int gpg_sign(gpg_key_t *sigkey) { } if (key->size != ksz) { THROW(SW_CONDITIONS_NOT_SATISFIED); + return 0; } //sign @@ -82,6 +83,7 @@ static int gpg_sign(gpg_key_t *sigkey) { key = &sigkey->key.ecfp256; if (key->d_len != 32) { THROW(SW_CONDITIONS_NOT_SATISFIED); + return 0; } //sign if (sigkey->attributes.value[0] == 19) { @@ -122,7 +124,7 @@ static int gpg_sign(gpg_key_t *sigkey) { } // --- PSO:CDS NOT SUPPORTED THROW(SW_REFERENCED_DATA_NOT_FOUND); - + return 0; } @@ -133,6 +135,7 @@ int gpg_apdu_pso(unsigned int pso) { case 0x9e9a: { return gpg_sign(&G_gpg_vstate.kslot->sig); } + // --- PSO:DEC --- case 0x8086: { unsigned int msg_len; @@ -141,11 +144,12 @@ int gpg_apdu_pso(unsigned int pso) { pad_byte = gpg_io_fetch_u8(); switch(pad_byte) { - // --- RSA + // --- PSO:DEC:RSA case 0x00: { cx_rsa_private_key_t *key; if (G_gpg_vstate.kslot->dec.attributes.value[0] != 0x01) { THROW(SW_CONDITIONS_NOT_SATISFIED); + return 0; } ksz = (G_gpg_vstate.kslot->dec.attributes.value[1]<<8) | G_gpg_vstate.kslot->dec.attributes.value[2]; ksz = ksz>>3; @@ -167,6 +171,7 @@ int gpg_apdu_pso(unsigned int pso) { if ((key == NULL) || (key->size != ksz)) { THROW(SW_CONDITIONS_NOT_SATISFIED); + return 0; } msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset; sz = cx_rsa_decrypt(key, @@ -179,13 +184,15 @@ int gpg_apdu_pso(unsigned int pso) { gpg_io_inserted(sz); return SW_OK; } - // --- AES + + // --- PSO:DEC:AES case 0x02: { cx_aes_key_t *key; unsigned int sz; key = &G_gpg_vstate.kslot->AES_dec; if (!(key->size != 16)) { THROW(SW_CONDITIONS_NOT_SATISFIED+5); + return 0; } msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset; sz = cx_aes(key, @@ -197,26 +204,31 @@ int gpg_apdu_pso(unsigned int pso) { gpg_io_inserted(sz); return SW_OK; } - // --- ECDH + + // --- PSO:DEC:ECDH case 0xA6: { cx_ecfp_private_key_t *key; unsigned int sz; unsigned int curve; if (G_gpg_vstate.kslot->dec.attributes.value[0] != 18) { THROW(SW_CONDITIONS_NOT_SATISFIED); + return 0; } key = &G_gpg_vstate.kslot->dec.key.ecfp256; if (key->d_len != 32) { THROW(SW_CONDITIONS_NOT_SATISFIED); + return 0; } gpg_io_fetch_l(&l); gpg_io_fetch_tl(&t, &l); if (t != 0x7f49) { THROW(SW_WRONG_DATA); + return 0; } gpg_io_fetch_tl(&t, &l); if (t != 0x86) { THROW(SW_WRONG_DATA); + return 0; } curve = gpg_oid2curve(G_gpg_vstate.kslot->dec.attributes.value+1, G_gpg_vstate.kslot->dec.attributes.length-1); @@ -246,18 +258,23 @@ int gpg_apdu_pso(unsigned int pso) { gpg_io_insert( G_gpg_vstate.work.io_buffer+128,sz); return SW_OK; } - // --- PSO:DEC NOT SUPPORTDED - default: - THROW(SW_REFERENCED_DATA_NOT_FOUND); - } - //--- PSO NOT SUPPPORTED --- - default: - THROW(SW_REFERENCED_DATA_NOT_FOUND); + // --- PSO:DEC:xx NOT SUPPORTDED + default: + THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; + } } - THROW(SW_WRONG_DATA); - }} + + //--- PSO:yy NOT SUPPPORTED --- + default: + THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; + } + THROW(SW_REFERENCED_DATA_NOT_FOUND); + return 0; +} int gpg_apdu_internal_authenticate() { @@ -267,6 +284,7 @@ int gpg_apdu_internal_authenticate() { if (G_gpg_vstate.kslot->aut.attributes.value[0] == 1) { if ( G_gpg_vstate.io_length > ((G_gpg_vstate.kslot->aut.attributes.value[1]<<8)|G_gpg_vstate.kslot->aut.attributes.value[2])*40/100) { THROW(SW_WRONG_LENGTH); + return 0; } } return gpg_sign(&G_gpg_vstate.kslot->aut); diff --git a/src/gpg_select.c b/src/gpg_select.c index ccfe145..0130f24 100644 --- a/src/gpg_select.c +++ b/src/gpg_select.c @@ -37,6 +37,7 @@ int gpg_apdu_select() { sw = SW_OK; } else { THROW(SW_FILE_NOT_FOUND); + return 0; } return sw; } diff --git a/src/gpg_types.h b/src/gpg_types.h index f9b4451..3ec867d 100644 --- a/src/gpg_types.h +++ b/src/gpg_types.h @@ -36,6 +36,7 @@ #define GPG_KEY_ATTRIBUTES_LENGTH 12 +#define GPG_RSA_DEFAULT_PUB 0x010001U struct gpg_pin_s { //initial pin length, 0 means not set @@ -113,6 +114,8 @@ struct gpg_nv_state_s { /* 01F1 (01F2 is volatile)*/ unsigned char config_slot[3]; + /* RSA exponent */ + unsigned int default_RSA_exponent; /* 0101 0102 0103 0104 */ LV(private_DO1, GPG_EXT_PRIVATE_DO_LENGTH);