Compare commits

..

22 Commits

Author SHA1 Message Date
NIIBE Yutaka
c98f1fe8c6 fix usb config 2012-02-02 14:17:51 +09:00
NIIBE Yutaka
14673b825b version 0.17 2012-02-02 14:09:38 +09:00
NIIBE Yutaka
6550dd5353 space removal 2012-02-02 13:15:23 +09:00
NIIBE Yutaka
3d732a7c2d command chaining change 2012-02-02 12:18:47 +09:00
NIIBE Yutaka
aff9080b35 add alignment for gnuk.ld.in, add ChangeLog entries. 2012-01-21 00:33:17 +09:00
NIIBE Yutaka
21debc0567 no ext lc and le but short APDU only 2012-01-20 18:18:23 +09:00
NIIBE Yutaka
f92ee76db5 fixes two bugs 2012-01-19 14:23:01 +09:00
NIIBE Yutaka
87e4fd50c1 New API between gpg and ccid layer 2012-01-18 18:59:16 +09:00
NIIBE Yutaka
cbb2c6aab5 clean up USB API 2 2012-01-16 13:24:31 +09:00
NIIBE Yutaka
00541d7627 clean up USB API 2012-01-16 12:17:45 +09:00
NIIBE Yutaka
27277e56ee update pinpadtest.py 2012-01-12 10:39:16 +09:00
NIIBE Yutaka
4ee4417fb5 fix adding semicolon 2012-01-10 16:47:48 +09:00
NIIBE Yutaka
11351c8cae pinmodify is OK for unblock and put resetcode 2012-01-10 16:02:53 +09:00
NIIBE Yutaka
6abac73354 add an entry for NEWS 2012-01-05 17:04:00 +09:00
NIIBE Yutaka
41537cc827 check DF name on SELECT command 2012-01-05 15:14:35 +09:00
NIIBE Yutaka
a4e0e67340 pinpadtest.py: name change 2012-01-05 10:15:00 +09:00
NIIBE Yutaka
58f8470446 pinpad-test.py: comment change 2012-01-05 10:13:42 +09:00
NIIBE Yutaka
885e1c4ecb pinpad-test.py: add comment 2012-01-05 10:12:24 +09:00
NIIBE Yutaka
2c111d0b20 add result for pinpad-test 2012-01-04 17:33:34 +09:00
NIIBE Yutaka
35a62354ae pinpad-test.py: add --pinmin, --unblock2, and --put2 2012-01-04 11:57:19 +09:00
NIIBE Yutaka
18f3e72c32 fix pinpad-test.py for --add 2012-01-04 09:32:41 +09:00
NIIBE Yutaka
121df70044 fix long standing bug of RxCount setting for buffer bound (was bug in STmicro's software) 2011-12-28 22:16:14 +09:00
22 changed files with 1719 additions and 757 deletions

160
ChangeLog
View File

@@ -1,5 +1,165 @@
2012-02-02 Niibe Yutaka <gniibe@fsij.org>
* Version 0.17.
* src/usb_desc.c (gnukStringSerial): Updated.
(gnukConfigDescriptor): Short APDU only.
* tool/gnuk_put_binary.py (cmd_get_response): New.
(cmd_select_openpgp, cmd_get_data): Call cmd_get_response.
2012-01-30 Niibe Yutaka <gniibe@fsij.org>
* src/usb-icc.c (struct ccid): Add chained_cls_ins_p1_p2.
(end_cmd_apdu_head, icc_cmd_apdu_data, icc_handle_data): Add checking
CMD APDU head for command chaining.
2012-01-20 Niibe Yutaka <gniibe@fsij.org>
Short APDU only CCID driver.
* STM32_USB-FS-Device_Driver/src/usb_core.c (DataStageOut)
(DataStageIn): Use usb_lld_to_pmabuf and usb_lld_from_pmabuf.
* src/configure (CERTDO_SUPPORT): Comment fix.
* src/gnuk.h (struct adpu): expected_res_size has type uint16_t.
(MAX_CMD_APDU_DATA_SIZE, MAX_RES_APDU_DATA_SIZE): New.
(MAX_CMD_APDU_SIZE, MAX_RES_APDU_SIZE, USB_BUF_SIZE): Remove.
(icc_state_p): New.
(set_res_sw): Rename from set_res_apdu.
* src/call-rsa.c (rsa_decrypt): Use MAX_RES_APDU_DATA_SIZE.
* src/openpgp.c (set_res_sw): Rename from set_res_apdu.
* src/openpgp.h: Use set_res_sw.
* src/main.c: Handle icc_state_p.
* src/openpgp-do.c (historical_bytes): command chaining but short
APDU only.
(extended_capabilities): Change for short APDU only.
* src/usb-icc.c (USB_BUF_SIZE): Define here (was in gnuk.h).
(struct ep_in, epi_init, struct ep_out, epo_init, endpoint_out)
(endpoint_in, icc_state_p, struct ccid, APDU_STATE_WAIT_COMMAND)
(APDU_STATE_COMMAND_CHAINING, APDU_STATE_COMMAND_RECEIVED)
(APDU_STATE_RESULT, APDU_STATE_RESULT_GET_RESPONSE, ccid_reset)
(ccid_init, CMD_APDU_HEAD_SIZE, apdu_init, notify_tx, no_buf)
(set_sw1sw2, get_sw1sw2, notify_icc, end_icc_rx, end_abdata)
(end_cmd_apdu_head, end_nomore_data, end_cmd_apdu_data)
(nomore_data, INS_GET_RESPONSE, icc_cmd_apdu_data, icc_abdata)
(icc_send_data_block_0x9000, icc_send_data_block_gr, ccid): New.
(icc_data_size, icc_seq, icc_next_p, icc_chain_p, icc_tx_size)
(icc_thread, icc_state, gpg_thread, ICC_RESPONSE_MSG_DATA_SIZE):
Remove.
(EP1_IN_Callback): Rewrite using epi.
(EP2_OUT_Callback): Rewrite using epo.
(icc_prepare_receive): Rewrite using epo and struct ccid.
(ATR): Change ofr short APDU only.
(icc_error, icc_power_on, icc_send_status, icc_power_off)
(icc_send_data_block, icc_send_params, icc_handle_data)
(icc_handle_timeout, USBthread): Rewrite using struct ccid.
* src/usb_desc.c (gnukConfigDescriptor): dwFeatures: Short APDU
level, dwMaxCCIDMessageLength: 271.
* src/usb_lld.c (usb_lld_to_pmabuf, usb_lld_from_pmabuf): New.
* src/usb_lld.h (usb_lld_txcpy, void usb_lld_write) Use
usb_lld_to_pmabuf.
(usb_lld_rxcpy): Use usb_lld_from_pmabuf.
* src/stmusb.mk (usb_mem.c): Remove.
* gnuk_put_binary.py (cmd_select_openpgp): No response APDU data.
(cmd_verify, cmd_write_binary): Send short APDU.
(__main__): Remove RANDOM_NUMBER_BITS support.
Bug fix for CERTDO_SUPPORT.
* src/gnuk.ld.in: Add missing alignment for _data_pool (when no
CERTDO_SUPPORT).
2012-01-19 Niibe Yutaka <gniibe@fsij.org>
* src/usb-icc.c (icc_handle_data): Handle the case when it only
sends 0x90 and 0x00 correctly.
* src/openpgp-do.c (gpg_do_get_data): Fix res_apdu_data_len.
2012-01-18 Niibe Yutaka <gniibe@fsij.org>
Clean up API between application layer and CCID layer.
* tool/gnuk_put_binary.py, gnuk_put_binary_libusb.py: Don't append
0x9000 at the data, any more.
* src/usb-icc.c (icc_data_size, icc_buffer, icc_seq): Make them
internal.
(res_APDU_size, res_APDU_pointer): Removed.
(icc_handle_data, USBthread): Follow new API of struct apdu.
* src/call-rsa.c (rsa_sign, rsa_decrypt): Likewise.
* src/openpgp.c (CLS, INS, P1, P2): New.
(set_res_apdu, cmd_verify, cmd_change_password)
(cmd_reset_user_password, cmd_put_data, cmd_pgp_gakp)
(cmd_read_binary, cmd_select_file, cmd_pso)
(cmd_internal_authenticate, cmd_update_binary, cmd_write_binary)
(process_command_apdu, GPGthread): Follow new API of struct apdu.
* src/openpgp-do.c (gpg_do_get_data, gpg_do_public_key): Follow
new API of struct apdu.
* src/gnuk.h (struct apdu, apdu): New.
(cmd_APDU, icc_data_size, cmd_APDU_size, icc_buffer): Removed.
(res_APDU, res_APDU_size): Use members of struct apdu.
2012-01-16 Niibe Yutaka <gniibe@fsij.org>
Adopt new USB API.
* src/usb_msc.c (usb_start_transmit): Use usb_lld_write.
(EP6_IN_Callback): Use usb_lld_tx_data_len and usb_lld_write.
(usb_start_receive): Use usb_lld_rx_enable.
(EP7_OUT_Callback): Use usb_lld_rx_data_len, usb_lld_rxcpy
and usb_lld_rx_enable
(msc_handle_command): Use usb_lld_stall_rx and usb_lld_stall_tx.
* src/usb_lld.h (usb_lld_stall_tx, usb_lld_stall_rx)
(usb_lld_tx_data_len): New.
* src/main.c (STDOUTthread): Use usb_lld_write.
* src/usb-icc.c (EP1_IN_Callback, icc_error, icc_power_on)
(icc_send_status, icc_send_data_block, icc_send_params): Use
usb_lld_write (was: USB_SIL_Write).
(EP2_OUT_Callback): Use usb_lld_rx_data_len, usb_lld_rxcpy,
and usb_lld_rx_enable (was: USB_SIL_Read and SetEPRxValid).
(icc_prepare_receive): Use usb_lld_rx_enable.
* src/stmusb.mk (STMUSBSRC): Dont' include usb_sil.c.
* src/usb_lld.h (usb_lld_txcpy, usb_lld_tx_enable)
(usb_lld_write, usb_lld_rx_enable, usb_lld_rx_data_len)
(usb_lld_rxcpy): New.
* src/usb_prop.c (SetEPRxCount_allocated_size): Fix the
implementation. (ST's SetEPRxCount is actually meant to
setup allocated size, which is confusing).
(gnuk_device_init): Don't call USB_SIL_Init.
2012-01-10 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp.c (GPGthread): Allow INS_RESET_RETRY_COUNTER and
INS_PUT_DATA for pinentry targets.
2012-01-05 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_select_file): Check DF name.
* tool/pinpadtest.py: Rename from pinpad-test.py.
2011-12-28 Niibe Yutaka <gniibe@fsij.org>
* src/usb_prop.c (SetEPRxCount_allocated_size): New.
(gnuk_device_reset): Use SetEPRxCount_allocated_size.
* src/usb_msc.c (usb_start_receive): Don't set RxCount register
here.
* STM32_USB-FS-Device_Driver/src/usb_core.c (Standard_ClearFeature)
(Post0_Process): Don't need to set RxCount register.
* src/usb_prop.c (msc_lun_info) [PINPAD_DND_SUPPORT]: ifdef-out.
* src/usb-icc.c (EP2_OUT_Callback): Fix apdu size == 49 bug,

