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.
This commit is contained in:
Cédric Mesnil 2017-05-04 17:30:53 +02:00
parent 980d24d1e7
commit 2e0d755fb6
16 changed files with 369 additions and 53 deletions

View File

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

View File

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

View File

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

209
sdk/usbd_ccid_if.h Executable file
View File

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

View File

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

View File

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

View File

@ -30,6 +30,7 @@ int gpg_apdu_get_data(unsigned int ref) {
int sw;
if (G_gpg_vstate.DO_current != ref) {
G_gpg_vstate.DO_current = ref;
G_gpg_vstate.DO_reccord = 0;
@ -64,6 +65,10 @@ int gpg_apdu_get_data(unsigned int ref) {
case 0x01F2:
gpg_io_insert_u8(G_gpg_vstate.slot);
break;
/* ----------------- Config RSA exponent ----------------- */
case 0x01F8:
gpg_io_insert_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<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_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;

View File

@ -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:

View File

@ -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;
}

View File

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

View File

@ -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];

View File

@ -131,6 +131,7 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
default:
THROW(INVALID_PARAMETER);
return 0;
}
return 0;
}

View File

@ -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,

View File

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

View File

@ -37,6 +37,7 @@ int gpg_apdu_select() {
sw = SW_OK;
} else {
THROW(SW_FILE_NOT_FOUND);
return 0;
}
return sw;
}

View File

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