Compare commits
41 Commits
release/0.
...
extended-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f92ee76db5 | ||
|
|
87e4fd50c1 | ||
|
|
cbb2c6aab5 | ||
|
|
00541d7627 | ||
|
|
27277e56ee | ||
|
|
4ee4417fb5 | ||
|
|
11351c8cae | ||
|
|
6abac73354 | ||
|
|
41537cc827 | ||
|
|
a4e0e67340 | ||
|
|
58f8470446 | ||
|
|
885e1c4ecb | ||
|
|
2c111d0b20 | ||
|
|
35a62354ae | ||
|
|
18f3e72c32 | ||
|
|
121df70044 | ||
|
|
48d89973c6 | ||
|
|
60c1fe47ce | ||
|
|
c53afe1f96 | ||
|
|
3074058ff7 | ||
|
|
a0c8cf2ff4 | ||
|
|
c0ab2ae830 | ||
|
|
a08669dfcd | ||
|
|
4a75aa47df | ||
|
|
1145fe0ad8 | ||
|
|
e2a4be1444 | ||
|
|
b4d36a429f | ||
|
|
a955cbec2f | ||
|
|
828b8f5768 | ||
|
|
d9be456fed | ||
|
|
5a9194d136 | ||
|
|
f58233aa5d | ||
|
|
ec409fe8a4 | ||
|
|
231c50d9b5 | ||
|
|
696de23b52 | ||
|
|
b113e6fa7b | ||
|
|
9dcb59f6aa | ||
|
|
351ce68729 | ||
|
|
142dbabfd8 | ||
|
|
1e94b262af | ||
|
|
268c41634a |
15
AUTHORS
15
AUTHORS
@@ -6,6 +6,14 @@ Kaz Kojima:
|
||||
|
||||
NIIBE Yutaka:
|
||||
Founder of the project.
|
||||
Added FST_01 support:
|
||||
boards/FST_01/board.c
|
||||
boards/FST_01/board.h
|
||||
boards/FST_01/mcuconf.h
|
||||
Added FST_01_00 support:
|
||||
boards/FST_01_00/board.c
|
||||
boards/FST_01_00/board.h
|
||||
boards/FST_01_00/mcuconf.h
|
||||
Added STBee support:
|
||||
boards/STBEE/board.c
|
||||
boards/STBEE/board.h
|
||||
@@ -28,6 +36,9 @@ NIIBE Yutaka:
|
||||
tool/intel_hex.py
|
||||
Wrote a tool for Gnuk:
|
||||
tool/gnuk_put_binary.py
|
||||
tool/gnuk_put_binary_libusb.py
|
||||
Wrote a tool for USB Hub:
|
||||
tool/hub_ctrl.py
|
||||
Wrote:
|
||||
gnuk.svg
|
||||
src/configure
|
||||
@@ -49,5 +60,9 @@ NIIBE Yutaka:
|
||||
src/random.c
|
||||
src/pin-cir.c
|
||||
src/pin-dial.c
|
||||
src/pin-dnd.c
|
||||
src/usb_msc.c
|
||||
src/usb_msc.h
|
||||
src/neug.c
|
||||
*
|
||||
and others.
|
||||
|
||||
208
ChangeLog
208
ChangeLog
@@ -1,3 +1,211 @@
|
||||
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,
|
||||
we don't assume host sends ZLP (But accepts ZLP, just in case).
|
||||
|
||||
2011-12-22 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (extended_capabilities) [CERTDO_SUPPORT]:
|
||||
conditionalize.
|
||||
|
||||
2011-12-21 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (gpg_do_get_data) [CERTDO_SUPPORT]: ifdef out.
|
||||
|
||||
* src/gnuk.ld.in (.gnuk_ch_certificate): Only valid
|
||||
when --enable-certdo.
|
||||
|
||||
* src/flash.c (flash_check_blank) [CERTDO_SUPPORT]: ifdef out.
|
||||
(flash_erase_binary) [CERTDO_SUPPORT]: Likewise.
|
||||
(flash_write_binary) [CERTDO_SUPPORT]: Likewise.
|
||||
|
||||
* src/configure (certdo): New.
|
||||
(--enable-certdo, --disable-certdo): New options.
|
||||
Remove cheking for /dev/random.
|
||||
|
||||
* src/config.h.in (@CERTDO_DEFINE@): New.
|
||||
|
||||
2011-12-20 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb_msc.c (msc_handle_command): SCSI_START_STOP_UNIT command
|
||||
with stop/eject/close means cancelling pinentry.
|
||||
|
||||
* src/pin-dnd.c (pinpad_finish_entry, parse_directory_sector):
|
||||
Implement "cancel".
|
||||
(pinpad_getline): Likewise.
|
||||
(msc_scsi_stop): New.
|
||||
|
||||
2011-12-16 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_put_binary_libusb.py (gnuk_token.cmd_select_openpgp):
|
||||
Fix apdu parameter.
|
||||
|
||||
* tool/gnuk_put_binary.py (GnukToken.cmd_select_openpgp): Ditto.
|
||||
|
||||
* tool/pinpad-test.py: New.
|
||||
|
||||
2011-12-14 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.16.
|
||||
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
* boards/STM8S_DISCOVERY/board.h, board.c: Fix for PINPAD_SUPPORT.
|
||||
* boards/STBEE_MINI/board.h, board.c: Likewise.
|
||||
* boards/STBEE/board.h, board.c: Likewise.
|
||||
* boards/FST_01/board.c: Likewise.
|
||||
|
||||
2011-12-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Add pinpad DND support.
|
||||
* src/Makefile.in (CSRC) [ENABLE_PINPAD]: Add usb_msc.c.
|
||||
* src/configure (pinpad): Add dnd support.
|
||||
* src/gnuk.h [PINPAD_DND_SUPPORT]: Add declarations.
|
||||
* src/main.c (STDOUTthread): Add PUSH packet.
|
||||
(main) [PINPAD_DND_SUPPORT]: Call msc_init.
|
||||
* src/usb_conf.h (EP_NUM): Add the case of PINPAD_DND_SUPPORT.
|
||||
(ENDP6_TXADDR, ENDP7_RXADDR): New.
|
||||
(ENDP4_TXADDR, ENDP5_RXADDR): Changed for smaller buffer.
|
||||
* src/usb_desc.c (gnukConfigDescriptor): Add Mass storage device.
|
||||
* src/usb_msc.c, src/usb_msc.h, src/pin-dnd.c: New.
|
||||
* src/usb_prop.c: Include "usb_msc.h".
|
||||
(gnuk_device_reset): Add initialization of ENDP6 and ENDP7.
|
||||
(gnuk_device_SetInterface): Add initialization of ENDP6 and ENDP7.
|
||||
(NUM_INTERFACES): Handle cases for PINPAD_DND_SUPPORT.
|
||||
(msc_lun_info): New.
|
||||
(gnuk_setup_with_data, gnuk_setup_with_nodata): Handle standard
|
||||
request for Mass storage device.
|
||||
* Virtual_COM_Port/usb_desc.h (VIRTUAL_COM_PORT_DATA_SIZE): Since
|
||||
there isn't enough hardware buffer, smaller value (was: 64).
|
||||
|
||||
* src/ac.c (verify_user_0): Add access argument.
|
||||
(verify_pso_cds, verify_other, verify_admin_0): Follow the change.
|
||||
* src/openpgp.c (cmd_change_password): Likewise.
|
||||
|
||||
2011-12-08 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb-icc.c: Not include "usb_desc.h".
|
||||
|
||||
* src/usb_endp.c (EP5_OUT_Callback): Fix minor bug.
|
||||
|
||||
2011-12-07 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb_desc.c (gnukDeviceDescriptor): Changed bcdUSB = 1.1.
|
||||
Gnuk device conforms to USB 2.0 full speed device, but when it was
|
||||
2.0, some OS informs users, "you can connect the device to 2.0
|
||||
compliant hub so that it can have better bandwidth", which is not
|
||||
the case for full speed device.
|
||||
|
||||
* src/openpgp.c (GPGthread): Handle bConfirmPIN parameter.
|
||||
|
||||
* src/usb-icc.c (icc_handle_data): Pass PC_to_RDR_Secure
|
||||
information to gpg_thread using memory of cmd_APDU.
|
||||
|
||||
2011-12-01 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/gnuk.h (EV_PINPAD_INPUT_DONE, EV_NOP, EV_CMD_AVAILABLE)
|
||||
(EV_VERIFY_CMD_AVAILABLE, EV_MODIFY_CMD_AVAILABLE): New.
|
||||
* src/usb-icc.c (icc_power_off, icc_handle_data): Use EV_NOP,
|
||||
EV_CMD_AVAILABLE, EV_VERIFY_CMD_AVAILABLE, and EV_MODIFY_CMD_AVAILABLE.
|
||||
* src/pin-cir.c (cir_timer_interrupt): Use EV_PINPAD_INPUT_DONE.
|
||||
* src/pin-dial.c (dial_sw_interrupt, pinpad_getline): Ditto.
|
||||
(EV_SW_PUSH): Remove.
|
||||
|
||||
* src/openpgp.h (GPG_FUNCTION_NOT_SUPPORTED): New.
|
||||
(GPG_CONDITION_NOT_SATISFIED): New.
|
||||
* src/openpgp.c (cmd_change_password): Use GPG_FUNCTION_NOT_SUPPORTED.
|
||||
|
||||
* src/openpgp.c (cmd_verify, cmd_change_password)
|
||||
(cmd_reset_user_password, cmd_put_data): Remove pinpad handling...
|
||||
(GPGthread): ... and implement pinpad handling here.
|
||||
|
||||
2011-11-29 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_put_data) [PINPAD_SUPPORT]: Support pinpad
|
||||
input (for reset code).
|
||||
|
||||
2011-11-24 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.15.
|
||||
|
||||
57
NEWS
57
NEWS
@@ -1,5 +1,60 @@
|
||||
Gnuk NEWS - User visible changes
|
||||
|
||||
* Major changes in Gnuk 0.17
|
||||
|
||||
Released 2012-01-XX, by NIIBE Yutaka
|
||||
|
||||
** ISO 7816 SELECT command behavior is 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 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
|
||||
work as current version of GnuPG, this is now optional feature.
|
||||
You can enable this data object by specifying --enable-certdo at
|
||||
configure time.
|
||||
|
||||
** With DnD pinentry, user can cancel pin input
|
||||
Now, user can cancel pin input by unmounting device before finishing
|
||||
DnD.
|
||||
|
||||
** New tool: pinpadtest.py
|
||||
The tool pinpadtest.py is PC/SC test tool for pinentry of pinpad with
|
||||
OpenPGP card v2.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.16
|
||||
|
||||
Released 2011-12-14, by NIIBE Yutaka
|
||||
|
||||
** DnD pinentry support is added and it's default to pinentry support
|
||||
DnD pinentry support doesn't require any hardware extension, but
|
||||
emulates mass storage class device of USB. User inputs pass phrase
|
||||
by "drag and drop"-ing folders using file manager or something.
|
||||
|
||||
** Bug fix for VERIFY for CHV2
|
||||
With no keys, VERIFY command for CHV2 used to fail even if pass phrase
|
||||
is correct. It was intentional, because CHV2 verification would be
|
||||
useless with no keys. But there is a corner case for PRIVATE-DOs,
|
||||
which may requires CHV2 verification. Even though Gnuk doesn't
|
||||
support any PRIVATE-DOs, it is good to be fixed.
|
||||
|
||||
** Changed bcdUSB = 1.1
|
||||
Gnuk device conforms to USB 2.0 full speed device, but when it was
|
||||
2.0, some OS informs users, "you can connect the device to 2.0
|
||||
compliant hub so that it can have better bandwidth", which is not
|
||||
the case for full speed device.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.15
|
||||
|
||||
Released 2011-11-24, by NIIBE Yutaka
|
||||
@@ -9,7 +64,7 @@ Flying Stone Technology's open hardware, Flying Stone Tiny 01 is
|
||||
supported.
|
||||
|
||||
** Flash writing tool for "DfuSe" is improved
|
||||
Now, it support holes and unaligned blocks in hex file.
|
||||
Now, it supports holes and unaligned blocks in hex file.
|
||||
|
||||
** Experimental PIN-pad support (by TV controller) change
|
||||
Now, Gnuk has codetables for conversion from CIR code to ASCII code.
|
||||
|
||||
27
README
27
README
@@ -1,7 +1,7 @@
|
||||
Gnuk - software for GnuPG USB Token
|
||||
|
||||
Version 0.15
|
||||
2011-11-24
|
||||
Version 0.16
|
||||
2011-12-14
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
@@ -9,8 +9,8 @@ What's Gnuk?
|
||||
============
|
||||
|
||||
Gnuk is software implementation of a USB token for GNU Privacy Guard.
|
||||
Gnuk supports OpenPGP card protocol version 2, and it runs on STM32
|
||||
processor.
|
||||
Gnuk supports OpenPGP card protocol version 2, and it runs on
|
||||
STM32F103 processor.
|
||||
|
||||
I wish that Gnuk will be a developer's soother who uses GnuPG. I have
|
||||
been nervous of storing secret key(s) on usual secondary storage.
|
||||
@@ -94,21 +94,22 @@ Qa: With GNOME, I can't use Gnuk Token for SSH. How can we use it for SSH?
|
||||
Aa: You need to deactivate seahorse-agent and gnome-keyring, but use
|
||||
gpg-agant for the role of ssh-agent. For gnome-keyring please do:
|
||||
|
||||
$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
|
||||
$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
|
||||
|
||||
Qb: With GNOME 3, I can't use Gnuk Token at all. Why?
|
||||
Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
|
||||
|
||||
$ gnome-session-properties
|
||||
$ gnome-session-properties
|
||||
|
||||
and at the tab of "Startup Programs", disable check buttons for "GPG Password Agent" and "SSH Key Agent".
|
||||
and at the tab of "Startup Programs", disable check buttons for
|
||||
"GPG Password Agent" and "SSH Key Agent".
|
||||
|
||||
|
||||
|
||||
Release notes
|
||||
=============
|
||||
|
||||
This is sixteenth release of Gnuk. While it works well for specific
|
||||
This is seventeenth release of Gnuk. While it works well for specific
|
||||
usages and it is considered stable, it is still somewhat experimental.
|
||||
|
||||
Tested features are:
|
||||
@@ -172,6 +173,16 @@ Another PIN-pad support is connecting rotary encoder, push switch and
|
||||
7-segment LED display. Both of PIN verification and PIN modification
|
||||
are supported for this circuit extension.
|
||||
|
||||
Recently, "DnDpinentry" support is added. This is using usual file
|
||||
manager for pinentry. User does "drag and drop" folders and it will
|
||||
be pin entry. This feature doesn't require any additional hardware.
|
||||
See doc/settings-for-DnDpinentry for your desktop configuration.
|
||||
|
||||
Note that you need pinpad support for GnuPG, it's currently in the
|
||||
master branch of GnuPG git repository at git.gnupg.org, and it's under
|
||||
evaluation. When it will be considered stable, it will be put onto
|
||||
stable branch.
|
||||
|
||||
|
||||
Souce code
|
||||
==========
|
||||
|
||||
@@ -308,7 +308,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
|
||||
@@ -1019,8 +1018,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);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
|
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
|
||||
|
||||
#define VIRTUAL_COM_PORT_DATA_SIZE 64
|
||||
#define VIRTUAL_COM_PORT_DATA_SIZE 16
|
||||
#define VIRTUAL_COM_PORT_INT_SIZE 8
|
||||
|
||||
#define VIRTUAL_COM_PORT_SIZ_DEVICE_DESC 18
|
||||
|
||||
@@ -15,7 +15,7 @@ hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
/* PA0/TIM2_CH1 = 1 (pull up) */
|
||||
/* PA1/TIM2_CH2 = 0 (pull down) */
|
||||
/* PA2/TIM2_CH3 <= Vout of CIR receiver module */
|
||||
@@ -66,7 +66,7 @@ set_led (int value)
|
||||
palClearPad (IOPORT2, GPIOB_LED);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@ hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
/* EXTI0 <= PB0 */
|
||||
AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB;
|
||||
@@ -69,7 +68,6 @@ hwinit1 (void)
|
||||
/* Generate UEV to upload PSC and ARR */
|
||||
TIM4->EGR = TIM_EGR_UG;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -90,7 +88,6 @@ set_led (int value)
|
||||
palSetPad (IOPORT4, GPIOD_LED1);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
@@ -156,4 +153,3 @@ CH_IRQ_HANDLER (EXTI2_IRQHandler)
|
||||
CH_IRQ_EPILOGUE ();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#define BOARD_STBEE
|
||||
#define BOARD_NAME "STBee"
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
|
||||
#define HAVE_7SEGLED 1
|
||||
/*
|
||||
* Timer assignment for CIR
|
||||
@@ -89,7 +89,7 @@
|
||||
* Please refer to the STM32 Reference Manual for details.
|
||||
*/
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
|
||||
/*
|
||||
* Port A setup.
|
||||
* PA6 - (TIM3_CH1) input with pull-up
|
||||
|
||||
@@ -15,11 +15,12 @@ hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_SUPPORT) && !defined(DFU_SUPPORT)
|
||||
palWritePort(IOPORT2, 0x7fff); /* Only clear GPIOB_7SEG_DP */
|
||||
while (palReadPad (IOPORT2, GPIOB_BUTTON) != 0)
|
||||
; /* Wait for JTAG debugger connection */
|
||||
palWritePort(IOPORT2, 0xffff); /* All set */
|
||||
#endif
|
||||
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
/* EXTI0 <= PB0 */
|
||||
@@ -73,7 +74,6 @@ hwinit1 (void)
|
||||
TIM4->ARR = 31;
|
||||
/* Generate UEV to upload PSC and ARR */
|
||||
TIM4->EGR = TIM_EGR_UG;
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
* Disable JTAG and SWD, done after hwinit1_common as HAL resets AFIO
|
||||
@@ -101,7 +101,6 @@ set_led (int value)
|
||||
palSetPad (IOPORT1, GPIOA_LED1);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
@@ -167,4 +166,3 @@ CH_IRQ_HANDLER (EXTI2_IRQHandler)
|
||||
CH_IRQ_EPILOGUE ();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#define BOARD_NAME "STBee Mini"
|
||||
#define CPU_WITH_NO_GPIOE 1
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
|
||||
#define HAVE_7SEGLED 1
|
||||
/*
|
||||
* Timer assignment for CIR
|
||||
@@ -92,7 +92,7 @@
|
||||
* Please refer to the STM32 Reference Manual for details.
|
||||
*/
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
|
||||
/*
|
||||
* Port A setup.
|
||||
* PA6 - (TIM3_CH1) input with pull-up
|
||||
|
||||
@@ -15,7 +15,7 @@ hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
/* EXTI5 <= PB5 */
|
||||
AFIO->EXTICR[1] = AFIO_EXTICR2_EXTI5_PB;
|
||||
EXTI->IMR = 0;
|
||||
@@ -62,7 +62,7 @@ set_led (int value)
|
||||
palClearPad (IOPORT1, GPIOA_LED);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
#define VAL_GPIOACRH 0x88888883 /* PA15...PA8 */
|
||||
#define VAL_GPIOAODR 0xFFFFFFFF
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
/*
|
||||
* Port B setup.
|
||||
* Everything input with pull-up except:
|
||||
|
||||
34
doc/settings-for-DnDpinentry
Normal file
34
doc/settings-for-DnDpinentry
Normal file
@@ -0,0 +1,34 @@
|
||||
On GNU/Linux Desktop, I use udisks-glue so that DnDpinentry folder can
|
||||
be mounted with sync and noatime options.
|
||||
|
||||
After installing udisks-glue, I invoke gnome-session-properties to
|
||||
add udisks-glue to "Startup Program".
|
||||
|
||||
Then, I have two files to configure udisks (disable udisks for
|
||||
DnDpinentry) and udisks-glue (enable and specify options for DnDpinentry).
|
||||
|
||||
/etc/udev/rules.d/88-udisks.rules
|
||||
---------------
|
||||
ENV{ID_VENDOR}=="FSIJ", ENV{DEVTYPE}=="disk", ENV{ID_FS_LABEL}=="DnDpinentry", ENV{UDISKS_PRESENTATION_NOPOLICY}="1"
|
||||
---------------
|
||||
|
||||
~/.udisks-glue.conf
|
||||
---------------
|
||||
filter gone {
|
||||
label = "DnDpinentry"
|
||||
optical = false
|
||||
}
|
||||
|
||||
match gone {
|
||||
automount = true
|
||||
automount_options = { sync, noatime }
|
||||
}
|
||||
---------------
|
||||
|
||||
We need following setting for pinentry. Or else, you can't do
|
||||
anything when pinentry grabs mouse focus.
|
||||
|
||||
~/.gnupg/gpg-agent.conf
|
||||
---------------
|
||||
no-grab
|
||||
---------------
|
||||
@@ -101,6 +101,10 @@ ifneq ($(ENABLE_PINPAD),)
|
||||
CSRC += pin-$(ENABLE_PINPAD).c
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_PINPAD),dnd)
|
||||
CSRC += usb_msc.c
|
||||
endif
|
||||
|
||||
# List ASM source files here
|
||||
ASMSRC = $(PORTASM) \
|
||||
$(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/vectors.s
|
||||
|
||||
57
src/ac.c
57
src/ac.c
@@ -57,11 +57,11 @@ ac_reset_other (void)
|
||||
}
|
||||
|
||||
int
|
||||
verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
const uint8_t *ks_pw1)
|
||||
{
|
||||
int pw_len;
|
||||
int r;
|
||||
int r1, r2;
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
|
||||
if (gpg_pw_locked (PW_ERR_PW1))
|
||||
@@ -90,10 +90,23 @@ verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
|
||||
success_one_step:
|
||||
sha1 (pw, pw_len, keystring);
|
||||
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring))
|
||||
< 0)
|
||||
goto failure;
|
||||
else if (r == 0)
|
||||
if (access == AC_PSO_CDS_AUTHORIZED)
|
||||
{
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
r2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring);
|
||||
r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, keystring);
|
||||
}
|
||||
|
||||
if (r1 < 0 || r2 < 0)
|
||||
{
|
||||
gpg_pw_increment_err_counter (PW_ERR_PW1);
|
||||
return -1;
|
||||
}
|
||||
else if (r1 == 0 && r2 == 0)
|
||||
if (ks_pw1 != NULL && memcmp (ks_pw1+1, keystring, KEYSTRING_MD_SIZE) != 0)
|
||||
goto failure;
|
||||
|
||||
@@ -113,7 +126,7 @@ verify_pso_cds (const uint8_t *pw, int pw_len)
|
||||
DEBUG_INFO ("verify_pso_cds\r\n");
|
||||
DEBUG_BYTE (pw_len);
|
||||
|
||||
r = verify_user_0 (pw, pw_len, pw_len, ks_pw1);
|
||||
r = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, pw_len, pw_len, ks_pw1);
|
||||
if (r > 0)
|
||||
auth_status |= AC_PSO_CDS_AUTHORIZED;
|
||||
return r;
|
||||
@@ -122,29 +135,16 @@ verify_pso_cds (const uint8_t *pw, int pw_len)
|
||||
int
|
||||
verify_other (const uint8_t *pw, int pw_len)
|
||||
{
|
||||
int r1, r2;
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
int r;
|
||||
|
||||
DEBUG_INFO ("verify_other\r\n");
|
||||
DEBUG_BYTE (pw_len);
|
||||
|
||||
if (gpg_pw_locked (PW_ERR_PW1))
|
||||
return 0;
|
||||
|
||||
sha1 (pw, pw_len, keystring);
|
||||
if ((r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring)) < 0
|
||||
|| (r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER,
|
||||
keystring)) < 0)
|
||||
{
|
||||
gpg_pw_increment_err_counter (PW_ERR_PW1);
|
||||
return -1;
|
||||
}
|
||||
else if (r1 == 0 && r2 == 0)
|
||||
/* No key is available. Fail even if password can match. */
|
||||
return -1;
|
||||
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
auth_status |= AC_OTHER_AUTHORIZED;
|
||||
return 1;
|
||||
r = verify_user_0 (AC_OTHER_AUTHORIZED, pw, pw_len, pw_len, ks_pw1);
|
||||
if (r > 0)
|
||||
auth_status |= AC_OTHER_AUTHORIZED;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -230,7 +230,8 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
|
||||
|
||||
if (ks_pw1 != NULL)
|
||||
{ /* empty PW3, but PW1 exists */
|
||||
int r = verify_user_0 (pw, buf_len, pw_len_known, ks_pw1);
|
||||
int r = verify_user_0 (AC_PSO_CDS_AUTHORIZED,
|
||||
pw, buf_len, pw_len_known, ks_pw1);
|
||||
|
||||
if (r > 0)
|
||||
admin_authorized = BY_USER;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
@DFU_DEFINE@
|
||||
@PINPAD_DEFINE@
|
||||
@PINPAD_MORE_DEFINE@
|
||||
@CERTDO_DEFINE@
|
||||
|
||||
46
src/configure
vendored
46
src/configure
vendored
@@ -26,12 +26,7 @@ verbose=no
|
||||
with_dfu=default
|
||||
debug=no
|
||||
pinpad=no
|
||||
|
||||
# check /dev/random
|
||||
if test ! -e /dev/random; then
|
||||
echo "/dev/random is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
certdo=no
|
||||
|
||||
# Process each option
|
||||
for option; do
|
||||
@@ -57,6 +52,10 @@ for option; do
|
||||
pinpad=$optarg ;;
|
||||
--disable-pinpad)
|
||||
pinpad=no ;;
|
||||
--enable-certdo)
|
||||
certdo=yes ;;
|
||||
--disable-certdo)
|
||||
certdo=no ;;
|
||||
--with-dfu)
|
||||
with_dfu=yes ;;
|
||||
--without-dfu)
|
||||
@@ -86,8 +85,9 @@ Configuration:
|
||||
STM8S_DISCOVERY
|
||||
STBEE
|
||||
--enable-debug debug with virtual COM port [no]
|
||||
--enable-pinpad={cir,dial}
|
||||
PIN input device support [no]
|
||||
--enable-pinpad={dnd,cir,dial}
|
||||
PIN entry support [no]
|
||||
--enable-certdo support CERT.3 data object [no]
|
||||
--with-dfu build image for DFU [<target specific>]
|
||||
EOF
|
||||
exit 0
|
||||
@@ -159,10 +159,10 @@ if test "$pinpad" = "no"; then
|
||||
PINPAD_MORE_DEFINE=""
|
||||
echo "PIN pad option disabled"
|
||||
elif test "$pinpad" = "yes"; then
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=cir"
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=dnd"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
PINPAD_MORE_DEFINE="#define PINPAD_CIR_SUPPORT 1"
|
||||
echo "PIN pad option enabled (cir)"
|
||||
PINPAD_MORE_DEFINE="#define PINPAD_DND_SUPPORT 1"
|
||||
echo "PIN pad option enabled (dnd)"
|
||||
else
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
@@ -170,16 +170,34 @@ else
|
||||
echo "PIN pad option enabled ($pinpad)"
|
||||
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)"
|
||||
else
|
||||
CERTDO_DEFINE="#undef CERTDO_SUPPORT"
|
||||
echo "CERT.3 Data Object is not supported"
|
||||
fi
|
||||
|
||||
sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \
|
||||
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
|
||||
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
|
||||
< Makefile.in > Makefile
|
||||
sed -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
if test "$certdo" = "yes"; then
|
||||
sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \
|
||||
-e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
< gnuk.ld.in > gnuk.ld
|
||||
else
|
||||
sed -e "/^@CERTDO_SUPPORT_START@$/,/^@CERTDO_SUPPORT_END@$/ d" \
|
||||
-e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
< gnuk.ld.in > gnuk.ld
|
||||
fi
|
||||
sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
|
||||
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
|
||||
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
|
||||
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
|
||||
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
|
||||
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
|
||||
< config.h.in > config.h
|
||||
exit 0
|
||||
|
||||
16
src/flash.c
16
src/flash.c
@@ -581,6 +581,7 @@ flash_cnt123_clear (const uint8_t **addr_p)
|
||||
}
|
||||
|
||||
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
static int
|
||||
flash_check_blank (const uint8_t *page, int size)
|
||||
{
|
||||
@@ -592,17 +593,16 @@ flash_check_blank (const uint8_t *page, int size)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define FLASH_CH_CERTIFICATE_SIZE 2048
|
||||
int
|
||||
flash_erase_binary (uint8_t file_id)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
p = &ch_certificate_start;
|
||||
const uint8_t *p = &ch_certificate_start;
|
||||
if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0)
|
||||
{
|
||||
flash_erase_page ((uint32_t)p);
|
||||
@@ -614,6 +614,9 @@ flash_erase_binary (uint8_t file_id)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
#else
|
||||
(void)file_id;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -625,12 +628,15 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
|
||||
uint16_t maxsize;
|
||||
const uint8_t *p;
|
||||
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
maxsize = FLASH_CH_CERTIFICATE_SIZE;
|
||||
p = &ch_certificate_start;
|
||||
}
|
||||
else if (file_id == FILEID_SERIAL_NO)
|
||||
else
|
||||
#endif
|
||||
if (file_id == FILEID_SERIAL_NO)
|
||||
{
|
||||
maxsize = 6;
|
||||
p = &openpgpcard_aid[8];
|
||||
|
||||
73
src/gnuk.h
73
src/gnuk.h
@@ -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,19 +25,36 @@ 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 */
|
||||
uint32_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 */
|
||||
|
||||
/* GPG thread */
|
||||
#define EV_PINPAD_INPUT_DONE ((eventmask_t)1)
|
||||
#define EV_NOP ((eventmask_t)2)
|
||||
#define EV_CMD_AVAILABLE ((eventmask_t)4)
|
||||
#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) */
|
||||
@@ -31,12 +62,8 @@ extern void *memmove(void *dest, const void *src, size_t n);
|
||||
|
||||
#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
|
||||
@@ -47,7 +74,6 @@ extern const uint8_t *res_APDU_pointer;
|
||||
*/
|
||||
#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
|
||||
{
|
||||
@@ -79,8 +105,8 @@ extern void gpg_pw_increment_err_counter (uint8_t which);
|
||||
extern int ac_check_status (uint8_t ac_flag);
|
||||
extern int verify_pso_cds (const uint8_t *pw, int pw_len);
|
||||
extern int verify_other (const uint8_t *pw, int pw_len);
|
||||
extern int verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
const uint8_t *ks_pw1);
|
||||
extern int verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len,
|
||||
int pw_len_known, const uint8_t *ks_pw1);
|
||||
extern int verify_admin (const uint8_t *pw, int pw_len);
|
||||
extern int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known);
|
||||
|
||||
@@ -343,13 +369,20 @@ extern Thread *main_thread;
|
||||
extern void led_blink (int spec);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
# if defined(PINPAD_CIR_SUPPORT)
|
||||
extern void cir_ext_disable (void);
|
||||
extern void cir_ext_enable (void);
|
||||
#elif defined(PINPAD_DIAL_SUPPORT)
|
||||
# elif defined(PINPAD_DIAL_SUPPORT)
|
||||
extern void dial_sw_disable (void);
|
||||
extern void dial_sw_enable (void);
|
||||
#endif
|
||||
# elif defined(PINPAD_DND_SUPPORT)
|
||||
extern uint8_t media_available;
|
||||
extern void msc_init (void);
|
||||
extern void msc_media_insert_change (int available);
|
||||
extern int msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size);
|
||||
extern int msc_scsi_read (uint32_t lba, const uint8_t **sector_p);
|
||||
extern void msc_scsi_stop (uint8_t code);
|
||||
# endif
|
||||
#define PIN_INPUT_CURRENT 1
|
||||
#define PIN_INPUT_NEW 2
|
||||
#define PIN_INPUT_CONFIRM 3
|
||||
|
||||
@@ -115,6 +115,7 @@ SECTIONS
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
|
||||
@CERTDO_SUPPORT_START@
|
||||
.gnuk_ch_certificate :
|
||||
{
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
@@ -123,6 +124,7 @@ SECTIONS
|
||||
. += 1920;
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
} > flash =0xffffffff
|
||||
@CERTDO_SUPPORT_END@
|
||||
|
||||
.gnuk_flash :
|
||||
{
|
||||
|
||||
13
src/main.c
13
src/main.c
@@ -106,10 +106,14 @@ STDOUTthread (void *arg)
|
||||
|
||||
p = stdout.str;
|
||||
len = stdout.size;
|
||||
while (len > 0)
|
||||
while (1)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len == 0)
|
||||
if (count_in != VIRTUAL_COM_PORT_DATA_SIZE)
|
||||
break;
|
||||
|
||||
if (len < VIRTUAL_COM_PORT_DATA_SIZE)
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
@@ -128,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);
|
||||
}
|
||||
@@ -386,6 +389,10 @@ main (int argc, char **argv)
|
||||
chThdCreateStatic (waUSBthread, sizeof(waUSBthread),
|
||||
NORMALPRIO, USBthread, NULL);
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
msc_init ();
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
@@ -98,14 +98,18 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
|
||||
*/
|
||||
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
|
||||
0x00, 0x00, /* Max get challenge */
|
||||
#ifdef CERTDO_SUPPORT
|
||||
0x07, 0xfe, /* max. length of cardholder certificate (2KB - 2)*/
|
||||
#else
|
||||
0x00, 0x00,
|
||||
#endif
|
||||
/* Max. length of command data */
|
||||
(MAX_CMD_APDU_SIZE>>8), (MAX_CMD_APDU_SIZE&0xff),
|
||||
/* Max. length of response data */
|
||||
#if 0
|
||||
(MAX_RES_APDU_SIZE>>8), (MAX_RES_APDU_SIZE&0xff),
|
||||
#else
|
||||
#ifdef CERTDO_SUPPORT
|
||||
0x08, 0x00, /* the case of cardholder ceritificate */
|
||||
#else
|
||||
(MAX_RES_APDU_SIZE>>8), (MAX_RES_APDU_SIZE&0xff),
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -413,10 +417,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
|
||||
@@ -1241,20 +1247,22 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
|
||||
void
|
||||
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
|
||||
{
|
||||
const struct do_table_entry *do_p = get_do_entry (tag);
|
||||
|
||||
@@ -1270,9 +1278,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
|
||||
@@ -1406,8 +1413,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");
|
||||
|
||||
411
src/openpgp.c
411
src/openpgp.c
@@ -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
|
||||
@@ -64,9 +69,7 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = {
|
||||
void
|
||||
set_res_apdu (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,40 +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);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
if (cmd_APDU_size == 4)
|
||||
/* Verification with pinpad */
|
||||
{
|
||||
len = get_pinpad_input (PIN_INPUT_CURRENT);
|
||||
if (len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
pw = pin_input_buffer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
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);
|
||||
@@ -231,7 +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 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;
|
||||
@@ -242,62 +221,20 @@ cmd_change_password (void)
|
||||
DEBUG_INFO ("Change PW\r\n");
|
||||
DEBUG_BYTE (who);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
if (cmd_APDU_size == 4)
|
||||
/* Modification with pinpad */
|
||||
len = apdu.cmd_apdu_data_len;
|
||||
pw = apdu.cmd_apdu_data;
|
||||
|
||||
if (p1 != 0)
|
||||
{
|
||||
pw_len = get_pinpad_input (PIN_INPUT_CURRENT);
|
||||
if (pw_len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
pw = &cmd_APDU[5];
|
||||
memcpy (&cmd_APDU[5], pin_input_buffer, pw_len);
|
||||
newpw = pw + pw_len;
|
||||
|
||||
newpw_len = get_pinpad_input (PIN_INPUT_NEW);
|
||||
if (newpw_len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&cmd_APDU[5]+pw_len, pin_input_buffer, newpw_len);
|
||||
|
||||
len = get_pinpad_input (PIN_INPUT_CONFIRM);
|
||||
if (len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (len != newpw_len || memcmp (newpw, pin_input_buffer, len) != 0)
|
||||
{
|
||||
GPG_SECURITY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
len = cmd_APDU[4] = pw_len + newpw_len;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
len = cmd_APDU[4];
|
||||
pw = &cmd_APDU[5];
|
||||
if (len == 0) /* extended length */
|
||||
{
|
||||
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
|
||||
pw += 2;
|
||||
}
|
||||
GPG_FUNCTION_NOT_SUPPORTED();
|
||||
return;
|
||||
}
|
||||
|
||||
if (who == BY_USER) /* PW1 */
|
||||
{
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
|
||||
pw_len = verify_user_0 (pw, len, -1, ks_pw1);
|
||||
pw_len = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, len, -1, ks_pw1);
|
||||
|
||||
if (pw_len < 0)
|
||||
{
|
||||
@@ -383,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;
|
||||
@@ -395,61 +332,8 @@ cmd_reset_user_password (void)
|
||||
DEBUG_INFO ("Reset PW1\r\n");
|
||||
DEBUG_BYTE (p1);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
if (cmd_APDU_size == 4)
|
||||
/* Modification with pinpad */
|
||||
{
|
||||
if (p1 == 0x00) /* by User with Reseting Code */
|
||||
{
|
||||
pw_len = get_pinpad_input (PIN_INPUT_CURRENT);
|
||||
if (pw_len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&cmd_APDU[5], pin_input_buffer, pw_len);
|
||||
}
|
||||
else
|
||||
pw_len = 0;
|
||||
|
||||
pw = &cmd_APDU[5];
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = get_pinpad_input (PIN_INPUT_NEW);
|
||||
if (newpw_len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&cmd_APDU[5]+pw_len, pin_input_buffer, newpw_len);
|
||||
|
||||
len = get_pinpad_input (PIN_INPUT_CONFIRM);
|
||||
if (len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (len != newpw_len || memcmp (newpw, pin_input_buffer, len) != 0)
|
||||
{
|
||||
GPG_SECURITY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
len = cmd_APDU[4] = pw_len + newpw_len;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
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 */
|
||||
{
|
||||
@@ -571,16 +455,9 @@ cmd_put_data (void)
|
||||
if (file_selection != FILE_DF_OPENPGP)
|
||||
GPG_NO_RECORD();
|
||||
|
||||
tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
|
||||
len = cmd_APDU_size - 5;
|
||||
data = &cmd_APDU[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);
|
||||
}
|
||||
|
||||
@@ -588,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))
|
||||
@@ -615,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
|
||||
{
|
||||
@@ -630,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_WORD (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
|
||||
{
|
||||
@@ -651,8 +530,8 @@ cmd_select_file (void)
|
||||
res_APDU_size += 2;
|
||||
}
|
||||
}
|
||||
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");
|
||||
/*
|
||||
@@ -661,11 +540,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 ();
|
||||
}
|
||||
@@ -673,12 +552,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;
|
||||
@@ -696,7 +574,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");
|
||||
|
||||
@@ -709,21 +587,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))
|
||||
{
|
||||
@@ -732,24 +603,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)
|
||||
{
|
||||
@@ -761,7 +632,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);
|
||||
@@ -774,9 +645,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 ();
|
||||
@@ -784,9 +654,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 ();
|
||||
}
|
||||
|
||||
@@ -796,19 +666,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);
|
||||
|
||||
@@ -819,7 +682,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 ();
|
||||
@@ -827,9 +690,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 ();
|
||||
}
|
||||
|
||||
@@ -840,17 +703,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))
|
||||
@@ -860,10 +716,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)
|
||||
{
|
||||
@@ -888,14 +744,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");
|
||||
@@ -911,17 +767,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))
|
||||
@@ -931,10 +780,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
|
||||
@@ -952,14 +801,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");
|
||||
@@ -999,7 +848,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)
|
||||
@@ -1026,17 +875,99 @@ GPGthread (void *arg)
|
||||
|
||||
while (!chThdShouldTerminate ())
|
||||
{
|
||||
chEvtWaitOne (ALL_EVENTS);
|
||||
eventmask_t m = chEvtWaitOne (ALL_EVENTS);
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
int len, pw_len, newpw_len;
|
||||
#endif
|
||||
|
||||
DEBUG_INFO ("GPG!: ");
|
||||
|
||||
res_APDU_pointer = NULL; /* default */
|
||||
|
||||
if (icc_data_size != 0)
|
||||
if (m == EV_VERIFY_CMD_AVAILABLE)
|
||||
{
|
||||
process_command_apdu ();
|
||||
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
if (INS (apdu) != INS_VERIFY)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
goto done;
|
||||
}
|
||||
|
||||
pw_len = get_pinpad_input (PIN_INPUT_CURRENT);
|
||||
if (pw_len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
goto done;
|
||||
}
|
||||
memcpy (apdu.cmd_apdu_data, pin_input_buffer, pw_len);
|
||||
apdu.cmd_apdu_data_len = pw_len;
|
||||
#else
|
||||
GPG_ERROR ();
|
||||
goto done;
|
||||
#endif
|
||||
}
|
||||
else if (m == EV_MODIFY_CMD_AVAILABLE)
|
||||
{
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
uint8_t bConfirmPIN = apdu.cmd_apdu_data[5];
|
||||
uint8_t *p = apdu.cmd_apdu_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;
|
||||
}
|
||||
|
||||
if ((bConfirmPIN & 2)) /* Require old PIN */
|
||||
{
|
||||
pw_len = get_pinpad_input (PIN_INPUT_CURRENT);
|
||||
if (pw_len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
goto done;
|
||||
}
|
||||
memcpy (p, pin_input_buffer, pw_len);
|
||||
p += pw_len;
|
||||
}
|
||||
else
|
||||
pw_len = 0;
|
||||
|
||||
newpw_len = get_pinpad_input (PIN_INPUT_NEW);
|
||||
if (newpw_len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
goto done;
|
||||
}
|
||||
memcpy (p, pin_input_buffer, newpw_len);
|
||||
|
||||
if ((bConfirmPIN & 1)) /* New PIN twice */
|
||||
{
|
||||
len = get_pinpad_input (PIN_INPUT_CONFIRM);
|
||||
if (len < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (len != newpw_len || memcmp (p, pin_input_buffer, len) != 0)
|
||||
{
|
||||
GPG_SECURITY_FAILURE ();
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
apdu.cmd_apdu_data_len = pw_len + newpw_len;
|
||||
#else
|
||||
GPG_ERROR ();
|
||||
goto done;
|
||||
#endif
|
||||
}
|
||||
else if (m == EV_NOP)
|
||||
continue;
|
||||
|
||||
process_command_apdu ();
|
||||
done:
|
||||
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
|
||||
}
|
||||
|
||||
gpg_fini ();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#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)
|
||||
|
||||
@@ -910,7 +910,7 @@ cir_timer_interrupt (void)
|
||||
cir_input_last = now;
|
||||
/* Notify thread */
|
||||
if (pin_thread)
|
||||
chEvtSignalI (pin_thread, (eventmask_t)1);
|
||||
chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE);
|
||||
}
|
||||
|
||||
#if defined(DEBUG_CIR)
|
||||
|
||||
@@ -117,13 +117,12 @@ blink_dp (void)
|
||||
}
|
||||
|
||||
static Thread *pin_thread;
|
||||
#define EV_SW_PUSH (eventmask_t)1
|
||||
|
||||
void
|
||||
dial_sw_interrupt (void)
|
||||
{
|
||||
dial_sw_disable ();
|
||||
chEvtSignalI (pin_thread, EV_SW_PUSH);
|
||||
chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE);
|
||||
palClearPad (IOPORT1, GPIOA_LED2);
|
||||
}
|
||||
|
||||
@@ -157,7 +156,7 @@ pinpad_getline (int msg_code, systime_t timeout)
|
||||
dial_sw_enable ();
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_DISP_BLINK_INTERVAL0);
|
||||
|
||||
if (m == EV_SW_PUSH || sw_push_count)
|
||||
if (m == EV_PINPAD_INPUT_DONE || sw_push_count)
|
||||
{
|
||||
if (palReadPad (IOPORT2, GPIOB_BUTTON) == 0)
|
||||
sw_push_count++;
|
||||
|
||||
372
src/pin-dnd.c
Normal file
372
src/pin-dnd.c
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* pin-dnd.c -- PIN input support (Drag and Drop with File Manager)
|
||||
*
|
||||
* Copyright (C) 2011 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
*
|
||||
* Gnuk is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "board.h"
|
||||
#include "gnuk.h"
|
||||
#include "usb_msc.h"
|
||||
|
||||
struct folder {
|
||||
uint8_t parent;
|
||||
uint8_t children[7];
|
||||
};
|
||||
|
||||
static struct folder folders[8];
|
||||
static const struct folder folder_ini = { 0, { 1, 2, 3, 4, 5, 6, 7 } };
|
||||
|
||||
|
||||
uint8_t pin_input_buffer[MAX_PIN_CHARS];
|
||||
uint8_t pin_input_len;
|
||||
|
||||
static Thread *pin_thread;
|
||||
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
*/
|
||||
int
|
||||
pinpad_getline (int msg_code, systime_t timeout)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
(void)msg_code;
|
||||
(void)timeout;
|
||||
|
||||
DEBUG_INFO (">>>\r\n");
|
||||
|
||||
pin_input_len = 0;
|
||||
|
||||
msc_media_insert_change (1);
|
||||
|
||||
memset (folders, 0, sizeof folders);
|
||||
memcpy (folders, &folder_ini, sizeof folder_ini);
|
||||
|
||||
while (1)
|
||||
{
|
||||
chSysLock ();
|
||||
pin_thread = chThdSelf ();
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
|
||||
led_blink (0);
|
||||
if (msg != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
msc_media_insert_change (0);
|
||||
|
||||
if (msg == 1)
|
||||
return pin_input_len;
|
||||
else
|
||||
return -1; /* cancel */
|
||||
}
|
||||
|
||||
static void pinpad_input (void)
|
||||
{
|
||||
chSysLock ();
|
||||
pin_thread->p_u.rdymsg = 0;
|
||||
chSchReadyI (pin_thread);
|
||||
chSysUnlock ();
|
||||
}
|
||||
|
||||
static void pinpad_finish_entry (int cancel)
|
||||
{
|
||||
chSysLock ();
|
||||
if (cancel)
|
||||
pin_thread->p_u.rdymsg = 2;
|
||||
else
|
||||
pin_thread->p_u.rdymsg = 1;
|
||||
chSchReadyI (pin_thread);
|
||||
chSysUnlock ();
|
||||
}
|
||||
|
||||
#define TOTAL_SECTOR 68
|
||||
|
||||
/*
|
||||
|
||||
blk=0: master boot record sector
|
||||
blk=1: fat0
|
||||
blk=2: fat1
|
||||
blk=3: root directory
|
||||
blk=4: fat cluster #2
|
||||
...
|
||||
blk=4+63: fat cluster #2+63
|
||||
*/
|
||||
|
||||
static const uint8_t d0_0_sector[] = {
|
||||
0xeb, 0x3c, /* Jump instruction */
|
||||
0x90, /* NOP */
|
||||
|
||||
0x6d, 0x6b, 0x64, 0x6f, 0x73, 0x66, 0x73, 0x20, /* "mkdosfs " */
|
||||
|
||||
0x00, 0x02, /* Bytes per sector: 512 */
|
||||
|
||||
0x01, /* sectors per cluster: 1 */
|
||||
0x01, 0x00, /* reserved sector count: 1 */
|
||||
0x02, /* Number of FATs: 2 */
|
||||
0x10, 0x00, /* Max. root directory entries: 16 (1 sector) */
|
||||
TOTAL_SECTOR, 0x00, /* total sectors: 68 */
|
||||
0xf8, /* media descriptor: fixed disk */
|
||||
0x01, 0x00, /* sectors per FAT: 1 */
|
||||
0x04, 0x00, /* sectors per track: 4 */
|
||||
0x01, 0x00, /* number of heads: 1 */
|
||||
0x00, 0x00, 0x00, 0x00, /* hidden sectors: 0 */
|
||||
0x00, 0x00, 0x00, 0x00, /* total sectors (long) */
|
||||
0x00, /* drive number */
|
||||
0x00, /* reserved */
|
||||
0x29, /* extended boot signature */
|
||||
0xbf, 0x86, 0x75, 0xea, /* Volume ID (serial number) (Little endian) */
|
||||
|
||||
/* Volume label: DNDpinentry */
|
||||
'D', 'n', 'D', 'p', 'i', 'n', 'e', 'n', 't', 'r', 'y',
|
||||
|
||||
0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, /* FAT12 */
|
||||
|
||||
0x0e, /* push cs */
|
||||
0x1f, /* pop ds */
|
||||
0xbe, 0x5b, 0x7c, /* mov si, offset message_txt */
|
||||
0xac, /* 1: lodsb */
|
||||
0x22, 0xc0, /* and al, al */
|
||||
0x74, 0x0b, /* jz 2f */
|
||||
0x56, /* push si */
|
||||
0xb4, 0x0e, /* mov ah, 0eh */
|
||||
0xbb, 0x07, 0x00, /* mov bx, 0007h */
|
||||
0xcd, 0x10, /* int 10h ; output char color=white */
|
||||
0x5e, /* pop si */
|
||||
0xeb, 0xf0, /* jmp 1b */
|
||||
0x32, 0xe4, /* 2: xor ah, ah */
|
||||
0xcd, 0x16, /* int 16h; key input */
|
||||
0xcd, 0x19, /* int 19h; load OS */
|
||||
0xeb, 0xfe, /* 3: jmp 3b */
|
||||
|
||||
/* "This is not a bootable disk... \r\n" */
|
||||
0x54, 0x68, 0x69, 0x73, 0x20,
|
||||
0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61,
|
||||
0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20,
|
||||
0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20,
|
||||
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61,
|
||||
0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79,
|
||||
0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72,
|
||||
0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20,
|
||||
0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74,
|
||||
0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e,
|
||||
0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t d0_fat0_sector[] = {
|
||||
0xf8, 0xff, 0xff, /* Media descriptor: fixed disk */ /* EOC */
|
||||
0xff, 0xff, 0xff, /* cluster 2: used */ /* cluster 3: used */
|
||||
0xff, 0xff, 0xff, /* cluster 4: used */ /* cluster 5: used */
|
||||
0xff, 0xff, 0xff, /* cluster 6: used */ /* cluster 7: used */
|
||||
0xff, 0x0f, 0x00, /* cluster 8: used */ /* cluster 9: free */
|
||||
};
|
||||
|
||||
static uint8_t the_sector[512];
|
||||
|
||||
#define FOLDER_INDEX_TO_CLUSTER_NO(i) (i+1)
|
||||
#define CLUSTER_NO_TO_FOLDER_INDEX(n) (n-1)
|
||||
#define FOLDER_INDEX_TO_LBA(i) (i+3)
|
||||
#define LBA_TO_FOLDER_INDEX(lba) (lba-3)
|
||||
#define FOLDER_INDEX_TO_DIRCHAR(i) ('A'+i-1)
|
||||
#define DIRCHAR_TO_FOLDER_INDEX(c) (c - 'A' + 1)
|
||||
|
||||
static uint8_t *fill_file_entry (uint8_t *p, const uint8_t *filename,
|
||||
uint16_t cluster_no)
|
||||
{
|
||||
memcpy (p, filename, 8+3);
|
||||
p += 11;
|
||||
*p++ = 0x10; /* directory */
|
||||
*p++ = 0x00; /* reserved */
|
||||
memcpy (p, "\x64\x3b\xa7\x61\x3f", 5); /* create time */
|
||||
p += 5;
|
||||
memcpy (p, "\x61\x3f", 2); /* last access */
|
||||
p += 2;
|
||||
*p++ = 0x00; *p++ = 0x00; /* ea-index */
|
||||
memcpy (p, "\x3b\xa7\x61\x3f", 4); /* last modified */
|
||||
p += 4;
|
||||
memcpy (p, &cluster_no, 2); /* cluster # */
|
||||
p += 2;
|
||||
*p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* file size */
|
||||
return p;
|
||||
}
|
||||
|
||||
static void build_directory_sector (uint8_t *p, uint8_t index)
|
||||
{
|
||||
uint16_t cluster_no = FOLDER_INDEX_TO_CLUSTER_NO (index);
|
||||
int i;
|
||||
uint8_t filename[11] = { 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20 };
|
||||
uint8_t child;
|
||||
|
||||
memset (p, 0, 512);
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
p = fill_file_entry (p, filename, cluster_no);
|
||||
filename[1] = 0x2e;
|
||||
p = fill_file_entry (p, filename, 0);
|
||||
filename[1] = 0x20;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
if ((child = folders[index].children[i]) != 0)
|
||||
{
|
||||
filename[0] = FOLDER_INDEX_TO_DIRCHAR (child);
|
||||
p = fill_file_entry (p, filename, FOLDER_INDEX_TO_CLUSTER_NO (child));
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int
|
||||
msc_scsi_read (uint32_t lba, const uint8_t **sector_p)
|
||||
{
|
||||
if (!media_available)
|
||||
return SCSI_ERROR_NOT_READY;
|
||||
|
||||
if (lba >= TOTAL_SECTOR)
|
||||
return SCSI_ERROR_ILLEAGAL_REQUEST;
|
||||
|
||||
switch (lba)
|
||||
{
|
||||
case 0:
|
||||
*sector_p = the_sector;
|
||||
memcpy (the_sector, d0_0_sector, sizeof d0_0_sector);
|
||||
memset (the_sector + sizeof d0_0_sector, 0, 512 - sizeof d0_0_sector);
|
||||
the_sector[510] = 0x55;
|
||||
the_sector[511] = 0xaa;
|
||||
return 0;
|
||||
case 1:
|
||||
case 2:
|
||||
*sector_p = the_sector;
|
||||
memcpy (the_sector, d0_fat0_sector, sizeof d0_fat0_sector);
|
||||
memset (the_sector + sizeof d0_fat0_sector, 0,
|
||||
512 - sizeof d0_fat0_sector);
|
||||
return 0;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
*sector_p = the_sector;
|
||||
build_directory_sector (the_sector, LBA_TO_FOLDER_INDEX (lba));
|
||||
return 0;
|
||||
default:
|
||||
*sector_p = the_sector;
|
||||
memset (the_sector, 0, 512);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void parse_directory_sector (const uint8_t *p, uint8_t index)
|
||||
{
|
||||
int i;
|
||||
uint8_t child;
|
||||
int input = 0;
|
||||
int num_children = 0;
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
uint16_t cluster_no;
|
||||
uint8_t dest_index;
|
||||
|
||||
p += 32; /* skip "." */
|
||||
|
||||
/* ".." */
|
||||
cluster_no = p[26] | (p[27] << 8);
|
||||
dest_index = CLUSTER_NO_TO_FOLDER_INDEX (cluster_no);
|
||||
|
||||
if (dest_index < 1 || dest_index > 7)
|
||||
; /* it can be 255 : root_dir */
|
||||
else
|
||||
if (pin_input_len < MAX_PIN_CHARS - 2)
|
||||
{
|
||||
pin_input_buffer[pin_input_len++]
|
||||
= FOLDER_INDEX_TO_DIRCHAR (index);
|
||||
pin_input_buffer[pin_input_len++]
|
||||
= FOLDER_INDEX_TO_DIRCHAR (dest_index);
|
||||
input = 1;
|
||||
}
|
||||
|
||||
p += 32;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if (*p >= 'A' && *p <= 'G')
|
||||
{
|
||||
child = DIRCHAR_TO_FOLDER_INDEX (*p);
|
||||
folders[index].children[i] = child;
|
||||
num_children++;
|
||||
}
|
||||
else
|
||||
folders[index].children[i] = 0;
|
||||
p += 32;
|
||||
}
|
||||
|
||||
if (index == 0 && num_children == 1)
|
||||
pinpad_finish_entry (0);
|
||||
else if (input)
|
||||
pinpad_input ();
|
||||
}
|
||||
|
||||
int
|
||||
msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!media_available)
|
||||
return SCSI_ERROR_NOT_READY;
|
||||
|
||||
if (lba >= TOTAL_SECTOR)
|
||||
return SCSI_ERROR_ILLEAGAL_REQUEST;
|
||||
|
||||
if (lba == 1)
|
||||
return 0; /* updating FAT, just ignore */
|
||||
|
||||
if (lba <= 2 || lba >= 11)
|
||||
return SCSI_ERROR_DATA_PROTECT;
|
||||
else
|
||||
{
|
||||
uint8_t index = LBA_TO_FOLDER_INDEX (lba);
|
||||
|
||||
parse_directory_sector (buf, index);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
msc_scsi_stop (uint8_t code)
|
||||
{
|
||||
(void)code;
|
||||
pinpad_finish_entry (1);
|
||||
}
|
||||
@@ -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_regs.c
|
||||
|
||||
345
src/usb-icc.c
345
src/usb-icc.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* usb-icc.c -- USB CCID/ICCD protocol handling
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 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,10 +26,12 @@
|
||||
#include "hal.h"
|
||||
#include "gnuk.h"
|
||||
#include "usb_lib.h"
|
||||
#include "usb_desc.h"
|
||||
#include "usb_mem.h"
|
||||
#include "hw_config.h"
|
||||
#include "usb_istr.h"
|
||||
#include "usb_lld.h"
|
||||
|
||||
struct apdu apdu;
|
||||
|
||||
#define ICC_SET_PARAMS 0x61 /* non-ICCD command */
|
||||
#define ICC_POWER_ON 0x62
|
||||
@@ -74,7 +76,7 @@ struct icc_header {
|
||||
uint16_t param;
|
||||
} __attribute__((packed));
|
||||
|
||||
int icc_data_size;
|
||||
static int icc_data_size;
|
||||
|
||||
/*
|
||||
* USB-ICC communication could be considered "half duplex".
|
||||
@@ -94,8 +96,8 @@ int icc_data_size;
|
||||
* The buffer will be filled by multiple RX transactions (Bulk-OUT)
|
||||
* or will be used for multiple TX transactions (Bulk-IN)
|
||||
*/
|
||||
uint8_t icc_buffer[USB_BUF_SIZE];
|
||||
uint8_t icc_seq;
|
||||
static uint8_t icc_buffer[USB_BUF_SIZE];
|
||||
static uint8_t icc_seq;
|
||||
|
||||
/*
|
||||
* Pointer to ICC_BUFFER
|
||||
@@ -132,8 +134,7 @@ EP1_IN_Callback (void)
|
||||
{
|
||||
/* Send the last 0-DATA transcation of Bulk-IN in the transactions */
|
||||
icc_next_p = NULL;
|
||||
USB_SIL_Write (EP1_IN, icc_buffer, 0);
|
||||
SetEPTxValid (ENDP1);
|
||||
usb_lld_write (ENDP1, icc_buffer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -147,8 +148,7 @@ EP1_IN_Callback (void)
|
||||
tx_size = &icc_buffer[icc_tx_size] - p;
|
||||
}
|
||||
|
||||
USB_SIL_Write (EP1_IN, p, tx_size);
|
||||
SetEPTxValid (ENDP1);
|
||||
usb_lld_write (ENDP1, p, tx_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ icc_prepare_receive (int chain)
|
||||
else
|
||||
icc_next_p = icc_buffer;
|
||||
|
||||
SetEPRxValid (ENDP2);
|
||||
usb_lld_rx_enable (ENDP2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,13 +170,33 @@ void
|
||||
EP2_OUT_Callback (void)
|
||||
{
|
||||
int len;
|
||||
struct icc_header *icc_header;
|
||||
int data_len_so_far;
|
||||
int data_len;
|
||||
|
||||
len = USB_SIL_Read (EP2_OUT, icc_next_p);
|
||||
len = usb_lld_rx_data_len (ENDP2);
|
||||
usb_lld_rxcpy (icc_next_p, ENDP2, 0, len);
|
||||
if (len == 0)
|
||||
{ /* Just ignore Zero Length Packet (ZLP), if any */
|
||||
usb_lld_rx_enable (ENDP2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len == USB_LL_BUF_SIZE) /* The sequence of transactions continues */
|
||||
icc_next_p += len;
|
||||
|
||||
if (icc_chain_p)
|
||||
icc_header = (struct icc_header *)icc_chain_p;
|
||||
else
|
||||
icc_header = (struct icc_header *)icc_buffer;
|
||||
|
||||
data_len = icc_header->data_len; /* NOTE: We're little endian */
|
||||
data_len_so_far = (icc_next_p - (uint8_t *)icc_header) - ICC_MSG_HEADER_SIZE;
|
||||
|
||||
if (len == USB_LL_BUF_SIZE
|
||||
&& data_len != data_len_so_far)
|
||||
/* The sequence of transactions continues */
|
||||
{
|
||||
icc_next_p += USB_LL_BUF_SIZE;
|
||||
SetEPRxValid (ENDP2);
|
||||
usb_lld_rx_enable (ENDP2);
|
||||
if ((icc_next_p - icc_buffer) >= USB_BUF_SIZE)
|
||||
/* No room to receive any more */
|
||||
{
|
||||
@@ -187,27 +207,18 @@ EP2_OUT_Callback (void)
|
||||
* (and discard the whole block)
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: It is possible a transaction may stall when the size of
|
||||
* BULK_OUT transaction it's bigger than USB_BUF_SIZE and stops
|
||||
* with just USB_LL_BUF_SIZE packet. Device will remain waiting
|
||||
* another packet.
|
||||
*/
|
||||
}
|
||||
else /* Finished */
|
||||
{
|
||||
struct icc_header *icc_header;
|
||||
int data_len;
|
||||
|
||||
icc_next_p += len;
|
||||
if (icc_chain_p)
|
||||
{
|
||||
icc_header = (struct icc_header *)icc_chain_p;
|
||||
icc_data_size = (icc_next_p - icc_chain_p) - ICC_MSG_HEADER_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
icc_header = (struct icc_header *)icc_buffer;
|
||||
icc_data_size = (icc_next_p - icc_buffer) - ICC_MSG_HEADER_SIZE;
|
||||
}
|
||||
|
||||
/* NOTE: We're little endian, nothing to convert */
|
||||
data_len = icc_header->data_len;
|
||||
icc_seq = icc_header->seq;
|
||||
icc_data_size = data_len_so_far;
|
||||
icc_seq = icc_header->seq; /* NOTE: We're little endian */
|
||||
|
||||
if (icc_data_size != data_len)
|
||||
{
|
||||
@@ -289,8 +300,7 @@ icc_error (int offset)
|
||||
|
||||
icc_next_p = NULL; /* This is a single transaction Bulk-IN */
|
||||
icc_tx_size = ICC_MSG_HEADER_SIZE;
|
||||
USB_SIL_Write (EP1_IN, icc_reply, icc_tx_size);
|
||||
SetEPTxValid (ENDP1);
|
||||
usb_lld_write (ENDP1, icc_reply, icc_tx_size);
|
||||
}
|
||||
|
||||
static Thread *gpg_thread;
|
||||
@@ -323,8 +333,7 @@ icc_power_on (void)
|
||||
|
||||
icc_next_p = NULL; /* This is a single transaction Bulk-IN */
|
||||
icc_tx_size = ICC_MSG_HEADER_SIZE + size_atr;
|
||||
USB_SIL_Write (EP1_IN, icc_buffer, icc_tx_size);
|
||||
SetEPTxValid (ENDP1);
|
||||
usb_lld_write (ENDP1, icc_buffer, icc_tx_size);
|
||||
DEBUG_INFO ("ON\r\n");
|
||||
|
||||
return ICC_STATE_WAIT;
|
||||
@@ -358,8 +367,7 @@ icc_send_status (void)
|
||||
|
||||
icc_next_p = NULL; /* This is a single transaction Bulk-IN */
|
||||
icc_tx_size = ICC_MSG_HEADER_SIZE;
|
||||
USB_SIL_Write (EP1_IN, icc_reply, icc_tx_size);
|
||||
SetEPTxValid (ENDP1);
|
||||
usb_lld_write (ENDP1, icc_reply, icc_tx_size);
|
||||
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("St\r\n");
|
||||
@@ -374,7 +382,7 @@ icc_power_off (void)
|
||||
if (gpg_thread)
|
||||
{
|
||||
chThdTerminate (gpg_thread);
|
||||
chEvtSignal (gpg_thread, (eventmask_t)1);
|
||||
chEvtSignal (gpg_thread, EV_NOP);
|
||||
chThdWait (gpg_thread);
|
||||
gpg_thread = NULL;
|
||||
}
|
||||
@@ -385,9 +393,6 @@ icc_power_off (void)
|
||||
return ICC_STATE_START;
|
||||
}
|
||||
|
||||
int res_APDU_size;
|
||||
const uint8_t *res_APDU_pointer;
|
||||
|
||||
static void
|
||||
icc_send_data_block (int len, uint8_t status, uint8_t chain)
|
||||
{
|
||||
@@ -419,8 +424,7 @@ icc_send_data_block (int len, uint8_t status, uint8_t chain)
|
||||
else
|
||||
icc_next_p = p + USB_LL_BUF_SIZE;
|
||||
|
||||
USB_SIL_Write (EP1_IN, p, tx_size);
|
||||
SetEPTxValid (ENDP1);
|
||||
usb_lld_write (ENDP1, p, tx_size);
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("DATA\r\n");
|
||||
#endif
|
||||
@@ -449,8 +453,7 @@ icc_send_params (void)
|
||||
|
||||
icc_next_p = NULL; /* This is a single transaction Bulk-IN */
|
||||
icc_tx_size = ICC_MSG_HEADER_SIZE + 7;
|
||||
USB_SIL_Write (EP1_IN, icc_buffer, icc_tx_size);
|
||||
SetEPTxValid (ENDP1);
|
||||
usb_lld_write (ENDP1, icc_buffer, icc_tx_size);
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("DATA\r\n");
|
||||
#endif
|
||||
@@ -497,7 +500,88 @@ icc_handle_data (void)
|
||||
{
|
||||
if (icc_header->param == 0)
|
||||
{ /* Give this message to GPG thread */
|
||||
chEvtSignal (gpg_thread, (eventmask_t)1);
|
||||
run_gpg_thread:
|
||||
apdu.seq = icc_seq;
|
||||
apdu.cmd_apdu_head = &icc_buffer[ICC_MSG_HEADER_SIZE];
|
||||
|
||||
apdu.sw = 0x9000;
|
||||
apdu.res_apdu_data_len = 0;
|
||||
apdu.res_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE];
|
||||
|
||||
if (icc_data_size < 4)
|
||||
{
|
||||
icc_error (ICC_MSG_HEADER_SIZE + icc_data_size);
|
||||
next_state = ICC_STATE_WAIT;
|
||||
break;
|
||||
}
|
||||
else if (icc_data_size == 4)
|
||||
{ /* No Lc and No Le */
|
||||
apdu.cmd_apdu_data = NULL;
|
||||
apdu.cmd_apdu_data_len = 0;
|
||||
apdu.expected_res_size = 0;
|
||||
apdu.cmd_apdu_head[4] = 0;
|
||||
}
|
||||
else if (icc_data_size == 5)
|
||||
{ /* No Lc but Le */
|
||||
apdu.cmd_apdu_data = NULL;
|
||||
apdu.cmd_apdu_data_len = 0;
|
||||
apdu.expected_res_size = apdu.cmd_apdu_head[4];
|
||||
if (apdu.expected_res_size == 0)
|
||||
apdu.expected_res_size = 256;
|
||||
apdu.cmd_apdu_head[4] = 0;
|
||||
}
|
||||
else if (apdu.cmd_apdu_head[4] == 0)
|
||||
{ /* extended Lc or extended Le */
|
||||
apdu.cmd_apdu_data = apdu.cmd_apdu_head + 7;
|
||||
apdu.cmd_apdu_data_len
|
||||
= (apdu.cmd_apdu_head[5] << 8) + apdu.cmd_apdu_head[6];
|
||||
if (icc_data_size == 7)
|
||||
{ /* No Lc but extended Le */
|
||||
apdu.expected_res_size = apdu.cmd_apdu_data_len;
|
||||
apdu.cmd_apdu_data_len = 0;
|
||||
}
|
||||
else if (icc_data_size == apdu.cmd_apdu_data_len + 7)
|
||||
apdu.expected_res_size = 0;
|
||||
else if (icc_data_size == apdu.cmd_apdu_data_len + 7 + 2)
|
||||
{
|
||||
apdu.expected_res_size
|
||||
= (icc_buffer[ICC_MSG_HEADER_SIZE + 7
|
||||
+ apdu.cmd_apdu_data_len] << 8)
|
||||
| icc_buffer[ICC_MSG_HEADER_SIZE + 7
|
||||
+ apdu.cmd_apdu_data_len + 1];
|
||||
if (apdu.expected_res_size == 0)
|
||||
apdu.expected_res_size = 65536;
|
||||
}
|
||||
else
|
||||
{
|
||||
icc_error (ICC_MSG_HEADER_SIZE + 5);
|
||||
next_state = ICC_STATE_WAIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* short Lc */
|
||||
{
|
||||
apdu.cmd_apdu_data = apdu.cmd_apdu_head + 5;
|
||||
apdu.cmd_apdu_data_len = apdu.cmd_apdu_head[4];
|
||||
if (icc_data_size == apdu.cmd_apdu_data_len + 5)
|
||||
apdu.expected_res_size = 0;
|
||||
else if (icc_data_size == apdu.cmd_apdu_data_len + 5 + 1)
|
||||
{
|
||||
apdu.expected_res_size
|
||||
= icc_buffer[ICC_MSG_HEADER_SIZE + 5
|
||||
+ apdu.cmd_apdu_data_len];
|
||||
if (apdu.expected_res_size == 0)
|
||||
apdu.expected_res_size = 256;
|
||||
}
|
||||
else
|
||||
{
|
||||
icc_error (ICC_MSG_HEADER_SIZE + 5);
|
||||
next_state = ICC_STATE_WAIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chEvtSignal (gpg_thread, EV_CMD_AVAILABLE);
|
||||
next_state = ICC_STATE_EXECUTE;
|
||||
}
|
||||
else if (icc_header->param == 1)
|
||||
@@ -519,12 +603,29 @@ icc_handle_data (void)
|
||||
{
|
||||
if (icc_buffer[10] == 0x00) /* PIN verification */
|
||||
{
|
||||
cmd_APDU[0] = icc_buffer[25];
|
||||
cmd_APDU[1] = icc_buffer[26];
|
||||
cmd_APDU[2] = icc_buffer[27];
|
||||
cmd_APDU[3] = icc_buffer[28];
|
||||
icc_data_size = 4;
|
||||
chEvtSignal (gpg_thread, (eventmask_t)1);
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+0] = icc_buffer[25];
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+1] = icc_buffer[26];
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+2] = icc_buffer[27];
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+3] = icc_buffer[28];
|
||||
/**/
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+5] = 0; /* bConfirmPIN */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+6] = icc_buffer[17]; /* bEntryValidationCondition */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+7] = icc_buffer[18]; /* bNumberMessage */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+8] = icc_buffer[19]; /* wLangId L */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+9] = icc_buffer[20]; /* wLangId H */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+10] = icc_buffer[21]; /* bMsgIndex */
|
||||
|
||||
apdu.seq = icc_seq;
|
||||
apdu.cmd_apdu_head = &icc_buffer[ICC_MSG_HEADER_SIZE+0];
|
||||
apdu.cmd_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE+5];
|
||||
apdu.cmd_apdu_data_len = 6;
|
||||
apdu.expected_res_size = 0;
|
||||
|
||||
apdu.sw = 0x9000;
|
||||
apdu.res_apdu_data_len = 0;
|
||||
apdu.res_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE];
|
||||
|
||||
chEvtSignal (gpg_thread, EV_VERIFY_CMD_AVAILABLE);
|
||||
next_state = ICC_STATE_EXECUTE;
|
||||
}
|
||||
else if (icc_buffer[10] == 0x01) /* PIN Modification */
|
||||
@@ -535,12 +636,33 @@ icc_handle_data (void)
|
||||
num_msgs = 1;
|
||||
else if (num_msgs == 0xff)
|
||||
num_msgs = 3;
|
||||
cmd_APDU[0] = icc_buffer[27 + num_msgs];
|
||||
cmd_APDU[1] = icc_buffer[28 + num_msgs];
|
||||
cmd_APDU[2] = icc_buffer[29 + num_msgs];
|
||||
cmd_APDU[3] = icc_buffer[30 + num_msgs];
|
||||
icc_data_size = 4;
|
||||
chEvtSignal (gpg_thread, (eventmask_t)1);
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+0] = icc_buffer[27 + num_msgs];
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+1] = icc_buffer[28 + num_msgs];
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+2] = icc_buffer[29 + num_msgs];
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+3] = icc_buffer[30 + num_msgs];
|
||||
/**/
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+5] = icc_buffer[19]; /* bConfirmPIN */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+6] = icc_buffer[20]; /* bEntryValidationCondition */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+7] = icc_buffer[21]; /* bNumberMessage */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+8] = icc_buffer[22]; /* wLangId L */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+9] = icc_buffer[23]; /* wLangId H */
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+10] = icc_buffer[24]; /* bMsgIndex, bMsgIndex1 */
|
||||
if (num_msgs >= 2)
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+11] = icc_buffer[25]; /* bMsgIndex2 */
|
||||
if (num_msgs == 3)
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+12] = icc_buffer[26]; /* bMsgIndex3 */
|
||||
|
||||
apdu.seq = icc_seq;
|
||||
apdu.cmd_apdu_head = &icc_buffer[ICC_MSG_HEADER_SIZE+0];
|
||||
apdu.cmd_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE+5];
|
||||
apdu.cmd_apdu_data_len = 5 + num_msgs;
|
||||
apdu.expected_res_size = 0;
|
||||
|
||||
apdu.sw = 0x9000;
|
||||
apdu.res_apdu_data_len = 0;
|
||||
apdu.res_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE];
|
||||
|
||||
chEvtSignal (gpg_thread, EV_MODIFY_CMD_AVAILABLE);
|
||||
next_state = ICC_STATE_EXECUTE;
|
||||
}
|
||||
else
|
||||
@@ -571,8 +693,7 @@ icc_handle_data (void)
|
||||
icc_next_p -= ICC_MSG_HEADER_SIZE;
|
||||
icc_data_size = icc_next_p - icc_buffer - ICC_MSG_HEADER_SIZE;
|
||||
icc_chain_p = NULL;
|
||||
next_state = ICC_STATE_EXECUTE;
|
||||
chEvtSignal (gpg_thread, (eventmask_t)1);
|
||||
goto run_gpg_thread;
|
||||
}
|
||||
else /* icc_header->param == 3 is not supported. */
|
||||
{
|
||||
@@ -610,26 +731,78 @@ icc_handle_data (void)
|
||||
{
|
||||
if (icc_header->param == 0x10)
|
||||
{
|
||||
if (res_APDU_pointer != NULL)
|
||||
int len = apdu.res_apdu_data_len;
|
||||
|
||||
if (apdu.res_apdu_data == NULL)
|
||||
{ /* send status word(s) of 0x9000 */
|
||||
len = 0;
|
||||
|
||||
if (apdu.res_apdu_data_len == 2)
|
||||
{
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE] = 0x90;
|
||||
len++;
|
||||
}
|
||||
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+len] = 0x00;
|
||||
len++;
|
||||
}
|
||||
else if (apdu.res_apdu_data != &icc_buffer[ICC_MSG_HEADER_SIZE])
|
||||
{
|
||||
memcpy (res_APDU, res_APDU_pointer,
|
||||
ICC_RESPONSE_MSG_DATA_SIZE);
|
||||
res_APDU_pointer += ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
if (apdu.res_apdu_data_len > ICC_RESPONSE_MSG_DATA_SIZE)
|
||||
{
|
||||
memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE],
|
||||
apdu.res_apdu_data, ICC_RESPONSE_MSG_DATA_SIZE);
|
||||
apdu.res_apdu_data += ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
apdu.res_apdu_data_len -= ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
}
|
||||
else if (apdu.res_apdu_data_len == ICC_RESPONSE_MSG_DATA_SIZE)
|
||||
{
|
||||
memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE],
|
||||
apdu.res_apdu_data, ICC_RESPONSE_MSG_DATA_SIZE);
|
||||
apdu.res_apdu_data = NULL;
|
||||
apdu.res_apdu_data_len = 2;
|
||||
}
|
||||
else if (apdu.res_apdu_data_len
|
||||
== ICC_RESPONSE_MSG_DATA_SIZE - 1)
|
||||
{
|
||||
memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE],
|
||||
apdu.res_apdu_data, apdu.res_apdu_data_len);
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len]
|
||||
= 0x90;
|
||||
apdu.res_apdu_data = NULL;
|
||||
apdu.res_apdu_data_len = 1;
|
||||
len += 1;
|
||||
}
|
||||
else if (apdu.res_apdu_data_len
|
||||
<= ICC_RESPONSE_MSG_DATA_SIZE - 2)
|
||||
{
|
||||
memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE],
|
||||
apdu.res_apdu_data, apdu.res_apdu_data_len);
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len]
|
||||
= 0x90;
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len+1]
|
||||
= 0x00;
|
||||
apdu.res_apdu_data = NULL;
|
||||
apdu.res_apdu_data_len = 0;
|
||||
len += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
memmove (res_APDU, res_APDU+ICC_RESPONSE_MSG_DATA_SIZE,
|
||||
res_APDU_size);
|
||||
|
||||
if (res_APDU_size <= ICC_RESPONSE_MSG_DATA_SIZE)
|
||||
{
|
||||
icc_send_data_block (res_APDU_size, 0, 0x02);
|
||||
memmove (&icc_buffer[ICC_MSG_HEADER_SIZE],
|
||||
&icc_buffer[ICC_MSG_HEADER_SIZE]
|
||||
+ICC_RESPONSE_MSG_DATA_SIZE,
|
||||
apdu.res_apdu_data_len);
|
||||
apdu.res_apdu_data_len -= ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
}
|
||||
|
||||
if (len <= ICC_RESPONSE_MSG_DATA_SIZE)
|
||||
{
|
||||
icc_send_data_block (len, 0, 0x02);
|
||||
next_state = ICC_STATE_WAIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
icc_send_data_block (ICC_RESPONSE_MSG_DATA_SIZE, 0, 0x03);
|
||||
res_APDU_size -= ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
}
|
||||
icc_send_data_block (ICC_RESPONSE_MSG_DATA_SIZE, 0, 0x03);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -698,26 +871,36 @@ USBthread (void *arg)
|
||||
else if (m == EV_EXEC_FINISHED)
|
||||
if (icc_state == ICC_STATE_EXECUTE)
|
||||
{
|
||||
if (res_APDU_pointer != NULL)
|
||||
if (apdu.res_apdu_data != &icc_buffer[ICC_MSG_HEADER_SIZE])
|
||||
{
|
||||
memcpy (res_APDU, res_APDU_pointer, ICC_RESPONSE_MSG_DATA_SIZE);
|
||||
res_APDU_pointer += ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
/* Assume that
|
||||
* apdu.res_apdu_data_len > ICC_RESPONSE_MSG_DATA_SIZE
|
||||
*/
|
||||
memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE],
|
||||
apdu.res_apdu_data, ICC_RESPONSE_MSG_DATA_SIZE);
|
||||
apdu.res_apdu_data += ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len] = (apdu.sw >> 8);
|
||||
icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len+1] = (apdu.sw & 0xff);
|
||||
apdu.res_apdu_data_len += 2;
|
||||
}
|
||||
|
||||
if (res_APDU_size <= ICC_RESPONSE_MSG_DATA_SIZE)
|
||||
if (apdu.res_apdu_data_len <= ICC_RESPONSE_MSG_DATA_SIZE)
|
||||
{
|
||||
icc_send_data_block (res_APDU_size, 0, 0);
|
||||
icc_send_data_block (apdu.res_apdu_data_len, 0, 0);
|
||||
icc_state = ICC_STATE_WAIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
icc_send_data_block (ICC_RESPONSE_MSG_DATA_SIZE, 0, 0x01);
|
||||
res_APDU_size -= ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
apdu.res_apdu_data_len -= ICC_RESPONSE_MSG_DATA_SIZE;
|
||||
icc_state = ICC_STATE_SEND;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* XXX: error */
|
||||
{ /* error */
|
||||
DEBUG_INFO ("ERR07\r\n");
|
||||
}
|
||||
else if (m == EV_TX_FINISHED)
|
||||
|
||||
@@ -8,10 +8,14 @@
|
||||
#ifndef __USB_CONF_H
|
||||
#define __USB_CONF_H
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#define EP_NUM (6)
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
# define EP_NUM (8)
|
||||
#else
|
||||
#define EP_NUM (3)
|
||||
# ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
# define EP_NUM (6)
|
||||
# else
|
||||
# define EP_NUM (3)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define BTABLE_ADDRESS (0x00)
|
||||
@@ -28,9 +32,14 @@
|
||||
/* EP3 */
|
||||
#define ENDP3_TXADDR (0x140)
|
||||
/* EP4 */
|
||||
#define ENDP4_TXADDR (0x180)
|
||||
#define ENDP4_TXADDR (0x150)
|
||||
/* EP5 */
|
||||
#define ENDP5_RXADDR (0x190)
|
||||
#define ENDP5_RXADDR (0x160)
|
||||
|
||||
/* EP6 */
|
||||
#define ENDP6_TXADDR (0x180)
|
||||
/* EP7 */
|
||||
#define ENDP7_RXADDR (0x1c0)
|
||||
|
||||
#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
static const uint8_t gnukDeviceDescriptor[] = {
|
||||
18, /* bLength */
|
||||
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x00, 0x02, /* bcdUSB = 2.00 */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0x00, /* bDeviceClass: 0 means deferred to interface */
|
||||
0x00, /* bDeviceSubClass */
|
||||
0x00, /* bDeviceProtocol */
|
||||
@@ -29,14 +29,29 @@ static const uint8_t gnukDeviceDescriptor[] = {
|
||||
0x01 /* bNumConfigurations */
|
||||
};
|
||||
|
||||
#define ICC_TOTAL_LENGTH (9+9+54+7+7)
|
||||
#define ICC_NUM_INTERFACES 1
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#define W_TOTAL_LENGTH (9+9+54+7+7+9+5+5+4+5+7+9+7+7)
|
||||
#define NUM_INTERFACES 3 /* two for CDC, one for GPG */
|
||||
#define VCOM_TOTAL_LENGTH (9+5+5+4+5+7+9+7+7)
|
||||
#define VCOM_NUM_INTERFACES 2
|
||||
#else
|
||||
#define W_TOTAL_LENGTH (9+9+54+7+7)
|
||||
#define NUM_INTERFACES 1 /* GPG only */
|
||||
#define VCOM_TOTAL_LENGTH 0
|
||||
#define VCOM_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
#define MSC_TOTAL_LENGTH (9+7+7)
|
||||
#define MSC_NUM_INTERFACES 1
|
||||
#else
|
||||
#define MSC_TOTAL_LENGTH 0
|
||||
#define MSC_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#define W_TOTAL_LENGTH (ICC_TOTAL_LENGTH+VCOM_TOTAL_LENGTH+MSC_TOTAL_LENGTH)
|
||||
#define NUM_INTERFACES (ICC_NUM_INTERFACES+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
||||
|
||||
|
||||
/* Configuation Descriptor */
|
||||
static const uint8_t gnukConfigDescriptor[] = {
|
||||
9, /* bLength: Configuation Descriptor size */
|
||||
@@ -105,7 +120,7 @@ static const uint8_t gnukConfigDescriptor[] = {
|
||||
0xff, /* bClassEnvelope: */
|
||||
0, 0, /* wLCDLayout: FIXED VALUE */
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DND_SUPPORT)
|
||||
1, /* bPinSupport: with PIN pad (verify) */
|
||||
#elif defined(PINPAD_DIAL_SUPPORT)
|
||||
3, /* bPinSupport: with PIN pad (verify, modify) */
|
||||
@@ -193,7 +208,40 @@ static const uint8_t gnukConfigDescriptor[] = {
|
||||
0x83, /* bEndpointAddress: (IN3) */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
||||
0x00 /* bInterval */
|
||||
0x00, /* bInterval */
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
/* Interface Descriptor.*/
|
||||
9, /* bLength: Interface Descriptor size */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
0x03, /* bInterfaceNumber. */
|
||||
#else
|
||||
0x01, /* bInterfaceNumber. */
|
||||
#endif
|
||||
0x00, /* bAlternateSetting. */
|
||||
0x02, /* bNumEndpoints. */
|
||||
0x08, /* bInterfaceClass (Mass Stprage). */
|
||||
0x06, /* bInterfaceSubClass (SCSI
|
||||
transparent command set, MSCO
|
||||
chapter 2). */
|
||||
0x50, /* bInterfaceProtocol (Bulk-Only
|
||||
Mass Storage, MSCO chapter 3). */
|
||||
0x00, /* iInterface. */
|
||||
/* Endpoint Descriptor.*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
0x86, /* bEndpointAddress: (IN6) */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval (ignored for bulk). */
|
||||
/* Endpoint Descriptor.*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
0x07, /* bEndpointAddress: (OUT7) */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval (ignored for bulk). */
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -227,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, '5', 0, /* Version number of Gnuk */
|
||||
'0', 0, '.', 0, '1', 0, '6', 0, /* Version number of Gnuk */
|
||||
'-', 0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
||||
@@ -18,5 +18,5 @@ EP3_IN_Callback(void)
|
||||
void
|
||||
EP5_OUT_Callback(void)
|
||||
{
|
||||
SetEPRxValid (ENDP3);
|
||||
SetEPRxValid (ENDP5);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "usb_lib.h"
|
||||
#include "usb_lld.h"
|
||||
|
||||
extern void USB_Istr (void);
|
||||
|
||||
@@ -1,2 +1,52 @@
|
||||
#define STM32_USB_IRQ_PRIORITY 11
|
||||
void usb_lld_init (void);
|
||||
|
||||
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 uint8_t *src,
|
||||
int ep_num, int offset, size_t len)
|
||||
{
|
||||
UserToPMABufferCopy ((uint8_t *)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, void *buf, size_t len)
|
||||
{
|
||||
UserToPMABufferCopy (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)
|
||||
{
|
||||
PMAToUserBufferCopy (dst, GetEPRxAddr (ep_num) + offset, len);
|
||||
}
|
||||
|
||||
552
src/usb_msc.c
Normal file
552
src/usb_msc.c
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* usb_msc.c -- USB Mass Storage Class protocol handling
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Gnuk is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "usb_lib.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb_msc.h"
|
||||
|
||||
struct usb_endp_in {
|
||||
const uint8_t *txbuf; /* Pointer to the transmission buffer. */
|
||||
size_t txsize; /* Transmit transfer size remained. */
|
||||
size_t txcnt; /* Transmitted bytes so far. */
|
||||
};
|
||||
|
||||
struct usb_endp_out {
|
||||
uint8_t *rxbuf; /* Pointer to the receive buffer. */
|
||||
size_t rxsize; /* Requested receive transfer size. */
|
||||
size_t rxcnt; /* Received bytes so far. */
|
||||
};
|
||||
|
||||
static struct usb_endp_in ep6_in;
|
||||
static struct usb_endp_out ep7_out;
|
||||
|
||||
static Thread *the_thread;
|
||||
|
||||
#define ENDP_MAX_SIZE 64
|
||||
|
||||
static uint8_t msc_state;
|
||||
|
||||
|
||||
static void usb_start_transmit (const uint8_t *p, size_t n)
|
||||
{
|
||||
size_t pkt_len = n > ENDP_MAX_SIZE ? ENDP_MAX_SIZE : n;
|
||||
|
||||
ep6_in.txbuf = p;
|
||||
ep6_in.txsize = n;
|
||||
ep6_in.txcnt = 0;
|
||||
|
||||
usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, pkt_len);
|
||||
}
|
||||
|
||||
/* "Data Transmitted" callback */
|
||||
void EP6_IN_Callback (void)
|
||||
{
|
||||
size_t n = (size_t)usb_lld_tx_data_len (ENDP6);
|
||||
|
||||
ep6_in.txbuf += n;
|
||||
ep6_in.txcnt += n;
|
||||
ep6_in.txsize -= n;
|
||||
|
||||
if (ep6_in.txsize > 0) /* More data to be sent */
|
||||
{
|
||||
if (ep6_in.txsize > ENDP_MAX_SIZE)
|
||||
n = ENDP_MAX_SIZE;
|
||||
else
|
||||
n = ep6_in.txsize;
|
||||
usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, n);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Transmit has been completed, notify the waiting thread */
|
||||
switch (msc_state)
|
||||
{
|
||||
case MSC_SENDING_CSW:
|
||||
case MSC_DATA_IN:
|
||||
if (the_thread != NULL) {
|
||||
Thread *tp;
|
||||
chSysLockFromIsr ();
|
||||
tp = the_thread;
|
||||
the_thread = NULL;
|
||||
tp->p_u.rdymsg = RDY_OK;
|
||||
chSchReadyI (tp);
|
||||
chSysUnlockFromIsr ();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void usb_start_receive (uint8_t *p, size_t n)
|
||||
{
|
||||
ep7_out.rxbuf = p;
|
||||
ep7_out.rxsize = n;
|
||||
ep7_out.rxcnt = 0;
|
||||
usb_lld_rx_enable (ENDP7);
|
||||
}
|
||||
|
||||
/* "Data Received" call back */
|
||||
void EP7_OUT_Callback (void)
|
||||
{
|
||||
size_t n = (size_t)usb_lld_rx_data_len (ENDP7);
|
||||
int err = 0;
|
||||
|
||||
if (n > ep7_out.rxsize)
|
||||
{ /* buffer overflow */
|
||||
err = 1;
|
||||
n = ep7_out.rxsize;
|
||||
}
|
||||
|
||||
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 */
|
||||
usb_lld_rx_enable (ENDP7);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Receiving has been completed, notify the waiting thread */
|
||||
switch (msc_state)
|
||||
{
|
||||
case MSC_IDLE:
|
||||
case MSC_DATA_OUT:
|
||||
if (the_thread != NULL) {
|
||||
Thread *tp;
|
||||
chSysLockFromIsr ();
|
||||
tp = the_thread;
|
||||
the_thread = NULL;
|
||||
tp->p_u.rdymsg = err? RDY_RESET : RDY_OK;
|
||||
chSchReadyI (tp);
|
||||
chSysUnlockFromIsr ();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t scsi_inquiry_data_00[] = { 0, 0, 0, 0, 0 };
|
||||
|
||||
static const uint8_t scsi_inquiry_data[] = {
|
||||
0x00, /* Direct Access Device. */
|
||||
0x80, /* RMB = 1: Removable Medium. */
|
||||
0x05, /* Version: SPC-3. */
|
||||
0x02, /* Response format: SPC-3. */
|
||||
36 - 4, /* Additional Length. */
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
/* Vendor Identification */
|
||||
'F', 'S', 'I', 'J', ' ', ' ', ' ', ' ',
|
||||
/* Product Identification */
|
||||
'V', 'i', 'r', 't', 'u', 'a', 'l', ' ',
|
||||
'D', 'i', 's', 'k', ' ', ' ', ' ', ' ',
|
||||
/* Product Revision Level */
|
||||
'1', '.', '0', ' '
|
||||
};
|
||||
|
||||
static uint8_t scsi_sense_data_desc[] = {
|
||||
0x72, /* Response Code: descriptor, current */
|
||||
0x02, /* Sense Key */
|
||||
0x3a, /* ASC (additional sense code) */
|
||||
0x00, /* ASCQ (additional sense code qualifier) */
|
||||
0x00, 0x00, 0x00,
|
||||
0x00, /* Additional Sense Length */
|
||||
};
|
||||
|
||||
static uint8_t scsi_sense_data_fixed[] = {
|
||||
0x70, /* Response Code: fixed, current */
|
||||
0x00,
|
||||
0x02, /* Sense Key */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, /* Additional Sense Length */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x3a, /* ASC (additional sense code) */
|
||||
0x00, /* ASCQ (additional sense code qualifier) */
|
||||
0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static void set_scsi_sense_data(uint8_t sense_key, uint8_t asc) {
|
||||
scsi_sense_data_desc[1] = scsi_sense_data_fixed[2] = sense_key;
|
||||
scsi_sense_data_desc[2] = scsi_sense_data_fixed[12] = asc;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t buf[512];
|
||||
|
||||
static uint8_t contingent_allegiance;
|
||||
static uint8_t keep_contingent_allegiance;
|
||||
|
||||
uint8_t media_available;
|
||||
|
||||
void msc_media_insert_change (int available)
|
||||
{
|
||||
contingent_allegiance = 1;
|
||||
media_available = available;
|
||||
if (available)
|
||||
{
|
||||
set_scsi_sense_data (0x06, 0x28); /* UNIT_ATTENTION */
|
||||
keep_contingent_allegiance = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_scsi_sense_data (0x02, 0x3a); /* NOT_READY */
|
||||
keep_contingent_allegiance = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t scsi_read_format_capacities (uint32_t *nblocks,
|
||||
uint32_t *secsize)
|
||||
{
|
||||
*nblocks = 68;
|
||||
*secsize = 512;
|
||||
if (media_available)
|
||||
return 2; /* Formatted Media.*/
|
||||
else
|
||||
return 3; /* No Media.*/
|
||||
}
|
||||
|
||||
static struct CBW CBW;
|
||||
|
||||
static struct CSW CSW;
|
||||
|
||||
|
||||
static int msc_recv_data (void)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
chSysLock ();
|
||||
msc_state = MSC_DATA_OUT;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_receive (buf, 512);
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msc_send_data (const uint8_t *p, size_t n)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
chSysLock ();
|
||||
msc_state = MSC_DATA_IN;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_transmit (p, n);
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
CSW.dCSWDataResidue -= (uint32_t)n;
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static void msc_send_result (const uint8_t *p, size_t n)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
if (n > CBW.dCBWDataTransferLength)
|
||||
n = CBW.dCBWDataTransferLength;
|
||||
|
||||
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||
msc_send_data (p, n);
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
}
|
||||
|
||||
CSW.dCSWSignature = MSC_CSW_SIGNATURE;
|
||||
chSysLock ();
|
||||
msc_state = MSC_SENDING_CSW;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_transmit ((uint8_t *)&CSW, sizeof CSW);
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void msc_handle_command (void)
|
||||
{
|
||||
size_t n;
|
||||
uint32_t nblocks, secsize;
|
||||
uint32_t lba;
|
||||
int r;
|
||||
msg_t msg;
|
||||
|
||||
chSysLock();
|
||||
msc_state = MSC_IDLE;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_receive ((uint8_t *)&CBW, sizeof CBW);
|
||||
chSchGoSleepTimeoutS (THD_STATE_SUSPENDED, MS2ST (1000));
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
|
||||
if (msg != RDY_OK)
|
||||
{
|
||||
/* Error occured, ignore the request and go into error state */
|
||||
msc_state = MSC_ERROR;
|
||||
if (msg != RDY_TIMEOUT)
|
||||
{
|
||||
chSysLock ();
|
||||
usb_lld_stall_rx (ENDP7);
|
||||
chSysUnlock ();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n = ep7_out.rxcnt;
|
||||
|
||||
if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE))
|
||||
{
|
||||
msc_state = MSC_ERROR;
|
||||
chSysLock ();
|
||||
usb_lld_stall_rx (ENDP7);
|
||||
chSysUnlock ();
|
||||
return;
|
||||
}
|
||||
|
||||
CSW.dCSWTag = CBW.dCBWTag;
|
||||
switch (CBW.CBWCB[0]) {
|
||||
case SCSI_REQUEST_SENSE:
|
||||
if (CBW.CBWCB[1] & 0x01) /* DESC */
|
||||
msc_send_result ((uint8_t *)&scsi_sense_data_desc,
|
||||
sizeof scsi_sense_data_desc);
|
||||
else
|
||||
msc_send_result ((uint8_t *)&scsi_sense_data_fixed,
|
||||
sizeof scsi_sense_data_fixed);
|
||||
/* After the error is reported, clear it, if it's . */
|
||||
if (!keep_contingent_allegiance)
|
||||
{
|
||||
contingent_allegiance = 0;
|
||||
set_scsi_sense_data (0x00, 0x00);
|
||||
}
|
||||
return;
|
||||
case SCSI_INQUIRY:
|
||||
if (CBW.CBWCB[1] & 0x01) /* EVPD */
|
||||
/* assume page 00 */
|
||||
msc_send_result ((uint8_t *)&scsi_inquiry_data_00,
|
||||
sizeof scsi_inquiry_data_00);
|
||||
else
|
||||
msc_send_result ((uint8_t *)&scsi_inquiry_data,
|
||||
sizeof scsi_inquiry_data);
|
||||
return;
|
||||
case SCSI_READ_FORMAT_CAPACITIES:
|
||||
buf[8] = scsi_read_format_capacities (&nblocks, &secsize);
|
||||
buf[0] = buf[1] = buf[2] = 0;
|
||||
buf[3] = 8;
|
||||
buf[4] = (uint8_t)(nblocks >> 24);
|
||||
buf[5] = (uint8_t)(nblocks >> 16);
|
||||
buf[6] = (uint8_t)(nblocks >> 8);
|
||||
buf[7] = (uint8_t)(nblocks >> 0);
|
||||
buf[9] = (uint8_t)(secsize >> 16);
|
||||
buf[10] = (uint8_t)(secsize >> 8);
|
||||
buf[11] = (uint8_t)(secsize >> 0);
|
||||
msc_send_result (buf, 12);
|
||||
return;
|
||||
case SCSI_START_STOP_UNIT:
|
||||
if (CBW.CBWCB[4] == 0x00 /* stop */
|
||||
|| CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
|
||||
{
|
||||
msc_scsi_stop (CBW.CBWCB[4]);
|
||||
set_scsi_sense_data (0x05, 0x24); /* ILLEGAL_REQUEST */
|
||||
contingent_allegiance = 1;
|
||||
keep_contingent_allegiance = 1;
|
||||
}
|
||||
/* CBW.CBWCB[4] == 0x01 *//* start */
|
||||
goto success;
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
if (contingent_allegiance)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
CSW.dCSWDataResidue = 0;
|
||||
msc_send_result (NULL, 0);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
success:
|
||||
case SCSI_SYNCHRONIZE_CACHE:
|
||||
case SCSI_VERIFY10:
|
||||
case SCSI_ALLOW_MEDIUM_REMOVAL:
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||
msc_send_result (NULL, 0);
|
||||
return;
|
||||
case SCSI_MODE_SENSE6:
|
||||
buf[0] = 0x03;
|
||||
buf[1] = buf[2] = buf[3] = 0;
|
||||
msc_send_result (buf, 4);
|
||||
return;
|
||||
case SCSI_READ_CAPACITY10:
|
||||
scsi_read_format_capacities (&nblocks, &secsize);
|
||||
buf[0] = (uint8_t)((nblocks - 1) >> 24);
|
||||
buf[1] = (uint8_t)((nblocks - 1) >> 16);
|
||||
buf[2] = (uint8_t)((nblocks - 1) >> 8);
|
||||
buf[3] = (uint8_t)((nblocks - 1) >> 0);
|
||||
buf[4] = (uint8_t)(secsize >> 24);
|
||||
buf[5] = (uint8_t)(secsize >> 16);
|
||||
buf[6] = (uint8_t)(secsize >> 8);
|
||||
buf[7] = (uint8_t)(secsize >> 0);
|
||||
msc_send_result (buf, 8);
|
||||
return;
|
||||
case SCSI_READ10:
|
||||
case SCSI_WRITE10:
|
||||
break;
|
||||
default:
|
||||
if (CBW.dCBWDataTransferLength == 0)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
CSW.dCSWDataResidue = 0;
|
||||
msc_send_result (NULL, 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
msc_state = MSC_ERROR;
|
||||
chSysLock ();
|
||||
usb_lld_stall_tx (ENDP6);
|
||||
usb_lld_stall_rx (ENDP7);
|
||||
chSysUnlock ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16)
|
||||
| (CBW.CBWCB[4] << 8) | CBW.CBWCB[5];
|
||||
|
||||
/* Transfer direction.*/
|
||||
if (CBW.bmCBWFlags & 0x80)
|
||||
{
|
||||
/* IN, Device to Host.*/
|
||||
msc_state = MSC_DATA_IN;
|
||||
if (CBW.CBWCB[0] == SCSI_READ10)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
CSW.dCSWDataResidue = 0;
|
||||
while (1)
|
||||
{
|
||||
if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((r = msc_scsi_read (lba, &p)) == 0)
|
||||
{
|
||||
msc_send_data (p, 512);
|
||||
if (++CBW.CBWCB[5] == 0)
|
||||
if (++CBW.CBWCB[4] == 0)
|
||||
if (++CBW.CBWCB[3] == 0)
|
||||
++CBW.CBWCB[2];
|
||||
if (CBW.CBWCB[8]-- == 0)
|
||||
CBW.CBWCB[7]--;
|
||||
CSW.dCSWDataResidue += 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
contingent_allegiance = 1;
|
||||
if (r == SCSI_ERROR_NOT_READY)
|
||||
set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
|
||||
else
|
||||
set_scsi_sense_data (r, 0x00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msc_send_result (NULL, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OUT, Host to Device.*/
|
||||
if (CBW.CBWCB[0] == SCSI_WRITE10)
|
||||
{
|
||||
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
break;
|
||||
}
|
||||
|
||||
msc_recv_data ();
|
||||
if ((r = msc_scsi_write (lba, buf, 512)) == 0)
|
||||
{
|
||||
if (++CBW.CBWCB[5] == 0)
|
||||
if (++CBW.CBWCB[4] == 0)
|
||||
if (++CBW.CBWCB[3] == 0)
|
||||
++CBW.CBWCB[2];
|
||||
if (CBW.CBWCB[8]-- == 0)
|
||||
CBW.CBWCB[7]--;
|
||||
CSW.dCSWDataResidue -= 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
contingent_allegiance = 1;
|
||||
if (r == SCSI_ERROR_NOT_READY)
|
||||
set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
|
||||
else
|
||||
set_scsi_sense_data (r, 0x00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msc_send_result (NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static msg_t
|
||||
msc_main (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
/* Initially, it starts with no media */
|
||||
msc_media_insert_change (0);
|
||||
while (1)
|
||||
msc_handle_command ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WORKING_AREA(wa_msc_thread, 128);
|
||||
|
||||
void msc_init (void)
|
||||
{
|
||||
chThdCreateStatic (wa_msc_thread, sizeof (wa_msc_thread),
|
||||
NORMALPRIO, msc_main, NULL);
|
||||
}
|
||||
52
src/usb_msc.h
Normal file
52
src/usb_msc.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#define MSC_CBW_SIGNATURE 0x43425355
|
||||
#define MSC_CSW_SIGNATURE 0x53425355
|
||||
|
||||
#define MSC_GET_MAX_LUN_COMMAND 0xFE
|
||||
#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF
|
||||
|
||||
#define MSC_CSW_STATUS_PASSED 0
|
||||
#define MSC_CSW_STATUS_FAILED 1
|
||||
|
||||
#define SCSI_INQUIRY 0x12
|
||||
#define SCSI_MODE_SENSE6 0x1A
|
||||
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||
#define SCSI_READ10 0x28
|
||||
#define SCSI_READ_CAPACITY10 0x25
|
||||
#define SCSI_REQUEST_SENSE 0x03
|
||||
#define SCSI_START_STOP_UNIT 0x1B
|
||||
#define SCSI_TEST_UNIT_READY 0x00
|
||||
#define SCSI_WRITE10 0x2A
|
||||
#define SCSI_VERIFY10 0x2F
|
||||
#define SCSI_READ_FORMAT_CAPACITIES 0x23
|
||||
|
||||
#define SCSI_SYNCHRONIZE_CACHE 0x35
|
||||
|
||||
#define MSC_IDLE 0
|
||||
#define MSC_DATA_OUT 1
|
||||
#define MSC_DATA_IN 2
|
||||
#define MSC_SENDING_CSW 3
|
||||
#define MSC_ERROR 4
|
||||
|
||||
struct CBW {
|
||||
uint32_t dCBWSignature;
|
||||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bmCBWFlags;
|
||||
uint8_t bCBWLUN;
|
||||
uint8_t bCBWCBLength;
|
||||
uint8_t CBWCB[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CSW {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SCSI_ERROR_NOT_READY 2
|
||||
#define SCSI_ERROR_ILLEAGAL_REQUEST 5
|
||||
#define SCSI_ERROR_UNIT_ATTENTION 6
|
||||
#define SCSI_ERROR_DATA_PROTECT 7
|
||||
|
||||
extern uint8_t media_available;
|
||||
152
src/usb_prop.c
152
src/usb_prop.c
@@ -36,6 +36,24 @@
|
||||
#include "usb-cdc-vport.c"
|
||||
#endif
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
#include "usb_msc.h"
|
||||
#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)
|
||||
@@ -46,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;
|
||||
}
|
||||
@@ -71,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 */
|
||||
@@ -83,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);
|
||||
|
||||
@@ -103,11 +123,26 @@ 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
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
/* Initialize Endpoint 6 */
|
||||
SetEPType (ENDP6, EP_BULK);
|
||||
SetEPTxAddr (ENDP6, ENDP6_TXADDR);
|
||||
SetEPTxStatus (ENDP6, EP_TX_NAK);
|
||||
SetEPRxStatus (ENDP6, EP_RX_DIS);
|
||||
|
||||
/* 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
|
||||
|
||||
/* Set this device to response on default address */
|
||||
SetDeviceAddress (0);
|
||||
|
||||
@@ -153,6 +188,21 @@ gnuk_device_SetInterface (void)
|
||||
ClearDTOG_TX (ENDP3);
|
||||
}
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
# ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (intf == 3)
|
||||
{
|
||||
ClearDTOG_TX (ENDP6);
|
||||
ClearDTOG_RX (ENDP7);
|
||||
}
|
||||
# else
|
||||
else if (intf == 1)
|
||||
{
|
||||
ClearDTOG_TX (ENDP6);
|
||||
ClearDTOG_RX (ENDP7);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -200,10 +250,18 @@ gnuk_device_GetStringDescriptor (uint16_t Length)
|
||||
(PONE_DESCRIPTOR)&String_Descriptor[wValue0]);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#define NUM_INTERFACES 3 /* two for CDC, one for CCID */
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
# ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
# define NUM_INTERFACES 4 /* two for CDC, one for CCID, and MSC */
|
||||
# else
|
||||
# define NUM_INTERFACES 2 /* CCID and MSC */
|
||||
# endif
|
||||
#else
|
||||
#define NUM_INTERFACES 1 /* CCID only */
|
||||
# ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
# define NUM_INTERFACES 3 /* two for CDC, one for CCID */
|
||||
# else
|
||||
# define NUM_INTERFACES 1 /* CCID only */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static RESULT
|
||||
@@ -247,11 +305,26 @@ gnuk_data_rates (uint16_t len)
|
||||
return (uint8_t *)data_rate_table;
|
||||
}
|
||||
|
||||
#if defined(PINPAD_DND_SUPPORT)
|
||||
static const uint8_t lun_table[] = { 0, 0, 0, 0, };
|
||||
static uint8_t *
|
||||
msc_lun_info (uint16_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
pInformation->Ctrl_Info.Usb_wLength = sizeof (lun_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uint8_t *)lun_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
static RESULT
|
||||
gnuk_setup_with_data (uint8_t RequestNo)
|
||||
{
|
||||
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
||||
if (pInformation->USBwIndex0 == 0) /* Interface */
|
||||
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
|
||||
if (pInformation->USBwIndex0 == 0)
|
||||
{
|
||||
if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
|
||||
{
|
||||
@@ -270,23 +343,41 @@ gnuk_setup_with_data (uint8_t RequestNo)
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
else
|
||||
#if defined(PINPAD_DND_SUPPORT)
|
||||
# if defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
else if (pInformation->USBwIndex0 == 1)
|
||||
return Virtual_Com_Port_Data_Setup (RequestNo);
|
||||
else if (pInformation->USBwIndex0 == 3)
|
||||
# else
|
||||
else if (pInformation->USBwIndex0 == 1)
|
||||
# endif
|
||||
{
|
||||
#if defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
return Virtual_Com_Port_Data_Setup (RequestNo);
|
||||
#else
|
||||
return USB_UNSUPPORT;
|
||||
#endif
|
||||
if (RequestNo == MSC_GET_MAX_LUN_COMMAND)
|
||||
{
|
||||
pInformation->Ctrl_Info.CopyData = msc_lun_info;
|
||||
pInformation->Ctrl_Info.Usb_wOffset = 0;
|
||||
msc_lun_info (0);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
#elif defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
else if (pInformation->USBwIndex0 == 1)
|
||||
return Virtual_Com_Port_Data_Setup (RequestNo);
|
||||
#endif
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
|
||||
static RESULT
|
||||
gnuk_setup_with_nodata (uint8_t RequestNo)
|
||||
{
|
||||
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
||||
if (pInformation->USBwIndex0 == 0) /* Interface */
|
||||
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
|
||||
if (pInformation->USBwIndex0 == 0)
|
||||
{
|
||||
if (RequestNo == USB_CCID_REQ_ABORT)
|
||||
/* wValue: bSeq, bSlot */
|
||||
@@ -295,14 +386,29 @@ gnuk_setup_with_nodata (uint8_t RequestNo)
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
else
|
||||
#if defined(PINPAD_DND_SUPPORT)
|
||||
# if defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
else if (pInformation->USBwIndex0 == 1)
|
||||
return Virtual_Com_Port_NoData_Setup (RequestNo);
|
||||
else if (pInformation->USBwIndex0 == 3)
|
||||
# else
|
||||
else if (pInformation->USBwIndex0 == 1)
|
||||
# endif
|
||||
{
|
||||
#if defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
return Virtual_Com_Port_NoData_Setup (RequestNo);
|
||||
#else
|
||||
return USB_UNSUPPORT;
|
||||
#endif
|
||||
if (RequestNo == MSC_MASS_STORAGE_RESET_COMMAND)
|
||||
{
|
||||
/* Should call resetting MSC thread, something like msc_reset() */
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
#elif defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
else if (pInformation->USBwIndex0 == 1)
|
||||
return Virtual_Com_Port_NoData_Setup (RequestNo);
|
||||
#endif
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class GnukToken(object):
|
||||
apdu = [0x00, 0x20, 0x00, 0x80+who, 0, 0, len(passwd)] + s2l(passwd)
|
||||
response, sw1, sw2 = self.connection.transmit(apdu)
|
||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||
raise ValueError, "cmd_verify"
|
||||
raise ValueError, ("%02x%02x" % (sw1, sw2))
|
||||
|
||||
def cmd_write_binary(self, fileid, data, is_update):
|
||||
count = 0
|
||||
@@ -66,22 +66,22 @@ class GnukToken(object):
|
||||
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, 0x0c, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
|
||||
apdu = [0x00, 0xa4, 0x04, 0x00, 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"
|
||||
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"
|
||||
raise ValueError, ("%02x%02x" % (sw1, sw2))
|
||||
return response
|
||||
|
||||
def compare(data_original, data_in_device):
|
||||
@@ -165,6 +165,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)
|
||||
|
||||
@@ -189,7 +189,7 @@ class gnuk_token:
|
||||
count += 1
|
||||
|
||||
def cmd_select_openpgp(self):
|
||||
cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
|
||||
cmd_data = iso7816_compose(0xa4, 0x04, 0x00, "\xD2\x76\x00\x01\x24\x01")
|
||||
sw = self.icc_send_cmd(cmd_data)
|
||||
if len(sw) != 2:
|
||||
raise ValueError, "cmd_select_openpgp"
|
||||
@@ -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)
|
||||
|
||||
398
tool/pinpadtest.py
Executable file
398
tool/pinpadtest.py
Executable file
@@ -0,0 +1,398 @@
|
||||
#! /usr/bin/python
|
||||
|
||||
"""
|
||||
pinpadtest.py - a tool to test variable length pin entry with pinpad
|
||||
|
||||
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.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
# Assume only single CCID device is attached to computer with card
|
||||
|
||||
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
|
||||
else:
|
||||
return 0x03 # bConfirmPIN: old PIN and new PIN twice
|
||||
|
||||
class Card(object):
|
||||
def __init__(self, add_a_byte, pinmin, pinmax):
|
||||
cardtype = AnyCardType()
|
||||
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):
|
||||
p = self.connection.control(CM_IOCTL_GET_FEATURE_REQUEST, [])
|
||||
i = 0
|
||||
while i < len(p):
|
||||
code = p[i]
|
||||
l = p[i+1]
|
||||
i = i + 2
|
||||
if l == 4:
|
||||
ioctl = (p[i] << 24) | (p[i+1] << 16) | (p[i+2] << 8) | p[i+3]
|
||||
i = i + l
|
||||
else:
|
||||
i = i + l
|
||||
continue
|
||||
if code == FEATURE_VERIFY_PIN_DIRECT:
|
||||
self.verify_ioctl = ioctl
|
||||
elif code == FEATURE_MODIFY_PIN_DIRECT:
|
||||
self.modify_ioctl = ioctl
|
||||
if self.verify_ioctl == -1:
|
||||
raise ValueError, "Not supported"
|
||||
|
||||
def cmd_select_openpgp(self):
|
||||
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
|
||||
response, sw1, sw2 = self.connection.transmit(apdu)
|
||||
if sw1 == 0x61: # More data
|
||||
response, sw1, sw2 = self.connection.transmit([0x00, 0xc0, 0, 0, sw2])
|
||||
elif not (sw1 == 0x90 and sw2 == 0x00):
|
||||
raise ValueError, ("cmd_select_openpgp %02x %02x" % (sw1, sw2))
|
||||
|
||||
def possibly_add_dummy_byte(self):
|
||||
if self.another_byte:
|
||||
return [ 0 ]
|
||||
else:
|
||||
return []
|
||||
|
||||
def cmd_verify_pinpad(self, who):
|
||||
apdu = [0x00, 0x20, 0x00, 0x80+who ]
|
||||
pin_verify = [ 0x00, # bTimeOut
|
||||
0x00, # bTimeOut2
|
||||
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
|
||||
0x00, # bmPINBlockString
|
||||
0x00, # bmPINLengthFormat
|
||||
self.pinmax, # wPINMaxExtraDigit Low (PINmax)
|
||||
self.pinmin, # wPINMaxExtraDigit High (PINmin)
|
||||
0x02, # bEntryValidationCondition
|
||||
0x01, # bNumberMessage
|
||||
0x00, # wLangId Low
|
||||
0x00, # wLangId High
|
||||
0x00, # bMsgIndex
|
||||
0x00, # bTeoPrologue[0]
|
||||
0x00, # bTeoPrologue[1]
|
||||
0x00 # bTeoPrologue[2]
|
||||
]
|
||||
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]
|
||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||
raise ValueError, ("cmd_verify_pinpad %02x %02x" % (sw1, sw2))
|
||||
|
||||
def send_modify_pinpad(self, apdu, single_step, command):
|
||||
if self.modify_ioctl == -1:
|
||||
raise ValueError, "Not supported"
|
||||
pin_modify = [ 0x00, # bTimerOut
|
||||
0x00, # bTimerOut2
|
||||
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
|
||||
0x00, # bmPINBlockString
|
||||
0x00, # bmPINLengthFormat
|
||||
0x00, # bInsertionOffsetOld
|
||||
0x00, # bInsertionOffsetNew
|
||||
self.pinmax, # wPINMaxExtraDigit Low (PINmax)
|
||||
self.pinmin, # wPINMaxExtraDigit High (PINmin)
|
||||
confirm_pin_setting(single_step),
|
||||
0x02, # bEntryValidationCondition
|
||||
0x03, # bNumberMessage
|
||||
0x00, # wLangId Low
|
||||
0x00, # wLangId High
|
||||
0x00, # bMsgIndex1
|
||||
0x01, # bMsgIndex2
|
||||
0x02, # bMsgIndex3
|
||||
0x00, # bTeoPrologue[0]
|
||||
0x00, # bTeoPrologue[1]
|
||||
0x00 # bTeoPrologue[2]
|
||||
]
|
||||
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")
|
||||
|
||||
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):
|
||||
apdu = [0x00, 0xda, 0x00, 0xd3]
|
||||
self.send_modify_pinpad(apdu, True, "cmd_put_resetcode_pinpad")
|
||||
|
||||
def cmd_change_reference_data_pinpad(self, who, is_exchange):
|
||||
if is_exchange:
|
||||
apdu = [0x00, 0x24, 1, 0x80+who]
|
||||
else:
|
||||
apdu = [0x00, 0x24, 0x00, 0x80+who]
|
||||
self.send_modify_pinpad(apdu, is_exchange,
|
||||
"cmd_change_reference_data_pinpad")
|
||||
|
||||
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()
|
||||
print "ATR:", toHexString( card.connection.getATR() )
|
||||
|
||||
card.get_features()
|
||||
|
||||
card.cmd_select_openpgp()
|
||||
if method == "verify":
|
||||
if who == BY_USER:
|
||||
print "Please input User's PIN"
|
||||
else:
|
||||
print "Please input Admin's PIN"
|
||||
card.cmd_verify_pinpad(who)
|
||||
elif method == "change":
|
||||
if change_by_two_steps:
|
||||
if who == BY_USER:
|
||||
print "Please input User's PIN"
|
||||
else:
|
||||
print "Please input Admin's PIN"
|
||||
card.cmd_verify_pinpad(who)
|
||||
if who == BY_USER:
|
||||
print "Please input New User's PIN twice"
|
||||
else:
|
||||
print "Please input New Admin's PIN twice"
|
||||
card.cmd_change_reference_data_pinpad(who, True)
|
||||
else:
|
||||
if who == BY_USER:
|
||||
print "Please input User's PIN"
|
||||
print "and New User's PIN twice"
|
||||
else:
|
||||
print "Please input Admin's PIN"
|
||||
print "and New Admin's PIN twice"
|
||||
card.cmd_change_reference_data_pinpad(who, False)
|
||||
elif method == "unblock":
|
||||
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"
|
||||
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()
|
||||
|
||||
print "OK."
|
||||
return 0
|
||||
|
||||
def print_usage():
|
||||
print "pinpad-test: testing pinentry of PC/SC card reader"
|
||||
print " help:"
|
||||
print "\t--help:\t\tthis message"
|
||||
print " method:\t\t\t\t\t\t\t[verify]"
|
||||
print "\t--verify:\tverify PIN"
|
||||
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 "
|
||||
print " $ pinpad-test --admin # verify admin's PIN "
|
||||
print " $ pinpad-test --change # change user's PIN "
|
||||
print " $ pinpad-test --change --admin # change admin's PIN "
|
||||
print " $ pinpad-test --change2 # change user's PIN by two steps"
|
||||
print " $ pinpad-test --change2 --admin # change admin's PIN by two steps"
|
||||
print " $ pinpad-test --unblock # change user's PIN by reset code"
|
||||
print " $ pinpad-test --unblock --admin # change user's PIN by admin's PIN"
|
||||
print " $ pinpad-test --put # setup resetcode "
|
||||
|
||||
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:
|
||||
option = sys.argv[1]
|
||||
sys.argv.pop(1)
|
||||
if option == '--admin':
|
||||
who = BY_ADMIN
|
||||
elif option == '--change':
|
||||
method = "change"
|
||||
elif option == '--change2':
|
||||
method = "change"
|
||||
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':
|
||||
print_usage()
|
||||
exit(0)
|
||||
else:
|
||||
raise ValueError, option
|
||||
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
|
||||
Reference in New Issue
Block a user