22
NEWS
View File

@@ -2,15 +2,25 @@ Gnuk NEWS - User visible changes
* Major changes in Gnuk 0.17
Released 2012-01-XX, by NIIBE Yutaka
Released 2012-02-02, by NIIBE Yutaka
** USB CCID/ICCD low level bug is fixed
** USB CCID/ICCD protocol implementation change
Gnuk now only supports short APDU level exchange, not support.
extended APDU level exchange. Thus, Gnuk could be compatible to older
host side software implementation.
** ISO 7816 SELECT command behavior is somewhat strict now
Old implementations do not check DF name for SELECT command.
This causes some trouble when Gnuk Token is identified as if it were
different card/token. Now, DF name of OpenPGP card is checked.
** USB CCID/ICCD low-level bug is fixed
When the size of command APDU data is just 49, the lower level packet
size is 64. This is maximum size of BULK-OUT transfer packet, and
caused trouble in the past implementations. Example is setting url
(0x5f50) as: http://www.gniibe.org/adpu-string-size-is-just-49
This is because the past implementations expect ZLP (zero size
packet). Now, it has been fixed. You can use any size.
This is because the past implementations expect ZLP (zero length
packet). Now, it has been fixed. You can use any size of string.
** CERT.3 Data Object (0x7f21) is now optional
As there's no valid use case for this data object and it does not
@@ -22,8 +32,8 @@ configure time.
Now, user can cancel pin input by unmounting device before finishing
DnD.
** New tool: pinpad-test.py
The tool pinpad-test.py is PC/SC test tool for pinentry of pinpad with
** New tool: pinpadtest.py
The tool pinpadtest.py is PC/SC test tool for pinentry of pinpad with
OpenPGP card v2.

23
README
View File

@@ -1,7 +1,7 @@
Gnuk - software for GnuPG USB Token
Version 0.16
2011-12-14
Version 0.17
2012-02-02
Niibe Yutaka
Free Software Initiative of Japan
@@ -104,12 +104,15 @@ Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
and at the tab of "Startup Programs", disable check buttons for
"GPG Password Agent" and "SSH Key Agent".
Qc: Do you know a good SWD debugger to connect FST-01 or something?
Ac: Perhaps, you can use a part of STM32F4 Discovery Kit as SWD
debugger. It seems that there is a free software tool for that.
Release notes
=============
This is seventeenth release of Gnuk. While it works well for specific
This is eighteenth release of Gnuk. While it works well for specific
usages and it is considered stable, it is still somewhat experimental.
Tested features are:
@@ -127,18 +130,13 @@ Tested features are:
* Changing value of password status bytes (0x00C4): forcesig
* Verify with pin pad
* Modify with pin pad
* Card holder certificate
It is known not-working well:
* For some version of kernel and libccid, --enable-debug can't
work well. Please disable DEBUG option if it doesn't work well.
* Card holder certificate
It is implemented in Gnuk side. But its large size matters
(> 1KB). Some versions of GnuPG cannot handle a data object
of large size with PC/SC backend. Specifically,
handle_transmit function in pcsc-wrapper.c uses the buffer
of size 1024-byte.
work well. Please make sure to disable DEBUG option if it
doesn't work well.
Not supported feature(s):
@@ -241,8 +239,7 @@ Gnuk is distributed with external source code.
Host Requirements
=================
For GNU/Linux, libccid version >= 1.3.11 is required.
libccid version == 1.3.9 is known not working well by the issue [r4235].
For GNU/Linux, libccid version >= 1.3.11 is recommended.
I think that it should not be requirment but the kernel version of my use is:
Linux version 2.6.32-5-686 (Debian 2.6.32-18) (ben@decadent.org.uk) (gcc version 4.3.5 (Debian 4.3.5-2) ) #1 SMP Sat Jul 24 02:27:10 UTC 2010

View File

@@ -15,6 +15,9 @@
/* Includes ------------------------------------------------------------------*/
#include "usb_lib.h"
extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, uint32_t n);
extern void usb_lld_from_pmabuf (void *dst, uint16_t addr, uint32_t n);
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ValBit(VAR,Place) (VAR & (1 << Place))
@@ -308,7 +311,6 @@ RESULT Standard_ClearFeature(void)
if (Related_Endpoint == ENDP0)
{
/* After clear the STALL, enable the default endpoint receiver */
SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize);
_SetEPRxStatus(Related_Endpoint, EP_RX_VALID);
}
else
@@ -461,7 +463,7 @@ void DataStageOut(void)
#ifdef STM32F10X_CL
OTGD_FS_PCD_EP_Read(ENDP0, Buffer, Length);
#else
PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length);
usb_lld_from_pmabuf (Buffer, GetEPRxAddr(ENDP0), Length);
#endif /* STM32F10X_CL */
}
@@ -545,7 +547,7 @@ void DataStageIn(void)
#ifdef STM32F10X_CL
OTGD_FS_PCD_EP_Write (ENDP0, DataBuffer, Length);
#else
UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);
usb_lld_to_pmabuf (DataBuffer, GetEPTxAddr(ENDP0), Length);
#endif /* STM32F10X_CL */
SetEPTxCount(ENDP0, Length);
@@ -1019,8 +1021,6 @@ uint8_t Post0_Process(void)
USB_OTG_EP *ep;
#endif /* STM32F10X_CL */
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
if (pInformation->ControlState == STALLED)
{
vSetEPRxStatus(EP_RX_STALL);

View File

@@ -25,6 +25,7 @@
#include "config.h"
#include "ch.h"
#include "gnuk.h"
#include "openpgp.h"
#include "polarssl/config.h"
#include "polarssl/rsa.h"
@@ -84,10 +85,9 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
}
else
{
res_APDU[RSA_SIGNATURE_LENGTH] = 0x90;
res_APDU[RSA_SIGNATURE_LENGTH+1] = 0x00;
res_APDU_size = RSA_SIGNATURE_LENGTH + 2;
res_APDU_size = RSA_SIGNATURE_LENGTH;
DEBUG_INFO ("done.\r\n");
GPG_SUCCESS ();
return 0;
}
}
@@ -167,7 +167,7 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
#endif
r = rsa_pkcs1_decrypt (&rsa_ctx, RSA_PRIVATE, &output_len,
input, output, MAX_RES_APDU_SIZE - 2);
input, output, MAX_RES_APDU_DATA_SIZE);
rsa_free (&rsa_ctx);
if (r < 0)
{
@@ -177,10 +177,9 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
}
else
{
res_APDU[output_len] = 0x90;
res_APDU[output_len+1] = 0x00;
res_APDU_size = output_len + 2;
res_APDU_size = output_len;
DEBUG_INFO ("done.\r\n");
GPG_SUCCESS ();
return 0;
}
}

2
src/configure vendored
View File

