1.1.0 fixes

Fix PIN management
   PINPAD CCID command was in conflict with new PIN get status APDU. Use class CLA=0xEF to
   differenciate both case.

Fix Terminate status management

Fix RC code setting

Add MSE support
Set MSE supported in capabilities
This commit is contained in:
Cédric Mesnil 2017-09-05 23:47:16 +02:00
parent 38e143d248
commit cf6e295e47
11 changed files with 128 additions and 35 deletions

View File

@ -109,6 +109,7 @@ class GPGCard() :
if device.startswith("ledger:"):
self.token = getDongle(True)
self.exchange = self._exchange_ledger
self.disconnect = self._disconnect_ledger
elif device.startswith("pcsc:"):
allreaders = readers()
for r in allreaders:
@ -120,6 +121,7 @@ class GPGCard() :
self.connection = r.createConnection()
self.connection.connect()
self.exchange = self._exchange_pcsc
self.disconnect = self._disconnect_pcsc
else:
#print("No")
pass
@ -127,6 +129,8 @@ class GPGCard() :
print("No token")
### APDU interface ###
def _exchange_ledger(self,cmd,sw=0x9000):
resp = b''
@ -159,6 +163,14 @@ class GPGCard() :
sw = (sw1<<8)|sw2
#print("xch S resp: %s %.04x"%(binascii.hexlify(resp),sw))
return resp,sw
def _disconnect_ledger(self):
return self.token.close()
def _disconnect_pcsc(self):
r = self.connection.disconnect()
#self.connection.releaseContext()
return r
def select(self):
apdu = binascii.unhexlify(b"00A4040006D27600012401")

View File

@ -513,7 +513,7 @@ uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
case 0: // verify pin
//ret_len = dwLength - 15;
ret_len = 5;
os_memmove(G_io_apdu_buffer, pbuf+15, 5);
off = 15;
break;
case 1: // modify pin
@ -531,7 +531,6 @@ uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
}
//ret_len = dwLength - off;
ret_len = 5;
os_memmove(G_io_apdu_buffer, pbuf+off, 5);
break;
default: // unsupported
@ -540,7 +539,9 @@ uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter,
CCID_Send_Reply(&USBD_Device);
return SLOTERROR_CMD_NOT_SUPPORTED;
}
return SC_XferBlock(G_io_apdu_buffer, ret_len, &ret_len);
pbuf += off;
pbuf[0] = 0xEF;
return SC_XferBlock(pbuf, ret_len, &ret_len);
}
// prepare the apdu to be processed by the application

View File

@ -654,10 +654,27 @@ int gpg_apdu_put_data(unsigned int ref) {
}
/* ----------------- RC ----------------- */
case 0xD3:
sw = gpg_apdu_change_ref_data();
break;
case 0xD3: {
gpg_pin_t *pin;
pin = gpg_pin_get_pin(PIN_ID_RC);
if (G_gpg_vstate.io_length == 0) {
gpg_nvm_write(pin, NULL, sizeof(gpg_pin_t));
}
else if ((G_gpg_vstate.io_length > GPG_MAX_PW_LENGTH) ||
(G_gpg_vstate.io_length < 8)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
} else {
gpg_pin_set(pin,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
G_gpg_vstate.io_length);
}
sw = SW_OK;
break;
}
/* ----------------- UIF ----------------- */
case 0xD6:
ptr_v = G_gpg_vstate.kslot->sig.UIF;

View File