@@ -173,7 +173,7 @@ fi
# --enable-certdo option
if test "$certdo" = "yes"; then
CERTDO_DEFINE="#define CERTDO_SUPPORT 1"
echo "CERT.3 Data Object is supported (Note: it is not supported by GnuPG)"
echo "CERT.3 Data Object is supported"
else
CERTDO_DEFINE="#undef CERTDO_SUPPORT"
echo "CERT.3 Data Object is not supported"

View File

@@ -1,3 +1,17 @@
/*
* We declare some of libc functions here, because we will
* remove dependency on libc in future, possibly.
*/
extern size_t strlen (const char *s);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern void *memcpy (void *dest, const void *src, size_t n);
extern void *memset (void *s, int c, size_t n);
extern int memcmp (const void *s1, const void *s2, size_t n);
extern void *memmove(void *dest, const void *src, size_t n);
/*
* Debug functions
*/
extern Thread *stdout_thread;
#define EV_TX_READY ((eventmask_t)1)
@@ -11,16 +25,26 @@ extern void put_binary (const char *s, int len);
extern void _write (const char *, int);
/*
* We declare some of libc functions here, because we will
* remove dependency on libc in future.
* Application layer <-> CCID layer data structure
*/
extern size_t strlen (const char *s);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern void *memcpy (void *dest, const void *src, size_t n);
extern void *memset (void *s, int c, size_t n);
extern int memcmp (const void *s1, const void *s2, size_t n);
extern void *memmove(void *dest, const void *src, size_t n);
struct apdu {
uint8_t seq;
/* command APDU */
uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */
uint8_t *cmd_apdu_data;
uint16_t cmd_apdu_data_len; /* Nc, calculated by Lc field */
uint16_t expected_res_size; /* Ne, calculated by Le field */
/* response APDU */
uint16_t sw;
uint8_t *res_apdu_data;
uint16_t res_apdu_data_len;
};
extern struct apdu apdu;
#define EV_EXEC_FINISHED ((eventmask_t)2) /* GPG Execution finished */
@@ -31,31 +55,19 @@ extern void *memmove(void *dest, const void *src, size_t n);
#define EV_VERIFY_CMD_AVAILABLE ((eventmask_t)8)
#define EV_MODIFY_CMD_AVAILABLE ((eventmask_t)16)
/* maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */
#define MAX_CMD_APDU_SIZE (7+282) /* header + data */
/* maximum res apdu data is public key 5+9+256+2 (gpg_do_public_key) */
#define MAX_RES_APDU_SIZE ((5+9+256)+2) /* Data + status */
/* Maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */
#define MAX_CMD_APDU_DATA_SIZE (22+4+128+128) /* without header */
/* Maximum res apdu data is public key 5+9+256 (gpg_do_public_key) */
#define MAX_RES_APDU_DATA_SIZE (5+9+256) /* without trailer */
#define ICC_MSG_HEADER_SIZE 10
#define cmd_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE])
#define res_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE])
extern int icc_data_size;
#define cmd_APDU_size icc_data_size
extern int res_APDU_size;
extern const uint8_t *res_APDU_pointer;
#define res_APDU apdu.res_apdu_data
#define res_APDU_size apdu.res_apdu_data_len
/* USB buffer size of LL (Low-level): size of single Bulk transaction */
#define USB_LL_BUF_SIZE 64
/*
* USB buffer size of USB-ICC driver
* (Changing this, dwMaxCCIDMessageLength too !!)
*/
#define USB_BUF_SIZE ((10 + 10 + MAX_CMD_APDU_SIZE + USB_LL_BUF_SIZE - 1) \
/ USB_LL_BUF_SIZE * USB_LL_BUF_SIZE)
extern uint8_t icc_buffer[USB_BUF_SIZE];
enum icc_state
{
ICC_STATE_START, /* Initial */
@@ -66,7 +78,7 @@ enum icc_state
ICC_STATE_SEND, /* APDU Sent Partially */
};
extern volatile enum icc_state icc_state;
extern enum icc_state *icc_state_p;
extern volatile uint8_t auth_status;
#define AC_NONE_AUTHORIZED 0x00
@@ -97,7 +109,7 @@ extern void ac_reset_admin (void);
extern void ac_fini (void);
extern void set_res_apdu (uint8_t sw1, uint8_t sw2);
extern void set_res_sw (uint8_t sw1, uint8_t sw2);
extern uint16_t data_objects_number_of_bytes;
extern void gpg_data_scan (const uint8_t *p);

View File

@@ -128,6 +128,7 @@ SECTIONS
.gnuk_flash :
{
. = ALIGN (@FLASH_PAGE_SIZE@);
_data_pool = .;
KEEP(*(.gnuk_data))
. = ALIGN(@FLASH_PAGE_SIZE@);

View File

@@ -132,8 +132,7 @@ STDOUTthread (void *arg)
chEvtClear (EV_TX_READY);
USB_SIL_Write (EP3_IN, buffer_in, count_in);
SetEPTxValid (ENDP3);
usb_lld_write (ENDP3, buffer_in, count_in);
chEvtWaitOne (EV_TX_READY);
}
@@ -288,6 +287,13 @@ static void display_fatal_code (void)
static void display_status_code (void)
{
enum icc_state icc_state;
if (icc_state_p == NULL)
icc_state = ICC_STATE_START;
else
icc_state = *icc_state_p;
if (icc_state == ICC_STATE_START)
{
set_led (1);

View File

@@ -77,12 +77,11 @@ uint16_t data_objects_number_of_bytes;
static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
10,
0x00,
0x31, 0x80, /* Full DF name */
0x31, 0x84, /* Full DF name, GET DATA, MF */
0x73,
0x80, 0x01, 0x40, /* Full DF name */
0x80, 0x01, 0x80, /* Full DF name */
/* 1-byte */
/* No command chaining */
/* Extended Lc and Le */
/* Command chaining, No extended Lc and Le */
0x00, 0x90, 0x00 /* Status info (no life cycle management) */
};
@@ -90,27 +89,24 @@ static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
10,
0x30, /*
* No SM, No get challenge,
* No SM,
* No get challenge,
* Key import supported,
* PW status byte can be put,
* No private_use_DO,
* No algo change allowed
*/
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
0x00, 0x00, /* Max get challenge */
0x00, 0x00, /* Max get challenge (0: Get challenge not supported) */
#ifdef CERTDO_SUPPORT
0x07, 0xfe, /* max. length of cardholder certificate (2KB - 2)*/
0x08, 0x00, /* max. length of cardholder certificate (2KiB) */
#else
0x00, 0x00,
#endif
/* Max. length of command data */
(MAX_CMD_APDU_SIZE>>8), (MAX_CMD_APDU_SIZE&0xff),
/* Max. length of response data */
#ifdef CERTDO_SUPPORT
0x08, 0x00, /* the case of cardholder ceritificate */
#else
(MAX_RES_APDU_SIZE>>8), (MAX_RES_APDU_SIZE&0xff),
#endif
/* Max. length of command APDU data */
0x00, 0xff,
/* Max. length of response APDU data */
0x01, 0x00,
};
/* Algorithm Attributes */
@@ -417,10 +413,12 @@ do_kgtime_all (uint16_t tag, int with_tag)
}
const uint8_t openpgpcard_aid[] = {
0xd2, 0x76, 0x00, 0x01, 0x24, 0x01,
0x02, 0x00, /* Version 2.0 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
0xd2, 0x76, /* D: National, 276: DEU ISO 3166-1 */
0x00, 0x01, 0x24, /* Registered Application Provider Identifier */
0x01, /* Application: OpenPGPcard */
0x02, 0x00, /* Version 2.0 */
/* v. id */ /* serial number */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
};
static int
@@ -1248,16 +1246,16 @@ gpg_do_get_data (uint16_t tag, int with_tag)
#if defined(CERTDO_SUPPORT)
if (tag == GPG_DO_CH_CERTIFICATE)
{
res_APDU_pointer = &ch_certificate_start;
res_APDU_size = ((res_APDU_pointer[2] << 8) | res_APDU_pointer[3]);
if (res_APDU_size == 0xffff)
apdu.res_apdu_data = &ch_certificate_start;
apdu.res_apdu_data_len = ((apdu.res_apdu_data[2] << 8) | apdu.res_apdu_data[3]);
if (apdu.res_apdu_data_len == 0xffff)
{
res_APDU_pointer = NULL;
apdu.res_apdu_data_len = 0;
GPG_NO_RECORD ();
}
else
/* Add length of (tag+len) and status word (0x9000) at the end */
res_APDU_size += 4 + 2;
/* Add length of (tag+len) */
apdu.res_apdu_data_len += 4;
}
else
#endif
@@ -1276,9 +1274,8 @@ gpg_do_get_data (uint16_t tag, int with_tag)
GPG_SECURITY_FAILURE ();
else
{
*res_p++ = 0x90;
*res_p++ = 0x00;
res_APDU_size = res_p - res_APDU;
GPG_SUCCESS ();
}
}
else
@@ -1412,8 +1409,8 @@ gpg_do_public_key (uint8_t kk_byte)
*res_p++ = 0x01; *res_p++ = 0x00; *res_p++ = 0x01;
/* Success */
*res_p++ = 0x90; *res_p++ = 0x00;
res_APDU_size = res_p - res_APDU;
GPG_SUCCESS ();
}
DEBUG_INFO ("done.\r\n");