@ -236,7 +236,7 @@ int gpg_dispatch() {
unsigned int tag,t,l;
int sw;
if ((G_gpg_vstate.io_cla != 0x00) && (G_gpg_vstate.io_cla != 0x10)) {
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;
}
@ -271,7 +271,6 @@ int gpg_dispatch() {
}
/* Other commands allowed if not terminated */
if (N_gpg_pstate->histo[7] != 0x07) {
THROW(SW_STATE_TERMINATED);

View File

@ -92,7 +92,7 @@ int gpg_oid2curve(unsigned char* oid, unsigned int len) {
/* -------------------------------*/
const unsigned char C_ext_capabilities[10] = {
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -RFU
//-SM, +getchallenge, +keyimport, +PWchangeable, +privateDO, +algAttrChangeable, +AES, -KDF
0x7E,
// No SM,
0x00,
@ -104,8 +104,8 @@ const unsigned char C_ext_capabilities[10] = {
SHORT(GPG_EXT_PRIVATE_DO_LENGTH),
//PIN block formart 2 not supported
0x00,
//RFU
0x00
//MSE
0x01
};

View File

@ -247,7 +247,7 @@ int gpg_io_fetch(unsigned char* buffer, int len) {
int gpg_io_do(unsigned int io_flags) {
//if pending input chaining
if (G_gpg_vstate.io_cla & 0x01) {
if (G_gpg_vstate.io_cla & 0x10) {
goto in_chaining;
}

78
src/gpg_mse.c Normal file
View File

@ -0,0 +1,78 @@
/* Copyright 2017 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "os.h"
#include "cx.h"
#include "gpg_types.h"
#include "gpg_api.h"
#include "gpg_vars.h"
static int gpg_mse_set(int crt, int ref) {
if (crt == 0xA4) {
if (ref == 0x02) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->dec;
}
if (ref == 0x03) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->aut;
}
}
if (crt == 0xB8) {
if (ref == 0x02) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->dec;
}
if (ref == 0x03) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->aut;
}
}
return 0;
}
int gpg_mse_reset() {
gpg_mse_set(0xA4, 0x03);
gpg_mse_set(0xB8, 0x02);
return 0;
}
int gpg_apdu_mse() {
int crt,ref;
if ((G_gpg_vstate.io_p1 != 0x41) ||
((G_gpg_vstate.io_p2 != 0xA4)&&(G_gpg_vstate.io_p2 != 0xB8))) {
THROW(SW_INCORRECT_P1P2);
return SW_INCORRECT_P1P2;
}
crt = gpg_io_fetch_u16();
if (crt != 0x8301) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
ref = gpg_io_fetch_u8();
if ((ref != 0x02) && (ref != 0x03)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_mse_set(crt,ref);
gpg_io_discard(1);
return SW_OK;
}

View File

@ -83,6 +83,7 @@ static void gpg_pin_check_throw(gpg_pin_t *pin, int pinID,
return;
}
THROW(sw);
return;
}
int gpg_pin_check(gpg_pin_t *pin, int pinID,
@ -143,10 +144,8 @@ int gpg_apdu_verify() {
return SW_WRONG_DATA;
}
//PINPAD
if (G_gpg_vstate.io_cla==0xFF) {
//PINPAD
if (G_gpg_vstate.io_cla == 0xEF) {
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
@ -220,25 +219,7 @@ int gpg_apdu_change_ref_data() {
gpg_pin_set_verified(pin->ref,0);
// --- RC pin ---
if (pin->ref == PIN_ID_RC) {
newlen = G_gpg_vstate.io_length;
if (newlen == 0) {
gpg_nvm_write(pin, NULL, sizeof(gpg_pin_t));
}
else if ((newlen > GPG_MAX_PW_LENGTH) ||
(newlen < 8)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
} else {
gpg_pin_set(pin,
G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,
newlen);
}
gpg_io_discard(1);
return SW_OK;
}
// --- PW1/PW3 pin ---
if (gpg_pin_is_blocked(pin)) {

View File

@ -24,6 +24,7 @@
#ifndef GPG_DEBUG_MAIN
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
ux_state_t ux;
#else
extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
int apdu_n;

View File

@ -36,6 +36,9 @@ int gpg_apdu_select() {
}
gpg_io_discard(0);
if (N_gpg_pstate->histo[7] != 0x07) {
THROW(SW_STATE_TERMINATED);
}
sw = SW_OK;
} else {
THROW(SW_FILE_NOT_FOUND);

View File

@ -179,6 +179,7 @@ struct gpg_v_state_s {
unsigned char seed_mode;
/* io state*/
unsigned char io_cla;
unsigned char io_ins;
unsigned char io_p1;