View File

@@ -29,6 +29,11 @@
#include "polarssl/config.h"
#include "polarssl/sha1.h"
#define CLS(a) a.cmd_apdu_head[0]
#define INS(a) a.cmd_apdu_head[1]
#define P1(a) a.cmd_apdu_head[2]
#define P2(a) a.cmd_apdu_head[3]
#define INS_VERIFY 0x20
#define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_PSO 0x2a
@@ -62,11 +67,9 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = {
};
void
set_res_apdu (uint8_t sw1, uint8_t sw2)
set_res_sw (uint8_t sw1, uint8_t sw2)
{
res_APDU_size = 2;
res_APDU[0] = sw1;
res_APDU[1] = sw2;
apdu.sw = (sw1 << 8) | sw2;
}
#define FILE_NONE 0
@@ -117,22 +120,15 @@ static void
cmd_verify (void)
{
int len;
uint8_t p2 = cmd_APDU[3];
uint8_t p2 = P2 (apdu);
int r;
int data_start = 5;
const uint8_t *pw;
DEBUG_INFO (" - VERIFY\r\n");
DEBUG_BYTE (p2);
len = cmd_APDU[4];
if (len == 0) /* extended length */
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
data_start = 7;
}
pw = &cmd_APDU[data_start];
len = apdu.cmd_apdu_data_len;
pw = apdu.cmd_apdu_data;
if (p2 == 0x81)
r = verify_pso_cds (pw, len);
@@ -213,8 +209,8 @@ cmd_change_password (void)
uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
uint8_t *new_ks = &new_ks0[1];
uint8_t p1 = cmd_APDU[2]; /* 0: change (old+new), 1: exchange (new) */
uint8_t p2 = cmd_APDU[3];
uint8_t p1 = P1 (apdu); /* 0: change (old+new), 1: exchange (new) */
uint8_t p2 = P2 (apdu);
int len;
const uint8_t *pw;
const uint8_t *newpw;
@@ -225,13 +221,8 @@ cmd_change_password (void)
DEBUG_INFO ("Change PW\r\n");
DEBUG_BYTE (who);
len = cmd_APDU[4];
pw = &cmd_APDU[5];
if (len == 0) /* extended length */
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
pw += 2;
}
len = apdu.cmd_apdu_data_len;
pw = apdu.cmd_apdu_data;
if (p1 != 0)
{
@@ -329,7 +320,7 @@ cmd_change_password (void)
static void
cmd_reset_user_password (void)
{
uint8_t p1 = cmd_APDU[2];
uint8_t p1 = P1 (apdu);
int len;
const uint8_t *pw;
const uint8_t *newpw;
@@ -341,13 +332,8 @@ cmd_reset_user_password (void)
DEBUG_INFO ("Reset PW1\r\n");
DEBUG_BYTE (p1);
len = cmd_APDU[4];
pw = &cmd_APDU[5];
if (len == 0) /* extended length */
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
pw += 2;
}
len = apdu.cmd_apdu_data_len;
pw = apdu.cmd_apdu_data;
if (p1 == 0x00) /* by User with Reseting Code */
{
@@ -469,17 +455,9 @@ cmd_put_data (void)
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD();
tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
data = &cmd_APDU[5];
len = cmd_APDU_size - 5;
if (len >= 256)
/* extended Lc */
{
data += 2;
len -= 2;
}
tag = ((P1 (apdu)<<8) | P2 (apdu));
len = apdu.cmd_apdu_data_len;
data = apdu.cmd_apdu_data;
gpg_do_put_data (tag, data, len);
}
@@ -487,16 +465,11 @@ static void
cmd_pgp_gakp (void)
{
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
DEBUG_BYTE (cmd_APDU[2]);
DEBUG_BYTE (P1 (apdu));
if (cmd_APDU[2] == 0x81)
if (P1 (apdu) == 0x81)
/* Get public key */
{
if (cmd_APDU[4] == 0)
gpg_do_public_key (cmd_APDU[7]);
else
gpg_do_public_key (cmd_APDU[5]);
}
gpg_do_public_key (apdu.cmd_apdu_data[0]);
else
{ /* Generate key pair */
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
@@ -514,7 +487,7 @@ cmd_read_binary (void)
if (file_selection == FILE_EF_SERIAL)
{
if (cmd_APDU[3] >= 6)
if (P2 (apdu) >= 6)
GPG_BAD_P0_P1 ();
else
{
@@ -529,16 +502,23 @@ cmd_read_binary (void)
static void
cmd_select_file (void)
{
if (cmd_APDU[2] == 4) /* Selection by DF name: it must be OpenPGP card */
if (P1 (apdu) == 4) /* Selection by DF name */
{
DEBUG_INFO (" - select DF by name\r\n");
/*
* P2 == 0, LC=6, name = D2 76 00 01 24 01
*/
/* name = D2 76 00 01 24 01 */
if (apdu.cmd_apdu_data_len != 6
|| memcmp (openpgpcard_aid, apdu.cmd_apdu_data, 6) != 0)
{
DEBUG_SHORT (apdu.cmd_apdu_data_len);
DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
GPG_NO_FILE ();
return;
}
file_selection = FILE_DF_OPENPGP;
if (cmd_APDU[3] == 0x0c) /* No FCI */
if ((P2 (apdu) & 0x0c) == 0x0c) /* No FCI */
GPG_SUCCESS ();
else
{
@@ -548,10 +528,11 @@ cmd_select_file (void)
res_APDU[1] = 0x12;
res_APDU[2] = 0x84; /* overwrite: DF name */
res_APDU_size += 2;
GPG_SUCCESS ();
}
}
else if (cmd_APDU[4] == 2
&& cmd_APDU[5] == 0x2f && cmd_APDU[6] == 0x02)
else if (apdu.cmd_apdu_data_len == 2
&& apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02)
{
DEBUG_INFO (" - select 0x2f02 EF\r\n");
/*
@@ -560,11 +541,11 @@ cmd_select_file (void)
GPG_SUCCESS ();
file_selection = FILE_EF_SERIAL;
}
else if (cmd_APDU[4] == 2
&& cmd_APDU[5] == 0x3f && cmd_APDU[6] == 0x00)
else if (apdu.cmd_apdu_data_len == 2
&& apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00)
{
DEBUG_INFO (" - select ROOT MF\r\n");
if (cmd_APDU[3] == 0x0c)
if (P2 (apdu) == 0x0c)
{
GPG_SUCCESS ();
}
@@ -572,12 +553,11 @@ cmd_select_file (void)
{
int len = sizeof (select_file_TOP_result);
res_APDU_size = 2 + len;
res_APDU_size = len;
memcpy (res_APDU, select_file_TOP_result, len);
res_APDU[2] = (data_objects_number_of_bytes & 0xff);
res_APDU[3] = (data_objects_number_of_bytes >> 8);
res_APDU[len] = 0x90;
res_APDU[len+1] = 0x00;
GPG_SUCCESS ();
}
file_selection = FILE_MF;
@@ -595,7 +575,7 @@ cmd_select_file (void)
static void
cmd_get_data (void)
{
uint16_t tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
DEBUG_INFO (" - Get Data\r\n");
@@ -608,21 +588,14 @@ cmd_get_data (void)
static void
cmd_pso (void)
{
int len = cmd_APDU[4];
int data_start = 5;
int len = apdu.cmd_apdu_data_len;
int r;
if (len == 0)
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
data_start = 7;
}
DEBUG_INFO (" - PSO: ");
DEBUG_WORD ((uint32_t)&r);
DEBUG_BINARY (cmd_APDU, cmd_APDU_size);
DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
if (cmd_APDU[2] == 0x9e && cmd_APDU[3] == 0x9a)
if (P1 (apdu) == 0x9e && P2 (apdu) == 0x9a)
{
if (!ac_check_status (AC_PSO_CDS_AUTHORIZED))
{
@@ -631,24 +604,24 @@ cmd_pso (void)
return;
}
if (cmd_APDU_size != 7 + 34 + 2 /* MD5 */
/* Header (with Extended Lc)=7, size of digestInfo, and Le=2-byte */
&& cmd_APDU_size != 7 + 35 + 2 /* SHA1 / RIPEMD-160 */
&& cmd_APDU_size != 7 + 47 + 2 /* SHA224 */
&& cmd_APDU_size != 7 + 51 + 2 /* SHA256 */
&& cmd_APDU_size != 7 + 67 + 2 /* SHA384 */
&& cmd_APDU_size != 7 + 83 + 2) /* SHA512 */
/* Check size of digestInfo */
if (len != 34 /* MD5 */
&& len != 35 /* SHA1 / RIPEMD-160 */
&& len != 47 /* SHA224 */
&& len != 51 /* SHA256 */
&& len != 67 /* SHA384 */
&& len != 83) /* SHA512 */
{
DEBUG_INFO (" wrong length: ");
DEBUG_SHORT (cmd_APDU_size);
DEBUG_SHORT (len);
GPG_ERROR ();
}
else
{
DEBUG_SHORT (len); /* Should be cmd_APDU_size - 8 [- 1] */
DEBUG_SHORT (len);
DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN);
r = rsa_sign (&cmd_APDU[data_start], res_APDU, len,
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_SIGNING]);
if (r < 0)
{
@@ -660,7 +633,7 @@ cmd_pso (void)
gpg_increment_digital_signature_counter ();
}
}
else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86)
else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86)
{
DEBUG_SHORT (len);
DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN);
@@ -673,9 +646,8 @@ cmd_pso (void)
}
/* Skip padding 0x00 */
data_start++;
len--;
r = rsa_decrypt (&cmd_APDU[data_start], res_APDU, len,
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
&kd[GPG_KEY_FOR_DECRYPTION]);
if (r < 0)
GPG_ERROR ();
@@ -683,9 +655,9 @@ cmd_pso (void)
else
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd_APDU[2]);
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd_APDU[3]);
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
}
@@ -695,19 +667,12 @@ cmd_pso (void)
static void
cmd_internal_authenticate (void)
{
int len = cmd_APDU[4];
int data_start = 5;
int len = apdu.cmd_apdu_data_len;
int r;
if (len == 0)
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
data_start = 7;
}
DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
if (cmd_APDU[2] == 0x00 && cmd_APDU[3] == 0x00)
if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
{
DEBUG_SHORT (len);
@@ -718,7 +683,7 @@ cmd_internal_authenticate (void)
return;
}
r = rsa_sign (&cmd_APDU[data_start], res_APDU, len,
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_AUTHENTICATION]);
if (r < 0)
GPG_ERROR ();
@@ -726,9 +691,9 @@ cmd_internal_authenticate (void)
else
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd_APDU[2]);
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd_APDU[3]);
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
}
@@ -739,17 +704,10 @@ cmd_internal_authenticate (void)
static void
cmd_update_binary (void)
{
int len = cmd_APDU[4];
int data_start = 5;
int len = apdu.cmd_apdu_data_len;
uint16_t offset;
int r;
if (len == 0)
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
data_start = 7;
}
DEBUG_INFO (" - UPDATE BINARY\r\n");
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
@@ -759,10 +717,10 @@ cmd_update_binary (void)
return;
}
if ((cmd_APDU[2] & 0x80))
if ((cmd_APDU[2] & 0x7f) <= FILEID_RANDOM)
if ((P1 (apdu) & 0x80))
if ((P1 (apdu) & 0x7f) <= FILEID_RANDOM)
{
file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f);
file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f);
r = flash_erase_binary (file_selection - FILE_EF_CH_CERTIFICATE);
if (r < 0)
{
@@ -787,14 +745,14 @@ cmd_update_binary (void)
return;
}
offset = (cmd_APDU[2] << 8) | cmd_APDU[3];
offset = (P1 (apdu) << 8) | P2 (apdu);
}
DEBUG_SHORT (len);
DEBUG_SHORT (offset);
r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
&cmd_APDU[data_start], len, offset);
apdu.cmd_apdu_data, len, offset);
if (r < 0)
{
DEBUG_INFO ("memory error.\r\n");
@@ -810,17 +768,10 @@ cmd_update_binary (void)
static void
cmd_write_binary (void)
{
int len = cmd_APDU[4];
int data_start = 5;
int len = apdu.cmd_apdu_data_len;
uint16_t offset;
int r;
if (len == 0)
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
data_start = 7;
}
DEBUG_INFO (" - WRITE BINARY\r\n");
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
@@ -830,10 +781,10 @@ cmd_write_binary (void)
return;
}
if ((cmd_APDU[2] & 0x80))
if ((cmd_APDU[2] & 0x7f) <= FILEID_SERIAL_NO)
if ((P1 (apdu) & 0x80))
if ((P1 (apdu) & 0x7f) <= FILEID_SERIAL_NO)
{
file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f);
file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f);
offset = 0;
}
else
@@ -851,14 +802,14 @@ cmd_write_binary (void)
return;
}
offset = (cmd_APDU[2] << 8) | cmd_APDU[3];
offset = (P1 (apdu) << 8) | P2 (apdu);
}
DEBUG_SHORT (len);
DEBUG_SHORT (offset);
r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
&cmd_APDU[data_start], len, offset);
apdu.cmd_apdu_data, len, offset);
if (r < 0)
{
DEBUG_INFO ("memory error.\r\n");
@@ -898,7 +849,7 @@ static void
process_command_apdu (void)
{
int i;
uint8_t cmd = cmd_APDU[1];
uint8_t cmd = INS (apdu);
for (i = 0; i < NUM_CMDS; i++)
if (cmds[i].command == cmd)
@@ -932,12 +883,10 @@ GPGthread (void *arg)
DEBUG_INFO ("GPG!: ");
res_APDU_pointer = NULL;
if (m == EV_VERIFY_CMD_AVAILABLE)
{
#if defined(PINPAD_SUPPORT)
if (cmd_APDU[1] != INS_VERIFY)
if (INS (apdu) != INS_VERIFY)
{
GPG_CONDITION_NOT_SATISFIED ();
goto done;
@@ -949,9 +898,8 @@ GPGthread (void *arg)
GPG_ERROR ();
goto done;
}
memcpy (&cmd_APDU[5], pin_input_buffer, pw_len);
cmd_APDU[4] = pw_len;
icc_data_size = 5 + pw_len;
memcpy (apdu.cmd_apdu_data, pin_input_buffer, pw_len);
apdu.cmd_apdu_data_len = pw_len;
#else
GPG_ERROR ();
goto done;
@@ -960,10 +908,12 @@ GPGthread (void *arg)
else if (m == EV_MODIFY_CMD_AVAILABLE)
{
#if defined(PINPAD_SUPPORT)
uint8_t bConfirmPIN = cmd_APDU[4];
uint8_t *p = &cmd_APDU[5];
uint8_t bConfirmPIN = apdu.cmd_apdu_data[5];
uint8_t *p = apdu.cmd_apdu_data;
if (cmd_APDU[1] != INS_CHANGE_REFERENCE_DATA)
if (INS (apdu) != INS_CHANGE_REFERENCE_DATA
&& INS (apdu) != INS_RESET_RETRY_COUNTER
&& INS (apdu) != INS_PUT_DATA)
{
GPG_CONDITION_NOT_SATISFIED ();
goto done;
@@ -1007,8 +957,7 @@ GPGthread (void *arg)
}
}
len = cmd_APDU[4] = pw_len + newpw_len;
icc_data_size = 5 + len;
apdu.cmd_apdu_data_len = pw_len + newpw_len;
#else
GPG_ERROR ();
goto done;
@@ -1017,12 +966,9 @@ GPGthread (void *arg)
else if (m == EV_NOP)
continue;
if (icc_data_size != 0)
{
process_command_apdu ();
done:
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
}
process_command_apdu ();
done:
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
}
gpg_fini ();

View File

@@ -1,12 +1,12 @@
#define GPG_MEMORY_FAILURE() set_res_apdu (0x65, 0x81)
#define GPG_SECURITY_FAILURE() set_res_apdu (0x69, 0x82)
#define GPG_SECURITY_AUTH_BLOCKED() set_res_apdu (0x69, 0x83)
#define GPG_CONDITION_NOT_SATISFIED() set_res_apdu (0x69, 0x85)
#define GPG_COMMAND_NOT_ALLOWED() set_res_apdu (0x69, 0x86)
#define GPG_FUNCTION_NOT_SUPPORTED() set_res_apdu (0x6a, 0x81)
#define GPG_NO_FILE() set_res_apdu (0x6a, 0x82)
#define GPG_NO_RECORD() set_res_apdu (0x6a, 0x88)
#define GPG_BAD_P0_P1() set_res_apdu (0x6b, 0x00)
#define GPG_NO_INS() set_res_apdu (0x6d, 0x00)
#define GPG_ERROR() set_res_apdu (0x6f, 0x00)
#define GPG_SUCCESS() set_res_apdu (0x90, 0x00)
#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82)
#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83)
#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85)
#define GPG_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81)
#define GPG_NO_FILE() set_res_sw (0x6a, 0x82)
#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88)
#define GPG_BAD_P0_P1() set_res_sw (0x6b, 0x00)
#define GPG_NO_INS() set_res_sw (0x6d, 0x00)
#define GPG_ERROR() set_res_sw (0x6f, 0x00)
#define GPG_SUCCESS() set_res_sw (0x90, 0x00)

View File

@@ -1,7 +1,7 @@
STMUSBDIR = ../STM32_USB-FS-Device_Driver
STMUSBSRCDIR = $(STMUSBDIR)/src
STMUSBINCDIR = $(STMUSBDIR)/inc
STMUSBSRC= $(STMUSBSRCDIR)/usb_sil.c \
STMUSBSRC= \
$(STMUSBSRCDIR)/usb_init.c $(STMUSBSRCDIR)/usb_int.c \
$(STMUSBSRCDIR)/usb_mem.c $(STMUSBSRCDIR)/usb_core.c \
$(STMUSBSRCDIR)/usb_core.c \
$(STMUSBSRCDIR)/usb_regs.c

File diff suppressed because it is too large Load Diff

View File

@@ -101,8 +101,8 @@ static const uint8_t gnukConfigDescriptor[] = {
* It is different now for better interaction to GPG's in-stock
* ccid-driver.
*/
0x42, 0x08, 0x04, 0x00, /* dwFeatures (not ICCD):
* Short and extended APDU level: 0x40000 *
0x42, 0x08, 0x02, 0x00, /* dwFeatures (not ICCD):
* Short APDU level : 0x20000 *
* (what? means ICCD?) : 0x00800 *
* Automatic IFSD : 0x00400
* NAD value other than 0x00 : 0x00200
@@ -115,7 +115,7 @@ static const uint8_t gnukConfigDescriptor[] = {
* Auto activaction of ICC : 0x00004
* Automatic conf. based on ATR : 0x00002 g
*/
0x40, 0x01, 0, 0, /* dwMaxCCIDMessageLength */
0x0f, 0x01, 0, 0, /* dwMaxCCIDMessageLength: 271 */
0xff, /* bClassGetResponse: */
0xff, /* bClassEnvelope: */
0, 0, /* wLCDLayout: FIXED VALUE */
@@ -275,7 +275,7 @@ static const uint8_t gnukStringProduct[] = {
const uint8_t gnukStringSerial[] = {
13*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
'0', 0, '.', 0, '1', 0, '6', 0, /* Version number of Gnuk */
'0', 0, '.', 0, '1', 0, '7', 0, /* Version number of Gnuk */
'-', 0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,

View File

@@ -1,5 +1,6 @@
#include "ch.h"
#include "hal.h"
#include "usb_lib.h"
#include "usb_lld.h"
extern void USB_Istr (void);
@@ -26,3 +27,76 @@ void usb_lld_init (void) {
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0;
}
void usb_lld_to_pmabuf (const void *src, uint16_t wPMABufAddr, size_t n)
{
const uint8_t *s = (const uint8_t *)src;
uint16_t *p;
uint16_t w;
if (n == 0)
return;
if ((wPMABufAddr & 1))
{
p = (uint16_t *)(PMAAddr + (wPMABufAddr - 1) * 2);
w = *p;
w = (w & 0xff) | (*s++) << 8;
*p = w;
p += 2;
n--;
}
else
p = (uint16_t *)(PMAAddr + wPMABufAddr * 2);
while (n >= 2)
{
w = *s++;
w |= (*s++) << 8;
*p = w;
p += 2;
n -= 2;
}
if (n > 0)
{
w = *s;
*p = w;
}
}
void usb_lld_from_pmabuf (void *dst, uint16_t wPMABufAddr, size_t n)
{
uint8_t *d = (uint8_t *)dst;
uint16_t *p;
uint16_t w;
if (n == 0)
return;
if ((wPMABufAddr & 1))
{
p = (uint16_t *)(PMAAddr + (wPMABufAddr - 1) * 2);
w = *p;
*d++ = (w >> 8);
p += 2;
n--;
}
else
p = (uint16_t *)(PMAAddr + wPMABufAddr * 2);
while (n >= 2)
{
w = *p;
*d++ = (w & 0xff);
*d++ = (w >> 8);
p += 2;
n -= 2;
}
if (n > 0)
{
w = *p;
*d = (w & 0xff);
}
}

View File

@@ -1,2 +1,55 @@
#define STM32_USB_IRQ_PRIORITY 11
void usb_lld_init (void);
extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
extern void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n);
extern inline void usb_lld_stall_tx (int ep_num)
{
SetEPTxStatus (ep_num, EP_TX_STALL);
}
extern inline void usb_lld_stall_rx (int ep_num)
{
SetEPRxStatus (ep_num, EP_RX_STALL);
}
extern inline int usb_lld_tx_data_len (int ep_num)
{
return GetEPTxCount (ep_num);
}
extern inline void usb_lld_txcpy (const void *src,
int ep_num, int offset, size_t len)
{
usb_lld_to_pmabuf (src, GetEPTxAddr (ep_num) + offset, len);
}
extern inline void usb_lld_tx_enable (int ep_num, size_t len)
{
SetEPTxCount (ep_num, len);
SetEPTxValid (ep_num);
}
extern inline void usb_lld_write (uint8_t ep_num, const void *buf, size_t len)
{
usb_lld_to_pmabuf (buf, GetEPTxAddr (ep_num), len);
SetEPTxCount (ep_num, len);
SetEPTxValid (ep_num);
}
extern inline void usb_lld_rx_enable (int ep_num)
{
SetEPRxValid (ep_num);
}
extern inline int usb_lld_rx_data_len (int ep_num)
{
return GetEPRxCount (ep_num);
}
extern inline void usb_lld_rxcpy (uint8_t *dst,
int ep_num, int offset, size_t len)
{
usb_lld_from_pmabuf (dst, GetEPRxAddr (ep_num) + offset, len);
}

View File

@@ -1,7 +1,7 @@
/*
* usb_msc.c -- USB Mass Storage Class protocol handling
*
* Copyright (C) 2011 Free Software Initiative of Japan
* Copyright (C) 2011, 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -26,6 +26,7 @@
#include "config.h"
#include "ch.h"
#include "gnuk.h"
#include "usb_lld.h"
#include "usb_msc.h"
struct usb_endp_in {
@@ -50,11 +51,6 @@ static Thread *the_thread;
static uint8_t msc_state;
static void usb_stall_transmit (void)
{
SetEPTxStatus (ENDP6, EP_TX_STALL);
}
static void usb_start_transmit (const uint8_t *p, size_t n)
{
size_t pkt_len = n > ENDP_MAX_SIZE ? ENDP_MAX_SIZE : n;
@@ -63,14 +59,13 @@ static void usb_start_transmit (const uint8_t *p, size_t n)
ep6_in.txsize = n;
ep6_in.txcnt = 0;
USB_SIL_Write (EP6_IN, (uint8_t *)ep6_in.txbuf, pkt_len);
SetEPTxValid (ENDP6);
usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, pkt_len);
}
/* "Data Transmitted" callback */
void EP6_IN_Callback (void)
{
size_t n = (size_t)GetEPTxCount (ENDP6);
size_t n = (size_t)usb_lld_tx_data_len (ENDP6);
ep6_in.txbuf += n;
ep6_in.txcnt += n;
@@ -82,8 +77,7 @@ void EP6_IN_Callback (void)
n = ENDP_MAX_SIZE;
else
n = ep6_in.txsize;
USB_SIL_Write (EP6_IN, (uint8_t *)ep6_in.txbuf, n);
SetEPTxValid (ENDP6);
usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, n);
return;
}
@@ -108,43 +102,34 @@ void EP6_IN_Callback (void)
}
static void usb_stall_receive (void)
{
SetEPRxStatus (ENDP7, EP_RX_STALL);
}
static void usb_start_receive (uint8_t *p, size_t n)
{
ep7_out.rxbuf = p;
ep7_out.rxsize = n;
ep7_out.rxcnt = 0;
if (n < ENDP_MAX_SIZE)
SetEPRxCount (ENDP7, n);
else
SetEPRxCount (ENDP7, ENDP_MAX_SIZE);
SetEPRxValid (ENDP7);
usb_lld_rx_enable (ENDP7);
}
/* "Data Received" call back */
void EP7_OUT_Callback (void)
{
size_t n = (size_t)GetEPRxCount (ENDP7);
size_t n = (size_t)usb_lld_rx_data_len (ENDP7);
int err = 0;
if (n > ep7_out.rxsize)
{ /* buffer overflow */
err = 1;
SetEPRxCount (ENDP7, ep7_out.rxsize);
n = ep7_out.rxsize;
}
n = USB_SIL_Read (EP7_OUT, ep7_out.rxbuf);
usb_lld_rxcpy (ep7_out.rxbuf, ENDP7, 0, n);
ep7_out.rxbuf += n;
ep7_out.rxcnt += n;
ep7_out.rxsize -= n;
if (n == ENDP_MAX_SIZE && ep7_out.rxsize != 0)
{ /* More data to be received */
SetEPRxValid (ENDP7);
usb_lld_rx_enable (ENDP7);
return;
}
@@ -333,7 +318,7 @@ void msc_handle_command (void)
if (msg != RDY_TIMEOUT)
{
chSysLock ();
usb_stall_receive ();
usb_lld_stall_rx (ENDP7);
chSysUnlock ();
}
return;
@@ -345,7 +330,7 @@ void msc_handle_command (void)
{
msc_state = MSC_ERROR;
chSysLock ();
usb_stall_receive ();
usb_lld_stall_rx (ENDP7);
chSysUnlock ();
return;
}
@@ -448,8 +433,8 @@ void msc_handle_command (void)
{
msc_state = MSC_ERROR;
chSysLock ();
usb_stall_transmit ();
usb_stall_receive ();
usb_lld_stall_tx (ENDP6);
usb_lld_stall_rx (ENDP7);
chSysUnlock ();
return;
}

View File

@@ -41,6 +41,20 @@
#endif
static void
SetEPRxCount_allocated_size (uint8_t bEpNum, uint16_t wCount)
{ /* Assume wCount is even */
uint32_t *pdwReg = _pEPRxCount (bEpNum);
uint16_t value;
if (wCount <= 62)
value = (wCount & 0x3e) << 9;
else
value = 0x8000 | (((wCount >> 5) - 1) << 10);
*pdwReg = (uint32_t)value;
}
static void
gnuk_device_init (void)
{
@@ -50,7 +64,9 @@ gnuk_device_init (void)
PowerOn ();
/* Perform basic device initialization operations */
USB_SIL_Init ();
_SetISTR (0);
wInterrupt_Mask = IMR_MSK;
_SetCNTR (wInterrupt_Mask);
bDeviceState = UNCONNECTED;
}
@@ -75,7 +91,7 @@ gnuk_device_reset (void)
SetEPRxAddr (ENDP0, ENDP0_RXADDR);
SetEPTxAddr (ENDP0, ENDP0_TXADDR);
Clear_Status_Out (ENDP0);
SetEPRxCount (ENDP0, GNUK_MAX_PACKET_SIZE);
SetEPRxCount_allocated_size (ENDP0, GNUK_MAX_PACKET_SIZE);
SetEPRxValid (ENDP0);
/* Initialize Endpoint 1 */
@@ -87,7 +103,7 @@ gnuk_device_reset (void)
/* Initialize Endpoint 2 */
SetEPType (ENDP2, EP_BULK);
SetEPRxAddr (ENDP2, ENDP2_RXADDR);
SetEPRxCount (ENDP2, GNUK_MAX_PACKET_SIZE);
SetEPRxCount_allocated_size (ENDP2, GNUK_MAX_PACKET_SIZE);
SetEPRxStatus (ENDP2, EP_RX_VALID);
SetEPTxStatus (ENDP2, EP_TX_DIS);
@@ -107,7 +123,7 @@ gnuk_device_reset (void)
/* Initialize Endpoint 5 */
SetEPType (ENDP5, EP_BULK);
SetEPRxAddr (ENDP5, ENDP5_RXADDR);
SetEPRxCount (ENDP5, VIRTUAL_COM_PORT_DATA_SIZE);
SetEPRxCount_allocated_size (ENDP5, VIRTUAL_COM_PORT_DATA_SIZE);
SetEPRxStatus (ENDP5, EP_RX_VALID);
SetEPTxStatus (ENDP5, EP_TX_DIS);
#endif
@@ -122,6 +138,7 @@ gnuk_device_reset (void)
/* Initialize Endpoint 7 */
SetEPType (ENDP7, EP_BULK);
SetEPRxAddr (ENDP7, ENDP7_RXADDR);
SetEPRxCount_allocated_size (ENDP7, 64);
SetEPRxStatus (ENDP7, EP_RX_STALL);
SetEPTxStatus (ENDP7, EP_TX_DIS);
#endif

View File

@@ -43,11 +43,18 @@ class GnukToken(object):
cardservice = cardrequest.waitforcard()
self.connection = cardservice.connection
def cmd_verify(self, who, passwd):
apdu = [0x00, 0x20, 0x00, 0x80+who, 0, 0, len(passwd)] + s2l(passwd)
def cmd_get_response(self, expected_len):
apdu = [0x00, 0xc0, 0x00, 0x00, expected_len ]
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, "cmd_verify"
raise ValueError, ("%02x%02x" % (sw1, sw2))
return response
def cmd_verify(self, who, passwd):
apdu = [0x00, 0x20, 0x00, 0x80+who, len(passwd)] + s2l(passwd)
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%02x%02x" % (sw1, sw2))
def cmd_write_binary(self, fileid, data, is_update):
count = 0
@@ -59,29 +66,43 @@ class GnukToken(object):
while count*256 < data_len:
if count == 0:
d = data[:256]
apdu = [0x00, ins, 0x80+fileid, 0x00, 0, len(d)>>8, len(d)&0xff] + s2l(d)
if len(d) <= 255:
apdu = [0x00, ins, 0x80+fileid, 0x00, len(d) ] + s2l(d)
else:
apdu0 = [0x10, ins, 0x80+fileid, 0x00, 255 ] + s2l(d[:255])
response, sw1, sw2 = self.connection.transmit(apdu0)
apdu = [0x00, ins, 0x80+fileid, 0x00, 1 ] + s2l(d[255:])
else:
d = data[256*count:256*(count+1)]
apdu = [0x00, ins, count, 0x00, 0, len(d)>>8, len(d)&0xff] + s2l(d)
if len(d) <= 255:
apdu = [0x00, ins, count, 0x00, len(d) ] + s2l(d)
else:
apdu0 = [0x10, ins, count, 0x00, 255 ] + s2l(d[:255])
response, sw1, sw2 = self.connection.transmit(apdu0)
apdu = [0x00, ins, 0x80+fileid, 0x00, 1 ] + s2l(d[255:])
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
if is_update:
raise ValueError, "cmd_update_binary"
raise ValueError, ("%02x%02x" % (sw1, sw2))
else:
raise ValueError, "cmd_write_binary"
raise ValueError, ("%02x%02x" % (sw1, sw2))
count += 1
def cmd_select_openpgp(self):
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
apdu = [0x00, 0xa4, 0x04, 0x0c, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, "cmd_select_openpgp"
if sw1 == 0x61:
response = self.cmd_get_response(sw2)
elif not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%02x%02x" % (sw1, sw2))
def cmd_get_data(self, tagh, tagl):
apdu = [0x00, 0xca, tagh, tagl]
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, "cmd_get_data"
if sw1 == 0x61:
response = self.cmd_get_response(sw2)
elif not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%02x%02x" % (sw1, sw2))
return response
def compare(data_original, data_in_device):
@@ -146,18 +167,6 @@ if __name__ == '__main__':
exit(1)
print "Writing serial number"
data = binascii.unhexlify(serial_data_hex)
elif sys.argv[1] == '-r':
fileid = 1 # Random number bits
if len(sys.argv) == 3:
filename = sys.argv[2]
f = open(filename)
else:
filename = stdin
f = sys.stdin
data = f.read()
f.close()
print "%s: %d" % (filename, len(data))
print "Updating random bits"
else:
fileid = 0 # Card holder certificate
filename = sys.argv[1]
@@ -165,6 +174,5 @@ if __name__ == '__main__':
data = f.read()
f.close()
print "%s: %d" % (filename, len(data))
data += "\x90\x00"
print "Updating card holder certificate"
main(fileid, is_update, data, passwd)

View File

@@ -289,6 +289,5 @@ if __name__ == '__main__':
data = f.read()
f.close()
print "%s: %d" % (filename, len(data))
data += "\x90\x00"
print "Updating card holder certificate"
main(fileid, is_update, data)

View File

@@ -1,9 +1,9 @@
#! /usr/bin/python
"""
pinpad-test.py - a tool to test pinpad support by card reader.
pinpadtest.py - a tool to test variable length pin entry with pinpad
Copyright (C) 2011 Free Software Initiative of Japan
Copyright (C) 2011, 2012 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -30,14 +30,20 @@ from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.util import toHexString
from getpass import getpass
CM_IOCTL_GET_FEATURE_REQUEST = (0x42000000 + 3400)
FEATURE_VERIFY_PIN_DIRECT = 0x06
FEATURE_MODIFY_PIN_DIRECT = 0x07
BY_ADMIN = 3
BY_USER = 1
PIN_MIN_DEFAULT = 6 # min of OpenPGP card
PIN_MAX_DEFAULT = 15 # max of VASCO DIGIPASS 920
def s2l(s):
return [ ord(c) for c in s ]
def confirm_pin_setting(single_step):
if single_step:
return 0x01 # bConfirmPIN: new PIN twice
@@ -45,14 +51,15 @@ def confirm_pin_setting(single_step):
return 0x03 # bConfirmPIN: old PIN and new PIN twice
class Card(object):
def __init__(self, add_a_byte, pinmax):
def __init__(self, add_a_byte, pinmin, pinmax):
cardtype = AnyCardType()
cardrequest = CardRequest(timeout=1, cardType=cardtype)
cardrequest = CardRequest(timeout=10, cardType=cardtype)
cardservice = cardrequest.waitforcard()
self.connection = cardservice.connection
self.verify_ioctl = -1
self.modify_ioctl = -1
self.another_byte = add_a_byte
self.pinmin = pinmin
self.pinmax = pinmax
def get_features(self):
@@ -97,7 +104,7 @@ class Card(object):
0x00, # bmPINBlockString
0x00, # bmPINLengthFormat
self.pinmax, # wPINMaxExtraDigit Low (PINmax)
1, # wPINMaxExtraDigit High (PINmin)
self.pinmin, # wPINMaxExtraDigit High (PINmin)
0x02, # bEntryValidationCondition
0x01, # bNumberMessage
0x00, # wLangId Low
@@ -107,7 +114,8 @@ class Card(object):
0x00, # bTeoPrologue[1]
0x00 # bTeoPrologue[2]
]
pin_verify += [ len(apdu), 0, 0, 0 ] + apdu + self.possibly_add_dummy_byte()
apdu += self.possibly_add_dummy_byte()
pin_verify += [ len(apdu), 0, 0, 0 ] + apdu
data = self.connection.control(self.verify_ioctl,pin_verify)
sw1 = data[0]
sw2 = data[1]
@@ -125,7 +133,7 @@ class Card(object):
0x00, # bInsertionOffsetOld
0x00, # bInsertionOffsetNew
self.pinmax, # wPINMaxExtraDigit Low (PINmax)
1, # wPINMaxExtraDigit High (PINmin)
self.pinmin, # wPINMaxExtraDigit High (PINmin)
confirm_pin_setting(single_step),
0x02, # bEntryValidationCondition
0x03, # bNumberMessage
@@ -138,20 +146,37 @@ class Card(object):
0x00, # bTeoPrologue[1]
0x00 # bTeoPrologue[2]
]
pin_modify += [ len(apdu), 0, 0, 0 ] + apdu + self.possibly_add_dummy_byte()
apdu += self.possibly_add_dummy_byte()
pin_modify += [ len(apdu), 0, 0, 0 ] + apdu
data = self.connection.control(self.modify_ioctl,pin_modify)
sw1 = data[0]
sw2 = data[1]
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%s %02x %02x" % (command, sw1, sw2))
def cmd_reset_retry_counter(self, who, data):
if who == BY_ADMIN:
apdu = [0x00, 0x2c, 0x02, 0x81, len(data) ] + data # BY_ADMIN
else:
apdu = [0x00, 0x2c, 0x00, 0x81, len(data) ] + data # BY_USER with resetcode
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("cmd_reset_retry_counter %02x %02x" % (sw1, sw2))
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
def cmd_reset_retry_counter_pinpad(self, who):
if who == BY_ADMIN:
apdu = [0x00, 0x2c, 0x02, 0x81] # BY_ADMIN
self.send_modify_pinpad(apdu, True, "cmd_reset_retry_counter_pinpad")
else:
apdu = [0x00, 0x2c, 0x00, 0x81] # BY_USER with resetcode
self.send_modify_pinpad(apdu, False, "cmd_reset_retry_counter_pinpad")
self.send_modify_pinpad(apdu, False, "cmd_reset_retry_counter_pinpad")
def cmd_put_resetcode(self, data):
apdu = [0x00, 0xda, 0x00, 0xd3, len(data) ] + data # BY_ADMIN
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("cmd_put_resetcode %02x %02x" % (sw1, sw2))
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
def cmd_put_resetcode_pinpad(self):
@@ -166,11 +191,8 @@ class Card(object):
self.send_modify_pinpad(apdu, is_exchange,
"cmd_change_reference_data_pinpad")
# "Vasco DIGIPASS 920 [CCID] 00 00"
# "FSIJ Gnuk (0.16-34006F06) 00 00"
def main(who, method, add_a_byte, pinmax, change_by_two_steps):
card = Card(add_a_byte, pinmax)
def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps):
card = Card(add_a_byte, pinmin, pinmax)
card.connection.connect()
print "Reader/Token:", card.connection.getReader()
@@ -206,20 +228,38 @@ def main(who, method, add_a_byte, pinmax, change_by_two_steps):
print "and New Admin's PIN twice"
card.cmd_change_reference_data_pinpad(who, False)
elif method == "unblock":
# It's always by single step
if who == BY_USER:
print "Please input reset code"
print "and New User's PIN twice"
if change_by_two_steps:
# It means using keyboard for new PIN
if who == BY_USER:
resetcode=s2l(getpass("Please input reset code from keyboard: "))
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
card.cmd_reset_retry_counter(who,resetcode+newpin)
else:
print "Please input Admin's PIN"
card.cmd_verify_pinpad(BY_ADMIN)
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
card.cmd_reset_retry_counter(who,newpin)
else:
if who == BY_USER:
print "Please input reset code"
print "and New User's PIN twice"
else:
print "Please input Admin's PIN"
card.cmd_verify_pinpad(BY_ADMIN)
print "Please input New User's PIN twice"
card.cmd_reset_retry_counter_pinpad(who)
elif method == "put":
if change_by_two_steps:
# It means using keyboard for new PIN
print "Please input Admin's PIN"
card.cmd_verify_pinpad(BY_ADMIN)
resetcode=s2l(getpass("Please input New Reset Code from keyboard: "))
card.cmd_put_resetcode(resetcode)
else:
print "Please input Admin's PIN"
print "and New User's PIN twice"
card.cmd_reset_retry_counter_pinpad(who)
elif method == "put":
# It's always by two steps
print "Please input Admin's PIN"
card.cmd_verify_pinpad(BY_ADMIN)
print "Please input New Reset Code twice"
card.cmd_put_resetcode_pinpad()
card.cmd_verify_pinpad(BY_ADMIN)
print "Please input New Reset Code twice"
card.cmd_put_resetcode_pinpad()
else:
raise ValueError, method
card.connection.disconnect()
@@ -236,10 +276,13 @@ def print_usage():
print "\t--change:\tchange PIN (old PIN, new PIN twice)"
print "\t--change2:\tchange PIN by two steps (old PIN, new PIN twice)"
print "\t--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)"
print "\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)"
print "\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)"
print "\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)"
print " options:"
print "\t--admin:\tby administrator\t\t\t[False]"
print "\t--add:\t\tadd a dummy byte at the end of APDU\t[False]"
print "\t--pinmin:\tspecify minimum length of PIN\t\t[6]"
print "\t--pinmax:\tspecify maximum length of PIN\t\t[15]"
print "EXAMPLES:"
print " $ pinpad-test # verify user's PIN "
@@ -256,6 +299,7 @@ if __name__ == '__main__':
who = BY_USER
method = "verify"
add_a_byte = False
pinmin = PIN_MIN_DEFAULT
pinmax = PIN_MAX_DEFAULT
change_by_two_steps = False
while len(sys.argv) >= 2:
@@ -270,13 +314,22 @@ if __name__ == '__main__':
change_by_two_steps = True
elif option == '--unblock':
method = "unblock"
elif option == '--unblock2':
method = "unblock"
change_by_two_steps = True
elif option == '--add':
add_a_byte = True
elif option == '--pinmin':
pinmin = int(sys.argv[1])
sys.argv.pop(1)
elif option == '--pinmax':
pinmax = int(sys.argv[1])
sys.argv.pop(1)
elif option == '--put':
method = "put"
elif option == '--put2':
method = "put"
change_by_two_steps = True
elif option == "verify":
method = "verify"
elif option == '--help':
@@ -284,8 +337,62 @@ if __name__ == '__main__':
exit(0)
else:
raise ValueError, option
main(who, method, add_a_byte, pinmax, change_by_two_steps)
main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps)
# Failure
# 67 00: Wrong length; no further indication
# 69 82: Security status not satisfied: pin doesn't match
# 69 85: Conditions of use not satisfied
# 6b 00: Wrong parameters P1-P2
# 6b 80
# 64 02: PIN different
# General
# OpenPGP card v2 doesn't support CHANGE REFERENCE DATA in exchanging
# mode (with P1 == 01, replacing PIN).
# FAIL: --change2 fails with 6b 00 (after input of PIN)
# FAIL: --change2 --admin fails with 6b 00 (after input of PIN)
# "FSIJ Gnuk (0.16-34006F06) 00 00"
# Works well except --change2
# It could support --put and --unblock, but currently it's disabled.
# "Vasco DIGIPASS 920 [CCID] 00 00"
# OK: --verify
# OK: --verify --admin
# OK: --change
# OK: --change --admin
# OK: --unblock
# FAIL: --unblock --admin fails with 69 85 (after input of PIN)
# FAIL: --put fails with 6b 80 (before input of resetcode)
# OK: --put2
# FAIL: --unblock2 fails with 69 85
# FAIL: --unblock2 --admin fails with 69 85 (after input of PIN)
# 0c4b:0500 Reiner SCT Kartensysteme GmbH
# "REINER SCT cyberJack RFID standard (7592671050) 00 00"
# OK: --verify
# OK: --verify --admin
# OK: --change
# OK: --change --admin
# OK: --unblock
# OK: --unblock --admin
# FAIL: --put fails with 69 85
# Gemalto GemPC Pinpad 00 00
# It asks users PIN with --add but it results 67 00
# It seems that it doesn't support variable length PIN
# Firmware version: GemTwRC2-V2.10-GL04
# 072f:90d2 Advanced Card Systems, Ltd
# ACS ACR83U 01 00
# --verify failed with 6b 80
# 08e6:34c2 Gemplus
# Gemalto Ezio Shield PinPad 01 00
# works well
# FAIL: --unblock2 fails with 6d 00
# 076b:3821 OmniKey AG CardMan 3821
# OmniKey CardMan 3821 01 00
# Works well with --pinmax 31 --pinmin 1