Compare commits

...

102 Commits

Author SHA1 Message Date
NIIBE Yutaka
48d89973c6 fixed long standing bug of ZLP 2011-12-28 12:27:16 +09:00
NIIBE Yutaka
60c1fe47ce fix pinpad-test.py 2011-12-27 14:10:39 +09:00
NIIBE Yutaka
c53afe1f96 fix pinpad-test.py 2011-12-27 10:34:24 +09:00
NIIBE Yutaka
3074058ff7 more fix to CERTDO_SUPPORT 2011-12-22 17:10:41 +09:00
NIIBE Yutaka
a0c8cf2ff4 Data Object 0x7f21 is now optional 2011-12-21 14:14:28 +09:00
NIIBE Yutaka
c0ab2ae830 DnDpinentry: cancellation 2011-12-20 10:39:47 +09:00
NIIBE Yutaka
a08669dfcd add messages to pinpad-test.py 2011-12-19 12:28:01 +09:00
NIIBE Yutaka
4a75aa47df improve pinpad-test.py 2011-12-19 12:17:22 +09:00
NIIBE Yutaka
1145fe0ad8 add new tool pinpad-test.py 2011-12-16 16:42:09 +09:00
NIIBE Yutaka
e2a4be1444 version 0.16 2011-12-14 12:51:26 +09:00
NIIBE Yutaka
b4d36a429f Fixes for PINPAD_SUPPORT 2011-12-14 12:45:20 +09:00
NIIBE Yutaka
a955cbec2f doc changes 2011-12-13 14:25:07 +09:00
NIIBE Yutaka
828b8f5768 merge dnd-support branch
fix vcom, change volume label
2011-12-13 13:29:23 +09:00
NIIBE Yutaka
d9be456fed fix 2011-12-13 11:26:12 +09:00
NIIBE Yutaka
5a9194d136 working now 2011-12-13 11:26:12 +09:00
NIIBE Yutaka
f58233aa5d more 2011-12-13 11:26:12 +09:00
NIIBE Yutaka
ec409fe8a4 rename 2011-12-13 11:26:12 +09:00
NIIBE Yutaka
231c50d9b5 cleanup 2011-12-13 11:26:11 +09:00
NIIBE Yutaka
696de23b52 usb mass storage class 2011-12-13 11:26:11 +09:00
NIIBE Yutaka
b113e6fa7b verify_other should not fail with no keys, but really checks PW1 2011-12-13 11:21:45 +09:00
NIIBE Yutaka
9dcb59f6aa minor cleanup 2011-12-08 10:56:48 +09:00
NIIBE Yutaka
351ce68729 better USB interoperability 2011-12-07 10:16:02 +09:00
NIIBE Yutaka
142dbabfd8 pinpad entry parameter handling 2011-12-07 09:38:48 +09:00
NIIBE Yutaka
1e94b262af pinpad support change 2011-12-01 18:23:10 +09:00
NIIBE Yutaka
268c41634a pinpad input for reset code 2011-11-29 15:18:25 +09:00
NIIBE Yutaka
bc71c39ea4 version 0.15 2011-11-24 15:40:38 +09:00
NIIBE Yutaka
0232c0a595 dfuse.py: fix handling of unaligned page 2011-11-24 13:54:12 +09:00
NIIBE Yutaka
62520ed0f4 tool/dfuse.py: support unaligned write and hole 2011-11-22 16:17:37 +09:00
NIIBE Yutaka
2c91633f59 add FST-01 description 2011-11-14 14:34:51 +09:00
NIIBE Yutaka
1ac7e20fb0 add FST_01 2011-11-14 14:22:37 +09:00
NIIBE Yutaka
e790bb783c change README and NEWS 2011-11-01 15:58:48 +09:00
NIIBE Yutaka
f45b7a5439 minor change for pin-cir.c 2011-11-01 15:13:58 +09:00
NIIBE Yutaka
6337371016 PIN input DIAL support change 2011-11-01 15:01:32 +09:00
NIIBE Yutaka
ed7e904aef PIN input CIR support change 2011-11-01 14:57:11 +09:00
NIIBE Yutaka
de39c484d0 support FST-01 8MHz 2011-11-01 11:41:20 +09:00
NIIBE Yutaka
ec7a2db43a cosmetic fix of src/ac.c 2011-11-01 11:39:47 +09:00
NIIBE Yutaka
f3a3808608 merge call-rsa.c change in the branch of rsa_1024_support. 2011-11-01 11:21:25 +09:00
NIIBE Yutaka
b2856d162e added more DEBUG_XX 2011-11-01 11:02:22 +09:00
NIIBE Yutaka
447139f74d fixed the bug for user who keeps using initial PW1 2011-11-01 11:01:16 +09:00
NIIBE Yutaka
683253b2eb workaround for GCC (summon-arm-toolchain) 2011-11-01 10:59:44 +09:00
NIIBE Yutaka
4749062338 increase (decreased) main (interrupt) stack size 2011-10-14 15:50:08 +09:00
NIIBE Yutaka
2181c1a428 version 0.14 2011-10-07 11:01:21 +09:00
NIIBE Yutaka
48f552b69b random_bits are not needed any more 2011-10-06 17:02:37 +09:00
NIIBE Yutaka
6aca64b664 cleanup 2011-10-06 16:58:20 +09:00
NIIBE Yutaka
3ec2df97b9 add missing neug.h 2011-10-06 16:57:28 +09:00
NIIBE Yutaka
94f2c25c3b NeuG integrated 2011-10-06 16:56:08 +09:00
NIIBE Yutaka
b1bb1354f8 Change for NeuG RNG 2011-10-06 11:23:49 +09:00
NIIBE Yutaka
1ef7813a53 add neug.c from NeuG/src/random.c 2011-10-06 11:22:51 +09:00
NIIBE Yutaka
9528867c2a minor boards fixes 2011-07-22 15:48:00 +09:00
NIIBE Yutaka
241f62238d add fix of Chibios 2011-07-04 15:57:05 +09:00
NIIBE Yutaka
dee75314fc adc macro rename patch (external) 2011-07-04 10:05:56 +09:00
NIIBE Yutaka
8bf1019df7 version 0.13 2011-06-15 08:52:02 +09:00
NIIBE Yutaka
e0b70894db more rsa tweak 2011-06-08 15:18:27 +09:00
NIIBE Yutaka
8c930952f2 more performance tweak 2011-05-31 10:17:38 +09:00
NIIBE Yutaka
09748fc046 bug fixes 2011-05-27 16:08:16 +09:00
NIIBE Yutaka
450807e8bf more rsa improvement 2011-05-27 11:11:41 +09:00
NIIBE Yutaka
ede8bdc2c0 rsa improvement 2011-05-26 12:04:45 +09:00
NIIBE Yutaka
4e1126f88c add tool/hub_ctrl.py, this is convenient for development if you have hub with the feature 2011-05-25 15:17:36 +09:00
NIIBE Yutaka
c620b73202 flash_unlock at the beginning 2011-05-16 10:14:09 +09:00
NIIBE Yutaka
2d07cd6f0d API change 2011-05-16 10:05:17 +09:00
NIIBE Yutaka
c254c9d558 version 0.12 2011-05-13 11:59:05 +09:00
NIIBE Yutaka
b146a8aa6d fix comments 2011-05-12 18:06:02 +09:00
NIIBE Yutaka
c04e5d816c fix condition of ac_check_status 2011-05-12 18:05:39 +09:00
NIIBE Yutaka
82fc1c7e93 fix dfuse.py 2011-05-12 14:01:03 +09:00
NIIBE Yutaka
0f4fac869c added gnuk.h fix 2011-05-12 11:22:08 +09:00
NIIBE Yutaka
112a9f51c2 -p option for gnuk_put_binary.py 2011-05-12 11:06:20 +09:00
NIIBE Yutaka
96de962cfc buf fix of password change 2011-05-12 11:04:14 +09:00
NIIBE Yutaka
c196992c76 modify random 2011-05-12 09:27:26 +09:00
NIIBE Yutaka
571e7af387 pw err counter fix 2011-05-12 08:42:57 +09:00
NIIBE Yutaka
74b21d307c VERIFY bug fixes 2011-05-11 23:33:38 +09:00
NIIBE Yutaka
d5e2950f46 bug fix of kdi size 2011-05-11 17:42:32 +09:00
NIIBE Yutaka
f20f05df8d openocd scripts 2011-05-11 16:49:52 +09:00
NIIBE Yutaka
58d9f554d1 pyscard version of put_binary 2011-05-11 16:49:22 +09:00
NIIBE Yutaka
fdaee50acb update NEWS and README 2011-05-11 16:48:08 +09:00
NIIBE Yutaka
995961a593 fix serial number initialization 2011-05-11 16:47:26 +09:00
NIIBE Yutaka
2fbdeb8d89 Revert change of usb-icc.c 2011-05-11 16:46:21 +09:00
NIIBE Yutaka
189f17c93c rename tool/gnuk_put_binary._libusb.py 2011-05-11 12:55:58 +09:00
NIIBE Yutaka
a32381c815 rename tool/gnuk_put_binary._libusb.py 2011-05-11 12:55:14 +09:00
NIIBE Yutaka
f62253e63f added FAQ section 2011-05-11 11:50:00 +09:00
NIIBE Yutaka
93a7515bcd serial number handling by ROM 2011-05-11 10:56:36 +09:00
NIIBE Yutaka
661c8e63dc save memory (5): header file 2011-05-11 09:44:43 +09:00
NIIBE Yutaka
0b5f579510 save memory (4) 2011-05-11 09:34:22 +09:00
NIIBE Yutaka
582612ddc7 save memory (3) 2011-05-11 09:31:16 +09:00
NIIBE Yutaka
0ef47be2da save memory (2) 2011-05-11 09:29:18 +09:00
NIIBE Yutaka
af1067688e save memory (1) 2011-05-11 09:27:49 +09:00
NIIBE Yutaka
782b41f47c doc fix 2011-05-10 15:50:53 +09:00
NIIBE Yutaka
8e765327b2 fixes 2011-05-10 15:13:15 +09:00
NIIBE Yutaka
96dc883954 cosmetic change 2011-05-10 10:11:46 +09:00
NIIBE Yutaka
fdbeb8c84d added missing entry of 0.11 2011-05-10 09:30:55 +09:00
NIIBE Yutaka
6c5ee62d61 API rename for password counters 2011-05-10 09:30:09 +09:00
NIIBE Yutaka
f58d639440 Bug fixes 2011-05-10 09:17:38 +09:00
NIIBE Yutaka
79c9ad9fd4 Prevent observation of PW3 emptiness 2011-05-10 09:11:40 +09:00
NIIBE Yutaka
a9ea672cf3 modify stickers 2011-04-21 11:04:52 +09:00
NIIBE Yutaka
05a8fa7951 fix sticker 2011-04-20 17:00:36 +09:00
NIIBE Yutaka
de4ff17bc9 added stickers 2011-04-20 14:40:32 +09:00
NIIBE Yutaka
9ca92ad02a change the horn of gnuk.svg 2011-04-20 10:03:54 +09:00
NIIBE Yutaka
4f2f93d806 change the color of gnuk.svg 2011-04-20 08:42:30 +09:00
NIIBE Yutaka
b08651f86b more gnuk.svg 2011-04-19 18:22:17 +09:00
NIIBE Yutaka
57fb94e900 gnuk.svg: improve a bit 2011-04-18 22:46:53 +09:00
NIIBE Yutaka
96a6e80eb0 merge 2011-04-18 22:20:41 +09:00
NIIBE Yutaka
6c79434549 Cleanup logo 2011-04-18 17:50:04 +09:00
NIIBE Yutaka
81368495d7 fix a bug of dfuse.py 2011-04-10 21:28:03 +09:00
66 changed files with 6601 additions and 1319 deletions

15
AUTHORS
View File

@@ -6,6 +6,14 @@ Kaz Kojima:
NIIBE Yutaka: NIIBE Yutaka:
Founder of the project. 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: Added STBee support:
boards/STBEE/board.c boards/STBEE/board.c
boards/STBEE/board.h boards/STBEE/board.h
@@ -28,6 +36,9 @@ NIIBE Yutaka:
tool/intel_hex.py tool/intel_hex.py
Wrote a tool for Gnuk: Wrote a tool for Gnuk:
tool/gnuk_put_binary.py tool/gnuk_put_binary.py
tool/gnuk_put_binary_libusb.py
Wrote a tool for USB Hub:
tool/hub_ctrl.py
Wrote: Wrote:
gnuk.svg gnuk.svg
src/configure src/configure
@@ -49,5 +60,9 @@ NIIBE Yutaka:
src/random.c src/random.c
src/pin-cir.c src/pin-cir.c
src/pin-dial.c src/pin-dial.c
src/pin-dnd.c
src/usb_msc.c
src/usb_msc.h
src/neug.c
* *
and others. and others.

378
ChangeLog
View File

@@ -1,3 +1,381 @@
2011-12-28 Niibe Yutaka <gniibe@fsij.org>
* 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.
* src/usb_desc.c (gnukStringSerial): Updated.
2011-11-22 Niibe Yutaka <gniibe@fsij.org>
* tool/dfuse.py (DFU_STM32.download, DFU_STM32.verify): Support
unaligned write and hole.
2011-11-14 Niibe Yutaka <gniibe@fsij.org>
* boards/FST_01/{mcuconf.h,board.h,board.c}: New.
2011-11-01 Niibe Yutaka <gniibe@fsij.org>
* src/pin-dial.c (pinpad_getline): New.
(pin_main): Remove.
* boards/STBEE_MINI/board.h (TIMx): Define.
boards/STBEE/board.h (TIMx): Ditto.
boards/STM8S_DISCOVERY/board.h: Ditto.
* src/pin-cir.c (pinpad_getline): New.
(cir_timer_interrupt, cir_ext_interrupt): Use TIMx.
(cir_key_is_backspace, cir_key_is_enter, pin_main, pindisp):
Remove.
(cir_codetable_dell_mr425, cir_codetable_aquos)
(cir_codetable_regza, cir_codetable_bravia, ch_is_backspace)
(ch_is_enter, find_char_codetable, hex, cir_getchar): New.
(cir_timer_interrupt): Don't filter out ADDRESS.
* src/openpgp.c (get_pinpad_input): Don't invoke thread,
but just call pinpad_getline.
* src/main.c (display_interaction, display_fatal_code)
(display_status_code, led_blink): New.
(main): Call display_* routine.
(fatal): Notify main thread.
* src/usb_prop.c (gnuk_device_SetConfiguration): Notify main
thread.
* src/pin-cir.c (pindisp): Remove.
* boards/FST_01_00: New (for 8MHz FST-01).
* src/ac.c (calc_md): Fix comparison.
* src/call-rsa.c (RSA_SIGNATURE_LENGTH): Use KEY_CONTENT_LEN.
(rsa_sign, rsa_decrypt): Likewise.
(modulus_calc): Don't assume it's 2048-bit.
* src/ac.c (verify_user_0): Fix for non-initialized PW1.
* src/Makefile.in (MCFLAGS): Override MCFLAGS option for newer
GCC of summon-arm-toolchain to add -mfix-cortex-m3-ldrd.
NOTE: This should not be needed (as -mcpu=cortex-m3 defaults
to -mfix-cortex-m3-ldrd for GCC-proper), but it is needed
to select arm-none-eabi/lib/thumb2/libc.a correctly.
2011-10-14 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.ld.in (__main_stack_size__): It's 1KB (was 512 byte).
2011-10-07 NIIBE Yutaka <gniibe@fsij.org>
* Version 0.14.
* src/usb_desc.c (gnukStringSerial): Updated.
* src/random.c (random_init): Call neug_prng_reseed.
2011-10-06 NIIBE Yutaka <gniibe@fsij.org>
* src/Makefile.in (random_bits): Remove.
* src/openpgp.c (GPGthread): Remove unused event message.
* src/main.c (main): Call random_init.
* src/gnuk.ld.in (__process_stack_size__): Fix.
(.gnuk_random): Removed.
* src/flash.c (flash_erase_binary, flash_write_binary): Remove
support of random_byte in flash ROM.
* src/neug.c (adccb): Use old API (was: chEvtSignalFlagsI).
(adccb_err): Remove.
(rng_gen, rng): Add the last argument adccb for adcStartConversion:
This is old API of ADC driver.
(adcgrpcfg): Remove callbacks, add CONT and SWSTART: This is old
API of ADC driver.
(adccb): Remove the first argument: This is old API of ADC driver.
(neug_wait_full): New.
* ChibiOS_2.0.8/os/hal/platforms/STM32/adc_lld.h (ADC_SAMPLE_1P5):
Add (from new API).
* src/random.c (random_init): New.
(random_bytes_get, random_bytes_free, get_salt): Use NeuG.
* src/Makefile.in (CSRC): Add neug.c.
* src/neug.c: New. Verbatim copy of NeuG/src/random.c.
* boards/common/mcuconf-common.h (USE_STM32_ADC1): TRUE for NewG RNG.
* src/chconf.h (CH_USE_SEMAPHORES): TRUE as ADC driver requires it.
* src/halconf.h (CH_HAL_USE_ADC); TRUE for NewG RNG.
2011-07-22 NIIBE Yutaka <gniibe@fsij.org>
* boards/OLIMEX_STM32_H103/board.h (BOARD_NAME): Fixed.
* boards/STBEE_MINI/mcuconf.h: Added missing include of
mcuconf-common.h.
2011-07-04 NIIBE Yutaka <gniibe@fsij.org>
* ChibiOS_2.0.8/os/ports/GCC/ARMCMx/chcore_v7m.c
(_port_irq_epilogue, _port_switch_from_isr): Apply a patch of 2.2.6.
* ChibiOS_2.0.8/os/hal/platforms/STM32/adc_lld.h: Apply a patch of
ADC from the branch of ChibiOS_2.0.X.
2011-06-15 NIIBE Yutaka <gniibe@fsij.org>
* Version 0.13.
* src/usb_desc.c (gnukStringSerial): Updated.
2011-06-08 NIIBE Yutaka <gniibe@fsij.org>
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
(MULADDC_1024_CORE, MULADDC_1024_LOOP): New.
* polarssl-0.14.0/library/bignum.c (mpi_mul_hlp): Use
MULADDC_1024_LOOP.
2011-05-31 NIIBE Yutaka <gniibe@fsij.org>
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
(MULADDC_HUIT, MULADDC_INIT, MULADDC_CORE, MULADDC_STOP): Tweak.
2011-05-27 NIIBE Yutaka <gniibe@fsij.org>
* tool/gnuk_put_binary.py (main): Confirm Serial ID is written
correctly.
* src/openpgp.c (cmd_write_binary): Fix FILE_EF_SERIAL comparison.
* src/gnuk.ld.in (.gnuk_random, .gnuk_ch_certificate): Put LONG to
have CONTENTS.
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
(MULADDC_HUIT): New.
2011-05-26 NIIBE Yutaka <gniibe@fsij.org>
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
(MULADDC_INIT): Add ADDS instruction to clear of carry flag.
(MULADDC_CORE): Tune to 6 instructions and less registers.
(MULADDC_STOP): Add ADC instruction to save carry flag.
2011-05-25 NIIBE Yutaka <gniibe@fsij.org>
* tool/hub_ctrl.py: New. Port of original C implementation.
2011-05-16 NIIBE Yutaka <gniibe@fsij.org>
* src/main.c (main): Call flash_unlock at the beginning.
(device_initialize_once): Don't call flash_unlock here.
* src/flash.c (flash_init): Likewise.
* src/openpgp.c (cmd_select_file): Don't use write_res_apdu.
(set_res_apdu): Rename from write_res_apdu. Just SW1 and SW2.
2011-05-13 NIIBE Yutaka <gniibe@fsij.org>
* Version 0.12.
2011-05-12 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_pso, cmd_internal_authenticate)
(cmd_update_binary, cmd_write_binary): Don't check pw locked.
* tool/dfuse.py (DFU_STM32.verify): Add missing colon.
* tool/dfuse.py (get_device): Restrict to STMicro DfuSe.
* tool/gnuk_put_binary.py (main): Add -p option to enter password.
* src/ac.c (verify_user_0): New.
(verify_pso_cds, verify_admin_0): Use verify_user_0.
* src/openpgp.c (cmd_change_password): Use verify_user_0.
* src/random.c (get_salt): Rename from get_random.
(random_bytes_get, random_bytes_free): It's 16-byte.
* src/ac.c (verify_admin_0): Use PW_ERR_PW1 counter when
authenticated by PW1.
2011-05-11 NIIBE Yutaka <gniibe@fsij.org>
* src/ac.c (verify_pso_cds, verify_other): Fail (with no counter
update) if key is not registered yet.
(verify_admin_0): Compare to OPENPGP_CARD_INITIAL_PW3 when empty
PW3 and non-empty PW1 but signing key is not registered yet.
* tool/gnuk_put_binary.py: New implementation by pyscard.
* src/main.c (device_initialize_once): New.
* src/usb_prop.c (gnukStringSerial): Move to...
* src/usb_desc.c (gnukStringSerial): here. Bump version to 0.12.
Fill by 0xff.
* src/usb_prop.c (gnuk_device_init)
(gnuk_device_GetStringDescriptor): Don't use RAM for
gnukStringSerial, use ROM like other string descriptor.
* src/usb_desc.c (String_Descriptor): Add gnukStringSerial.
* src/openpgp-do.c (gpg_get_pw1_lifetime): Make static.
(gpg_do_load_prvkey, gpg_do_write_prvkey): Use kdi.
(gpg_increment_digital_signature_counter): Call gpg_get_pw1_lifetime.
* src/openpgp.c (cmd_pso): Follow the change.
* src/flash.c (keystore_pool): Remove. Use &_keystore_pool.
* src/ac.c (auth_status): Don't assign 0 as it's automatically
cleared.
2011-05-10 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (gpg_pw_locked): Rename from gpg_passwd_locked.
(gpg_pw_get_err_counter): Rename from gpg_get_pw_err_counter.
(gpg_pw_reset_err_counter): Rename from gpg_reset_pw_err_counter.
(gpg_pw_increment_err_counter): Rename from gpg_increment_err_counter.
* src/ac.c, src/openpgp.c, src/gnuk.h: Follow the change.
Bug fixes.
* src/openpgp.c (cmd_reset_user_password, cmd_change_password)
* src/openpgp-do.c (proc_resetting_code): Fix check of return value.
* src/ac.c (ac_fini): Clear keystring_md_pw3.
Prevent observation of PW3 is emptiness by PW3's error counter.
Support verify_admin by PW1 when PW3 is empty.
* src/ac.c (admin_authorized): New.
(verify_admin_0): Set admin_authorized.
* src/openpgp-do.c (proc_resetting_code): Use admin_authorized.
(gpg_do_write_prvkey): Clear dek_encrypted_3 when keystring_admin
is NULL.
(proc_key_import): Checking admin_authorized, set keystring_admin.
* src/openpgp.c (cmd_reset_user_password): Use admin_authorized.
2011-04-18 NIIBE Yutaka <gniibe@fsij.org>
* gnuk.svg: Updated.
2011-04-15 NIIBE Yutaka <gniibe@fsij.org> 2011-04-15 NIIBE Yutaka <gniibe@fsij.org>
* Version 0.11. * Version 0.11.

View File

@@ -62,6 +62,20 @@
#define ADC_CHANNEL_SENSOR 16 /**< @brief Internal temperature sensor.*/ #define ADC_CHANNEL_SENSOR 16 /**< @brief Internal temperature sensor.*/
#define ADC_CHANNEL_VREFINT 17 /**< @brief Internal reference. */ #define ADC_CHANNEL_VREFINT 17 /**< @brief Internal reference. */
/**
* @name Sampling rates
* @{
*/
#define ADC_SAMPLE_1P5 0 /**< @brief 1.5 cycles sampling time. */
#define ADC_SAMPLE_7P5 1 /**< @brief 7.5 cycles sampling time. */
#define ADC_SAMPLE_13P5 2 /**< @brief 13.5 cycles sampling time. */
#define ADC_SAMPLE_28P5 3 /**< @brief 28.5 cycles sampling time. */
#define ADC_SAMPLE_41P5 4 /**< @brief 41.5 cycles sampling time. */
#define ADC_SAMPLE_55P5 5 /**< @brief 55.5 cycles sampling time. */
#define ADC_SAMPLE_71P5 6 /**< @brief 71.5 cycles sampling time. */
#define ADC_SAMPLE_239P5 7 /**< @brief 239.5 cycles sampling time. */
/** @} */
/*===========================================================================*/ /*===========================================================================*/
/* Driver pre-compile time settings. */ /* Driver pre-compile time settings. */
/*===========================================================================*/ /*===========================================================================*/
@@ -238,26 +252,51 @@ typedef struct {
/* Driver macros. */ /* Driver macros. */
/*===========================================================================*/ /*===========================================================================*/
/**
* @brief Number of channels in a conversion sequence.
*/
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20) #define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
#define ADC_SQR3_SQ0_N(n) ((n) << 0) #define ADC_SQR3_SQ1_N(n) ((n) << 0) /**< @brief 1st channel in seq. */
#define ADC_SQR3_SQ1_N(n) ((n) << 5) #define ADC_SQR3_SQ2_N(n) ((n) << 5) /**< @brief 2nd channel in seq. */
#define ADC_SQR3_SQ2_N(n) ((n) << 10) #define ADC_SQR3_SQ3_N(n) ((n) << 10) /**< @brief 3rd channel in seq. */
#define ADC_SQR3_SQ3_N(n) ((n) << 15) #define ADC_SQR3_SQ4_N(n) ((n) << 15) /**< @brief 4th channel in seq. */
#define ADC_SQR3_SQ4_N(n) ((n) << 20) #define ADC_SQR3_SQ5_N(n) ((n) << 20) /**< @brief 5th channel in seq. */
#define ADC_SQR3_SQ5_N(n) ((n) << 25) #define ADC_SQR3_SQ6_N(n) ((n) << 25) /**< @brief 6th channel in seq. */
#define ADC_SQR2_SQ6_N(n) ((n) << 0) #define ADC_SQR2_SQ7_N(n) ((n) << 0) /**< @brief 7th channel in seq. */
#define ADC_SQR2_SQ7_N(n) ((n) << 5) #define ADC_SQR2_SQ8_N(n) ((n) << 5) /**< @brief 8th channel in seq. */
#define ADC_SQR2_SQ8_N(n) ((n) << 10) #define ADC_SQR2_SQ9_N(n) ((n) << 10) /**< @brief 9th channel in seq. */
#define ADC_SQR2_SQ9_N(n) ((n) << 15) #define ADC_SQR2_SQ10_N(n) ((n) << 15) /**< @brief 10th channel in seq.*/
#define ADC_SQR2_SQ10_N(n) ((n) << 20) #define ADC_SQR2_SQ11_N(n) ((n) << 20) /**< @brief 11th channel in seq.*/
#define ADC_SQR2_SQ11_N(n) ((n) << 25) #define ADC_SQR2_SQ12_N(n) ((n) << 25) /**< @brief 12th channel in seq.*/
#define ADC_SQR1_SQ13_N(n) ((n) << 0) #define ADC_SQR1_SQ13_N(n) ((n) << 0) /**< @brief 13th channel in seq.*/
#define ADC_SQR1_SQ14_N(n) ((n) << 5) #define ADC_SQR1_SQ14_N(n) ((n) << 5) /**< @brief 14th channel in seq.*/
#define ADC_SQR1_SQ15_N(n) ((n) << 10) #define ADC_SQR1_SQ15_N(n) ((n) << 10) /**< @brief 15th channel in seq.*/
#define ADC_SQR1_SQ16_N(n) ((n) << 15) #define ADC_SQR1_SQ16_N(n) ((n) << 15) /**< @brief 16th channel in seq.*/
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0) /**< @brief AN0 sampling time. */
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3) /**< @brief AN1 sampling time. */
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6) /**< @brief AN2 sampling time. */
#define ADC_SMPR2_SMP_AN3(n) ((n) << 9) /**< @brief AN3 sampling time. */
#define ADC_SMPR2_SMP_AN4(n) ((n) << 12) /**< @brief AN4 sampling time. */
#define ADC_SMPR2_SMP_AN5(n) ((n) << 15) /**< @brief AN5 sampling time. */
#define ADC_SMPR2_SMP_AN6(n) ((n) << 18) /**< @brief AN6 sampling time. */
#define ADC_SMPR2_SMP_AN7(n) ((n) << 21) /**< @brief AN7 sampling time. */
#define ADC_SMPR2_SMP_AN8(n) ((n) << 24) /**< @brief AN8 sampling time. */
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27) /**< @brief AN9 sampling time. */
#define ADC_SMPR1_SMP_AN10(n) ((n) << 0) /**< @brief AN10 sampling time. */
#define ADC_SMPR1_SMP_AN11(n) ((n) << 3) /**< @brief AN11 sampling time. */
#define ADC_SMPR1_SMP_AN12(n) ((n) << 6) /**< @brief AN12 sampling time. */
#define ADC_SMPR1_SMP_AN13(n) ((n) << 9) /**< @brief AN13 sampling time. */
#define ADC_SMPR1_SMP_AN14(n) ((n) << 12) /**< @brief AN14 sampling time. */
#define ADC_SMPR1_SMP_AN15(n) ((n) << 15) /**< @brief AN15 sampling time. */
#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18) /**< @brief Temperature Sensor
sampling time. */
#define ADC_SMPR1_SMP_VREF(n) ((n) << 21) /**< @brief Voltage Reference
sampling time. */
/*===========================================================================*/ /*===========================================================================*/
/* External declarations. */ /* External declarations. */

View File

@@ -107,12 +107,12 @@ void SVCallVector(void) {
} }
/** /**
* @brief Reschedule verification and setup after an IRQ. * @brief Exception exit redirection to _port_switch_from_isr().
*/ */
void _port_irq_epilogue(void) { void _port_irq_epilogue(void) {
port_lock_from_isr(); port_lock_from_isr();
if ((SCB_ICSR & ICSR_RETTOBASE) && chSchIsRescRequiredExI()) { if ((SCB_ICSR & ICSR_RETTOBASE)) {
register struct extctx *ctxp; register struct extctx *ctxp;
/* Adding an artificial exception return context, there is no need to /* Adding an artificial exception return context, there is no need to
@@ -126,7 +126,6 @@ void _port_irq_epilogue(void) {
order to keep the rest of the context switching atomic.*/ order to keep the rest of the context switching atomic.*/
return; return;
} }
/* ISR exit without context switching.*/
port_unlock_from_isr(); port_unlock_from_isr();
} }
@@ -139,7 +138,8 @@ __attribute__((naked))
#endif #endif
void _port_switch_from_isr(void) { void _port_switch_from_isr(void) {
chSchDoRescheduleI(); if (chSchIsRescRequiredExI())
chSchDoRescheduleI();
asm volatile ("svc #0"); asm volatile ("svc #0");
} }

BIN
FSIJ-s.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

145
NEWS
View File

@@ -1,5 +1,150 @@
Gnuk NEWS - User visible changes Gnuk NEWS - User visible changes
* Major changes in Gnuk 0.17
Released 2012-01-XX, by NIIBE Yutaka
** USB CCID/ICCD low level bug is fixed
When the size of command APDU data is just 49, the lower level packet
size is 64. This is maximum size of BULK-OUT transfer packet, and
caused trouble in the past implementations. Example is setting url
(0x5f50) as: http://www.gniibe.org/adpu-string-size-is-just-49
This is because the past implementations expect ZLP (zero size
packet). Now, it has been fixed. You can use any size.
** 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: pinpad-test.py
The tool pinpad-test.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
** New targets: FST_01 and FST_01_00
Flying Stone Technology's open hardware, Flying Stone Tiny 01 is
supported.
** Flash writing tool for "DfuSe" is improved
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.
Note that only four controllers (of Dell, Sharp, Sony, and Toshiba)
are supported and tested.
** It is possible for users to keep using OPENPGP_CARD_INITIAL_PW1
With a bug fix of verify_user_0, it's now possible. Although it's not
recommended.
** Important bug fix and a workaround
In version 0.14, __main_stack_size__ (for interrupt handler) was too
small for some cases. This is fixed in 0.15.
In src/Makefile.in, added -mfix-cortex-m3-ldrd for correctly linking C
library for thumb2. This is needed for newer summon-arm-toolchain.
* Major changes in Gnuk 0.14
Released 2011-10-07, by NIIBE Yutaka
** Random number generator change
NeuG, Gniibe's True RNG implementation for STM32F103, has been
integrated to Gnuk. It is not needed to put random number bytes
(generated by host) to Token any more.
* Major changes in Gnuk 0.13
Released 2011-06-15, by NIIBE Yutaka
** Improved RSA routine.
About 20% speed improvement.
** New tool: hub_ctrl.
It is a Python implementation ported from original C implementation.
It is useful for development of USB target if you have a good hub.
You can power off/on the port to reset Gnuk Token.
* Major changes in Gnuk 0.12
Released 2011-05-13, by NIIBE Yutaka
** Admin-less mode is supported.
The OpenPGP card specification assumes existence of a security officer
(admin), who has privilege to manage the card. On the other hand,
many use cases of Gnuk are admin == user.
Thus, Gnuk now supports "admin-less" mode. In this mode, user can get
privilege with the password of PW1.
At the initialization of the card, Gnuk becomes compatible mode by
setting PW3. Without setting PW3, it becomes "admin-less" mode
by setting PW1.
** Important two bug fixes.
Gnuk (<= 0.11) has a bug which makes possible for attacker to change
user password to unknown state without knowing original password (when
no keys are loaded yet). No, attacker could not steal your identity
(cannot sign or decrypt), but it would be possible to disturb you.
Gnuk (<= 0.11) has a bug which makes possible for attacker to guess
admin password easily. When admin password is not set (the default
value of factory setting), failure of VERIFY doesn't increment error
counter in older versions. Observing no increment of error counter,
attacker could know that admin password is the one of factory setting.
** tool/gnuk_put_binary.py now uses pyscard.
Instead of PyUSB, it uses Python binding of PC/SC. PyUSB version is
still available as tool/gnuk_put_binary_libusb.py.
** Logo for Gnuk is updated.
** Gnuk Sticker SVG is available.
* Major changes in Gnuk 0.11
Released 2011-04-15, by NIIBE Yutaka
This is bug fixes only release.
* Major changes in Gnuk 0.10 * Major changes in Gnuk 0.10
Released 2011-02-10, by NIIBE Yutaka Released 2011-02-10, by NIIBE Yutaka

293
README
View File

@@ -1,7 +1,7 @@
Gnuk - software for GPG USB Token Gnuk - software for GnuPG USB Token
Version 0.11 Version 0.16
2011-04-15 2011-12-14
Niibe Yutaka Niibe Yutaka
Free Software Initiative of Japan 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 is software implementation of a USB token for GNU Privacy Guard.
Gnuk supports OpenPGP card protocol version 2, and it runs on STM32 Gnuk supports OpenPGP card protocol version 2, and it runs on
processor. STM32F103 processor.
I wish that Gnuk will be a developer's soother who uses GnuPG. I have 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. been nervous of storing secret key(s) on usual secondary storage.
@@ -19,45 +19,113 @@ me to bring a card reader all the time. With Gnuk, this issue will be
solved by a USB token which is small enough. solved by a USB token which is small enough.
Please look at the graphics of "gnuk.svg" for the software name. My Please look at the graphics of "gnuk.svg" for the software name. My
son used to be with his NUK(R), always, everywhere. I will be with a son used to be with his NUK(R), always, everywhere. I am with a USB
USB Token by Gnuk everywhere. Token by "Gnuk", always, everywhere.
FAQ
===
Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
card 2.0, GPF Crypto Stick, etc.) ?
http://www.g10code.de/p-card.html
http://www.privacyfoundation.de/crypto_stick/
A0: IMRHO, not quite. There is no ready-to-use out-of-box product.
(It is welcome for me that some vendor will manufacture Gnuk USB
Token. Even I can help design of hardware, if needed.)
Good points are:
* If you have skill of electronics and like DIY, you can build
Gnuk Token cheaper (see Q8-A8).
* You can study Gnuk to modify and to enhance. For example, you
can implement your own authentication method with some sensor
such as acceleration sensor.
* It is "of Free Software"; Gnuk is distributed under GPLv3+,
"by Free Software"; Gnuk development requires only Free Software
(GNU Toolchain, Python, etc.),
"for Free Software"; Gnuk supports GnuPG.
Q1: What kind of key algorithm is supported?
A1: Gnuk only supports 2048-bit RSA.
Q2: How long does it take for digital signing?
A2: It takes a second and a half or so.
Q3: What's your recommendation for target board?
A3: Orthodox choice is Olimex STM32-H103.
If you have skill of electronics and like DIY, STM32 part of STM8S
Discovery Kit might be the best choice.
Currently FST-01 (Flying Stone Tiny 01) is under development,
it will be the best choice, hopefully.
Q4: What's version of GnuPG are you using?
A4: In Debian GNU/Linux system, I use gnupg 1.4.11-3 and gnupg-agent
2.0.14-2 (in sid). With older versions, you can only sign with SHA1.
See: http://www.fsij.org/gnuk/gnupg2-fixes-needed
Q5: What's version of pcscd and libccid are you using?
A5: In Debian GNU/Linux system, I use pcscd 1.5.5-4 and libccid 1.3.11-2,
which is in squeeze. Note that you need to edit /etc/libccid_Info.plist
when using libccid (< 1.4.1).
Q6: What kinds of hardware is required for development?
A6: You need a target board plus a JTAG debugger. If you just want to
test Gnuk for target boards with DfuSe, JTAG debugger is not
the requirement. Note that for real use, you need JTAG debugger
to enable flash ROM protection.
Q7: How much does it cost?
A7: Olimex STM32-H103 plus ARM-USB-TINY-H cost 70 Euro or so.
Q8: How much does it cost for DIY version?
A8: STM8S Discovery Kit costs 750 JPY (< $10 USD) only. You can build
your own JTAG debugger using FTDI2232 module (1450 JPY), see:
http://www.fsij.org/gnuk/jtag_dongle_ftdi2232
Q9: I got an error like "gpg: selecting openpgp failed: ec=6.108", what's up?
A9: GnuPG's SCDaemon has problems for handling insertion/removal of
card/reader (problems are fixed in trunk). When your newly
inserted token is not found by GnuPG, try killing scdaemon and let
it to be invoked again. I do:
$ killall -9 scdaemon
and confirm scdaemon doesn't exist, then,
$ gpg-connect-agent learn /bye
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
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
and at the tab of "Startup Programs", disable check buttons for
"GPG Password Agent" and "SSH Key Agent".
Release notes Release notes
============= =============
This is twelfth 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. usages and it is considered stable, it is still somewhat experimental.
Note that you need to write random bits after installation of gnuk
executable to the chip. This procedure is required to share a single
executable among multiple devices.
Tested features are: Tested features are:
* Personalization of the card * Personalization of the card
* Changing Login name, URL, Name, Sex, Language, etc. * Changing Login name, URL, Name, Sex, Language, etc.
* Password handling (PW1, RC, PW3) * Password handling (PW1, RC, PW3)
* Key import for three types: * Key import for three types:
* key for digital signing * key for digital signing
* key for decryption * key for decryption
* key for authentication * key for authentication
* PSO: Digital Signature * PSO: Digital Signature
* PSO: Decipher * PSO: Decipher
* INTERNAL AUTHENTICATE * INTERNAL AUTHENTICATE
* Changing value of password status bytes (0x00C4): forcesig
* Changing value of password status bytes (0x00C4)
* Verify with pin pad * Verify with pin pad
* Modify with pin pad * Modify with pin pad
It is known not-working well: It is known not-working well:
@@ -66,28 +134,29 @@ It is known not-working well:
work well. Please disable DEBUG option if it doesn't work well. work well. Please disable DEBUG option if it doesn't work well.
* Card holder certificate * Card holder certificate
It is implemented in Gnuk side. But its size matters (> It is implemented in Gnuk side. But its large size matters
1KB). GnuPG cannot handle a data object of large size with (> 1KB). Some versions of GnuPG cannot handle a data object
PC/SC backend. Specifically, handle_transmit function in of large size with PC/SC backend. Specifically,
pcsc-wrapper.c uses the buffer of size 1024-byte. handle_transmit function in pcsc-wrapper.c uses the buffer
of size 1024-byte.
Not supported feature(s): Not supported feature(s):
* Overriding key import. You need to remove all keys first. * Overriding key import. You need to remove all keys first.
* Key generation on device side
* Key generation
Targets Targets
======= =======
We use Olimex STM32-H103 board. We also use STM32 part of STM8S We use Olimex STM32-H103 board and Flying Stone Tiny 01 (FST-01). We
Discovery Kit. also use STM32 part of STM8S Discovery Kit.
With DfuSe support, CQ STARM, STBee, and STBee Mini are also our With DfuSe support, CQ STARM, STBee, and STBee Mini are also our
targets. But those targets with DfuSe are basically not for normal targets. But those targets with DfuSe are basically not for normal
use but for experiments, because it would be impossible for DfuSe to use but for experiments, because it would be impossible for DfuSe to
disable read from flash. For real use, please consider killing DfuSe disable read from flash. For real use, please consider killing DfuSe
and enable read protect using JTAG debugger. and enable read protection using JTAG debugger.
I think that it could run on Olimex STM32-P103, or other boards with I think that it could run on Olimex STM32-P103, or other boards with
STM32F103. Besides, we are porting it to STM32 Primer 2. STM32F103. Besides, we are porting it to STM32 Primer 2.
@@ -104,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 7-segment LED display. Both of PIN verification and PIN modification
are supported for this circuit extension. 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 Souce code
========== ==========
@@ -124,8 +203,8 @@ The author(s) of Gnuk expect users of Gnuk will be able to access the
source code of Gnuk, so that users can study the code and can modify source code of Gnuk, so that users can study the code and can modify
if needed. This doesn't mean person who has a USB Token by Gnuk if needed. This doesn't mean person who has a USB Token by Gnuk
should be able to acess everything on the Token, regardless of its should be able to acess everything on the Token, regardless of its
protections. Private keys, random bytes, and other information should protections. Private keys, and other information should be protected
be protected properly. properly.
External source code External source code
@@ -145,6 +224,9 @@ Gnuk is distributed with external source code.
We use PolarSSL for RSA computation, AES encryption/decryption We use PolarSSL for RSA computation, AES encryption/decryption
and SHA-1 computation. and SHA-1 computation.
The file include/polarssl/bn_mul.h is heavily modified for ARM
Cortex-M3.
* STM32_USB-FS-Device_Driver/ -- a part of USB-FS-Device_Lib * STM32_USB-FS-Device_Driver/ -- a part of USB-FS-Device_Lib
* Virtual_COM_Port/ -- a part of USB-FS-Device_Lib * Virtual_COM_Port/ -- a part of USB-FS-Device_Lib
@@ -174,8 +256,24 @@ How to compile
You need GNU toolchain and newlib for 'arm-none-eabi' target. You need GNU toolchain and newlib for 'arm-none-eabi' target.
See http://github.com/esden/summon-arm-toolchain/ for preparation of See http://github.com/esden/summon-arm-toolchain/ (which includes fix
GNU Toolchain for 'arm-none-eabi' target. of binutils-2.21.1) for preparation of GNU Toolchain for
'arm-none-eabi' target.
# Note that we need to link correct C library (for string functions).
# For this purpose, Makefile.in contains following line:
#
# MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
#
# This should not be needed (as -mcpu=cortex-m3 means
# -mfix-cortex-m3-ldrd), but in practice it is needed for
# the configuration of patch-gcc-config-arm-t-arm-elf.diff in
# summon-arm-toolchain.
#
# In ChibiOS_2.0.8/os/ports/GCC/ARM/rules.mk, it specifies
# -mno-thumb-interwork option. This means that you should not
# link C library which contains ARM (not Thumb) code.
Change directory to `src': Change directory to `src':
@@ -212,6 +310,36 @@ Then, with another terminal, type following to write "gnuk.elf" to Flash ROM:
$ $
Flying Stone Tiny 01
--------------------
If you are using Flying Stone Tiny 01, you need a SWD writer. I am
using revision 946 of Simon Qian's Versaloon.
svn checkout -r 946 http://vsprog.googlecode.com/svn/trunk/
For OpenOCD, we need unofficial patch.
See the article of Versaloon Forum:
http://www.versaloon.com/bbs/viewtopic.php?p=16179
Type following to invoke OpenOCD:
$ openocd -f interface/vsllink.cfg -c "transport select swd" -c "swd_mode 2" -f target/stm32f1x.cfg
Then, with another terminal, type following to write "gnuk.elf" to Flash ROM:
$ telnet localhost 4444
> reset halt
> flash write_image erase gnuk.elf
> reset
> exit
$
STM8S Discovery Kit STM8S Discovery Kit
------------------- -------------------
@@ -280,45 +408,35 @@ accessing by JTAG debugger is recommended.
How to configure How to configure
================ ================
You need python and PyUSB (python-usb package in Debian). You need python and pyscard (python-pyscard package in Debian) or
PyUSB (python-usb package in Debian).
(1) In the 'src' directory, type (1) [pyscard] Stop scdaemon
[PyUSB] Stop the pcsc daemon.
$ make random_bits If scdaemon is running, please kill it, or you will get "Smartcard
Exception" by "Sharing violation".
In this process, it takes time for the command of $ killall -9 scdaemon
dd if=/dev/random bs=1 of=random_bits count=1024 In case of PyUSB tool, you need to stop pcscd.
Don't just wait, but do some other works on your PC.
/dev/random needs entropy to finish.
(2) Stop the pcsc daemon.
# /etc/init.d/pcscd stop # /etc/init.d/pcscd stop
(3) Write the random bits to the device
Connect your board to USB port of your PC. And invoke gnuk_put_binary.py: (2) [Optional] Write fixed serial number
# ../tool/gnuk_put_binary.py -r random_bits
random_bits: 1024
Updating random bits
...
(4) [Optional] Write fixed serial number
If you use fixed serial number in the file 'GNUK_SERIAL_NUMBER', you can do: If you use fixed serial number in the file 'GNUK_SERIAL_NUMBER', you can do:
# EMAIL=<YOUR-EMAIL-ADDRESS> ../tool/gnuk_put_binary.py -s ../GNUK_SERIAL_NUMBER $ EMAIL=<YOUR-EMAIL-ADDRESS> ../tool/gnuk_put_binary.py -s ../GNUK_SERIAL_NUMBER
Writing serial number Writing serial number
... ...
(5) [Optional] Write card holder certificate (3) [Optional] Write card holder certificate
If you have card holder certificate binary file, you can do: If you have card holder certificate binary file, you can do:
# ../tool/gnuk_put_binary.py ../../<YOUR-CERTIFICATE>.bin $ ../tool/gnuk_put_binary.py ../../<YOUR-CERTIFICATE>.bin
../../<YOUR-CERTIFICATE>.bin: <LENGTH-OF-YOUR-CERTIFICATE> ../../<YOUR-CERTIFICATE>.bin: <LENGTH-OF-YOUR-CERTIFICATE>
Updating card holder certificate Updating card holder certificate
... ...
@@ -383,7 +501,55 @@ Try following to see Gnuk runs:
$ gpg --card-status $ gpg --card-status
For more, see doc/DEMO. Personalize the Token and import keys
-------------------------------------
You can personalize the token, putting your information like: Name,
Login name, Sex, Languages, URL, etc., and password. To do so, GnuPG
command is:
$ gpg --card-edit
Note that the factory setting of user password is "123456" and admin
password is "12345678" as the specification.
No, Gnuk doesn't support key generation. You need to create your
keys on your computer, and import them to Gnuk Token. After you create
your keys (they must be 2048-bit RSA), you can import them.
For detail, please see doc/DEMO and doc/DEMO-2.
Note that it make sense to preserve your keys on your computer so that
you can import the keys (again) to (possibly another) Gnuk Token. In
this case, you can use GnuPG's option to specify the home directory by
--homedir.
After creating keys by:
$ gpg --gen-key
...
Copy directory which contains your secret keys to new directory named
<gpgdir-with-your-secret-keys>:
$ cp -pa $HOME/.gnupg <gpgdir-with-your-secret-keys>
Then, import keys by:
$ gpg --edit-key <YOUR-KEYID>
While your $HOME/.gnupg now doesn't have your secret keys after
import, <gpgdir-with-your-secret-keys> still has them. You can again
import them by:
$ gpg --homedir=<gpgdir-with-your-secret-keys> --edit-key <YOUR-KEYID>
Note that you *should not* save changes this time to preserve keys
on your computer. The session goes like this:
gpg> quit
Save changes? (y/N) n
Quit without saving? (y/N) y
@@ -413,15 +579,22 @@ linux/Documentation/usb/usbmon.txt
Read-only Git Repository Read-only Git Repository
======================== ========================
You can browse at http://www.gniibe.org/gitweb?p=gnuk.git;a=summary
You can get it by: You can get it by:
$ git clone git://www.gniibe.org/gnuk.git/
or
$ git clone http://www.gniibe.org/git/gnuk.git/ $ git clone http://www.gniibe.org/git/gnuk.git/
Information on the Web Information on the Web
====================== ======================
Please see: http://www.fsij.org/gnuk/ Please visit: http://www.fsij.org/gnuk/
Your Contributions Your Contributions

View File

@@ -28,7 +28,7 @@
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 #define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 #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_INT_SIZE 8
#define VIRTUAL_COM_PORT_SIZ_DEVICE_DESC 18 #define VIRTUAL_COM_PORT_SIZ_DEVICE_DESC 18

107
boards/FST_01/board.c Normal file
View File

@@ -0,0 +1,107 @@
#include "config.h"
#include "ch.h"
#include "hal.h"
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
hwinit1_common ();
#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 */
/* EXTI2 <= PA2 */
AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI2_PA;
EXTI->IMR = 0;
EXTI->FTSR = EXTI_FTSR_TR2;
NVICEnableVector(EXTI2_IRQn,
CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY));
/* TIM2 */
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST;
RCC->APB1RSTR = 0;
NVICEnableVector(TIM2_IRQn,
CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY));
TIM2->CR1 = TIM_CR1_URS | TIM_CR1_ARPE;
TIM2->CR2 = TIM_CR2_TI1S;
TIM2->SMCR = TIM_SMCR_TS_0 | TIM_SMCR_TS_2 | TIM_SMCR_SMS_2;
TIM2->DIER = 0; /* Disable interrupt for now */
TIM2->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_3
| TIM_CCMR1_CC2S_1 | TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_3;
TIM2->CCMR2 = 0;
TIM2->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC2P;
TIM2->PSC = 72 - 1; /* 1 MHz */
TIM2->ARR = 18000; /* 18 ms */
/* Generate UEV to upload PSC and ARR */
TIM2->EGR = TIM_EGR_UG;
#endif
}
void
USB_Cable_Config (int NewState)
{
if (NewState != DISABLE)
palSetPad (IOPORT1, GPIOA_USB_ENABLE);
else
palClearPad (IOPORT1, GPIOA_USB_ENABLE);
}
void
set_led (int value)
{
if (value)
palSetPad (IOPORT2, GPIOB_LED);
else
palClearPad (IOPORT2, GPIOB_LED);
}
#if defined(PINPAD_CIR_SUPPORT)
void
cir_ext_disable (void)
{
EXTI->PR = EXTI_PR_PR2;
EXTI->IMR &= ~EXTI_IMR_MR2;
}
void
cir_ext_enable (void)
{
EXTI->IMR |= EXTI_IMR_MR2;
}
extern void cir_ext_interrupt (void);
extern void cir_timer_interrupt (void);
CH_IRQ_HANDLER (EXTI2_IRQHandler)
{
CH_IRQ_PROLOGUE ();
chSysLockFromIsr ();
cir_ext_interrupt ();
chSysUnlockFromIsr ();
CH_IRQ_EPILOGUE ();
}
CH_IRQ_HANDLER (TIM2_IRQHandler)
{
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
cir_timer_interrupt ();
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
}
#endif

138
boards/FST_01/board.h Normal file
View File

@@ -0,0 +1,138 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT 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.
ChibiOS/RT 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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
#ifndef _BOARD_H_
#define _BOARD_H_
/*
* Setup for the FST-01 board.
*/
/*
* Board identifier.
*/
#define BOARD_FST_01
#define BOARD_NAME "FST-01"
/*
* Board frequencies.
*/
#define STM32_LSECLK 32768
#define STM32_HSECLK 12000000
/*
* MCU type, this macro is used by both the ST library and the ChibiOS/RT
* native STM32 HAL.
*/
#define STM32F10X_MD
#define CPU_WITH_NO_GPIOE 1
/*
* IO pins assignments.
*/
#define GPIOB_LED 0
#define GPIOA_USB_ENABLE 10
#define GPIOA_SPI1NSS 4
/*
* Timer assignment for CIR
*/
#define TIMx TIM2
/*
* I/O ports initial setup, this configuration is established soon after reset
* in the initialization code.
*
* The digits have the following meaning:
* 0 - Analog input.
* 1 - Push Pull output 10MHz.
* 2 - Push Pull output 2MHz.
* 3 - Push Pull output 50MHz.
* 4 - Digital input.
* 5 - Open Drain output 10MHz.
* 6 - Open Drain output 2MHz.
* 7 - Open Drain output 50MHz.
* 8 - Digital input with PullUp or PullDown resistor depending on ODR.
* 9 - Alternate Push Pull output 10MHz.
* A - Alternate Push Pull output 2MHz.
* B - Alternate Push Pull output 50MHz.
* C - Reserved.
* D - Alternate Open Drain output 10MHz.
* E - Alternate Open Drain output 2MHz.
* F - Alternate Open Drain output 50MHz.
* Please refer to the STM32 Reference Manual for details.
*/
/*
* Port A setup.
* PA0 - input with pull-up (TIM2_CH1)
* PA1 - input with pull-down (TIM2_CH2)
* PA2 - input with pull-up (TIM2_CH3)
* PA11 - input with pull-up (USBDM)
* PA12 - input with pull-up (USBDP)
* Everything input with pull-up except:
* PA10 - Push pull output (USB 1:ON 0:OFF)
*/
#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIOACRH 0x88888388 /* PA15...PA8 */
#define VAL_GPIOAODR 0xFFFFFFFD
/*
* Port B setup.
* Everything input with pull-up except:
* PB0 - Push pull output (LED 1:ON 0:OFF)
*/
#define VAL_GPIOBCRL 0x88888883 /* PB7...PB0 */
#define VAL_GPIOBCRH 0x88888888 /* PB15...PB8 */
#define VAL_GPIOBODR 0xFFFFFFFF
/*
* Port C setup.
* Everything input with pull-up except:
*/
#define VAL_GPIOCCRL 0x88888888 /* PC7...PC0 */
#define VAL_GPIOCCRH 0x88888888 /* PC15...PC8 */
#define VAL_GPIOCODR 0xFFFFFFFF
/*
* Port D setup.
* Everything input with pull-up except:
* PD0 - Normal input (XTAL).
* PD1 - Normal input (XTAL).
*/
#define VAL_GPIODCRL 0x88888844 /* PD7...PD0 */
#define VAL_GPIODCRH 0x88888888 /* PD15...PD8 */
#define VAL_GPIODODR 0xFFFFFFFF
/*
* Port E setup.
* Everything input with pull-up except:
*/
#define VAL_GPIOECRL 0x88888888 /* PE7...PE0 */
#define VAL_GPIOECRH 0x88888888 /* PE15...PE8 */
#define VAL_GPIOEODR 0xFFFFFFFF
#endif /* _BOARD_H_ */

15
boards/FST_01/mcuconf.h Normal file
View File

@@ -0,0 +1,15 @@
/*
* HAL driver system settings.
*/
#define STM32_SW STM32_SW_PLL
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE1 STM32_PPRE1_DIV2
#define STM32_PPRE2 STM32_PPRE2_DIV2
#define STM32_ADCPRE STM32_ADCPRE_DIV4
#define STM32_USBPRE STM32_USBPRE_DIV1P5
#define STM32_MCO STM32_MCO_NOCLOCK
#include "mcuconf-common.h"

36
boards/FST_01_00/board.c Normal file
View File

@@ -0,0 +1,36 @@
#include "config.h"
#include "ch.h"
#include "hal.h"
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
hwinit1_common ();
}
void
USB_Cable_Config (int NewState)
{
if (NewState != DISABLE)
palSetPad (IOPORT1, GPIOA_USB_ENABLE);
else
palClearPad (IOPORT1, GPIOA_USB_ENABLE);
}
void
set_led (int value)
{
if (value)
palSetPad (IOPORT1, GPIOA_LED);
else
palClearPad (IOPORT1, GPIOA_LED);
}

129
boards/FST_01_00/board.h Normal file
View File

@@ -0,0 +1,129 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT 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.
ChibiOS/RT 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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
#ifndef _BOARD_H_
#define _BOARD_H_
/*
* Setup for the FST-01 board (experimental version 00).
*/
/*
* Board identifier.
*/
#define BOARD_FST_01
#define BOARD_NAME "FST-01-00"
/*
* Board frequencies.
*/
#define STM32_LSECLK 32768
#define STM32_HSECLK 8000000
/*
* MCU type, this macro is used by both the ST library and the ChibiOS/RT
* native STM32 HAL.
*/
#define STM32F10X_MD
#define CPU_WITH_NO_GPIOE 1
/*
* IO pins assignments.
*/
#define GPIOA_LED 8
#define GPIOA_USB_ENABLE 10
/*
* I/O ports initial setup, this configuration is established soon after reset
* in the initialization code.
*
* The digits have the following meaning:
* 0 - Analog input.
* 1 - Push Pull output 10MHz.
* 2 - Push Pull output 2MHz.
* 3 - Push Pull output 50MHz.
* 4 - Digital input.
* 5 - Open Drain output 10MHz.
* 6 - Open Drain output 2MHz.
* 7 - Open Drain output 50MHz.
* 8 - Digital input with PullUp or PullDown resistor depending on ODR.
* 9 - Alternate Push Pull output 10MHz.
* A - Alternate Push Pull output 2MHz.
* B - Alternate Push Pull output 50MHz.
* C - Reserved.
* D - Alternate Open Drain output 10MHz.
* E - Alternate Open Drain output 2MHz.
* F - Alternate Open Drain output 50MHz.
* Please refer to the STM32 Reference Manual for details.
*/
/*
* Port A setup.
* PA11 - input with pull-up (USBDM)
* PA12 - input with pull-up (USBDP)
* Everything input with pull-up except:
* PA8 - Push pull output (LED 1:ON 0:OFF)
* PA10 - Push pull output (USB 1:ON 0:OFF)
*/
#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIOACRH 0x88888383 /* PA15...PA8 */
#define VAL_GPIOAODR 0xFFFFFFFF
/*
* Port B setup.
* Everything input with pull-up except:
*/
#define VAL_GPIOBCRL 0x88888888 /* PB7...PB0 */
#define VAL_GPIOBCRH 0x88888888 /* PB15...PB8 */
#define VAL_GPIOBODR 0xFFFFFFFF
/*
* Port C setup.
* Everything input with pull-up except:
*/
#define VAL_GPIOCCRL 0x88888888 /* PC7...PC0 */
#define VAL_GPIOCCRH 0x88888888 /* PC15...PC8 */
#define VAL_GPIOCODR 0xFFFFFFFF
/*
* Port D setup.
* Everything input with pull-up except:
* PD0 - Normal input (XTAL).
* PD1 - Normal input (XTAL).
*/
#define VAL_GPIODCRL 0x88888844 /* PD7...PD0 */
#define VAL_GPIODCRH 0x88888888 /* PD15...PD8 */
#define VAL_GPIODODR 0xFFFFFFFF
/*
* Port E setup.
* Everything input with pull-up except:
*/
#define VAL_GPIOECRL 0x88888888 /* PE7...PE0 */
#define VAL_GPIOECRH 0x88888888 /* PE15...PE8 */
#define VAL_GPIOEODR 0xFFFFFFFF
#endif /* _BOARD_H_ */

View File

@@ -0,0 +1,15 @@
/*
* HAL driver system settings.
*/
#define STM32_SW STM32_SW_PLL
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE1 STM32_PPRE1_DIV2
#define STM32_PPRE2 STM32_PPRE2_DIV2
#define STM32_ADCPRE STM32_ADCPRE_DIV4
#define STM32_USBPRE STM32_USBPRE_DIV1P5
#define STM32_MCO STM32_MCO_NOCLOCK
#include "mcuconf-common.h"

View File

@@ -28,14 +28,14 @@
#define _BOARD_H_ #define _BOARD_H_
/* /*
* Setup for the Olimex STM32-P103 proto board. * Setup for the Olimex STM32-H103 proto board.
*/ */
/* /*
* Board identifier. * Board identifier.
*/ */
#define BOARD_OLIMEX_STM32_P103 #define BOARD_OLIMEX_STM32_H103
#define BOARD_NAME "Olimex STM32-P103" #define BOARD_NAME "Olimex STM32-H103"
/* /*
* Board frequencies. * Board frequencies.

View File

@@ -15,7 +15,6 @@ hwinit1 (void)
{ {
hwinit1_common (); hwinit1_common ();
#if defined(PINPAD_SUPPORT)
#if defined(PINPAD_CIR_SUPPORT) #if defined(PINPAD_CIR_SUPPORT)
/* EXTI0 <= PB0 */ /* EXTI0 <= PB0 */
AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB; AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB;
@@ -69,7 +68,6 @@ hwinit1 (void)
/* Generate UEV to upload PSC and ARR */ /* Generate UEV to upload PSC and ARR */
TIM4->EGR = TIM_EGR_UG; TIM4->EGR = TIM_EGR_UG;
#endif #endif
#endif
} }
void void
@@ -90,7 +88,6 @@ set_led (int value)
palSetPad (IOPORT4, GPIOD_LED1); palSetPad (IOPORT4, GPIOD_LED1);
} }
#if defined(PINPAD_SUPPORT)
#if defined(PINPAD_CIR_SUPPORT) #if defined(PINPAD_CIR_SUPPORT)
void void
cir_ext_disable (void) cir_ext_disable (void)
@@ -156,4 +153,3 @@ CH_IRQ_HANDLER (EXTI2_IRQHandler)
CH_IRQ_EPILOGUE (); CH_IRQ_EPILOGUE ();
} }
#endif #endif
#endif

View File

@@ -38,8 +38,12 @@
#define BOARD_STBEE #define BOARD_STBEE
#define BOARD_NAME "STBee" #define BOARD_NAME "STBee"
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
#define HAVE_7SEGLED 1 #define HAVE_7SEGLED 1
/*
* Timer assignment for CIR
*/
#define TIMx TIM3
#endif #endif
/* /*
@@ -85,7 +89,7 @@
* Please refer to the STM32 Reference Manual for details. * 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. * Port A setup.
* PA6 - (TIM3_CH1) input with pull-up * PA6 - (TIM3_CH1) input with pull-up

View File

@@ -15,11 +15,12 @@ hwinit1 (void)
{ {
hwinit1_common (); hwinit1_common ();
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT) && !defined(DFU_SUPPORT)
palWritePort(IOPORT2, 0x7fff); /* Only clear GPIOB_7SEG_DP */ palWritePort(IOPORT2, 0x7fff); /* Only clear GPIOB_7SEG_DP */
while (palReadPad (IOPORT2, GPIOB_BUTTON) != 0) while (palReadPad (IOPORT2, GPIOB_BUTTON) != 0)
; /* Wait for JTAG debugger connection */ ; /* Wait for JTAG debugger connection */
palWritePort(IOPORT2, 0xffff); /* All set */ palWritePort(IOPORT2, 0xffff); /* All set */
#endif
#if defined(PINPAD_CIR_SUPPORT) #if defined(PINPAD_CIR_SUPPORT)
/* EXTI0 <= PB0 */ /* EXTI0 <= PB0 */
@@ -73,7 +74,6 @@ hwinit1 (void)
TIM4->ARR = 31; TIM4->ARR = 31;
/* Generate UEV to upload PSC and ARR */ /* Generate UEV to upload PSC and ARR */
TIM4->EGR = TIM_EGR_UG; TIM4->EGR = TIM_EGR_UG;
#endif
#endif #endif
/* /*
* Disable JTAG and SWD, done after hwinit1_common as HAL resets AFIO * Disable JTAG and SWD, done after hwinit1_common as HAL resets AFIO
@@ -101,7 +101,6 @@ set_led (int value)
palSetPad (IOPORT1, GPIOA_LED1); palSetPad (IOPORT1, GPIOA_LED1);
} }
#if defined(PINPAD_SUPPORT)
#if defined(PINPAD_CIR_SUPPORT) #if defined(PINPAD_CIR_SUPPORT)
void void
cir_ext_disable (void) cir_ext_disable (void)
@@ -167,4 +166,3 @@ CH_IRQ_HANDLER (EXTI2_IRQHandler)
CH_IRQ_EPILOGUE (); CH_IRQ_EPILOGUE ();
} }
#endif #endif
#endif

View File

@@ -39,8 +39,12 @@
#define BOARD_NAME "STBee Mini" #define BOARD_NAME "STBee Mini"
#define CPU_WITH_NO_GPIOE 1 #define CPU_WITH_NO_GPIOE 1
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
#define HAVE_7SEGLED 1 #define HAVE_7SEGLED 1
/*
* Timer assignment for CIR
*/
#define TIMx TIM3
#endif #endif
/* /*
@@ -88,7 +92,7 @@
* Please refer to the STM32 Reference Manual for details. * 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. * Port A setup.
* PA6 - (TIM3_CH1) input with pull-up * PA6 - (TIM3_CH1) input with pull-up

View File

@@ -10,3 +10,5 @@
#define STM32_PPRE2 STM32_PPRE2_DIV2 #define STM32_PPRE2 STM32_PPRE2_DIV2
#define STM32_ADCPRE STM32_ADCPRE_DIV4 #define STM32_ADCPRE STM32_ADCPRE_DIV4
#define STM32_MCO STM32_MCO_NOCLOCK #define STM32_MCO STM32_MCO_NOCLOCK
#include "mcuconf-common.h"

View File

@@ -15,7 +15,7 @@ hwinit1 (void)
{ {
hwinit1_common (); hwinit1_common ();
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT)
/* EXTI5 <= PB5 */ /* EXTI5 <= PB5 */
AFIO->EXTICR[1] = AFIO_EXTICR2_EXTI5_PB; AFIO->EXTICR[1] = AFIO_EXTICR2_EXTI5_PB;
EXTI->IMR = 0; EXTI->IMR = 0;
@@ -62,7 +62,7 @@ set_led (int value)
palClearPad (IOPORT1, GPIOA_LED); palClearPad (IOPORT1, GPIOA_LED);
} }
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT)
void void
cir_ext_disable (void) cir_ext_disable (void)
{ {

View File

@@ -56,6 +56,11 @@
*/ */
#define GPIOA_LED 8 #define GPIOA_LED 8
/*
* Timer assignment for CIR
*/
#define TIMx TIM3
/* /*
* I/O ports initial setup, this configuration is established soon after reset * I/O ports initial setup, this configuration is established soon after reset
* in the initialization code. * in the initialization code.
@@ -91,7 +96,7 @@
#define VAL_GPIOACRH 0x88888883 /* PA15...PA8 */ #define VAL_GPIOACRH 0x88888883 /* PA15...PA8 */
#define VAL_GPIOAODR 0xFFFFFFFF #define VAL_GPIOAODR 0xFFFFFFFF
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT)
/* /*
* Port B setup. * Port B setup.
* Everything input with pull-up except: * Everything input with pull-up except:

View File

@@ -41,7 +41,7 @@
/* /*
* ADC driver system settings. * ADC driver system settings.
*/ */
#define USE_STM32_ADC1 FALSE #define USE_STM32_ADC1 TRUE
#define STM32_ADC1_DMA_PRIORITY 3 #define STM32_ADC1_DMA_PRIORITY 3
#define STM32_ADC1_IRQ_PRIORITY 5 #define STM32_ADC1_IRQ_PRIORITY 5
#define STM32_ADC1_DMA_ERROR_HOOK() chSysHalt() #define STM32_ADC1_DMA_ERROR_HOOK() chSysHalt()

View File

@@ -1,17 +1,3 @@
* [DONE] configure support
configure script would be good to select a board and to generate
random serial number.
* Random number update
Currently, Gnuk doesn't have random number generator, but use random
bytes calculated by hosts. After Gnuk uses random number, the entry in
Flash ROM will be cleared. Some scheme to update random number bytes
is needed. Possibly, private Data Objects, or by another SELECT FILE.
* Random Number Generator * Random Number Generator
RNG is needed for Data Encryption Key to encrypt private key (P and Q). RNG is needed for Data Encryption Key to encrypt private key (P and Q).
@@ -24,21 +10,44 @@ be possible to get entropy from USB traffic (of other devices).
It would be good not to use malloc. It would be good not to use malloc.
* Flash ROM recover from unexpected shutdown during write
* [DONE] configure support
configure script would be good to select a board and to generate
random serial number.
* [DONE] Random number update
Implemented using SECECT_FILE and UPDATE_BINARY command, which is not
in the OpenPGP card specification.
Old description: Currently, Gnuk doesn't have random number generator,
but use random bytes calculated by hosts. After Gnuk uses random
number, the entry in Flash ROM will be cleared. Some scheme to update
random number bytes is needed. Possibly, private Data Objects, or by
another SELECT FILE.
* [DONE] Manufacture ID * [DONE] Manufacture ID
Get it from FSFE. Get it from FSFE.
* [Mostly DONE] Serial number * [DONE] Serial number
The AID of the card contains serial number. It should be unique. USB The AID of the card contains serial number. It should be unique. USB
serial number should be unique to identify different tokens, too. serial number should be unique to identify different tokens, too.
* Flash ROM recover from shutdown
* [DONE] Flash ROM garbage collection * [DONE] Flash ROM garbage collection
* Flash ROM protection * [DONE] Flash ROM protection
Flash ROM can be protected with OpenOCD. DfuSe users should know that
the content can be accessible by DfuSe, even if we enable read
protection of flash ROM. For proper protection, don't use DfuSe but
use OpenOCD to write and protect.

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

332
gnuk-sticker.svg Normal file
View File

@@ -0,0 +1,332 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="248.03149"
height="105.23622"
id="svg2"
version="1.1"
inkscape:version="0.47 r22583"
enable-background="new"
sodipodi:docname="gnuk-sticker.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4290">
<stop
style="stop-color:#000734;stop-opacity:1;"
offset="0"
id="stop4292" />
<stop
style="stop-color:#000734;stop-opacity:0;"
offset="1"
id="stop4294" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective2884"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<filter
height="1.2680969"
y="-0.13404847"
width="1.2847058"
x="-0.1423529"
id="filter0"
inkscape:collect="always">
<feGaussianBlur
id="feGaussianBlur0"
stdDeviation="2.0538481"
inkscape:collect="always" />
</filter>
<radialGradient
gradientUnits="userSpaceOnUse"
r="80"
fy="440"
fx="0"
cy="440"
cx="0"
id="radialGradient1"
xlink:href="#linearGradient1"
inkscape:collect="always" />
<linearGradient
id="linearGradient1">
<stop
id="stop0"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
style="stop-color:#f8fcff;stop-opacity:1;"
offset="0.0625"
id="stop1" />
<stop
style="stop-color:#f0f8ff;stop-opacity:1;"
offset="0.17166339"
id="stop2" />
<stop
style="stop-color:#ecf4ff;stop-opacity:1;"
offset="0.30279359"
id="stop3" />
<stop
id="stop4"
offset="0.5"
style="stop-color:#e8f0ff;stop-opacity:1;" />
<stop
style="stop-color:#e0ecff;stop-opacity:1;"
offset="0.65893352"
id="stop5" />
<stop
style="stop-color:#d8e8ff;stop-opacity:1;"
offset="0.83552629"
id="stop6" />
<stop
id="stop7"
offset="1"
style="stop-color:#d0e0ff;stop-opacity:1;" />
</linearGradient>
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.75369458,-1.760006,108.15135)"
r="201.5"
fy="750"
fx="450"
cy="750"
cx="450"
id="radialGradient0"
xlink:href="#linearGradient0"
inkscape:collect="always" />
<linearGradient
id="linearGradient0">
<stop
id="stop3620"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
style="stop-color:#c8c8e0;stop-opacity:1;"
offset="0.07"
id="stop3632" />
<stop
style="stop-color:#9696c8;stop-opacity:1;"
offset="0.17"
id="stop3630" />
<stop
style="stop-color:#6464b4;stop-opacity:1;"
offset="0.33"
id="stop3628" />
<stop
id="stop3634"
offset="0.5"
style="stop-color:#3232a0;stop-opacity:1;" />
<stop
style="stop-color:#282898;stop-opacity:1;"
offset="0.66"
id="stop3636" />
<stop
style="stop-color:#1e1e90;stop-opacity:1;"
offset="0.85"
id="stop3626" />
<stop
id="stop3622"
offset="1"
style="stop-color:#000088;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
id="perspective10-5"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 526.18109 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3830"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<filter
inkscape:collect="always"
id="filter3875">
<feBlend
inkscape:collect="always"
mode="screen"
in2="BackgroundImage"
id="feBlend3877" />
</filter>
<inkscape:perspective
id="perspective3903"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4290"
id="linearGradient4296"
x1="85.996228"
y1="1031.615"
x2="240.89818"
y2="1031.615"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="157.8139"
inkscape:cy="53.468164"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="mm"
objecttolerance="10000"
guidetolerance="10000"
inkscape:window-width="1271"
inkscape:window-height="718"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-947.12595)"
style="display:inline"
sodipodi:insensitive="true">
<rect
style="fill:#d9fffe;fill-opacity:1;stroke:none"
id="rect0"
width="248.19862"
height="105.23622"
x="0"
y="947.12598" />
<line id="line0"
x1="0" y1="947.12598" x2="20" y2="947.12598"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<line id="line1"
x1="248.19862" y1="947.12598" x2="248.19862" y2="957.12598"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<line id="line2"
x1="248.19862" y1="1052.3622" x2="228.19862" y2="1052.3622"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<line id="line3"
x1="0" y1="1052.3622" x2="0" y2="1042.3622"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<image
y="951.12598"
x="202.27382"
id="image2886"
height="28.346457"
width="41.757679"
xlink:href="FSIJ-s.png" />
<text
xml:space="preserve"
style="font-size:52.27830124px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#032b7f;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch Bold"
x="94.433884"
y="1014.9048"
id="text2890"
sodipodi:linespacing="100%"><tspan
sodipodi:role="line"
id="tspan2892"
x="94.433884"
y="1014.9048">GNUK</tspan></text>
<g
transform="matrix(-0.1014557,0,0,0.1014557,90.73972,926.6016)"
id="layer1-6"
inkscape:label="Layer 1">
<path
id="path0"
transform="matrix(-1.76,0,0,1.76,410,560)"
d="m 0,0 c 0,0 0,0 -76,0 0,0 -8,-9 -12,-12 -18,-15 -48,-48 -36,-84 4,-14 12,-36 12,-36 -10,6 -50,26 -66,54 -8,16 -18,30 -18,54 0,24 25,100 48,108 0,0 0,0 150,0 0,0 0,0 150,0 23,-8 48,-84 48,-108 0,-24 -10,-38 -18,-54 -16,-28 -46,-48 -66,-54 0,0 8,22 12,36 12,36 -18,69 -36,84 C 88,-9 80,0 80,0 z"
style="fill:#000050;fill-opacity:1;stroke:#000000;stroke-width:2.29999995px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccccscccscccccc"
id="path0-9"
d="m 411.01194,560.94628 c 0,0 0,0 133.76,0 0,0 14.08,-15.84 21.12,-21.12 31.68,-26.4 84.48,-84.48 63.36,-147.84 -7.04,-24.64 -21.12,-63.36 -21.12,-63.36 17.6,10.56 38,45.76 66.16,95.04 14.08,28.16 19.18,52.8 19.18,95.04 0,42.24 -44,176 -84.48,190.08 0,0 62.5,0 -201.5,0 0,0 62.5,0 -201.5,0 -40.48,-14.08 -84.48,-147.84 -84.48,-190.08 0,-42.24 5.1,-66.88 19.18,-95.04 28.16,-49.28 30.96,-84.48 66.16,-95.04 0,0 -14.08,38.72 -21.12,63.36 -21.12,63.36 31.68,121.44 63.36,147.84 7.04,5.28 21.12,21.12 21.12,21.12 z"
style="fill:#000040;fill-opacity:1;stroke:none"
inkscape:connector-curvature="0" />
<path
id="path1"
d="m 409.21999,592 c 0,0 90,0 90,-33 0,-20 -4,-28 -12,-40 -5,-8 -8,-18 -8,-28 -1,-13 -1,-20 8,-36 6,-9 8,-23 5,-33 -5,-14 -19,-23 -33,-25 -16,-5 -35,-4 -50,-5 -15,1 -34,0 -50,5 -14,2 -28,9 -33,25 -3,10 1,24 5,33 9,16 9,23 8,36 0,10 -3,20 -8,28 -8,12 -12,20 -12,40 0,33 90,33 90,33 z"
style="fill:#c0c0fd;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
transform="matrix(-0.75,0,0,0.8,410,100)"
id="path1-1"
d="m 0,592 c 0,0 -90,0 -90,-33 0,-20 4,-28 12,-40 5,-8 8,-18 8,-28 1,-13 1,-20 -8,-36 -6,-9 -8,-23 -5,-33 5,-14 19,-23 33,-25 16,-5 35,-4 50,-5 15,1 34,0 50,5 14,2 28,9 33,25 3,10 -1,24 -5,33 -9,16 -9,23 -8,36 0,10 3,20 8,28 8,12 12,20 12,40 0,33 -90,33 -90,33 z"
style="fill:url(#radialGradient1);fill-opacity:1;fill-rule:evenodd;stroke:#d0e0ff;stroke-width:10px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccsc"
id="path1-2"
d="m 344.11439,411.54794 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)" />
<path
transform="matrix(-1,0,0,1,949.00681,5.38669)"
sodipodi:nodetypes="ccccsc"
id="path1-3"
d="m 474.68123,406.16125 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)" />
<path
inkscape:connector-curvature="0"
id="path2"
d="M 236.90125,452.90625 C 135.34805,496.35376 97.060607,634.496 151.37,761.4375 c 50.02335,116.92341 158.1859,159.40625 257.75,159.40625 99.5641,0 207.72665,-42.48284 257.75,-159.40625 C 721.17939,634.496 682.89195,496.35376 581.33875,452.90625 526.07714,429.26367 466.8919,524.375 409.12,524.375 c -57.7719,0 -116.77668,-94.67646 -172.21875,-71.46875 z"
style="fill:#afcfff;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
d="m 538.23999,720 a 130,150 0 0 1 -260,0 130,150 0 1 1 260,0 z"
id="path3"
style="fill:url(#radialGradient0);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4"
d="m 538.30032,722.21875 c 56.32313,26.16396 100.82185,68.68738 119.76563,119.4375 33.50451,82.59901 -5.55269,179.72665 -93.67188,230.71875 -89.66782,55.4574 -224.43374,55.4574 -314.10156,0 -88.11919,-50.9921 -127.13733,-148.11974 -93.63281,-230.71875 18.61816,-50.41349 63.06491,-92.92973 119.25781,-119.1875 11.1304,10.32118 18.58377,23.0939 22.34375,36.6875 -5.94376,3.59375 -11.63988,7.47175 -16.99219,11.625 -73.95399,55.19241 -81.85302,155.28934 -18.59375,218.125 47.75721,51.30795 139.68,72.55545 213.4375,46.68755 87.41094,-28.2229 135.47694,-110.93384 113.94531,-183.2813 -9.09953,-36.85675 -36.47131,-70.33241 -73.67187,-92.96875 2.51871,-9.1715 6.69761,-18.00492 12.57812,-26 2.55237,-3.99852 5.70954,-7.71801 9.33594,-11.125 z"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4.47213602px;stroke-opacity:1" />
</g>
<text
xml:space="preserve"
style="font-size:18px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:85.00000238%;writing-mode:lr-tb;text-anchor:start;fill:#120054;fill-opacity:1;stroke:none;display:inline;font-family:Gentium Basic;-inkscape-font-specification:Gentium Basic Bold Italic"
x="98.368591"
y="1038.1145"
id="text3817"
sodipodi:linespacing="85.000002%"><tspan
sodipodi:role="line"
id="tspan4288"
style="fill:#120054;fill-opacity:1"
x="98.368591"
y="1038.1145">GnuPG USB Token</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

553
gnuk-stickers.svg Normal file
View File

@@ -0,0 +1,553 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
id="svg3961"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="gnuk-sticers.svg">
<defs
id="defs3">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3967" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="1031.615"
x2="240.89818"
y1="1031.615"
x1="85.996228"
id="linearGradient4296"
xlink:href="#linearGradient4290"
inkscape:collect="always" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
id="perspective3903" />
<filter
id="filter3875"
inkscape:collect="always">
<feBlend
id="feBlend3877"
in2="BackgroundImage"
mode="screen"
inkscape:collect="always" />
</filter>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
id="perspective3830" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10-5" />
<linearGradient
id="linearGradient0">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3620" />
<stop
id="stop3632"
offset="0.07"
style="stop-color:#c8c8e0;stop-opacity:1;" />
<stop
id="stop3630"
offset="0.17"
style="stop-color:#9696c8;stop-opacity:1;" />
<stop
id="stop3628"
offset="0.33"
style="stop-color:#6464b4;stop-opacity:1;" />
<stop
style="stop-color:#3232a0;stop-opacity:1;"
offset="0.5"
id="stop3634" />
<stop
id="stop3636"
offset="0.66"
style="stop-color:#282898;stop-opacity:1;" />
<stop
id="stop3626"
offset="0.85"
style="stop-color:#1e1e90;stop-opacity:1;" />
<stop
style="stop-color:#000088;stop-opacity:1;"
offset="1"
id="stop3622" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient0"
id="radialGradient0"
cx="450"
cy="750"
fx="450"
fy="750"
r="201.5"
gradientTransform="matrix(1,0,0,0.75369458,-1.760006,108.15135)"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient1">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop0" />
<stop
id="stop1"
offset="0.0625"
style="stop-color:#f8fcff;stop-opacity:1;" />
<stop
id="stop2"
offset="0.17166339"
style="stop-color:#f0f8ff;stop-opacity:1;" />
<stop
id="stop3"
offset="0.30279359"
style="stop-color:#ecf4ff;stop-opacity:1;" />
<stop
style="stop-color:#e8f0ff;stop-opacity:1;"
offset="0.5"
id="stop4" />
<stop
id="stop5"
offset="0.65893352"
style="stop-color:#e0ecff;stop-opacity:1;" />
<stop
id="stop6"
offset="0.83552629"
style="stop-color:#d8e8ff;stop-opacity:1;" />
<stop
style="stop-color:#d0e0ff;stop-opacity:1;"
offset="1"
id="stop7" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="radialGradient1"
cx="0"
cy="440"
fx="0"
fy="440"
r="80"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
id="filter0"
x="-0.1423529"
width="1.2847058"
y="-0.13404847"
height="1.2680969">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.0538481"
id="feGaussianBlur0" />
</filter>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
id="perspective2884" />
<inkscape:perspective
id="perspective10"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 526.18109 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient4290"
inkscape:collect="always">
<stop
id="stop4292"
offset="0"
style="stop-color:#000734;stop-opacity:1;" />
<stop
id="stop4294"
offset="1"
style="stop-color:#000734;stop-opacity:0;" />
</linearGradient>
</defs>
<sodipodi:namedview
inkscape:document-units="mm"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="-75.714286"
inkscape:cy="520"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1122"
inkscape:window-height="692"
inkscape:window-x="150"
inkscape:window-y="51"
inkscape:window-maximized="0" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
style="display:inline"
transform="translate(0.5,-946.62598)"
id="layer1-63"
inkscape:label="Layer1"
inkscape:tile-cx="124.59931"
inkscape:tile-cy="53.118107"
inkscape:tile-w="248.19862"
inkscape:tile-h="105.23622"
inkscape:tile-x0="0.5"
inkscape:tile-y0="0.49999656">
<rect
y="947.12598"
x="0"
height="105.23622"
width="248.19862"
id="rect0"
style="fill:#d9fffe;fill-opacity:1;stroke:none" />
<line id="line0"
x1="0" y1="947.12598" x2="20" y2="947.12598"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<line id="line1"
x1="248.19862" y1="947.12598" x2="248.19862" y2="957.12598"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<line id="line2"
x1="248.19862" y1="1052.3622" x2="228.19862" y2="1052.3622"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<line id="line3"
x1="0" y1="1052.3622" x2="0" y2="1042.3622"
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
<image
xlink:href="FSIJ-s.png"
width="41.757679"
height="28.346457"
id="image2886"
x="202.27382"
y="951.12598" />
<text
sodipodi:linespacing="100%"
id="text2890"
y="1014.9048"
x="94.433884"
style="font-size:52.27830124px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#032b7f;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch Bold"
xml:space="preserve"><tspan
y="1014.9048"
x="94.433884"
id="tspan2892"
sodipodi:role="line">GNUK</tspan></text>
<g
inkscape:label="Layer 1"
id="layer1-6"
transform="matrix(-0.1014557,0,0,0.1014557,90.73972,926.6016)">
<path
style="fill:#000050;fill-opacity:1;stroke:#000000;stroke-width:2.29999995px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 0,0 c 0,0 0,0 -76,0 0,0 -8,-9 -12,-12 -18,-15 -48,-48 -36,-84 4,-14 12,-36 12,-36 -10,6 -50,26 -66,54 -8,16 -18,30 -18,54 0,24 25,100 48,108 0,0 0,0 150,0 0,0 0,0 150,0 23,-8 48,-84 48,-108 0,-24 -10,-38 -18,-54 -16,-28 -46,-48 -66,-54 0,0 8,22 12,36 12,36 -18,69 -36,84 C 88,-9 80,0 80,0 z"
transform="matrix(-1.76,0,0,1.76,410,560)"
id="path0" />
<path
inkscape:connector-curvature="0"
style="fill:#000040;fill-opacity:1;stroke:none"
d="m 411.01194,560.94628 c 0,0 0,0 133.76,0 0,0 14.08,-15.84 21.12,-21.12 31.68,-26.4 84.48,-84.48 63.36,-147.84 -7.04,-24.64 -21.12,-63.36 -21.12,-63.36 17.6,10.56 38,45.76 66.16,95.04 14.08,28.16 19.18,52.8 19.18,95.04 0,42.24 -44,176 -84.48,190.08 0,0 62.5,0 -201.5,0 0,0 62.5,0 -201.5,0 -40.48,-14.08 -84.48,-147.84 -84.48,-190.08 0,-42.24 5.1,-66.88 19.18,-95.04 28.16,-49.28 30.96,-84.48 66.16,-95.04 0,0 -14.08,38.72 -21.12,63.36 -21.12,63.36 31.68,121.44 63.36,147.84 7.04,5.28 21.12,21.12 21.12,21.12 z"
id="path0-9"
sodipodi:nodetypes="ccccccscccscccccc" />
<path
style="fill:#c0c0fd;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 409.21999,592 c 0,0 90,0 90,-33 0,-20 -4,-28 -12,-40 -5,-8 -8,-18 -8,-28 -1,-13 -1,-20 8,-36 6,-9 8,-23 5,-33 -5,-14 -19,-23 -33,-25 -16,-5 -35,-4 -50,-5 -15,1 -34,0 -50,5 -14,2 -28,9 -33,25 -3,10 1,24 5,33 9,16 9,23 8,36 0,10 -3,20 -8,28 -8,12 -12,20 -12,40 0,33 90,33 90,33 z"
id="path1" />
<path
style="fill:url(#radialGradient1);fill-opacity:1;fill-rule:evenodd;stroke:#d0e0ff;stroke-width:10px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 0,592 c 0,0 -90,0 -90,-33 0,-20 4,-28 12,-40 5,-8 8,-18 8,-28 1,-13 1,-20 -8,-36 -6,-9 -8,-23 -5,-33 5,-14 19,-23 33,-25 16,-5 35,-4 50,-5 15,1 34,0 50,5 14,2 28,9 33,25 3,10 -1,24 -5,33 -9,16 -9,23 -8,36 0,10 3,20 8,28 8,12 12,20 12,40 0,33 -90,33 -90,33 z"
id="path1-1"
transform="matrix(-0.75,0,0,0.8,410,100)" />
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)"
d="m 344.11439,411.54794 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
id="path1-2"
sodipodi:nodetypes="ccccsc" />
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)"
d="m 474.68123,406.16125 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
id="path1-3"
sodipodi:nodetypes="ccccsc"
transform="matrix(-1,0,0,1,949.00681,5.38669)" />
<path
style="fill:#afcfff;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 236.90125,452.90625 C 135.34805,496.35376 97.060607,634.496 151.37,761.4375 c 50.02335,116.92341 158.1859,159.40625 257.75,159.40625 99.5641,0 207.72665,-42.48284 257.75,-159.40625 C 721.17939,634.496 682.89195,496.35376 581.33875,452.90625 526.07714,429.26367 466.8919,524.375 409.12,524.375 c -57.7719,0 -116.77668,-94.67646 -172.21875,-71.46875 z"
id="path2"
inkscape:connector-curvature="0" />
<path
style="fill:url(#radialGradient0);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path3"
d="m 538.23999,720 a 130,150 0 0 1 -260,0 130,150 0 1 1 260,0 z"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4.47213602px;stroke-opacity:1"
d="m 538.30032,722.21875 c 56.32313,26.16396 100.82185,68.68738 119.76563,119.4375 33.50451,82.59901 -5.55269,179.72665 -93.67188,230.71875 -89.66782,55.4574 -224.43374,55.4574 -314.10156,0 -88.11919,-50.9921 -127.13733,-148.11974 -93.63281,-230.71875 18.61816,-50.41349 63.06491,-92.92973 119.25781,-119.1875 11.1304,10.32118 18.58377,23.0939 22.34375,36.6875 -5.94376,3.59375 -11.63988,7.47175 -16.99219,11.625 -73.95399,55.19241 -81.85302,155.28934 -18.59375,218.125 47.75721,51.30795 139.68,72.55545 213.4375,46.68755 87.41094,-28.2229 135.47694,-110.93384 113.94531,-183.2813 -9.09953,-36.85675 -36.47131,-70.33241 -73.67187,-92.96875 2.51871,-9.1715 6.69761,-18.00492 12.57812,-26 2.55237,-3.99852 5.70954,-7.71801 9.33594,-11.125 z"
id="path4"
inkscape:connector-curvature="0" />
</g>
<text
sodipodi:linespacing="85.000002%"
id="text3817"
y="1038.1145"
x="98.368591"
style="font-size:18px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:85.00000238%;writing-mode:lr-tb;text-anchor:start;fill:#120054;fill-opacity:1;stroke:none;display:inline;font-family:Gentium Basic;-inkscape-font-specification:Gentium Basic Bold Italic"
xml:space="preserve"><tspan
y="1038.1145"
x="98.368591"
style="fill:#120054;fill-opacity:1"
id="tspan4288"
sodipodi:role="line">GnuPG USB Token</tspan></text>
</g>
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
id="use4758" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,105.23622)"
id="use4760" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,210.47244)"
id="use4762" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,315.70866)"
id="use4764" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,420.94489)"
id="use4766" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,526.18111)"
id="use4768" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,631.41733)"
id="use4770" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,736.65355)"
id="use4772" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,841.88977)"
id="use4774" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(0,947.12599)"
id="use4776" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,0)"
id="use4778" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,105.23622)"
id="use4780" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,210.47244)"
id="use4782" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,315.70866)"
id="use4784" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,420.94489)"
id="use4786" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,526.18111)"
id="use4788" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,631.41733)"
id="use4790" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,736.65355)"
id="use4792" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,841.88977)"
id="use4794" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(248.19862,947.12599)"
id="use4796" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,0)"
id="use4798" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,105.23622)"
id="use4800" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,210.47244)"
id="use4802" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,315.70866)"
id="use4804" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,420.94489)"
id="use4806" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,526.18111)"
id="use4808" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,631.41733)"
id="use4810" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,736.65355)"
id="use4812" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,841.88977)"
id="use4814" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#layer1-63"
xlink:href="#layer1-63"
transform="translate(496.39725,947.12599)"
id="use4816" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

224
gnuk.svg
View File

@@ -1,25 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<!-- Manually edited using GNU Emacs -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1052.3622" width="1052.3622"
height="744.09448" height="744.09448"
id="svg2" id="svg2"
version="1.1" version="1.1"
inkscape:version="0.47 r22583" inkscape:version="0.48.1 r9760"
sodipodi:docname="gnuk.svg" sodipodi:docname="gnuk.svg"
inkscape:export-filename="gnuk.png" inkscape:export-filename="gnuk.png"
inkscape:export-xdpi="30" inkscape:export-xdpi="30"
inkscape:export-ydpi="30"> inkscape:export-ydpi="30">
<defs <defs
id="defs4"> id="defs0">
<inkscape:perspective <inkscape:perspective
sodipodi:type="inkscape:persp3d" sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_x="0 : 526.18109 : 1"
@@ -27,27 +28,110 @@
inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" /> id="perspective10" />
<inkscape:perspective <linearGradient
id="perspective2830" id="linearGradient0">
inkscape:persp3d-origin="0.5 : 0.33333333 : 1" <stop
inkscape:vp_z="1 : 0.5 : 1" style="stop-color:#ffffff;stop-opacity:1;"
inkscape:vp_y="0 : 1000 : 0" offset="0"
inkscape:vp_x="0 : 0.5 : 1" id="stop3620" />
sodipodi:type="inkscape:persp3d" /> <stop
<inkscape:perspective id="stop3632"
id="perspective3627" offset="0.07"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1" style="stop-color:#c8c8e0;stop-opacity:1;" />
inkscape:vp_z="1 : 0.5 : 1" <stop
inkscape:vp_y="0 : 1000 : 0" id="stop3630"
inkscape:vp_x="0 : 0.5 : 1" offset="0.17"
sodipodi:type="inkscape:persp3d" /> style="stop-color:#9696c8;stop-opacity:1;" />
<inkscape:perspective <stop
id="perspective3682" id="stop3628"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1" offset="0.33"
inkscape:vp_z="1 : 0.5 : 1" style="stop-color:#6464b4;stop-opacity:1;" />
inkscape:vp_y="0 : 1000 : 0" <stop
inkscape:vp_x="0 : 0.5 : 1" style="stop-color:#3232a0;stop-opacity:1;"
sodipodi:type="inkscape:persp3d" /> offset="0.5"
id="stop3634" />
<stop
id="stop3636"
offset="0.66"
style="stop-color:#282898;stop-opacity:1;" />
<stop
id="stop3626"
offset="0.85"
style="stop-color:#1e1e90;stop-opacity:1;" />
<stop
style="stop-color:#000088;stop-opacity:1;"
offset="1"
id="stop3622" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient0"
id="radialGradient0"
cx="450"
cy="750"
fx="450"
fy="750"
r="201.5"
gradientTransform="matrix(1,0,0,0.75369458,-1.760006,108.15135)"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient1">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop0" />
<stop
id="stop1"
offset="0.0625"
style="stop-color:#f8fcff;stop-opacity:1;" />
<stop
id="stop2"
offset="0.17166339"
style="stop-color:#f0f8ff;stop-opacity:1;" />
<stop
id="stop3"
offset="0.30279359"
style="stop-color:#ecf4ff;stop-opacity:1;" />
<stop
style="stop-color:#e8f0ff;stop-opacity:1;"
offset="0.5"
id="stop4" />
<stop
id="stop5"
offset="0.65893352"
style="stop-color:#e0ecff;stop-opacity:1;" />
<stop
id="stop6"
offset="0.83552629"
style="stop-color:#d8e8ff;stop-opacity:1;" />
<stop
style="stop-color:#d0e0ff;stop-opacity:1;"
offset="1"
id="stop7" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="radialGradient1"
cx="0"
cy="440"
fx="0"
fy="440"
r="80"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1,0,0)" />
<filter
inkscape:collect="always"
id="filter0"
x="-0.1423529"
width="1.2847058"
y="-0.13404847"
height="1.2680969">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.0538481"
id="feGaussianBlur0" />
</filter>
</defs> </defs>
<sodipodi:namedview <sodipodi:namedview
id="base" id="base"
@@ -57,7 +141,7 @@
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="0.70032923" inkscape:zoom="0.70032923"
inkscape:cx="487.47769" inkscape:cx="47.684539"
inkscape:cy="434.02158" inkscape:cy="434.02158"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
@@ -68,10 +152,10 @@
inkscape:snap-smooth-nodes="true" inkscape:snap-smooth-nodes="true"
inkscape:object-nodes="true" inkscape:object-nodes="true"
inkscape:snap-intersection-paths="true" inkscape:snap-intersection-paths="true"
inkscape:window-width="876" inkscape:window-width="1014"
inkscape:window-height="747" inkscape:window-height="703"
inkscape:window-x="29" inkscape:window-x="0"
inkscape:window-y="26" inkscape:window-y="30"
inkscape:window-maximized="0"> inkscape:window-maximized="0">
<inkscape:grid <inkscape:grid
type="xygrid" type="xygrid"
@@ -82,14 +166,14 @@
snapvisiblegridlinesonly="true" /> snapvisiblegridlinesonly="true" />
</sodipodi:namedview> </sodipodi:namedview>
<metadata <metadata
id="metadata7"> id="metadata0">
<rdf:RDF> <rdf:RDF>
<cc:Work <cc:Work
rdf:about=""> rdf:about="">
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title> <dc:title />
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@@ -97,50 +181,52 @@
inkscape:label="Layer 1" inkscape:label="Layer 1"
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer1" id="layer1"
transform="translate(0,-308.2677)"> transform="matrix(-0.80,0,0,0.80,650,-250)">
<path <path
style="fill:#0000ff;fill-opacity:1;stroke:#000000;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:#000050;fill-opacity:1;stroke:#000000;stroke-width:2.3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 726.1305,600.36218 c 22.86832,-8.30901 48,-83.66895 48,-108 0,-24.33105 -10.30662,-51.88803 -24,-72 -13.12651,-19.27938 -60,-36 -60,-36 0,0 7.82067,22.19662 12,36 0,36 -37.18539,69.08582 -36,84 -4.37468,3.58638 -12,12 -12,12 -26.07681,26.07681 37.33885,96.59384 72,84 z" d="m 0,0 c 0,0 0,0 -76,0 0,0 -8,-9 -12,-12 -18,-15 -48,-48 -36,-84 4,-14 12,-36 12,-36 -10,6 -50,26 -66,54 -8,16 -18,30 -18,54 0,24 25,100 48,108 0,0 0,0 150,0 0,0 0,0 150,0 23,-8 48,-84 48,-108 0,-24 -10,-38 -18,-54 -16,-28 -46,-48 -66,-54 0,0 8,22 12,36 12,36 -18,69 -36,84 -4,3 -12,12 -12,12 z"
id="path3672-0" transform="matrix(-1.76,0,0,1.76,410,560)"
sodipodi:nodetypes="cssccccc" /> id="path0" />
<path <path
style="fill:#0000ff;fill-opacity:1;stroke:#000000;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" inkscape:connector-curvature="0"
d="m 204,600.36218 c -22.86832,-8.30901 -48,-83.66895 -48,-108 0,-24.33105 10.30662,-51.88803 24,-72 13.12651,-19.27938 60,-36 60,-36 0,0 -7.82067,22.19662 -12,36 0,36 37.18539,69.08582 36,84 4.37468,3.58638 12,12 12,12 26.07681,26.07681 -37.33885,96.59384 -72,84 z" style="fill:#000040;fill-opacity:1;stroke:none"
id="path3672" d="m 411.01194,560.94628 c 0,0 0,0 133.76,0 0,0 14.08,-15.84 21.12,-21.12 31.68,-26.4 84.48,-84.48 63.36,-147.84 -7.04,-24.64 -21.12,-63.36 -21.12,-63.36 17.6,10.56 38,45.76 66.16,95.04 14.08,28.16 19.18,52.8 19.18,95.04 0,42.24 -44,176 -84.48,190.08 0,0 62.5,0 -201.5,0 0,0 62.5,0 -201.5,0 -40.48,-14.08 -84.48,-147.84 -84.48,-190.08 0,-42.24 5.1,-66.88 19.18,-95.04 28.16,-49.28 30.96,-84.48 66.16,-95.04 0,0 -14.08,38.72 -21.12,63.36 -21.12,63.36 31.68,121.44 63.36,147.84 7.04,5.28 21.12,21.12 21.12,21.12 z"
sodipodi:nodetypes="cssccccc" /> id="path0-9"
sodipodi:nodetypes="ccccccscccscccccc" />
<path <path
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:#c0c0fd;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 387.06525,552.36218 c -10.14964,-12.99942 9.9849,-31.63115 12,-48 1.4662,-11.91009 2.75704,-24.32101 0,-36 -2.05497,-8.705 -9.94503,-15.295 -12,-24 -1.83802,-7.78599 -3.06147,-16.60896 0,-24 4.32957,-10.4525 13.5475,-19.67043 24,-24 33.25966,-13.7766 74.74034,-13.7766 108,0 10.4525,4.32957 19.67043,13.5475 24,24 3.06147,7.39104 1.83802,16.21401 0,24 -2.05497,8.705 -9.94503,15.295 -12,24 -2.75704,11.67899 -1.4662,24.08991 0,36 2.0151,16.36885 22.14964,35.00058 12,48 -32.00143,40.98668 -123.99857,40.98668 -156,0 z" d="m 409.21999,592 c 0,0 90,0 90,-33 0,-20 -4,-28 -12,-40 -5,-8 -8,-18 -8,-28 -1,-13 -1,-20 8,-36 6,-9 8,-23 5,-33 -5,-14 -19,-23 -33,-25 -16,-5 -35,-4 -50,-5 -15,1 -34,0 -50,5 -14,2 -28,9 -33,25 -3,10 1,24 5,33 9,16 9,23 8,36 0,10 -3,20 -8,28 -8,12 -12,20 -12,40 0,33 90,33 90,33 z"
id="path3670" id="path1" />
sodipodi:nodetypes="caaaaaaaaaaaa" />
<path <path
style="fill:#ffffaf;fill-opacity:1;stroke:#000000;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:url(#radialGradient1);fill-opacity:1;fill-rule:evenodd;stroke:#d0e0ff;stroke-width:10px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 245.06525,436.36218 c -56.01988,12.27447 -95.51412,82.82688 -100,140 -4.6642,59.44578 23.48729,132.68883 70,170 64.3239,51.59881 167.53789,100 250,100 82.46211,0 185.6761,-48.40119 250,-100 46.51271,-37.31117 74.6642,-110.55422 70,-170 -4.48588,-57.17312 -43.98012,-127.72553 -100,-140 -52.50286,-11.50385 -90.127,59.96073 -140,80 -25.50547,10.24825 -52.51263,20 -80,20 -27.48737,0 -54.49453,-9.75175 -80,-20 -49.873,-20.03927 -87.49714,-91.50385 -140,-80 z" d="m 0,592 c 0,0 -90,0 -90,-33 0,-20 4,-28 12,-40 5,-8 8,-18 8,-28 1,-13 1,-20 -8,-36 -6,-9 -8,-23 -5,-33 5,-14 19,-23 33,-25 16,-5 35,-4 50,-5 15,1 34,0 50,5 14,2 28,9 33,25 3,10 -1,24 -5,33 -9,16 -9,23 -8,36 0,10, 3,20 8,28 8,12 12,20 12,40 0,33 -90,33 -90,33 z"
id="path2818" id="path1-1"
sodipodi:nodetypes="cssssssssss" /> transform="matrix(-0.75,0,0,0.8,410,100)" />
<path <path
sodipodi:type="arc" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)"
style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 344.11439,411.54794 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
id="path2820" id="path1-2"
sodipodi:cx="480" sodipodi:nodetypes="ccccsc" />
sodipodi:cy="439.09448"
sodipodi:rx="100"
sodipodi:ry="75"
d="m 580,439.09448 a 100,75 0 1 1 -200,0 100,75 0 1 1 200,0 z"
transform="matrix(1.2,0,0,1,-108.71875,242.2677)" />
<path <path
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)"
d="m 468,683.55419 c -53.26272,0 -106.28935,23.67472 -145.72074,52.16211 -28.99055,20.94434 -50.12608,50.68828 -58.27926,81.16082 -10.16321,37.98504 -13.76535,84.29391 14.55851,115.9237 40.35231,45.0621 119.89779,69.56138 189.44149,69.56138 69.5437,0 149.08918,-24.49928 189.44149,-69.56138 C 685.76535,901.17103 682.16321,854.86216 672,816.87712 663.84682,786.40458 642.71129,756.66064 613.72074,735.7163 574.28935,707.22891 521.26272,683.55419 468,683.55419 z m -1.4468,22.772 c 45.32995,0 90.45998,19.43946 124.01861,42.83981 24.67281,17.20427 42.65953,41.61266 49.59841,66.64368 8.64953,31.20197 11.71709,69.26937 -12.38832,95.251 -34.34241,37.01536 -102.04258,57.14346 -161.2287,57.14346 -59.18615,0 -126.88629,-20.1281 -161.22873,-57.14346 -24.1054,-25.98163 -21.03783,-64.04903 -12.3883,-95.251 6.93887,-25.03102 24.92559,-49.43941 49.5984,-66.64368 33.55865,-23.40035 78.68865,-42.83981 124.01863,-42.83981 z" d="m 474.68123,406.16125 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
id="path2844" /> id="path1-3"
sodipodi:nodetypes="ccccsc"
transform="matrix(-1,0,0,1,949.00681,5.38669)" />
<path <path
sodipodi:type="arc" style="fill:#afcfff;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 236.90125,452.90625 C 135.34805,496.35376 97.060607,634.496 151.37,761.4375 c 50.02335,116.92341 158.1859,159.40625 257.75,159.40625 99.5641,0 207.72665,-42.48284 257.75,-159.40625 C 721.17939,634.496 682.89195,496.35376 581.33875,452.90625 526.07714,429.26367 466.8919,524.375 409.12,524.375 c -57.7719,0 -116.77668,-94.67646 -172.21875,-71.46875 z"
id="path2820-4" id="path2"
sodipodi:cx="480" inkscape:connector-curvature="0" />
sodipodi:cy="439.09448" <path
sodipodi:rx="100" style="fill:url(#radialGradient0);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:ry="75" id="path3"
d="m 580,439.09448 a 100,75 0 1 1 -200,0 100,75 0 1 1 200,0 z" d="m 538.23999,720 a 130,150 0 0 1 -260,0 130,150 0 1 1 260,0 z"
transform="matrix(1.2,0,0,1,-108.71875,256.2677)" /> inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4.47213602px;stroke-opacity:1"
d="m 538.30032,722.21875 c 56.32313,26.16396 100.82185,68.68738 119.76563,119.4375 33.50451,82.59901 -5.55269,179.72665 -93.67188,230.71875 -89.66782,55.4574 -224.43374,55.4574 -314.10156,0 -88.11919,-50.9921 -127.13733,-148.11974 -93.63281,-230.71875 18.61816,-50.41349 63.06491,-92.92973 119.25781,-119.1875 11.1304,10.32118 18.58377,23.0939 22.34375,36.6875 -5.94376,3.59375 -11.63988,7.47175 -16.99219,11.625 -73.95399,55.19241 -81.85302,155.28934 -18.59375,218.125 47.75721,51.30795 139.68,72.55545 213.4375,46.68755 87.41094,-28.2229 135.47694,-110.93384 113.94531,-183.2813 -9.09953,-36.85675 -36.47131,-70.33241 -73.67187,-92.96875 2.51871,-9.1715 6.69761,-18.00492 12.57812,-26 2.55237,-3.99852 5.70954,-7.71801 9.33594,-11.125 z"
id="path4"
inkscape:connector-curvature="0" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -495,27 +495,130 @@
#endif /* TriCore */ #endif /* TriCore */
#if defined(__arm__) #if defined(__arm__)
#define MULADDC_1024_CORE \
"ldmia %0!, { r5, r6, r7 } \n" \
"ldmia %1, { r8, r9, r10 } \n" \
"umull r11, r12, %2, r5 \n" \
"adcs r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r8, r8, r11 \n" \
"umull r11, r12, %2, r6 \n" \
"adcs r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r9, r9, r11 \n" \
"umull r11, r12, %2, r7 \n" \
"adcs r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r10, r10, r11 \n" \
"stmia %1!, { r8, r9, r10 } \n"
#define MULADDC_INIT \ #define MULADDC_1024_LOOP \
asm( "ldr r0, %0 " :: "m" (s)); \ asm( "tst %4, #0xfe0 \n" \
asm( "ldr r1, %0 " :: "m" (d)); \ "beq 0f \n" \
asm( "ldr r2, %0 " :: "m" (c)); \ "1: sub %4, %4, #32 \n" \
asm( "ldr r3, %0 " :: "m" (b)); "ldmia %0!, { r5, r6, r7 } \n" \
"ldmia %1, { r8, r9, r10 } \n" \
"umull r11, r12, %2, r5 \n" \
"adds r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r8, r8, r11 \n" \
"umull r11, r12, %2, r6 \n" \
"adcs r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r9, r9, r11 \n" \
"umull r11, r12, %2, r7 \n" \
"adcs r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r10, r10, r11 \n" \
"stmia %1!, { r8, r9, r10 } \n" \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE \
"ldmia %0!, { r5, r6 } \n" \
"ldmia %1, { r8, r9 } \n" \
"umull r11, r12, %2, r5 \n" \
"adcs r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r8, r8, r11 \n" \
"umull r11, r12, %2, r6 \n" \
"adcs r11, r11, %3 \n" \
"adc %3, r12, #0 \n" \
"adds r9, r9, r11 \n" \
"stmia %1!, { r8, r9 } \n" \
"adc %3, %3, #0 \n" \
"tst %4, #0xfe0 \n" \
"bne 1b \n" \
"0:" \
: "=r" (s), "=r" (d), "=r" (b), "=r" (c), "=r" (i) \
: "0" (s), "1" (d), "2" (b), "3" (c), "4" (i) \
: "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "memory", "cc" );
#define MULADDC_CORE \ /* Just for reference (dead code) */
asm( "ldr r4, [r0], #4 " ); \ #define MULADDC_HUIT \
asm( "mov r5, #0 " ); \ "ldmia %0!, { r4, r5 } \n" \
asm( "ldr r6, [r1] " ); \ "ldmia %1, { r8, r9 } \n" \
asm( "umlal r2, r5, r3, r4 " ); \ "umull r6, r7, %2, r4 \n" \
asm( "adds r7, r6, r2 " ); \ "adcs r6, r6, %3 \n" \
asm( "adc r2, r5, #0 " ); \ "adc %3, r7, #0 \n" \
asm( "str r7, [r1], #4 " ); "adds r8, r8, r6 \n" \
"umull r6, r7, %2, r5 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r9, r9, r6 \n" \
"stmia %1!, { r8, r9 } \n" \
"ldmia %0!, { r4, r5 } \n" \
"ldmia %1, { r8, r9 } \n" \
"umull r6, r7, %2, r4 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r8, r8, r6 \n" \
"umull r6, r7, %2, r5 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r9, r9, r6 \n" \
"stmia %1!, { r8, r9 } \n" \
"ldmia %0!, { r4, r5 } \n" \
"ldmia %1, { r8, r9 } \n" \
"umull r6, r7, %2, r4 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r8, r8, r6 \n" \
"umull r6, r7, %2, r5 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r9, r9, r6 \n" \
"stmia %1!, { r8, r9 } \n" \
"ldmia %0!, { r4, r5 } \n" \
"ldmia %1, { r8, r9 } \n" \
"umull r6, r7, %2, r4 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r8, r8, r6 \n" \
"umull r6, r7, %2, r5 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r9, r9, r6 \n" \
"stmia %1!, { r8, r9 } \n"
#define MULADDC_STOP \ #define MULADDC_INIT \
asm( "str r2, %0 " : "=m" (c)); \ asm( "adds %0, #0 \n"
asm( "str r1, %0 " : "=m" (d)); \
asm( "str r0, %0 " : "=m" (s) :: \ #define MULADDC_CORE \
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); "ldr r5, [%1] \n" \
"ldr r4, [%0], #4 \n" \
"umull r6, r7, %2, r4 \n" \
"adcs r6, r6, %3 \n" \
"adc %3, r7, #0 \n" \
"adds r5, r5, r6 \n" \
"str r5, [%1], #4 \n"
#define MULADDC_STOP \
"adc %3, %3, #0 " \
: "=r" (s), "=r" (d), "=r" (b), "=r" (c) \
: "0" (s), "1" (d), "2" (b), "3" (c) \
: "r4", "r5", "r6", "r7", "r8", "r9", "memory", "cc" );
#endif /* ARMv3 */ #endif /* ARMv3 */

View File

@@ -894,7 +894,16 @@ static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b )
{ {
t_int c = 0, t = 0; t_int c = 0, t = 0;
#if defined(MULADDC_HUIT) #if defined(MULADDC_1024_LOOP)
MULADDC_1024_LOOP
for( ; i > 0; i-- )
{
MULADDC_INIT
MULADDC_CORE
MULADDC_STOP
}
#elif defined(MULADDC_HUIT)
for( ; i >= 8; i -= 8 ) for( ; i >= 8; i -= 8 )
{ {
MULADDC_INIT MULADDC_INIT

View File

@@ -91,7 +91,7 @@ CSRC = $(PORTSRC) \
main.c usb_lld.c \ main.c usb_lld.c \
usb_desc.c usb_prop.c \ usb_desc.c usb_prop.c \
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c hardclock.c \ usb-icc.c openpgp.c ac.c openpgp-do.c flash.c hardclock.c \
random.c random.c neug.c
ifneq ($(ENABLE_DEBUG),) ifneq ($(ENABLE_DEBUG),)
CSRC += debug.c CSRC += debug.c
@@ -101,6 +101,10 @@ ifneq ($(ENABLE_PINPAD),)
CSRC += pin-$(ENABLE_PINPAD).c CSRC += pin-$(ENABLE_PINPAD).c
endif endif
ifeq ($(ENABLE_PINPAD),dnd)
CSRC += usb_msc.c
endif
# List ASM source files here # List ASM source files here
ASMSRC = $(PORTASM) \ ASMSRC = $(PORTASM) \
$(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/vectors.s $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/vectors.s
@@ -205,9 +209,7 @@ ifeq ($(USE_FWLIB),yes)
endif endif
include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
random_bits:
dd if=/dev/random bs=1 of=random_bits count=1024
distclean: clean distclean: clean
-rm -f Makefile gnuk.ld config.h random_bits -rm -f Makefile gnuk.ld config.h

184
src/ac.c
View File

@@ -28,7 +28,7 @@
#include "polarssl/config.h" #include "polarssl/config.h"
#include "polarssl/sha1.h" #include "polarssl/sha1.h"
uint8_t volatile auth_status = AC_NONE_AUTHORIZED; uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */
int int
ac_check_status (uint8_t ac_flag) ac_check_status (uint8_t ac_flag)
@@ -56,71 +56,95 @@ ac_reset_other (void)
auth_status &= ~AC_OTHER_AUTHORIZED; auth_status &= ~AC_OTHER_AUTHORIZED;
} }
int
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 r1, r2;
uint8_t keystring[KEYSTRING_MD_SIZE];
if (gpg_pw_locked (PW_ERR_PW1))
return 0;
if (ks_pw1 == NULL)
{
pw_len = strlen (OPENPGP_CARD_INITIAL_PW1);
if ((pw_len_known >= 0 && pw_len_known != pw_len)
|| buf_len < pw_len
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW1, pw_len))
goto failure;
else
goto success_one_step;
}
else
pw_len = ks_pw1[0];
if ((pw_len_known >= 0 && pw_len_known != pw_len)
|| buf_len < pw_len)
{
failure:
gpg_pw_increment_err_counter (PW_ERR_PW1);
return -1;
}
success_one_step:
sha1 (pw, pw_len, keystring);
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;
gpg_pw_reset_err_counter (PW_ERR_PW1);
return pw_len;
}
/* /*
* Verify for "Perform Security Operation : Compute Digital Signature" * Verify for "Perform Security Operation : Compute Digital Signature"
*/ */
int int
verify_pso_cds (const uint8_t *pw, int pw_len) verify_pso_cds (const uint8_t *pw, int pw_len)
{ {
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
int r; int r;
uint8_t keystring[KEYSTRING_SIZE_PW1];
if (gpg_passwd_locked (PW_ERR_PW1))
return 0;
DEBUG_INFO ("verify_pso_cds\r\n"); DEBUG_INFO ("verify_pso_cds\r\n");
DEBUG_BYTE (pw_len); DEBUG_BYTE (pw_len);
keystring[0] = pw_len; r = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, pw_len, pw_len, ks_pw1);
sha1 (pw, pw_len, keystring+1); if (r > 0)
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring+1)) < 0) auth_status |= AC_PSO_CDS_AUTHORIZED;
{ return r;
gpg_increment_pw_err_counter (PW_ERR_PW1);
return r;
}
else
gpg_reset_pw_err_counter (PW_ERR_PW1);
auth_status |= AC_PSO_CDS_AUTHORIZED;
return 1;
} }
int int
verify_other (const uint8_t *pw, int pw_len) verify_other (const uint8_t *pw, int pw_len)
{ {
const uint8_t *ks_pw1; const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
uint8_t pw1_keystring[KEYSTRING_SIZE_PW1]; int r;
DEBUG_INFO ("verify_other\r\n"); DEBUG_INFO ("verify_other\r\n");
DEBUG_BYTE (pw_len);
if (gpg_passwd_locked (PW_ERR_PW1)) r = verify_user_0 (AC_OTHER_AUTHORIZED, pw, pw_len, pw_len, ks_pw1);
return 0; if (r > 0)
auth_status |= AC_OTHER_AUTHORIZED;
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); return r;
if ((ks_pw1 == NULL && pw_len == strlen (OPENPGP_CARD_INITIAL_PW1))
|| (ks_pw1 != NULL && pw_len == ks_pw1[0]))
{ /* No problem */
pw1_keystring[0] = pw_len;
sha1 (pw, pw_len, pw1_keystring+1);
if (gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER,
pw1_keystring + 1) < 0)
goto error;
if (gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER,
pw1_keystring + 1) < 0)
goto error;
/* Reset counter as it's success now */
gpg_reset_pw_err_counter (PW_ERR_PW1);
auth_status |= AC_OTHER_AUTHORIZED;
return 1;
}
else
{
error:
gpg_increment_pw_err_counter (PW_ERR_PW1);
return 0;
}
} }
/* /*
@@ -148,7 +172,7 @@ calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
count -= pw_len + 8; count -= pw_len + 8;
} }
if (count < 8) if (count <= 8)
sha1_update (&sha1_ctx, salt, count); sha1_update (&sha1_ctx, salt, count);
else else
{ {
@@ -161,15 +185,15 @@ calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
memset (&sha1_ctx, 0, sizeof (sha1_ctx)); memset (&sha1_ctx, 0, sizeof (sha1_ctx));
} }
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
uint8_t admin_authorized;
int int
verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
{ {
const uint8_t *pw3_keystring; const uint8_t *pw3_keystring;
int pw_len; int pw_len;
if (gpg_passwd_locked (PW_ERR_PW3))
return 0;
pw3_keystring = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); pw3_keystring = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
if (pw3_keystring != NULL) if (pw3_keystring != NULL)
{ {
@@ -177,6 +201,9 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
uint8_t md[KEYSTRING_MD_SIZE]; uint8_t md[KEYSTRING_MD_SIZE];
const uint8_t *salt; const uint8_t *salt;
if (gpg_pw_locked (PW_ERR_PW3))
return 0;
pw_len = pw3_keystring[0]; pw_len = pw3_keystring[0];
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len) if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len)
goto failure; goto failure;
@@ -188,28 +215,46 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
if (memcmp (md, &pw3_keystring[1+8+1], KEYSTRING_MD_SIZE) != 0) if (memcmp (md, &pw3_keystring[1+8+1], KEYSTRING_MD_SIZE) != 0)
{ {
failure: failure:
gpg_increment_pw_err_counter (PW_ERR_PW3); gpg_pw_increment_err_counter (PW_ERR_PW3);
return -1; return -1;
} }
else
/* OK, the user is now authenticated */ admin_authorized = BY_ADMIN;
gpg_reset_pw_err_counter (PW_ERR_PW3); success: /* OK, the user is now authenticated */
gpg_pw_reset_err_counter (PW_ERR_PW3);
return pw_len;
} }
else else
/* For empty PW3, pass phrase should be OPENPGP_CARD_INITIAL_PW3 */
{ {
if ((pw_len_known >=0 const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
&& pw_len_known != strlen (OPENPGP_CARD_INITIAL_PW3))
|| buf_len < (int)strlen (OPENPGP_CARD_INITIAL_PW3)
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW3,
strlen (OPENPGP_CARD_INITIAL_PW3)) != 0)
/* It is failure, but we don't try to lock for the case of empty PW3 */
return -1;
if (ks_pw1 != NULL)
{ /* empty PW3, but PW1 exists */
int r = verify_user_0 (AC_PSO_CDS_AUTHORIZED,
pw, buf_len, pw_len_known, ks_pw1);
if (r > 0)
admin_authorized = BY_USER;
return r;
}
if (gpg_pw_locked (PW_ERR_PW3))
return 0;
/*
* For the case of empty PW3 (with empty PW1), pass phrase
* should be OPENPGP_CARD_INITIAL_PW3
*/
pw_len = strlen (OPENPGP_CARD_INITIAL_PW3); pw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
} if ((pw_len_known >=0 && pw_len_known != pw_len)
|| buf_len < pw_len
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW3, pw_len))
goto failure;
return pw_len; admin_authorized = BY_ADMIN;
goto success;
}
} }
void void
@@ -219,9 +264,9 @@ gpg_set_pw3 (const uint8_t *newpw, int newpw_len)
uint32_t random; uint32_t random;
ks[0] = newpw_len; ks[0] = newpw_len;
random = get_random (); random = get_salt ();
memcpy (&ks[1], &random, sizeof (random)); memcpy (&ks[1], &random, sizeof (random));
random = get_random (); random = get_salt ();
memcpy (&ks[5], &random, sizeof (random)); memcpy (&ks[5], &random, sizeof (random));
ks[9] = 0x60; /* 65536 iterations */ ks[9] = 0x60; /* 65536 iterations */
@@ -229,8 +274,6 @@ gpg_set_pw3 (const uint8_t *newpw, int newpw_len)
gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks, KEYSTRING_SIZE_PW3); gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks, KEYSTRING_SIZE_PW3);
} }
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
int int
verify_admin (const uint8_t *pw, int pw_len) verify_admin (const uint8_t *pw, int pw_len)
{ {
@@ -255,8 +298,9 @@ ac_reset_admin (void)
void void
ac_fini (void) ac_fini (void)
{ {
auth_status = AC_NONE_AUTHORIZED; memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE);
gpg_do_clear_prvkey (GPG_KEY_FOR_SIGNING); gpg_do_clear_prvkey (GPG_KEY_FOR_SIGNING);
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION); gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION); gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
auth_status = AC_NONE_AUTHORIZED;
} }

View File

@@ -1,7 +1,7 @@
/* /*
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol * call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
* *
* Copyright (C) 2010 Free Software Initiative of Japan * Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -28,7 +28,9 @@
#include "polarssl/config.h" #include "polarssl/config.h"
#include "polarssl/rsa.h" #include "polarssl/rsa.h"
#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */ #define RSA_SIGNATURE_LENGTH KEY_CONTENT_LEN
/* 256 byte == 2048-bit */
/* 128 byte == 1024-bit */
static rsa_context rsa_ctx; static rsa_context rsa_ctx;
@@ -43,10 +45,10 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
mpi_init (&P1, &Q1, &H, NULL); mpi_init (&P1, &Q1, &H, NULL);
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
rsa_ctx.len = 2048 / 8; rsa_ctx.len = KEY_CONTENT_LEN;
mpi_read_string (&rsa_ctx.E, 16, "10001"); mpi_read_string (&rsa_ctx.E, 16, "10001");
mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2); mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2);
mpi_read_binary (&rsa_ctx.Q, &kd->data[128], rsa_ctx.len / 2); mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2], rsa_ctx.len / 2);
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q); mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
mpi_sub_int (&P1, &rsa_ctx.P, 1); mpi_sub_int (&P1, &rsa_ctx.P, 1);
mpi_sub_int (&Q1, &rsa_ctx.Q, 1); mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
@@ -90,23 +92,25 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
} }
} }
/*
* LEN: length in byte
*/
const uint8_t * const uint8_t *
modulus_calc (const uint8_t *p, int len) modulus_calc (const uint8_t *p, int len)
{ {
mpi P, Q, N; mpi P, Q, N;
uint8_t *modulus; uint8_t *modulus;
(void)len; /* 2048-bit assumed */ modulus = malloc (len);
modulus = malloc (2048 / 8);
if (modulus == NULL) if (modulus == NULL)
return NULL; return NULL;
mpi_init (&P, &Q, &N, NULL); mpi_init (&P, &Q, &N, NULL);
mpi_read_binary (&P, p, 2048 / 8 / 2); mpi_read_binary (&P, p, len / 2);
mpi_read_binary (&Q, p + 128, 2048 / 8 / 2); mpi_read_binary (&Q, p + len / 2, len / 2);
mpi_mul_mpi (&N, &P, &Q); mpi_mul_mpi (&N, &P, &Q);
mpi_write_binary (&N, modulus, 2048 / 8); mpi_write_binary (&N, modulus, len);
mpi_free (&P, &Q, &N, NULL); mpi_free (&P, &Q, &N, NULL);
return modulus; return modulus;
} }
@@ -135,8 +139,9 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
DEBUG_WORD (msg_len); DEBUG_WORD (msg_len);
mpi_read_string (&rsa_ctx.E, 16, "10001"); mpi_read_string (&rsa_ctx.E, 16, "10001");
mpi_read_binary (&rsa_ctx.P, &kd->data[0], 2048 / 8 / 2); mpi_read_binary (&rsa_ctx.P, &kd->data[0], KEY_CONTENT_LEN / 2);
mpi_read_binary (&rsa_ctx.Q, &kd->data[128], 2048 / 8 / 2); mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2],
KEY_CONTENT_LEN / 2);
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q); mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
mpi_sub_int (&P1, &rsa_ctx.P, 1); mpi_sub_int (&P1, &rsa_ctx.P, 1);
mpi_sub_int (&Q1, &rsa_ctx.Q, 1); mpi_sub_int (&Q1, &rsa_ctx.Q, 1);

View File

@@ -10,7 +10,7 @@
#define CH_OPTIMIZE_SPEED TRUE #define CH_OPTIMIZE_SPEED TRUE
#define CH_USE_REGISTRY TRUE #define CH_USE_REGISTRY TRUE
#define CH_USE_WAITEXIT TRUE #define CH_USE_WAITEXIT TRUE
#define CH_USE_SEMAPHORES FALSE #define CH_USE_SEMAPHORES TRUE
#define CH_USE_SEMAPHORES_PRIORITY FALSE #define CH_USE_SEMAPHORES_PRIORITY FALSE
#define CH_USE_SEMSW FALSE #define CH_USE_SEMSW FALSE
#define CH_USE_MUTEXES TRUE #define CH_USE_MUTEXES TRUE

View File

@@ -5,7 +5,4 @@
@DFU_DEFINE@ @DFU_DEFINE@
@PINPAD_DEFINE@ @PINPAD_DEFINE@
@PINPAD_MORE_DEFINE@ @PINPAD_MORE_DEFINE@
@CERTDO_DEFINE@
#if !defined(__ASSEMBLER__)
extern const unsigned char *unique_device_id (void);
#endif

46
src/configure vendored
View File

@@ -26,12 +26,7 @@ verbose=no
with_dfu=default with_dfu=default
debug=no debug=no
pinpad=no pinpad=no
certdo=no
# check /dev/random
if test ! -e /dev/random; then
echo "/dev/random is required." >&2
exit 1
fi
# Process each option # Process each option
for option; do for option; do
@@ -57,6 +52,10 @@ for option; do
pinpad=$optarg ;; pinpad=$optarg ;;
--disable-pinpad) --disable-pinpad)
pinpad=no ;; pinpad=no ;;
--enable-certdo)
certdo=yes ;;
--disable-certdo)
certdo=no ;;
--with-dfu) --with-dfu)
with_dfu=yes ;; with_dfu=yes ;;
--without-dfu) --without-dfu)
@@ -86,8 +85,9 @@ Configuration:
STM8S_DISCOVERY STM8S_DISCOVERY
STBEE STBEE
--enable-debug debug with virtual COM port [no] --enable-debug debug with virtual COM port [no]
--enable-pinpad={cir,dial} --enable-pinpad={dnd,cir,dial}
PIN input device support [no] PIN entry support [no]
--enable-certdo support CERT.3 data object [no]
--with-dfu build image for DFU [<target specific>] --with-dfu build image for DFU [<target specific>]
EOF EOF
exit 0 exit 0
@@ -159,10 +159,10 @@ if test "$pinpad" = "no"; then
PINPAD_MORE_DEFINE="" PINPAD_MORE_DEFINE=""
echo "PIN pad option disabled" echo "PIN pad option disabled"
elif test "$pinpad" = "yes"; then elif test "$pinpad" = "yes"; then
PINPAD_MAKE_OPTION="ENABLE_PINPAD=cir" PINPAD_MAKE_OPTION="ENABLE_PINPAD=dnd"
PINPAD_DEFINE="#define PINPAD_SUPPORT 1" PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
PINPAD_MORE_DEFINE="#define PINPAD_CIR_SUPPORT 1" PINPAD_MORE_DEFINE="#define PINPAD_DND_SUPPORT 1"
echo "PIN pad option enabled (cir)" echo "PIN pad option enabled (dnd)"
else else
PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad" PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad"
PINPAD_DEFINE="#define PINPAD_SUPPORT 1" PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
@@ -170,16 +170,34 @@ else
echo "PIN pad option enabled ($pinpad)" echo "PIN pad option enabled ($pinpad)"
fi 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%" \ sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \ -e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \ -e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
< Makefile.in > Makefile < Makefile.in > Makefile
sed -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \ if test "$certdo" = "yes"; then
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \ 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 < 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/" \ sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \ -e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_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 < config.h.in > config.h
exit 0 exit 0

View File

@@ -24,9 +24,9 @@
/* /*
* We assume single DO size is less than 256. * We assume single DO size is less than 256.
* *
* NOTE: When we will support "Card holder certificate" (which size is * NOTE: "Card holder certificate" (which size is larger than 256) is
* larger than 256), it is not put into data pool, but is * not put into data pool, but is implemented by its own flash
* implemented by its own flash page(s). * page(s).
*/ */
#include "config.h" #include "config.h"
@@ -46,7 +46,7 @@ enum flash_status
FLASH_TIMEOUT FLASH_TIMEOUT
}; };
static void void
flash_unlock (void) flash_unlock (void)
{ {
FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY1;
@@ -143,14 +143,16 @@ flash_erase_page (uint32_t addr)
* .dtors * .dtors
* _etext * _etext
* .data * .data
* ... * _bss_start
* _etext + (_edata - _data) * .bss
* * _end
* flash-page-size align padding * <alignment to page>
* * ch_certificate_startp
* flash-page-size data pool * 2 * <2048 bytes>
* * _data_pool
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3) * <two pages>
* _keystore_pool
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3)
*/ */
#define FLASH_DATA_POOL_HEADER_SIZE 2 #define FLASH_DATA_POOL_HEADER_SIZE 2
#if defined(STM32F10X_HD) #if defined(STM32F10X_HD)
@@ -162,7 +164,7 @@ flash_erase_page (uint32_t addr)
#define FLASH_KEYSTORE_SIZE (512*3) #define FLASH_KEYSTORE_SIZE (512*3)
static const uint8_t *data_pool; static const uint8_t *data_pool;
static const uint8_t *keystore_pool; extern uint8_t _keystore_pool;
static uint8_t *last_p; static uint8_t *last_p;
static const uint8_t *keystore; static const uint8_t *keystore;
@@ -179,7 +181,6 @@ const uint8_t *
flash_init (void) flash_init (void)
{ {
const uint8_t *p; const uint8_t *p;
extern uint8_t _keystore_pool;
uint16_t gen0, gen1; uint16_t gen0, gen1;
uint16_t *gen0_p = (uint16_t *)&_data_pool; uint16_t *gen0_p = (uint16_t *)&_data_pool;
uint16_t *gen1_p = (uint16_t *)(&_data_pool + FLASH_PAGE_SIZE); uint16_t *gen1_p = (uint16_t *)(&_data_pool + FLASH_PAGE_SIZE);
@@ -196,16 +197,13 @@ flash_init (void)
else else
data_pool = &_data_pool; data_pool = &_data_pool;
keystore_pool = &_keystore_pool;
/* Seek empty keystore */ /* Seek empty keystore */
p = keystore_pool; p = &_keystore_pool;
while (*p != 0xff || *(p+1) != 0xff) while (*p != 0xff || *(p+1) != 0xff)
p += 512; p += 512;
keystore = p; keystore = p;
flash_unlock ();
return data_pool + FLASH_DATA_POOL_HEADER_SIZE; return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
} }
@@ -384,7 +382,7 @@ flash_key_alloc (void)
{ {
uint8_t *k = (uint8_t *)keystore; uint8_t *k = (uint8_t *)keystore;
if ((k - keystore_pool) >= FLASH_KEYSTORE_SIZE) if ((k - &_keystore_pool) >= FLASH_KEYSTORE_SIZE)
return NULL; return NULL;
keystore += 512; keystore += 512;
@@ -422,11 +420,11 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
void void
flash_keystore_release (void) flash_keystore_release (void)
{ {
flash_erase_page ((uint32_t)keystore_pool); flash_erase_page ((uint32_t)&_keystore_pool);
#if FLASH_KEYSTORE_SIZE > FLASH_PAGE_SIZE #if FLASH_KEYSTORE_SIZE > FLASH_PAGE_SIZE
flash_erase_page ((uint32_t)keystore_pool + FLASH_PAGE_SIZE); flash_erase_page ((uint32_t)&_keystore_pool + FLASH_PAGE_SIZE);
#endif #endif
keystore = keystore_pool; keystore = &_keystore_pool;
} }
void void
@@ -583,6 +581,7 @@ flash_cnt123_clear (const uint8_t **addr_p)
} }
#if defined(CERTDO_SUPPORT)
static int static int
flash_check_blank (const uint8_t *page, int size) flash_check_blank (const uint8_t *page, int size)
{ {
@@ -594,17 +593,16 @@ flash_check_blank (const uint8_t *page, int size)
return 1; return 1;
} }
#endif
#define FLASH_CH_CERTIFICATE_SIZE 2048 #define FLASH_CH_CERTIFICATE_SIZE 2048
int int
flash_erase_binary (uint8_t file_id) flash_erase_binary (uint8_t file_id)
{ {
const uint8_t *p; #if defined(CERTDO_SUPPORT)
if (file_id == FILEID_CH_CERTIFICATE) 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) if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0)
{ {
flash_erase_page ((uint32_t)p); flash_erase_page ((uint32_t)p);
@@ -613,18 +611,12 @@ flash_erase_binary (uint8_t file_id)
#endif #endif
} }
return 0;
}
else if (file_id == FILEID_RANDOM)
{
p = &random_bits_start;
if (flash_check_blank (p, FLASH_PAGE_SIZE) == 0)
flash_erase_page ((uint32_t)p);
return 0; return 0;
} }
else else
#else
(void)file_id;
#endif
return -1; return -1;
} }
@@ -636,17 +628,15 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
uint16_t maxsize; uint16_t maxsize;
const uint8_t *p; const uint8_t *p;
#if defined(CERTDO_SUPPORT)
if (file_id == FILEID_CH_CERTIFICATE) if (file_id == FILEID_CH_CERTIFICATE)
{ {
maxsize = FLASH_CH_CERTIFICATE_SIZE; maxsize = FLASH_CH_CERTIFICATE_SIZE;
p = &ch_certificate_start; p = &ch_certificate_start;
} }
else if (file_id == FILEID_RANDOM) else
{ #endif
maxsize = FLASH_PAGE_SIZE; if (file_id == FILEID_SERIAL_NO)
p = &random_bits_start;
}
else if (file_id == FILEID_SERIAL_NO)
{ {
maxsize = 6; maxsize = 6;
p = &openpgpcard_aid[8]; p = &openpgpcard_aid[8];

View File

@@ -24,6 +24,13 @@ extern void *memmove(void *dest, const void *src, size_t n);
#define EV_EXEC_FINISHED ((eventmask_t)2) /* GPG Execution finished */ #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) */ /* maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */
#define MAX_CMD_APDU_SIZE (7+282) /* header + data */ #define MAX_CMD_APDU_SIZE (7+282) /* header + data */
/* maximum res apdu data is public key 5+9+256+2 (gpg_do_public_key) */ /* maximum res apdu data is public key 5+9+256+2 (gpg_do_public_key) */
@@ -72,13 +79,15 @@ extern volatile uint8_t auth_status;
#define PW_ERR_PW1 0 #define PW_ERR_PW1 0
#define PW_ERR_RC 1 #define PW_ERR_RC 1
#define PW_ERR_PW3 2 #define PW_ERR_PW3 2
extern int gpg_passwd_locked (uint8_t which); extern int gpg_pw_locked (uint8_t which);
extern void gpg_reset_pw_err_counter (uint8_t which); extern void gpg_pw_reset_err_counter (uint8_t which);
extern void gpg_increment_pw_err_counter (uint8_t which); extern void gpg_pw_increment_err_counter (uint8_t which);
extern int ac_check_status (uint8_t ac_flag); extern int ac_check_status (uint8_t ac_flag);
extern int verify_pso_cds (const uint8_t *pw, int pw_len); 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_other (const uint8_t *pw, int pw_len);
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 (const uint8_t *pw, int pw_len);
extern int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known); extern int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known);
@@ -88,9 +97,8 @@ extern void ac_reset_admin (void);
extern void ac_fini (void); extern void ac_fini (void);
extern void write_res_apdu (const uint8_t *p, int len, extern void set_res_apdu (uint8_t sw1, uint8_t sw2);
uint8_t sw1, uint8_t sw2); extern uint16_t data_objects_number_of_bytes;
uint16_t data_objects_number_of_bytes;
extern void gpg_data_scan (const uint8_t *p); extern void gpg_data_scan (const uint8_t *p);
extern void gpg_data_copy (const uint8_t *p); extern void gpg_data_copy (const uint8_t *p);
@@ -106,6 +114,7 @@ enum kind_of_key {
GPG_KEY_FOR_AUTHENTICATION, GPG_KEY_FOR_AUTHENTICATION,
}; };
extern void flash_unlock (void);
extern const uint8_t *flash_init (void); extern const uint8_t *flash_init (void);
extern void flash_do_release (const uint8_t *); extern void flash_do_release (const uint8_t *);
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len); extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
@@ -122,7 +131,7 @@ extern void flash_reset_counter (uint8_t counter_tag_nr);
extern int flash_erase_binary (uint8_t file_id); extern int flash_erase_binary (uint8_t file_id);
extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t len, uint16_t offset); extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t len, uint16_t offset);
/* Linker set this symbol */ /* Linker set these two symbols */
extern uint8_t ch_certificate_start; extern uint8_t ch_certificate_start;
extern uint8_t random_bits_start; extern uint8_t random_bits_start;
@@ -133,6 +142,10 @@ extern uint8_t random_bits_start;
/* encrypted data content */ /* encrypted data content */
struct key_data { struct key_data {
uint8_t data[KEY_CONTENT_LEN]; /* p and q */ uint8_t data[KEY_CONTENT_LEN]; /* p and q */
};
struct key_data_internal {
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
uint32_t check; uint32_t check;
uint32_t random; uint32_t random;
char magic[KEY_MAGIC_LEN]; char magic[KEY_MAGIC_LEN];
@@ -143,7 +156,7 @@ struct key_data {
struct prvkey_data { struct prvkey_data {
const uint8_t *key_addr; const uint8_t *key_addr;
/* /*
* CRM: [C]heck, [R]andom, and [M]agic in struct key_data * CRM: [C]heck, [R]andom, and [M]agic in struct key_data_internal
* *
*/ */
uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE]; uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE];
@@ -211,6 +224,7 @@ extern void fatal (uint8_t code) __attribute__ ((noreturn));
#define FATAL_RANDOM 2 #define FATAL_RANDOM 2
extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE]; extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
extern uint8_t admin_authorized;
/*** Flash memory tag values ***/ /*** Flash memory tag values ***/
#define NR_NONE 0x00 #define NR_NONE 0x00
@@ -285,10 +299,12 @@ extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
#define SIZE_PW_STATUS_BYTES 7 #define SIZE_PW_STATUS_BYTES 7
/* 32-byte random bytes */ extern void random_init (void);
extern uint32_t get_random (void); /* 16-byte random bytes */
extern const uint8_t *random_bytes_get (void); extern const uint8_t *random_bytes_get (void);
extern void random_bytes_free (const uint8_t *); extern void random_bytes_free (const uint8_t *);
/* 4-byte salt */
extern uint32_t get_salt (void);
extern uint32_t hardclock (void); extern uint32_t hardclock (void);
@@ -308,8 +324,6 @@ extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
extern const uint8_t openpgpcard_aid[14]; extern const uint8_t openpgpcard_aid[14];
extern int gpg_get_pw1_lifetime (void);
extern void flash_bool_clear (const uint8_t **addr_p); extern void flash_bool_clear (const uint8_t **addr_p);
extern const uint8_t *flash_bool_write (uint8_t nr); extern const uint8_t *flash_bool_write (uint8_t nr);
extern int flash_cnt123_get_value (const uint8_t *p); extern int flash_cnt123_get_value (const uint8_t *p);
@@ -323,14 +337,33 @@ extern void flash_bool_write_internal (const uint8_t *p, int nr);
extern void flash_cnt123_write_internal (const uint8_t *p, int which, int v); extern void flash_cnt123_write_internal (const uint8_t *p, int which, int v);
extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len); extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len);
extern const unsigned char *unique_device_id (void);
extern const uint8_t gnukStringSerial[];
#define LED_ONESHOT_SHORT ((eventmask_t)1)
#define LED_ONESHOT_LONG ((eventmask_t)2)
#define LED_TWOSHOT ((eventmask_t)4)
#define LED_STATUS_MODE ((eventmask_t)8)
#define LED_INPUT_MODE ((eventmask_t)16)
#define LED_FATAL_MODE ((eventmask_t)32)
extern Thread *main_thread;
extern void led_blink (int spec);
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
#if defined(PINPAD_CIR_SUPPORT) # if defined(PINPAD_CIR_SUPPORT)
extern void cir_ext_disable (void); extern void cir_ext_disable (void);
extern void cir_ext_enable (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_disable (void);
extern void dial_sw_enable (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_CURRENT 1
#define PIN_INPUT_NEW 2 #define PIN_INPUT_NEW 2
#define PIN_INPUT_CONFIRM 3 #define PIN_INPUT_CONFIRM 3
@@ -338,5 +371,6 @@ extern void dial_sw_enable (void);
extern uint8_t pin_input_buffer[MAX_PIN_CHARS]; extern uint8_t pin_input_buffer[MAX_PIN_CHARS];
extern uint8_t pin_input_len; extern uint8_t pin_input_len;
extern msg_t pin_main (void *arg); extern int pinpad_getline (int msg_code, systime_t timeout);
#endif #endif

View File

@@ -28,7 +28,8 @@
* ST32F103 memory setup. * ST32F103 memory setup.
*/ */
__main_stack_size__ = 0x0400; __main_stack_size__ = 0x0400;
__stacks_total_size__ = __main_stack_size__; __process_stack_size__ = 0x0200;
__stacks_total_size__ = __main_stack_size__ + __process_stack_size__;
MEMORY MEMORY
{ {
@@ -114,21 +115,16 @@ SECTIONS
PROVIDE(end = .); PROVIDE(end = .);
_end = .; _end = .;
.gnuk_random : @CERTDO_SUPPORT_START@
{
. = ALIGN (@FLASH_PAGE_SIZE@);
random_bits_start = .;
. += 1;
. = ALIGN (@FLASH_PAGE_SIZE@);
} > flash =0xffffffff
.gnuk_ch_certificate : .gnuk_ch_certificate :
{ {
. = ALIGN (@FLASH_PAGE_SIZE@); . = ALIGN (@FLASH_PAGE_SIZE@);
ch_certificate_start = .; ch_certificate_start = .;
LONG(0xffffffff);
. += 1920; . += 1920;
. = ALIGN (@FLASH_PAGE_SIZE@); . = ALIGN (@FLASH_PAGE_SIZE@);
} > flash =0xffffffff } > flash =0xffffffff
@CERTDO_SUPPORT_END@
.gnuk_flash : .gnuk_flash :
{ {

View File

@@ -6,7 +6,7 @@
#include "mcuconf.h" #include "mcuconf.h"
#define CH_HAL_USE_PAL TRUE #define CH_HAL_USE_PAL TRUE
#define CH_HAL_USE_ADC FALSE #define CH_HAL_USE_ADC TRUE
#define CH_HAL_USE_CAN FALSE #define CH_HAL_USE_CAN FALSE
#define CH_HAL_USE_MAC FALSE #define CH_HAL_USE_MAC FALSE
#define CH_HAL_USE_PWM FALSE #define CH_HAL_USE_PWM FALSE

View File

@@ -1,7 +1,7 @@
/* /*
* main.c - main routine of Gnuk * main.c - main routine of Gnuk
* *
* Copyright (C) 2010 Free Software Initiative of Japan * Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -106,10 +106,14 @@ STDOUTthread (void *arg)
p = stdout.str; p = stdout.str;
len = stdout.size; len = stdout.size;
while (len > 0) while (1)
{ {
int i; int i;
if (len == 0)
if (count_in != VIRTUAL_COM_PORT_DATA_SIZE)
break;
if (len < VIRTUAL_COM_PORT_DATA_SIZE) if (len < VIRTUAL_COM_PORT_DATA_SIZE)
{ {
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
@@ -164,8 +168,193 @@ extern msg_t USBthread (void *arg);
#define LED_TIMEOUT_STOP MS2ST(500) #define LED_TIMEOUT_STOP MS2ST(500)
#define ID_OFFSET 12
static void
device_initialize_once (void)
{
const uint8_t *p = &gnukStringSerial[ID_OFFSET];
if (p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff)
{
/*
* This is the first time invocation.
* Setup serial number by unique device ID.
*/
const uint8_t *u = unique_device_id ();
int i;
for (i = 0; i < 4; i++)
{
uint8_t b = u[i];
uint8_t nibble;
nibble = (b >> 4);
nibble += (nibble >= 10 ? ('A' - 10) : '0');
flash_put_data_internal (&p[i*4], nibble);
nibble = (b & 0x0f);
nibble += (nibble >= 10 ? ('A' - 10) : '0');
flash_put_data_internal (&p[i*4+2], nibble);
}
}
}
static volatile uint8_t fatal_code; static volatile uint8_t fatal_code;
Thread *main_thread;
#define GNUK_INIT 0
#define GNUK_RUNNING 1
#define GNUK_INPUT_WAIT 2
#define GNUK_FATAL 255
/*
* 0 for initializing
* 1 for normal mode
* 2 for input waiting
* 255 for fatal
*/
static uint8_t main_mode;
static void display_interaction (void)
{
eventmask_t m;
while (1)
{
m = chEvtWaitOne (ALL_EVENTS);
set_led (1);
switch (m)
{
case LED_ONESHOT_SHORT:
chThdSleep (MS2ST (100));
break;
case LED_ONESHOT_LONG:
chThdSleep (MS2ST (400));
break;
case LED_TWOSHOT:
chThdSleep (MS2ST (50));
set_led (0);
chThdSleep (MS2ST (50));
set_led (1);
chThdSleep (MS2ST (50));
break;
case LED_STATUS_MODE:
chThdSleep (MS2ST (400));
set_led (0);
return;
case LED_FATAL_MODE:
main_mode = GNUK_FATAL;
set_led (0);
return;
default:
break;
}
set_led (0);
}
}
static void display_fatal_code (void)
{
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
set_led (1);
if (fatal_code & 1)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if (fatal_code & 2)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
static void display_status_code (void)
{
if (icc_state == ICC_STATE_START)
{
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 3);
}
else
/* GPGthread running */
{
set_led (1);
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
if (icc_state == ICC_STATE_WAIT)
{
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 2);
}
else if (icc_state == ICC_STATE_RECEIVE)
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
}
else
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
}
}
void
led_blink (int spec)
{
if (spec == 0)
chEvtSignal (main_thread, LED_ONESHOT_SHORT);
else if (spec == 1)
chEvtSignal (main_thread, LED_ONESHOT_LONG);
else
chEvtSignal (main_thread, LED_TWOSHOT);
}
/* /*
* Entry point. * Entry point.
* *
@@ -180,8 +369,13 @@ main (int argc, char **argv)
(void)argc; (void)argc;
(void)argv; (void)argv;
main_thread = chThdSelf ();
flash_unlock ();
device_initialize_once ();
usb_lld_init (); usb_lld_init ();
USB_Init(); USB_Init ();
random_init ();
#ifdef DEBUG #ifdef DEBUG
stdout_init (); stdout_init ();
@@ -196,107 +390,53 @@ main (int argc, char **argv)
chThdCreateStatic (waUSBthread, sizeof(waUSBthread), chThdCreateStatic (waUSBthread, sizeof(waUSBthread),
NORMALPRIO, USBthread, NULL); NORMALPRIO, USBthread, NULL);
#ifdef PINPAD_DND_SUPPORT
msc_init ();
#endif
while (1) while (1)
{ {
eventmask_t m;
count++; count++;
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL);
if (fatal_code != 0) switch (m)
{ {
case LED_STATUS_MODE:
main_mode = GNUK_RUNNING;
break;
case LED_FATAL_MODE:
main_mode = GNUK_FATAL;
break;
case LED_INPUT_MODE:
main_mode = GNUK_INPUT_WAIT;
set_led (1); set_led (1);
chThdSleep (LED_TIMEOUT_ZERO); chThdSleep (MS2ST (400));
set_led (0); set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL); break;
set_led (1); default:
chThdSleep (LED_TIMEOUT_ZERO); break;
set_led (0); }
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
set_led (1);
if (fatal_code & 1)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if (fatal_code & 2)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
if (bDeviceState != CONFIGURED) switch (main_mode)
{ {
case GNUK_FATAL:
display_fatal_code ();
break;
case GNUK_INIT:
set_led (1); set_led (1);
chThdSleep (LED_TIMEOUT_ZERO); chThdSleep (LED_TIMEOUT_ZERO);
set_led (0); set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 3); chThdSleep (LED_TIMEOUT_STOP * 3);
} break;
else case GNUK_INPUT_WAIT:
/* Device configured */ display_interaction ();
if (icc_state == ICC_STATE_START) break;
{ case GNUK_RUNNING:
set_led (1); default:
chThdSleep (LED_TIMEOUT_ONE); display_status_code ();
set_led (0); break;
chThdSleep (LED_TIMEOUT_STOP * 3); }
}
else
/* GPGthread running */
{
set_led (1);
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
if (icc_state == ICC_STATE_WAIT)
{
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 2);
}
else if (icc_state == ICC_STATE_RECEIVE)
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
}
else
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
}
}
#ifdef DEBUG_MORE #ifdef DEBUG_MORE
if (bDeviceState == CONFIGURED && (count % 10) == 0) if (bDeviceState == CONFIGURED && (count % 10) == 0)
@@ -316,6 +456,7 @@ void
fatal (uint8_t code) fatal (uint8_t code)
{ {
fatal_code = code; fatal_code = code;
chEvtSignal (main_thread, LED_FATAL_MODE);
_write ("fatal\r\n", 7); _write ("fatal\r\n", 7);
for (;;); for (;;);
} }

453
src/neug.c Normal file
View File

@@ -0,0 +1,453 @@
/*
* neug.c - random number generation (from NeuG/src/random.c)
*
* Copyright (C) 2011 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of NeuG, a Random Number Generator
* implementation (for STM32F103).
*
* NeuG 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 "hal.h"
static Thread *rng_thread;
#define ADC_DATA_AVAILABLE ((eventmask_t)1)
/* Total number of channels to be sampled by a single ADC operation.*/
#define ADC_GRP1_NUM_CHANNELS 2
/* Depth of the conversion buffer, channels are sampled one time each.*/
#define ADC_GRP1_BUF_DEPTH 4
/*
* ADC samples buffer.
*/
static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
static void adccb (adcsample_t *buffer, size_t n);
/*
* ADC conversion group.
* Mode: Linear buffer, 4 samples of 2 channels, SW triggered.
* Channels: Vref (1.5 cycles sample time, violating the spec.)
* Sensor (1.5 cycles sample time, violating the spec.)
*/
static const ADCConversionGroup adcgrpcfg = {
FALSE,
ADC_GRP1_NUM_CHANNELS,
0,
ADC_CR2_EXTSEL_SWSTART | ADC_CR2_TSVREFE | ADC_CR2_CONT,
ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_1P5) | ADC_SMPR1_SMP_VREF(ADC_SAMPLE_1P5),
0,
ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
0,
ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) | ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT)
};
/*
* ADC end conversion callback.
*/
static void adccb (adcsample_t *buffer, size_t n)
{
ADCDriver *adcp = &ADCD1;
(void) buffer; (void) n;
if (adcp->ad_state == ADC_COMPLETE)
chEvtSignalI (rng_thread, ADC_DATA_AVAILABLE);
}
/*
* TinyMT routines.
*
* See
* "Tiny Mersenne Twister (TinyMT): A small-sized variant of Mersenne Twister"
* by Mutsuo Saito and Makoto Matsumoto
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/
*/
/* Use the first example of TinyMT */
#define TMT_MAT1 0x8f7011ee
#define TMT_MAT2 0xfc78ff1f
#define TMT_TMAT 0x3793fdff
static uint32_t tmt[4];
static void tmt_one_step (void);
#define TMT_INIT_MIN_LOOP 8
#define TMT_INIT_PRE_LOOP 8
/**
* @brief TinyMT initialize function.
*/
static void tmt_init (uint32_t seed)
{
int i;
tmt[0] = seed;
tmt[1] = TMT_MAT1;
tmt[2] = TMT_MAT2;
tmt[3] = TMT_TMAT;
for (i = 1; i < TMT_INIT_MIN_LOOP; i++)
tmt[i & 3] ^= i + UINT32_C(1812433253) * (tmt[(i - 1) & 3]
^ (tmt[(i - 1) & 3] >> 30));
if ((tmt[0] & 0x7fffffff) == 0 && tmt[1] == 0 && tmt[2] == 0 && tmt[3] == 0)
{ /* Prevent all zero */
tmt[0] = 'T';
tmt[1] = 'I';
tmt[2] = 'N';
tmt[3] = 'Y';
}
for (i = 0; i < TMT_INIT_PRE_LOOP; i++)
tmt_one_step ();
}
/**
* @brief TinyMT one step function, call this every time before tmt_value.
*/
static void tmt_one_step (void)
{
uint32_t x, y;
y = tmt[3];
x = (tmt[0] & 0x7fffffff) ^ tmt[1] ^ tmt[2];
x ^= (x << 1);
y ^= (y >> 1) ^ x;
tmt[0] = tmt[1];
tmt[1] = tmt[2];
tmt[2] = x ^ (y << 10);
tmt[3] = y;
if ((y & 1))
{
tmt[1] ^= TMT_MAT1;
tmt[2] ^= TMT_MAT2;
}
}
/**
* @brief Get a random word (32-bit).
*/
static uint32_t tmt_value (void)
{
uint32_t t0, t1;
t0 = tmt[3];
t1 = tmt[0] + (tmt[2] >> 8);
t0 ^= t1;
if ((t1 & 1))
t0 ^= TMT_TMAT;
return t0;
}
/* 8 parallel CRC-16 shift registers, with randomly rotated feedback */
#define EPOOL_SIZE 16
static uint8_t epool[EPOOL_SIZE]; /* Big-endian */
static uint8_t ep_count;
/*
* Magic number seven.
*
* We did an experiment of measuring entropy of ADC output with MUST.
* The entropy of a byte by raw sampling of LSBs has more than 6.0 bit/byte.
* So, it is considered OK to get 4-byte from 7-byte (6x7 = 42 > 32).
*/
#define NUM_NOISE_INPUTS 7
#define SHIFT_RIGHT(f) ((f)>>1)
static void ep_add (uint8_t entropy_bits, uint8_t another_random_bit)
{
uint8_t v = epool[ep_count];
/* CRC-16-CCITT's Polynomial is: x^16 + x^12 + x^5 + 1 */
epool[(ep_count - 12)& 0x0f] ^= v;
epool[(ep_count - 5)& 0x0f] ^= v;
epool[ep_count] = SHIFT_RIGHT (v) ^ entropy_bits;
if ((v&1) || another_random_bit)
epool[ep_count] ^= 0xff;
ep_count = (ep_count + 1) & 0x0f;
}
#define FNV_INIT 2166136261U
#define FNV_PRIME 16777619
static uint32_t fnv32_hash (const uint8_t *buf, int len)
{
uint32_t v = FNV_INIT;
int i;
for (i = 0; i < len; i++)
{
v ^= buf[i];
v *= FNV_PRIME;
}
return v;
}
#define PROBABILITY_50_BY_TICK() ((SysTick->VAL & 0x02) != 0)
static uint32_t ep_output (void)
{
int i;
uint8_t buf[NUM_NOISE_INPUTS];
uint8_t *p = buf;
/*
* NUM_NOISE_INPUTS is seven.
*
* There are sixteen bytes in the CRC-16 buffer. We use seven
* outputs of CRC-16 buffer for final output. There are two parts;
* former 4 outputs which will be used directly, and latter 3
* outputs which will be used with feedback loop.
*/
/* At some probability, use latter 3 outputs of CRC-16 buffer */
for (i = NUM_NOISE_INPUTS - 1; i >= 4; i--)
if (PROBABILITY_50_BY_TICK ())
*p++ = epool[(ep_count+i) & 0x0f] ^ epool[(ep_count+i-4) & 0x0f];
/* Use former 4 outputs of CRC-16 buffer */
for (i = 3; i >= 0; i--)
*p++ = epool[(ep_count+i) & 0x0f];
return fnv32_hash (buf, p - buf);
}
/*
* Ring buffer, filled by generator, consumed by neug_get routine.
*/
struct rng_rb {
uint32_t *buf;
Mutex m;
CondVar data_available;
CondVar space_available;
uint8_t head, tail;
uint8_t size;
unsigned int full :1;
unsigned int empty :1;
};
static void rb_init (struct rng_rb *rb, uint32_t *p, uint8_t size)
{
rb->buf = p;
rb->size = size;
chMtxInit (&rb->m);
chCondInit (&rb->data_available);
chCondInit (&rb->space_available);
rb->head = rb->tail = 0;
rb->full = 0;
rb->empty = 1;
}
static void rb_add (struct rng_rb *rb, uint32_t v)
{
rb->buf[rb->tail++] = v;
if (rb->tail == rb->size)
rb->tail = 0;
if (rb->tail == rb->head)
rb->full = 1;
rb->empty = 0;
}
static uint32_t rb_del (struct rng_rb *rb)
{
uint32_t v = rb->buf[rb->head++];
if (rb->head == rb->size)
rb->head = 0;
if (rb->head == rb->tail)
rb->empty = 1;
rb->full = 0;
return v;
}
/**
* @brief Random number generation from ADC sampling.
* @param RB: Pointer to ring buffer structure
* @return -1 when failure, 0 otherwise.
* @note Called holding the mutex, with RB->full == 0.
* Keep generating until RB->full == 1.
*/
static int rng_gen (struct rng_rb *rb)
{
static uint8_t round = 0;
uint8_t b;
while (1)
{
chEvtWaitOne (ADC_DATA_AVAILABLE);
/* Got, ADC sampling data */
round++;
b = (((samp[0] & 0x01) << 0) | ((samp[1] & 0x01) << 1)
| ((samp[2] & 0x01) << 2) | ((samp[3] & 0x01) << 3)
| ((samp[4] & 0x01) << 4) | ((samp[5] & 0x01) << 5)
| ((samp[6] & 0x01) << 6) | ((samp[7] & 0x01) << 7));
adcStartConversion (&ADCD1, &adcgrpcfg, samp, ADC_GRP1_BUF_DEPTH, adccb);
/*
* Put a random byte to entropy pool.
*/
ep_add (b, PROBABILITY_50_BY_TICK ());
if ((round % NUM_NOISE_INPUTS) == 0)
{ /* We have enough entropy in the pool. */
uint32_t v = ep_output (); /* Get the random bits from the pool. */
/* Mix the random bits from the pool with the output of PRNG. */
tmt_one_step ();
v ^= tmt_value ();
/* We got the final random bits, add it to the ring buffer. */
rb_add (rb, v);
round = 0;
if (rb->full)
/* fully generated */
break;
}
}
return 0; /* success */
}
/**
* @brief Random number generation thread.
*/
static msg_t rng (void *arg)
{
struct rng_rb *rb = (struct rng_rb *)arg;
rng_thread = chThdSelf ();
adcStart (&ADCD1, NULL);
adcStartConversion (&ADCD1, &adcgrpcfg, samp, ADC_GRP1_BUF_DEPTH, adccb);
while (1)
{
chMtxLock (&rb->m);
while (rb->full)
chCondWait (&rb->space_available);
rng_gen (rb);
chCondSignal (&rb->data_available);
chMtxUnlock ();
}
return 0;
}
static struct rng_rb the_ring_buffer;
static WORKING_AREA(wa_rng, 128);
/**
* @brief Initialize NeuG.
*/
void
neug_init (uint32_t *buf, uint8_t size)
{
struct rng_rb *rb = &the_ring_buffer;
tmt_init (0);
rb_init (rb, buf, size);
chThdCreateStatic (wa_rng, sizeof (wa_rng), NORMALPRIO, rng, rb);
}
/**
* @breif Flush random bytes.
*/
void
neug_flush (void)
{
struct rng_rb *rb = &the_ring_buffer;
chMtxLock (&rb->m);
while (!rb->empty)
(void)rb_del (rb);
chCondSignal (&rb->space_available);
chMtxUnlock ();
}
/**
* @breif Set seed to PRNG
*/
void
neug_prng_reseed (void)
{
uint32_t seed = ep_output ();
tmt_init (seed);
neug_flush ();
}
/**
* @brief Wakes up RNG thread to generate random numbers.
*/
void
neug_kick_filling (void)
{
struct rng_rb *rb = &the_ring_buffer;
chMtxLock (&rb->m);
if (!rb->full)
chCondSignal (&rb->space_available);
chMtxUnlock ();
}
/**
* @brief Get random word (32-bit) from NeuG.
* @detail With NEUG_KICK_FILLING, it wakes up RNG thread.
* With NEUG_NO_KICK, it doesn't wake up RNG thread automatically,
* it is needed to call neug_kick_filling later.
*/
uint32_t
neug_get (int kick)
{
struct rng_rb *rb = &the_ring_buffer;
uint32_t v;
chMtxLock (&rb->m);
while (rb->empty)
chCondWait (&rb->data_available);
v = rb_del (rb);
if (kick)
chCondSignal (&rb->space_available);
chMtxUnlock ();
return v;
}
void
neug_wait_full (void)
{
struct rng_rb *rb = &the_ring_buffer;
chMtxLock (&rb->m);
while (!rb->full)
chCondWait (&rb->data_available);
chMtxUnlock ();
}

11
src/neug.h Normal file
View File

@@ -0,0 +1,11 @@
#define NEUG_NO_KICK 0
#define NEUG_KICK_FILLING 1
#define NEUG_PRE_LOOP 16
void neug_init (uint32_t *buf, uint8_t size);
void neug_prng_reseed (void);
uint32_t neug_get (int kick);
void neug_kick_filling (void);
void neug_flush (void);
void neug_wait_full (void);

View File

@@ -32,6 +32,117 @@
#include "polarssl/aes.h" #include "polarssl/aes.h"
#include "polarssl/sha1.h" #include "polarssl/sha1.h"
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
static const uint8_t *pw_err_counter_p[3];
static int
gpg_pw_get_err_counter (uint8_t which)
{
return flash_cnt123_get_value (pw_err_counter_p[which]);
}
int
gpg_pw_locked (uint8_t which)
{
if (gpg_pw_get_err_counter (which) >= PASSWORD_ERRORS_MAX)
return 1;
else
return 0;
}
void
gpg_pw_reset_err_counter (uint8_t which)
{
flash_cnt123_clear (&pw_err_counter_p[which]);
if (pw_err_counter_p[which] != NULL)
GPG_MEMORY_FAILURE ();
}
void
gpg_pw_increment_err_counter (uint8_t which)
{
flash_cnt123_increment (which, &pw_err_counter_p[which]);
}
uint16_t data_objects_number_of_bytes;
/*
* Compile time vars:
* Historical Bytes (template), Extended Capabilities,
* and Algorithm Attributes
*/
/* Historical Bytes (template) */
static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
10,
0x00,
0x31, 0x80, /* Full DF name */
0x73,
0x80, 0x01, 0x40, /* Full DF name */
/* 1-byte */
/* No command chaining */
/* Extended Lc and Le */
0x00, 0x90, 0x00 /* Status info (no life cycle management) */
};
/* Extended Capabilities */
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
10,
0x30, /*
* No SM, No get challenge,
* Key import supported,
* PW status byte can be put,
* No private_use_DO,
* No algo change allowed
*/
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
0x00, 0x00, /* Max get challenge */
#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 */
#ifdef CERTDO_SUPPORT
0x08, 0x00, /* the case of cardholder ceritificate */
#else
(MAX_RES_APDU_SIZE>>8), (MAX_RES_APDU_SIZE&0xff),
#endif
};
/* Algorithm Attributes */
static const uint8_t algorithm_attr[] __attribute__ ((aligned (1))) = {
6,
0x01, /* RSA */
0x08, 0x00, /* Length modulus (in bit): 2048 */
0x00, 0x20, /* Length exponent (in bit): 32 */
0x00 /* 0: p&q , 3: CRT with N (not yet supported) */
};
#define PW_LEN_MAX 127
/*
* Representation of PW1_LIFETIME:
* 0: PW1_LIEFTIME_P == NULL : PW1 is valid for single PSO:CDS command
* 1: PW1_LIEFTIME_P != NULL : PW1 is valid for several PSO:CDS commands
*
* The address in the variable PW1_LIEFTIME_P is used when filling zero
* in flash memory
*/
static const uint8_t *pw1_lifetime_p;
static int
gpg_get_pw1_lifetime (void)
{
if (pw1_lifetime_p == NULL)
return 0;
else
return 1;
}
static uint32_t digital_signature_counter; static uint32_t digital_signature_counter;
static const uint8_t * static const uint8_t *
@@ -75,112 +186,11 @@ gpg_increment_digital_signature_counter (void)
} }
digital_signature_counter = dsc; digital_signature_counter = dsc;
if (gpg_get_pw1_lifetime () == 0)
ac_reset_pso_cds ();
} }
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
static const uint8_t *pw_err_counter_p[3];
static int
gpg_get_pw_err_counter (uint8_t which)
{
return flash_cnt123_get_value (pw_err_counter_p[which]);
}
int
gpg_passwd_locked (uint8_t which)
{
if (gpg_get_pw_err_counter (which) >= PASSWORD_ERRORS_MAX)
return 1;
else
return 0;
}
void
gpg_reset_pw_err_counter (uint8_t which)
{
flash_cnt123_clear (&pw_err_counter_p[which]);
if (pw_err_counter_p[which] != NULL)
GPG_MEMORY_FAILURE ();
}
void
gpg_increment_pw_err_counter (uint8_t which)
{
flash_cnt123_increment (which, &pw_err_counter_p[which]);
}
uint16_t data_objects_number_of_bytes;
/*
* Compile time vars:
* Historical Bytes (template), Extended Capabilities,
* and Algorithm Attributes
*/
/* Historical Bytes (template) */
static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
10,
0x00,
0x31, 0x80, /* Full DF name */
0x73,
0x80, 0x01, 0x40, /* Full DF name */
/* 1-byte */
/* No command chaining */
/* Extended Lc and Le */
0x00, 0x90, 0x00 /* Status info (no life cycle management) */
};
/* Extended Capabilities */
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
10,
0x30, /*
* No SM, No get challenge,
* Key import supported,
* PW status byte can be put,
* No private_use_DO,
* No algo change allowed
*/
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
0x00, 0x00, /* Max get challenge */
0x07, 0xfe, /* max. length of cardholder certificate (2KB - 2)*/
/* 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
0x08, 0x00, /* the case of cardholder ceritificate */
#endif
};
/* Algorithm Attributes */
static const uint8_t algorithm_attr[] __attribute__ ((aligned (1))) = {
6,
0x01, /* RSA */
0x08, 0x00, /* Length modulus (in bit): 2048 */
0x00, 0x20, /* Length exponent (in bit): 32 */
0x00 /* 0: p&q , 3: CRT with N (not yet supported) */
};
#define PW_LEN_MAX 127
/*
* Representation of PW1_LIFETIME:
* 0: PW1_LIEFTIME_P == NULL : PW1 is valid for single PSO:CDS command
* 1: PW1_LIEFTIME_P != NULL : PW1 is valid for several PSO:CDS commands
*
* The address in the variable PW1_LIEFTIME_P is used when filling zero
* in flash memory
*/
static const uint8_t *pw1_lifetime_p;
int
gpg_get_pw1_lifetime (void)
{
if (pw1_lifetime_p == NULL)
return 0;
else
return 1;
}
#define SIZE_FINGER_PRINT 20 #define SIZE_FINGER_PRINT 20
#define SIZE_KEYGEN_TIME 4 /* RFC4880 */ #define SIZE_KEYGEN_TIME 4 /* RFC4880 */
@@ -502,9 +512,9 @@ rw_pw_status (uint16_t tag, int with_tag,
*res_p++ = PW_LEN_MAX; *res_p++ = PW_LEN_MAX;
*res_p++ = PW_LEN_MAX; *res_p++ = PW_LEN_MAX;
*res_p++ = PW_LEN_MAX; *res_p++ = PW_LEN_MAX;
*res_p++ = PASSWORD_ERRORS_MAX - gpg_get_pw_err_counter (PW_ERR_PW1); *res_p++ = PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW1);
*res_p++ = PASSWORD_ERRORS_MAX - gpg_get_pw_err_counter (PW_ERR_RC); *res_p++ = PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_RC);
*res_p++ = PASSWORD_ERRORS_MAX - gpg_get_pw_err_counter (PW_ERR_PW3); *res_p++ = PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW3);
return 1; return 1;
} }
} }
@@ -525,8 +535,8 @@ proc_resetting_code (const uint8_t *data, int len)
newpw = data; newpw = data;
sha1 (newpw, newpw_len, new_ks); sha1 (newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len; new_ks0[0] = newpw_len;
r = gpg_change_keystring (BY_ADMIN, old_ks, BY_RESETCODE, new_ks); r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
if (r < -2) if (r <= -2)
{ {
DEBUG_INFO ("memory error.\r\n"); DEBUG_INFO ("memory error.\r\n");
return 0; return 0;
@@ -547,7 +557,7 @@ proc_resetting_code (const uint8_t *data, int len)
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, 1); gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, 1);
} }
gpg_reset_pw_err_counter (PW_ERR_RC); gpg_pw_reset_err_counter (PW_ERR_RC);
return 1; return 1;
} }
@@ -619,23 +629,31 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
uint8_t *key_addr; uint8_t *key_addr;
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE]; uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
struct key_data_internal kdi;
DEBUG_INFO ("Loading private key: ");
DEBUG_BYTE (kk);
if (do_data == NULL) if (do_data == NULL)
return 0; return 0;
key_addr = *(uint8_t **)&(do_data)[1]; key_addr = *(uint8_t **)&(do_data)[1];
memcpy (kd[kk].data, key_addr, KEY_CONTENT_LEN); memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
memcpy (((uint8_t *)&kd[kk].check), do_data+5, ADDITIONAL_DATA_SIZE); memcpy (((uint8_t *)&kdi.check), do_data+5, ADDITIONAL_DATA_SIZE);
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE); decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
decrypt (dek, (uint8_t *)&kd[kk], sizeof (struct key_data));
if (memcmp (kd[kk].magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0) decrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
if (memcmp (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
{ {
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n"); DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
return -1; return -1;
} }
/* more sanity check??? */ /* more sanity check??? */
memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN);
return 1; return 1;
} }
@@ -656,7 +674,7 @@ static int8_t num_prv_keys;
static int static int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *keystring) const uint8_t *keystring_admin)
{ {
uint8_t nr = get_do_ptr_nr_for_kk (kk); uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *p; const uint8_t *p;
@@ -668,6 +686,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
const uint8_t *ks_pw1; const uint8_t *ks_pw1;
const uint8_t *ks_rc; const uint8_t *ks_rc;
struct key_data_internal kdi;
#if 0 #if 0
assert (key_len == KEY_CONTENT_LEN); assert (key_len == KEY_CONTENT_LEN);
@@ -703,10 +722,10 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
DEBUG_INFO ("key_addr: "); DEBUG_INFO ("key_addr: ");
DEBUG_WORD ((uint32_t)key_addr); DEBUG_WORD ((uint32_t)key_addr);
memcpy (kd[kk].data, key_data, KEY_CONTENT_LEN); memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
kd[kk].check = calc_check32 (key_data, KEY_CONTENT_LEN); kdi.check = calc_check32 (key_data, KEY_CONTENT_LEN);
kd[kk].random = get_random (); kdi.random = get_salt ();
memcpy (kd[kk].magic, GNUK_MAGIC, KEY_MAGIC_LEN); memcpy (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
dek = random_bytes_get (); /* 16-byte random bytes */ dek = random_bytes_get (); /* 16-byte random bytes */
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE); memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
@@ -715,9 +734,9 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC); ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
encrypt (dek, (uint8_t *)&kd[kk], sizeof (struct key_data)); encrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
r = flash_key_write (key_addr, kd[kk].data, modulus); r = flash_key_write (key_addr, kdi.data, modulus);
modulus_free (modulus); modulus_free (modulus);
if (r < 0) if (r < 0)
@@ -728,7 +747,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
} }
pd->key_addr = key_addr; pd->key_addr = key_addr;
memcpy (pd->crm_encrypted, (uint8_t *)&kd[kk].check, ADDITIONAL_DATA_SIZE); memcpy (pd->crm_encrypted, (uint8_t *)&kdi.check, ADDITIONAL_DATA_SIZE);
if (kk == GPG_KEY_FOR_SIGNING) if (kk == GPG_KEY_FOR_SIGNING)
ac_reset_pso_cds (); ac_reset_pso_cds ();
@@ -752,7 +771,10 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
else else
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE); memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
encrypt (keystring, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE); if (keystring_admin)
encrypt (keystring_admin, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
else
memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE);
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
do_ptr[nr - NR_DO__FIRST__] = p; do_ptr[nr - NR_DO__FIRST__] = p;
@@ -834,6 +856,12 @@ proc_key_import (const uint8_t *data, int len)
{ {
int r; int r;
enum kind_of_key kk; enum kind_of_key kk;
const uint8_t *keystring_admin;
if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3;
else
keystring_admin = NULL;
DEBUG_BINARY (data, len); DEBUG_BINARY (data, len);
@@ -869,7 +897,7 @@ proc_key_import (const uint8_t *data, int len)
/* It should starts with 00 01 00 01 (E) */ /* It should starts with 00 01 00 01 (E) */
/* Skip E, 4-byte */ /* Skip E, 4-byte */
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_md_pw3); r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin);
if (r < 0) if (r < 0)
return 0; return 0;
else else
@@ -941,8 +969,8 @@ gpg_do_table[] = {
{ GPG_DO_KEY_IMPORT, DO_PROC_WRITE, AC_NEVER, AC_ADMIN_AUTHORIZED, { GPG_DO_KEY_IMPORT, DO_PROC_WRITE, AC_NEVER, AC_ADMIN_AUTHORIZED,
proc_key_import }, proc_key_import },
#if 0 #if 0
/* Card holder certificate */ /* Card holder certificate is handled in special way, as its size is big */
{ GPG_DO_CH_CERTIFICATE, DO_PROC_READ, AC_ALWAYS, AC_NEVER, NULL }, { GPG_DO_CH_CERTIFICATE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
#endif #endif
}; };
@@ -1050,6 +1078,11 @@ gpg_data_scan (const uint8_t *p_start)
digital_signature_counter = (dsc_h14 << 10) | dsc_l10; digital_signature_counter = (dsc_h14 << 10) | dsc_l10;
} }
/*
* Write all data to newly allocated Flash ROM page (from P_START),
* updating PW1_LIFETIME_P, PW_ERR_COUNTER_P, and DO_PTR.
* Called by flash_copying_gc.
*/
void void
gpg_data_copy (const uint8_t *p_start) gpg_data_copy (const uint8_t *p_start)
{ {
@@ -1212,6 +1245,7 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
void void
gpg_do_get_data (uint16_t tag, int with_tag) gpg_do_get_data (uint16_t tag, int with_tag)
{ {
#if defined(CERTDO_SUPPORT)
if (tag == GPG_DO_CH_CERTIFICATE) if (tag == GPG_DO_CH_CERTIFICATE)
{ {
res_APDU_pointer = &ch_certificate_start; res_APDU_pointer = &ch_certificate_start;
@@ -1226,6 +1260,7 @@ gpg_do_get_data (uint16_t tag, int with_tag)
res_APDU_size += 4 + 2; res_APDU_size += 4 + 2;
} }
else else
#endif
{ {
const struct do_table_entry *do_p = get_do_entry (tag); const struct do_table_entry *do_p = get_do_entry (tag);

View File

@@ -62,13 +62,11 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = {
}; };
void void
write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2) set_res_apdu (uint8_t sw1, uint8_t sw2)
{ {
res_APDU_size = 2 + len; res_APDU_size = 2;
if (len) res_APDU[0] = sw1;
memcpy (res_APDU, p, len); res_APDU[1] = sw2;
res_APDU[len] = sw1;
res_APDU[len+1] = sw2;
} }
#define FILE_NONE 0 #define FILE_NONE 0
@@ -99,24 +97,19 @@ gpg_fini (void)
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
/* /*
* Invoke the thread PIN_MAIN, and let user input PIN string. * Let user input PIN string.
* Return length of the string. * Return length of the string.
* The string itself is in PIN_INPUT_BUFFER. * The string itself is in PIN_INPUT_BUFFER.
*/ */
static int static int
get_pinpad_input (int msg_code) get_pinpad_input (int msg_code)
{ {
Thread *t; int r;
t = chThdCreateFromHeap (NULL, THD_WA_SIZE (128), chEvtSignal (main_thread, LED_INPUT_MODE);
NORMALPRIO, pin_main, (void *)msg_code); r = pinpad_getline (msg_code, MS2ST (8000));
if (t == NULL) chEvtSignal (main_thread, LED_STATUS_MODE);
return -1; return r;
else
{
chThdWait (t);
return pin_input_len;
}
} }
#endif #endif
@@ -132,32 +125,14 @@ cmd_verify (void)
DEBUG_INFO (" - VERIFY\r\n"); DEBUG_INFO (" - VERIFY\r\n");
DEBUG_BYTE (p2); DEBUG_BYTE (p2);
#if defined(PINPAD_SUPPORT) len = cmd_APDU[4];
if (cmd_APDU_size == 4) if (len == 0) /* extended length */
/* Verification with pinpad */
{ {
len = get_pinpad_input (PIN_INPUT_CURRENT); len = (cmd_APDU[5]<<8) | cmd_APDU[6];
if (len < 0) data_start = 7;
{
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];
} }
pw = &cmd_APDU[data_start];
if (p2 == 0x81) if (p2 == 0x81)
r = verify_pso_cds (pw, len); r = verify_pso_cds (pw, len);
@@ -238,6 +213,7 @@ cmd_change_password (void)
uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_MD_SIZE+1]; uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
uint8_t *new_ks = &new_ks0[1]; uint8_t *new_ks = &new_ks0[1];
uint8_t p1 = cmd_APDU[2]; /* 0: change (old+new), 1: exchange (new) */
uint8_t p2 = cmd_APDU[3]; uint8_t p2 = cmd_APDU[3];
int len; int len;
const uint8_t *pw; const uint8_t *pw;
@@ -249,77 +225,40 @@ cmd_change_password (void)
DEBUG_INFO ("Change PW\r\n"); DEBUG_INFO ("Change PW\r\n");
DEBUG_BYTE (who); DEBUG_BYTE (who);
#if defined(PINPAD_SUPPORT) len = cmd_APDU[4];
if (cmd_APDU_size == 4) pw = &cmd_APDU[5];
/* Modification with pinpad */ if (len == 0) /* extended length */
{ {
pw_len = get_pinpad_input (PIN_INPUT_CURRENT); len = (cmd_APDU[5]<<8) | cmd_APDU[6];
if (pw_len < 0) pw += 2;
{
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 if (p1 != 0)
{ {
len = cmd_APDU[4]; GPG_FUNCTION_NOT_SUPPORTED();
pw = &cmd_APDU[5]; return;
if (len == 0) /* extended length */
{
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
pw += 2;
}
} }
if (who == BY_USER) /* PW1 */ if (who == BY_USER) /* PW1 */
{ {
const uint8_t *pk = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
if (pk == NULL) pw_len = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, len, -1, ks_pw1);
if (pw_len < 0)
{ {
if (len < (int)strlen (OPENPGP_CARD_INITIAL_PW1)) DEBUG_INFO ("permission denied.\r\n");
{ GPG_SECURITY_FAILURE ();
DEBUG_INFO ("permission denied.\r\n"); return;
GPG_SECURITY_FAILURE (); }
return; else if (pw_len == 0)
} {
DEBUG_INFO ("blocked.\r\n");
pw_len = strlen (OPENPGP_CARD_INITIAL_PW1); GPG_SECURITY_AUTH_BLOCKED ();
newpw = pw + pw_len; return;
newpw_len = len - pw_len;
} }
else else
{ {
pw_len = pk[0];
newpw = pw + pw_len; newpw = pw + pw_len;
newpw_len = len - pw_len; newpw_len = len - pw_len;
} }
@@ -353,7 +292,7 @@ cmd_change_password (void)
new_ks0[0] = newpw_len; new_ks0[0] = newpw_len;
r = gpg_change_keystring (who, old_ks, who, new_ks); r = gpg_change_keystring (who, old_ks, who, new_ks);
if (r < -2) if (r <= -2)
{ {
DEBUG_INFO ("memory error.\r\n"); DEBUG_INFO ("memory error.\r\n");
GPG_MEMORY_FAILURE (); GPG_MEMORY_FAILURE ();
@@ -368,7 +307,6 @@ cmd_change_password (void)
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
ac_reset_pso_cds (); ac_reset_pso_cds ();
ac_reset_other (); ac_reset_other ();
gpg_reset_pw_err_counter (PW_ERR_PW1);
DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n"); DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
GPG_SUCCESS (); GPG_SUCCESS ();
} }
@@ -377,7 +315,6 @@ cmd_change_password (void)
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1); gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
ac_reset_pso_cds (); ac_reset_pso_cds ();
ac_reset_other (); ac_reset_other ();
gpg_reset_pw_err_counter (PW_ERR_PW1);
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n"); DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
GPG_SUCCESS (); GPG_SUCCESS ();
} }
@@ -385,7 +322,6 @@ cmd_change_password (void)
{ {
DEBUG_INFO ("done.\r\n"); DEBUG_INFO ("done.\r\n");
ac_reset_admin (); ac_reset_admin ();
gpg_reset_pw_err_counter (PW_ERR_PW3);
GPG_SUCCESS (); GPG_SUCCESS ();
} }
} }
@@ -405,60 +341,12 @@ cmd_reset_user_password (void)
DEBUG_INFO ("Reset PW1\r\n"); DEBUG_INFO ("Reset PW1\r\n");
DEBUG_BYTE (p1); DEBUG_BYTE (p1);
#if defined(PINPAD_SUPPORT) len = cmd_APDU[4];
if (cmd_APDU_size == 4) pw = &cmd_APDU[5];
/* Modification with pinpad */ if (len == 0) /* extended length */
{ {
if (p1 == 0x00) /* by User with Reseting Code */ len = (cmd_APDU[5]<<8) | cmd_APDU[6];
{ pw += 2;
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;
}
} }
if (p1 == 0x00) /* by User with Reseting Code */ if (p1 == 0x00) /* by User with Reseting Code */
@@ -466,7 +354,7 @@ cmd_reset_user_password (void)
const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC); const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t old_ks[KEYSTRING_MD_SIZE];
if (gpg_passwd_locked (PW_ERR_RC)) if (gpg_pw_locked (PW_ERR_RC))
{ {
DEBUG_INFO ("blocked.\r\n"); DEBUG_INFO ("blocked.\r\n");
GPG_SECURITY_AUTH_BLOCKED (); GPG_SECURITY_AUTH_BLOCKED ();
@@ -487,7 +375,7 @@ cmd_reset_user_password (void)
sha1 (newpw, newpw_len, new_ks); sha1 (newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len; new_ks0[0] = newpw_len;
r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks); r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks);
if (r < -2) if (r <= -2)
{ {
DEBUG_INFO ("memory error.\r\n"); DEBUG_INFO ("memory error.\r\n");
GPG_MEMORY_FAILURE (); GPG_MEMORY_FAILURE ();
@@ -496,7 +384,7 @@ cmd_reset_user_password (void)
{ {
sec_fail: sec_fail:
DEBUG_INFO ("failed.\r\n"); DEBUG_INFO ("failed.\r\n");
gpg_increment_pw_err_counter (PW_ERR_RC); gpg_pw_increment_err_counter (PW_ERR_RC);
GPG_SECURITY_FAILURE (); GPG_SECURITY_FAILURE ();
} }
else if (r == 0) else if (r == 0)
@@ -508,8 +396,8 @@ cmd_reset_user_password (void)
KEYSTRING_SIZE_PW1); KEYSTRING_SIZE_PW1);
ac_reset_pso_cds (); ac_reset_pso_cds ();
ac_reset_other (); ac_reset_other ();
gpg_reset_pw_err_counter (PW_ERR_RC); gpg_pw_reset_err_counter (PW_ERR_RC);
gpg_reset_pw_err_counter (PW_ERR_PW1); gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS (); GPG_SUCCESS ();
} }
else else
@@ -517,8 +405,8 @@ cmd_reset_user_password (void)
DEBUG_INFO ("done.\r\n"); DEBUG_INFO ("done.\r\n");
ac_reset_pso_cds (); ac_reset_pso_cds ();
ac_reset_other (); ac_reset_other ();
gpg_reset_pw_err_counter (PW_ERR_RC); gpg_pw_reset_err_counter (PW_ERR_RC);
gpg_reset_pw_err_counter (PW_ERR_PW1); gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS (); GPG_SUCCESS ();
} }
} }
@@ -537,8 +425,8 @@ cmd_reset_user_password (void)
newpw = pw; newpw = pw;
sha1 (newpw, newpw_len, new_ks); sha1 (newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len; new_ks0[0] = newpw_len;
r = gpg_change_keystring (BY_ADMIN, old_ks, BY_USER, new_ks); r = gpg_change_keystring (admin_authorized, old_ks, BY_USER, new_ks);
if (r < -2) if (r <= -2)
{ {
DEBUG_INFO ("memory error.\r\n"); DEBUG_INFO ("memory error.\r\n");
GPG_MEMORY_FAILURE (); GPG_MEMORY_FAILURE ();
@@ -555,7 +443,7 @@ cmd_reset_user_password (void)
KEYSTRING_SIZE_PW1); KEYSTRING_SIZE_PW1);
ac_reset_pso_cds (); ac_reset_pso_cds ();
ac_reset_other (); ac_reset_other ();
gpg_reset_pw_err_counter (PW_ERR_PW1); gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS (); GPG_SUCCESS ();
} }
else else
@@ -563,7 +451,7 @@ cmd_reset_user_password (void)
DEBUG_INFO ("done.\r\n"); DEBUG_INFO ("done.\r\n");
ac_reset_pso_cds (); ac_reset_pso_cds ();
ac_reset_other (); ac_reset_other ();
gpg_reset_pw_err_counter (PW_ERR_PW1); gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS (); GPG_SUCCESS ();
} }
} }
@@ -582,8 +470,9 @@ cmd_put_data (void)
GPG_NO_RECORD(); GPG_NO_RECORD();
tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]); tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
len = cmd_APDU_size - 5;
data = &cmd_APDU[5]; data = &cmd_APDU[5];
len = cmd_APDU_size - 5;
if (len >= 256) if (len >= 256)
/* extended Lc */ /* extended Lc */
{ {
@@ -681,10 +570,14 @@ cmd_select_file (void)
} }
else else
{ {
write_res_apdu (select_file_TOP_result, int len = sizeof (select_file_TOP_result);
sizeof (select_file_TOP_result), 0x90, 0x00);
res_APDU_size = 2 + len;
memcpy (res_APDU, select_file_TOP_result, len);
res_APDU[2] = (data_objects_number_of_bytes & 0xff); res_APDU[2] = (data_objects_number_of_bytes & 0xff);
res_APDU[3] = (data_objects_number_of_bytes >> 8); res_APDU[3] = (data_objects_number_of_bytes >> 8);
res_APDU[len] = 0x90;
res_APDU[len+1] = 0x00;
} }
file_selection = FILE_MF; file_selection = FILE_MF;
@@ -727,6 +620,7 @@ cmd_pso (void)
DEBUG_INFO (" - PSO: "); DEBUG_INFO (" - PSO: ");
DEBUG_WORD ((uint32_t)&r); DEBUG_WORD ((uint32_t)&r);
DEBUG_BINARY (cmd_APDU, cmd_APDU_size);
if (cmd_APDU[2] == 0x9e && cmd_APDU[3] == 0x9a) if (cmd_APDU[2] == 0x9e && cmd_APDU[3] == 0x9a)
{ {
@@ -752,6 +646,7 @@ cmd_pso (void)
else else
{ {
DEBUG_SHORT (len); /* Should be cmd_APDU_size - 8 [- 1] */ DEBUG_SHORT (len); /* Should be cmd_APDU_size - 8 [- 1] */
DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN);
r = rsa_sign (&cmd_APDU[data_start], res_APDU, len, r = rsa_sign (&cmd_APDU[data_start], res_APDU, len,
&kd[GPG_KEY_FOR_SIGNING]); &kd[GPG_KEY_FOR_SIGNING]);
@@ -761,20 +656,16 @@ cmd_pso (void)
GPG_ERROR (); GPG_ERROR ();
} }
else else
{ /* Success */ /* Success */
if (gpg_get_pw1_lifetime () == 0) gpg_increment_digital_signature_counter ();
ac_reset_pso_cds ();
gpg_increment_digital_signature_counter ();
}
} }
} }
else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86) else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86)
{ {
DEBUG_SHORT (len); DEBUG_SHORT (len);
DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN);
if (gpg_passwd_locked (PW_ERR_PW1) if (!ac_check_status (AC_OTHER_AUTHORIZED))
|| !ac_check_status (AC_OTHER_AUTHORIZED))
{ {
DEBUG_INFO ("security error."); DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE (); GPG_SECURITY_FAILURE ();
@@ -790,7 +681,7 @@ cmd_pso (void)
GPG_ERROR (); GPG_ERROR ();
} }
else else
{ /* XXX: not yet supported */ {
DEBUG_INFO (" - ??"); DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd_APDU[2]); DEBUG_BYTE (cmd_APDU[2]);
DEBUG_INFO (" - ??"); DEBUG_INFO (" - ??");
@@ -820,8 +711,7 @@ cmd_internal_authenticate (void)
{ {
DEBUG_SHORT (len); DEBUG_SHORT (len);
if (gpg_passwd_locked (PW_ERR_PW1) if (!ac_check_status (AC_OTHER_AUTHORIZED))
|| !ac_check_status (AC_OTHER_AUTHORIZED))
{ {
DEBUG_INFO ("security error."); DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE (); GPG_SECURITY_FAILURE ();
@@ -862,7 +752,7 @@ cmd_update_binary (void)
DEBUG_INFO (" - UPDATE BINARY\r\n"); DEBUG_INFO (" - UPDATE BINARY\r\n");
if (gpg_passwd_locked (PW_ERR_PW3) || !ac_check_status (AC_ADMIN_AUTHORIZED)) if (!ac_check_status (AC_ADMIN_AUTHORIZED))
{ {
DEBUG_INFO ("security error."); DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE (); GPG_SECURITY_FAILURE ();
@@ -933,7 +823,7 @@ cmd_write_binary (void)
DEBUG_INFO (" - WRITE BINARY\r\n"); DEBUG_INFO (" - WRITE BINARY\r\n");
if (gpg_passwd_locked (PW_ERR_PW3) || !ac_check_status (AC_ADMIN_AUTHORIZED)) if (!ac_check_status (AC_ADMIN_AUTHORIZED))
{ {
DEBUG_INFO ("security error."); DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE (); GPG_SECURITY_FAILURE ();
@@ -955,7 +845,7 @@ cmd_write_binary (void)
{ {
if (file_selection != FILE_EF_CH_CERTIFICATE if (file_selection != FILE_EF_CH_CERTIFICATE
&& file_selection != FILE_EF_RANDOM && file_selection != FILE_EF_RANDOM
&& file_selection != FILEID_SERIAL_NO) && file_selection != FILE_EF_SERIAL)
{ {
GPG_COMMAND_NOT_ALLOWED (); GPG_COMMAND_NOT_ALLOWED ();
return; return;
@@ -1035,18 +925,102 @@ GPGthread (void *arg)
while (!chThdShouldTerminate ()) while (!chThdShouldTerminate ())
{ {
eventmask_t m; eventmask_t m = chEvtWaitOne (ALL_EVENTS);
#if defined(PINPAD_SUPPORT)
m = chEvtWaitOne (ALL_EVENTS); int len, pw_len, newpw_len;
#endif
DEBUG_INFO ("GPG!: "); DEBUG_INFO ("GPG!: ");
DEBUG_WORD ((uint32_t)&m);
res_APDU_pointer = NULL; /* default */ res_APDU_pointer = NULL;
if (m == EV_VERIFY_CMD_AVAILABLE)
{
#if defined(PINPAD_SUPPORT)
if (cmd_APDU[1] != 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 (&cmd_APDU[5], pin_input_buffer, pw_len);
cmd_APDU[4] = pw_len;
icc_data_size = 5 + pw_len;
#else
GPG_ERROR ();
goto done;
#endif
}
else if (m == EV_MODIFY_CMD_AVAILABLE)
{
#if defined(PINPAD_SUPPORT)
uint8_t bConfirmPIN = cmd_APDU[4];
uint8_t *p = &cmd_APDU[5];
if (cmd_APDU[1] != INS_CHANGE_REFERENCE_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;
}
}
len = cmd_APDU[4] = pw_len + newpw_len;
icc_data_size = 5 + len;
#else
GPG_ERROR ();
goto done;
#endif
}
else if (m == EV_NOP)
continue;
if (icc_data_size != 0) if (icc_data_size != 0)
{ {
process_command_apdu (); process_command_apdu ();
done:
chEvtSignal (icc_thread, EV_EXEC_FINISHED); chEvtSignal (icc_thread, EV_EXEC_FINISHED);
} }
} }

View File

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

View File

@@ -27,13 +27,41 @@
#include "board.h" #include "board.h"
#include "gnuk.h" #include "gnuk.h"
#if 0 #ifdef DEBUG
#define DEBUG_CIR 1 #define DEBUG_CIR 1
#endif #endif
uint8_t pin_input_buffer[MAX_PIN_CHARS]; uint8_t pin_input_buffer[MAX_PIN_CHARS];
uint8_t pin_input_len; uint8_t pin_input_len;
/*
* Supported/tested TV controllers:
*
* Controller of Toshiba REGZA
* Controller of Sony BRAVIA
* Controller of Sharp AQUOS
* Dell Wireless Travel Remote MR425
*
* The code supports RC-5 protocol in fact, but I don't have any
* controller at hand which I can test with, so I don't have any data
* for controller of RC-5.
*
* Current code assumes following mapping:
*
* --------------------------------------
* Protocol Controller
* --------------------------------------
* RC-6 Dell MR425
* NEC Toshiba REGZA
* Sharp Sharp AQUOS
* Sony Sony BRAVIA
* --------------------------------------
*
* In future, when I will have other controllers, this mapping will be
* (should be) configurable, at compile time at least, preferably at
* runtime.
*/
/* /*
* Philips RC-5 Protocol: 14-bit (MSB first) * Philips RC-5 Protocol: 14-bit (MSB first)
* *
@@ -69,18 +97,26 @@ uint8_t pin_input_len;
*/ */
/* /*
* PB0 / TIM3_CH3 * The implementation note of CIR signal decoding (on STM32).
*
* (1) Use EXTI interrupt to detect the first edge of signal.
* (2) Use Timer (with PWM input mode) to measure timings of square wave.
*
*/
/*
* Timer settings.
*
* See THE reference manual (RM0008) section 15.3.6 PWM input mode.
* *
* 72MHz * 72MHz
*
* Prescaler = 72 * Prescaler = 72
* *
* 1us * 1us
* *
* * TIMx_CR1
* TIM3_CR1 * CKD = 00 (tDTS = tCK_INT)
* CKD = 10 (sampling x4) * ARPE = 1 (buffered)
* ARPE = 0 (not buffered)
* CMS = 00 (up counter) * CMS = 00 (up counter)
* DIR = 0 (up counter) * DIR = 0 (up counter)
* OPM = 0 (up counter) * OPM = 0 (up counter)
@@ -88,13 +124,13 @@ uint8_t pin_input_len;
* UDIS = 0 (UEV (update event) enabled) * UDIS = 0 (UEV (update event) enabled)
* CEN = 1 (counter enable) * CEN = 1 (counter enable)
* *
* TIM3_CR2 * TIMx_CR2
* TI1S = 1 (TI1 is XOR of ch1, ch2, ch3) * TI1S = 1 (TI1 is XOR of ch1, ch2, ch3)
* MMS = 000 (TRGO at Reset) * MMS = 000 (TRGO at Reset)
* CCDS = 0 (DMA on capture) * CCDS = 0 (DMA on capture)
* RSVD = 000 * RSVD = 000
* *
* TIM3_SMCR * TIMx_SMCR
* ETP = 0 * ETP = 0
* ECE = 0 * ECE = 0
* ETPS = 00 * ETPS = 00
@@ -104,61 +140,37 @@ uint8_t pin_input_len;
* RSVD = 0 * RSVD = 0
* SMS = 100 (Reset-mode) * SMS = 100 (Reset-mode)
* *
* TIM3_DIER * TIMx_DIER
* *
* TIM3_SR * TIMx_SR
* *
* TIM3_EGR * TIMx_EGR
* *
* TIM3_CCMR1 * TIMx_CCMR1
* CC1S = 01 (TI1 selected) * CC1S = 01 (TI1 selected)
* CC2S = 10 (TI1 selected) * CC2S = 10 (TI1 selected)
* IC1F = 1001 (fSAMPLING=fDTS/8, N=8)
* IC2F = 1001 (fSAMPLING=fDTS/8, N=8)
* *
* TIM3_CCMR2 * TIMx_CCMR2
* *
* TIM3_CCER * TIMx_CCER
* CC2P = 1 (polarity = falling edge: TI1FP1) * CC2P = 1 (polarity = falling edge: TI1FP1)
* CC2E = 1 * CC2E = 1
* CC1P = 0 (polarity = rising edge: TI1FP1) * CC1P = 0 (polarity = rising edge: TI1FP1)
* CC1E = 1 * CC1E = 1
* *
* TIM3_CNT * TIMx_CNT
* TIM3_PSC = 71 * TIMx_PSC = 71
* TIM3_ARR = 18000 * TIMx_ARR = 18000
* *
* TIM3_CCR1 period * TIMx_CCR1 period
* TIM3_CCR2 duty * TIMx_CCR2 duty
* *
* TIM3_DCR * TIMx_DCR
* TIM3_DMAR * TIMx_DMAR
*/ */
#define PINDISP_TIMEOUT_INTERVAL0 MS2ST(25)
#define PINDISP_TIMEOUT_INTERVAL1 MS2ST(300)
static void
pindisp (uint8_t c)
{
#if defined(HAVE_7SEGLED)
switch (c)
{
case 'G':
palWritePort (IOPORT2, 0xa1ff);
break;
case 'P':
palWritePort (IOPORT2, 0x98ff);
break;
case '.':
palWritePort (IOPORT2, 0x7fff);
break;
default:
palWritePort (IOPORT2, 0xffff);
}
#else
(void)c;
#endif
}
#if defined(DEBUG_CIR) #if defined(DEBUG_CIR)
static uint16_t intr_ext; static uint16_t intr_ext;
static uint16_t intr_trg; static uint16_t intr_trg;
@@ -179,14 +191,6 @@ static uint8_t cir_proto;
#define CIR_PROTO_NEC 5 #define CIR_PROTO_NEC 5
#define CIR_PROTO_SHARP 6 #define CIR_PROTO_SHARP 6
#define CIR_KEY_RC6_ENTER 0x0d /* Mute */
#define CIR_KEY_RC6_BACKSPACE 0xa4 /* <= */
#define CIR_KEY_NEC_ENTER 0x3d /* 'kettei' */
#define CIR_KEY_NEC_BACKSPACE 0x3b /* 'modoru' */
#define CIR_KEY_SONY_ENTER 0x65 /* 'kettei' */
#define CIR_KEY_SONY_BACKSPACE 0xa3 /* 'modoru' */
#define CIR_KEY_SHARP_ENTER 0x0252 /* 'kettei' */
#define CIR_KEY_SHARP_BACKSPACE 0xe4 /* 'modoru' */
/* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */ /* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */
static uint8_t cir_data_zero; static uint8_t cir_data_zero;
@@ -196,6 +200,388 @@ static uint8_t cir_seq;
static systime_t cir_input_last; static systime_t cir_input_last;
#define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */ #define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */
static void
cir_init (void)
{
cir_data = 0;
cir_seq = 0;
/* Don't touch cir_proto here */
cir_ext_enable ();
}
#define CH_RETURN 0x0d
#define CH_BACKSPACE 0x08
struct codetable {
uint16_t cir_code;
uint8_t char_code;
};
/* NOTE: no way to input '0' */
static const struct codetable
cir_codetable_dell_mr425[] = {
{0x10, '7' }, /* Speaker Louder */
{0x11, '8' }, /* Speaker Quieter */
{0x0d, '9' }, /* Speaker Mute */
{0xce, 'a' }, /* Black triangle UP */
{0xcf, 'b' }, /* Black triangle DOWN */
{0x58, 'c' }, /* White triangle UP */
{0x5a, 'd' }, /* White triangle LEFT */
{0x5c, CH_RETURN }, /* Check */
{0x5b, 'e' }, /* White triangle RIGHT */
{0xa4, CH_BACKSPACE }, /* Back */
{0x59, 'f' }, /* White triangle DOWN */
{0x2f, '1' }, /* Rewind */
{0x2c, '2' }, /* Play / Pause */
{0x2e, '3' }, /* Forward */
{0x21, '4' }, /* Skip backward */
{0x31, '5' }, /* Stop */
{0x20, '6' }, /* Skip forward */
{0, 0} /* <<END>> */
};
#define CIR_ADDR_SHARP_AQUOS 0x028f
static const struct codetable
cir_codetable_aquos[] = {
{ 0x0116, ' ' }, /* Power */
{ 0x025e, '0' }, /* d */
{ 0x024e, '1' }, /* 1 */
{ 0x024f, '2' }, /* 2 */
{ 0x0250, '3' }, /* 3 */
{ 0x0251, '4' }, /* 4 */
{ 0x0252, '5' }, /* 5 */
{ 0x0253, '6' }, /* 6 */
{ 0x0254, '7' }, /* 7 */
{ 0x0255, '8' }, /* 8 */
{ 0x0256, '9' }, /* 9 */
{ 0x0257, 'a' }, /* 10/0 */
{ 0x0258, 'b' }, /* 11 */
{ 0x0259, 'c' }, /* 12 */
{ 0x0111, 'd' }, /* Ch ^ */
{ 0x0112, 'e' }, /* Ch v */
{ 0x0114, 'f' }, /* Vol + */
{ 0x0115, 'g' }, /* Vol - */
{ 0x0117, 'h' }, /* Mute */
{ 0x0280, 'i' }, /* BLUE */
{ 0x0281, 'j' }, /* RED */
{ 0x0282, 'k' }, /* GREEN */
{ 0x0283, 'l' }, /* YELLOW */
{ 0x011b, 'm' }, /* DISPLAY CONTROL (gamen hyouji) */
{ 0x01d5, 'n' }, /* DISPLAY SIZE */
{ 0x0157, 'o' }, /* UP */
{ 0x01d7, 'p' }, /* LEFT */
{ 0x01d8, 'q' }, /* RIGHT */
{ 0x0120, 'r' }, /* DOWN */
{ 0x0152, CH_RETURN }, /* Commit (kettei) */
{ 0x01e4, CH_BACKSPACE }, /* Back (modoru) */
{ 0x01f5, 's' }, /* Quit (shuuryou) */
{ 0x0b03, 't' }, /* Rewind (hayamodoshi) */
{ 0x0b01, 'u' }, /* Play (saisei) */
{ 0x0b04, 'v' }, /* Forward (hayaokuri) */
{ 0x0b02, 'w' }, /* Stop (teishi) */
{ 0x028a, 'x' }, /* BS */
{ 0x028b, 'y' }, /* CS */
{ 0x025f, 'z' }, /* Program information (bangumi jouhou) */
{ 0x0260, '\\' }, /* Program table (bangumi hyou) */
{ 0x0118, '|' }, /* Sound channel (onsei kirikae) */
{ 0x028e, '[' }, /* Ground Analog (chijou A) */
{ 0x0289, ']' }, /* Ground Digital (chijou D) */
{ 0x0b07, '\"' }, /* Feature select (kinou sentaku) */
{ 0x026b, '.' }, /* TV/Radio/Data (terebi/rajio/data) */
{ 0x025a, ',' }, /* 3 code input (3 keta nyuuryoku) */
{ 0x0267, ':' }, /* subtitle (jimaku) */
{ 0x0159, ';' }, /* hold (seishi) */
{ 0x01c4, 'A' }, /* Menu */
{ 0x011a, 'B' }, /* Off timer */
{ 0x0121, 'C' }, /* CATV */
{ 0x0b05, 'D' }, /* Record */
{ 0x0b06, 'E' }, /* Recording stop */
{ 0x0113, 'F' }, /* Inputs (nyuuryoku kirikae) */
{ 0x0275, 'G' }, /* other programs (ura bangumi) */
{ 0x0266, 'H' }, /* signal control (eizou kirikae) */
{ 0x01e7, 'I' }, /* AV position */
{ 0x027f, 'J' }, /* i.LINK */
{ 0x0b00, 'K' }, /* Recorder power */
{ 0x028f, 'L' }, /* as you like it (okonomi senkyoku) */
{0, 0} /* <<END>> */
};
#define CIR_ADDR_TOSHIBA_REGZA 0xbf40
static const struct codetable
cir_codetable_regza[] = {
{ 0x12, ' ' }, /* Power */
{ 0x14, '0' }, /* d (data) */
{ 0x01, '1' }, /* 1 */
{ 0x02, '2' }, /* 2 */
{ 0x03, '3' }, /* 3 */
{ 0x04, '4' }, /* 4 */
{ 0x05, '5' }, /* 5 */
{ 0x06, '6' }, /* 6 */
{ 0x07, '7' }, /* 7 */
{ 0x08, '8' }, /* 8 */
{ 0x09, '9' }, /* 9 */
{ 0x0a, 'a' }, /* 10 */
{ 0x0b, 'b' }, /* 11 */
{ 0x0c, 'c' }, /* 12 */
{ 0x1b, 'd' }, /* Ch ^ */
{ 0x1f, 'e' }, /* Ch v */
{ 0x1a, 'f' }, /* Vol + */
{ 0x1e, 'g' }, /* Vol - */
{ 0x10, 'h' }, /* Mute */
{ 0x73, 'i' }, /* BLUE */
{ 0x74, 'j' }, /* RED */
{ 0x75, 'k' }, /* GREEN */
{ 0x76, 'l' }, /* YELLOW */
{ 0x1c, 'm' }, /* Display control */
{ 0x2b, 'n' }, /* Display size */
{ 0x3e, 'o' }, /* UP */
{ 0x5f, 'p' }, /* LEFT */
{ 0x5b, 'q' }, /* RIGHT */
{ 0x3f, 'r' }, /* DOWN */
{ 0x3d, CH_RETURN }, /* Commit (kettei) */
{ 0x3b, CH_BACKSPACE }, /* Back (modoru) */
{ 0x3c, 's' }, /* Quit (shuuryou) */
{ 0x2c, 't' }, /* << (Rewind) */
{ 0x2d, 'u' }, /* >/|| (Play/Stop) */
{ 0x2e, 'v' }, /* >> (Forward) */
{ 0x2b, 'w' }, /* Stop (teishi) */
{ 0x7c, 'x' }, /* BS */
{ 0x7d, 'y' }, /* CS */
{ 0x71, 'z' }, /* Program information (bangumi setsumei) */
{ 0x77, '\\' }, /* Mini program table (mini bangumihyou) */
{ 0x13, '|' }, /* Sound (onta kirikae) */
{ 0x7a, '[' }, /* Ground Digital (chideji) */
{ 0x7b, ']' }, /* Ground Analog (chiana) */
{ 0xd0, '\"' }, /* Settings Menu (settei menu) */
{ 0x6d, '.' }, /* Radio/Data (rajio/data) */
{ 0x60, ',' }, /* CH 10-key input (search) */
{ 0x52, ':' }, /* subtitle (jimaku) */
{ 0x50, ';' }, /* hold (seishi) */
{ 0x3a, 'A' }, /* Input- (nyuuryokukirikae-) */
{ 0x0f, 'B' }, /* Input+ (nyuuryokukirikae+) */
{ 0x29, 'C' }, /* Two screens (nigamen) */
{ 0x25, 'D' }, /* Broadband */
{ 0x27, 'E' }, /* |<< Skip backward */
{ 0x26, 'F' }, /* >>| Skip forward */
{ 0x61, '!' }, /* 1 NHK1 */
{ 0x62, '@' }, /* 2 NHK2 */
{ 0x63, '#' }, /* 3 NHKh */
{ 0x64, '$' }, /* 4 BS Nihon TV */
{ 0x65, '%' }, /* 5 BS Asahi */
{ 0x66, '^' }, /* 6 BS-i */
{ 0x67, '&' }, /* 7 BSJ */
{ 0x68, '*' }, /* 8 BS Fuji */
{ 0x69, '(' }, /* 9 WOW */
{ 0x6a, ')' }, /* 10 Star */
{ 0x6b, '-' }, /* 11 BS11 */
{ 0x6c, '+' }, /* 12 TwellV */
{ 0x27, '=' }, /* Quick (Delete) */
{ 0x34, '<' }, /* REGZA link */
{ 0x6e, '>' }, /* Program Table */
{ 0x20, '/' }, /* ^^ */
{ 0x22, '\'' }, /* << */
{ 0x23, '?' }, /* >> */
{ 0x21, '_' }, /* vv */
{0, 0} /* <<END>> */
};
static const struct codetable
cir_codetable_bravia[] = {
{ 0x15, ' ' }, /* Power */
{ 0x95, '0' }, /* d (16-bit: 0x4b) */
{ 0x00, '1' }, /* 1 */
{ 0x01, '2' }, /* 2 */
{ 0x02, '3' }, /* 3 */
{ 0x03, '4' }, /* 4 */
{ 0x04, '5' }, /* 5 */
{ 0x05, '6' }, /* 6 */
{ 0x06, '7' }, /* 7 */
{ 0x07, '8' }, /* 8 */
{ 0x08, '9' }, /* 9 */
{ 0x09, 'a' }, /* 10 */
{ 0x0a, 'b' }, /* 11 */
{ 0x0b, 'c' }, /* 12 */
{ 0x10, 'd' }, /* CH+ */
{ 0x11, 'd' }, /* CH- */
{ 0x12, 'f' }, /* Vol+ */
{ 0x13, 'g' }, /* Vol- */
{ 0x14, 'h' }, /* Mute */
{ 0xa4, 'i' }, /* BLUE (16-bit: 0x4b) */
{ 0xa5, 'j' }, /* RED (16-bit: 0x4b) */
{ 0xa6, 'k' }, /* GREEN (16-bit: 0x4b) */
{ 0xa7, 'l' }, /* YELLOW (16-bit: 0x4b) */
{ 0x3a, 'm' }, /* DISPLAY control (gamen hyouji) */
{ 0x3d, 'n' }, /* Display Wide (waido kirikae) */
{ 0x74, 'o' }, /* UP */
{ 0x75, 'p' }, /* DOWN */
{ 0x33, 'q' }, /* RIGHT */
{ 0x34, 'r' }, /* LEFT */
{ 0x65, CH_RETURN }, /* Commit (kettei) */
{ 0xa3, CH_BACKSPACE }, /* Back (modoru) (16-bit: 0x4b) */
{ 0xac, 's' }, /* BS (16-bit: 0x4b) */
{ 0xab, 't' }, /* CS (16-bit: 0x4b) */
{ 0x5b, 'u' }, /* Program table (bangumi hyou) (16-bit: 0x52) */
{ 0x17, 'v' }, /* Sound channel (onsei kirikae) */
{ 0xa8, 'w' }, /* subtitle (jimaku) (16-bit: 0x4b) */
{ 0x5c, 'x' }, /* hold (memo) */
{ 0xb6, 'y' }, /* Tool (16-bit: 0x4b) */
{ 0x8c, 'z' }, /* 10 key input (10ki-) (16-bit: 0x4b) */
{ 0x60, '!' }, /* Menu */
{ 0xae, '@' }, /* Analog (16-bit: 0x4b) */
{ 0xb2, '#' }, /* Digital (16-bit: 0x4b) */
{ 0x25, '$' }, /* Input (nyuuryoku kirikae) */
{0, 0} /* <<END>> */,
};
static int
ch_is_backspace (int ch)
{
return ch == CH_BACKSPACE;
}
static int
ch_is_enter (int ch)
{
return ch == CH_RETURN;
}
/* liner search is good enough for this small amount of data */
static uint8_t
find_char_codetable (uint32_t cir_code, const struct codetable *ctp)
{
while (ctp->cir_code != 0x0000 || ctp->char_code != 0x00)
if (ctp->cir_code == cir_code)
return ctp->char_code;
else
ctp++;
/* Not found */
return cir_code & 0xff;
}
static int
hex (int x)
{
if (x < 10)
return x + '0';
else
return (x - 10) + 'a';
}
static int
cir_getchar (systime_t timeout)
{
uint16_t cir_addr;
eventmask_t m;
#if defined(DEBUG_CIR)
uint16_t *p;
#endif
#if defined(DEBUG_CIR)
cirinput_p = cirinput;
#endif
chEvtClear (ALL_EVENTS);
cir_init ();
m = chEvtWaitOneTimeout (ALL_EVENTS, timeout);
if (m == 0)
return -1;
#if defined(DEBUG_CIR)
DEBUG_INFO ("****\r\n");
DEBUG_SHORT (intr_ext);
DEBUG_SHORT (intr_trg);
DEBUG_SHORT (intr_ovf);
DEBUG_INFO ("----\r\n");
for (p = cirinput; p < cirinput_p; p++)
DEBUG_SHORT (*p);
DEBUG_INFO ("====\r\n");
cirinput_p = cirinput;
DEBUG_INFO ("**** CIR data:");
DEBUG_WORD (cir_data);
if (cir_seq > 48)
DEBUG_SHORT (cir_data_more);
DEBUG_BYTE (cir_seq);
#endif
switch (cir_proto)
{
case CIR_PROTO_RC5:
cir_data &= 0x003f;
goto err;
case CIR_PROTO_RC6:
cir_addr = cir_data >> 8; /* in case of cir_seq == 16. 32??? */
cir_data &= 0x00ff;
return find_char_codetable (cir_data, cir_codetable_dell_mr425);
case CIR_PROTO_NEC:
cir_addr = cir_data&0xffff;
if (cir_addr == CIR_ADDR_TOSHIBA_REGZA)
{
cir_data = (cir_data >> 16) & 0x00ff;
return find_char_codetable (cir_data, cir_codetable_regza);
}
else
goto err;
case CIR_PROTO_SHARP:
cir_addr = cir_data&0x0fff;
if (cir_addr == CIR_ADDR_SHARP_AQUOS)
{
cir_data = (cir_data>>16)&0x0fff;
return find_char_codetable (cir_data, cir_codetable_aquos);
}
else
goto err;
case CIR_PROTO_SONY:
/* Remove ADDRESS bits and filter COMMAND bits */
if (cir_seq == 1 + 12)
{
cir_addr = cir_data >> 7;
cir_data = cir_data & 0x007f;
/* ADDRESS = 0x01 (5-bit) */
}
else
{
cir_addr = cir_data >> 8;
cir_data = cir_data & 0x00ff;
/* ADDRESS = 0x4b or 0x52 (7-bit) */
}
return find_char_codetable (cir_data, cir_codetable_bravia);
err:
default:
/* encode debug information */
pin_input_len = 16;
pin_input_buffer[0] = hex (cir_proto >> 4);
pin_input_buffer[1] = hex (cir_proto & 0x0f);
pin_input_buffer[2] = ':';
pin_input_buffer[3] = hex ((cir_data >> 28) & 0x0f);
pin_input_buffer[4] = hex ((cir_data >> 24) & 0x0f);
pin_input_buffer[5] = hex ((cir_data >> 20) & 0x0f);
pin_input_buffer[6] = hex ((cir_data >> 16) & 0x0f);
pin_input_buffer[7] = hex ((cir_data >> 12) & 0x0f);
pin_input_buffer[8] = hex ((cir_data >> 8) & 0x0f);
pin_input_buffer[9] = hex ((cir_data >> 4) & 0x0f);
pin_input_buffer[10] = hex (cir_data & 0x0f);
pin_input_buffer[11] = ':';
pin_input_buffer[12] = hex ((cir_data_more >> 12) & 0x0f);
pin_input_buffer[13] = hex ((cir_data_more >> 8) & 0x0f);
pin_input_buffer[14] = hex ((cir_data_more >> 4) & 0x0f);
pin_input_buffer[15] = hex (cir_data_more & 0x0f);
return CH_RETURN;
}
}
/* /*
* RC-5 protocol doesn't have a start bit, while any other protocols * RC-5 protocol doesn't have a start bit, while any other protocols
* have the one. * have the one.
@@ -207,125 +593,56 @@ static systime_t cir_input_last;
#define CIR_BIT_PERIOD 1500 #define CIR_BIT_PERIOD 1500
#define CIR_BIT_SIRC_PERIOD_ON 1000 #define CIR_BIT_SIRC_PERIOD_ON 1000
static void
cir_init (void)
{
cir_data = 0;
cir_seq = 0;
/* Don't touch cir_proto here */
cir_ext_enable ();
}
static Thread *pin_thread; static Thread *pin_thread;
static int /*
cir_key_is_backspace (void) * 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)
{ {
return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_BACKSPACE)
|| (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_BACKSPACE)
|| (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_BACKSPACE)
|| (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_BACKSPACE);
}
static int
cir_key_is_enter (void)
{
return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_ENTER)
|| (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_ENTER)
|| (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_ENTER)
|| (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_ENTER);
}
msg_t
pin_main (void *arg)
{
uint8_t s = 0;
int msg_code = (int)arg;
(void)msg_code; (void)msg_code;
pin_thread = chThdSelf (); pin_thread = chThdSelf ();
#if defined(DEBUG_CIR) DEBUG_INFO (">>>\r\n");
cirinput_p = cirinput;
#endif
pin_input_len = 0; pin_input_len = 0;
chEvtClear (ALL_EVENTS); while (1)
cir_init ();
while (!chThdShouldTerminate ())
{ {
eventmask_t m; int ch;
m = chEvtWaitOneTimeout (ALL_EVENTS, PINDISP_TIMEOUT_INTERVAL1); ch = cir_getchar (timeout);
if (ch < 0)
return 0; /* timeout */
if (m) if (ch_is_backspace (ch))
{ {
#if defined(DEBUG_CIR) led_blink (2);
uint16_t *p; if (pin_input_len > 0)
pin_input_len--;
DEBUG_INFO ("****\r\n");
DEBUG_SHORT (intr_ext);
DEBUG_SHORT (intr_trg);
DEBUG_SHORT (intr_ovf);
DEBUG_INFO ("----\r\n");
for (p = cirinput; p < cirinput_p; p++)
DEBUG_SHORT (*p);
DEBUG_INFO ("====\r\n");
cirinput_p = cirinput;
#endif
DEBUG_INFO ("**** CIR data:");
DEBUG_WORD (cir_data);
if (cir_seq > 48)
{
DEBUG_SHORT (cir_data_more);
}
DEBUG_BYTE (cir_seq);
if (cir_key_is_backspace ())
{
if (pin_input_len > 0)
pin_input_len--;
}
else if (cir_key_is_enter ())
{
pindisp (' ');
chThdExit (0);
}
else if (pin_input_len < MAX_PIN_CHARS)
pin_input_buffer[pin_input_len++] = (uint8_t)cir_data;
cir_init ();
} }
else if (ch_is_enter (ch))
switch (s++) break;
else if (pin_input_len < MAX_PIN_CHARS)
{ {
case 0: led_blink (0);
pindisp ('G'); pin_input_buffer[pin_input_len++] = ch;
break;
case 1:
pindisp ('P');
break;
case 2:
pindisp ('G');
break;
case 3:
pindisp ('.');
break;
default:
pindisp (' ');
s = 0;
break;
} }
chThdSleep (PINDISP_TIMEOUT_INTERVAL0);
} }
cir_ext_disable (); cir_ext_disable ();
return 0;
return pin_input_len;
} }
/**
* @brief Interrupt handler of EXTI.
* @note This handler will be invoked at the beginning of signal.
* Setup timer to measure period and duty using PWM input mode.
*/
void void
cir_ext_interrupt (void) cir_ext_interrupt (void)
{ {
@@ -340,29 +657,33 @@ cir_ext_interrupt (void)
} }
#endif #endif
TIM3->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */ TIMx->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */
/* Enable Timer */ /* Enable Timer */
TIM3->SR &= ~(TIM_SR_UIF TIMx->SR &= ~(TIM_SR_UIF
| TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC1IF | TIM_SR_CC2IF
| TIM_SR_TIF | TIM_SR_TIF
| TIM_SR_CC1OF | TIM_SR_CC2OF); | TIM_SR_CC1OF | TIM_SR_CC2OF);
TIM3->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/; TIMx->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
TIM3->CR1 |= TIM_CR1_CEN; TIMx->CR1 |= TIM_CR1_CEN;
} }
#define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \ #define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \
* CIR_BIT_PERIOD_RC6 * 3 / 2) * CIR_BIT_PERIOD_RC6 * 3 / 2)
/**
* @brief Interrupt handler of timer.
* @note Timer is PWM input mode, this handler will be invoked on each cycle
*/
void void
cir_timer_interrupt (void) cir_timer_interrupt (void)
{ {
uint16_t period, on, off; uint16_t period, on, off;
period = TIM3->CCR1; period = TIMx->CCR1;
on = TIM3->CCR2; on = TIMx->CCR2;
off = period - on; off = period - on;
if ((TIM3->SR & TIM_SR_TIF)) if ((TIMx->SR & TIM_SR_TIF))
{ {
if (cir_seq == 0) if (cir_seq == 0)
{ {
@@ -477,23 +798,23 @@ cir_timer_interrupt (void)
intr_trg++; intr_trg++;
#endif #endif
TIM3->EGR = TIM_EGR_UG; /* Generate UEV */ TIMx->EGR = TIM_EGR_UG; /* Generate UEV */
TIM3->SR &= ~TIM_SR_TIF; TIMx->SR &= ~TIM_SR_TIF;
} }
else else
/* overflow occurred */ /* overflow occurred */
{ {
systime_t now = chTimeNow (); systime_t now = chTimeNow ();
TIM3->SR &= ~TIM_SR_UIF; TIMx->SR &= ~TIM_SR_UIF;
if (on > 0) if (on > 0)
{ {
uint8_t ignore_input = 0; uint8_t ignore_input = 0;
/* Disable the timer */ /* Disable the timer */
TIM3->CR1 &= ~TIM_CR1_CEN; TIMx->CR1 &= ~TIM_CR1_CEN;
TIM3->DIER = 0; TIMx->DIER = 0;
if (cir_seq == 12 || cir_seq == 15) if (cir_seq == 12 || cir_seq == 15)
{ {
@@ -536,14 +857,9 @@ cir_timer_interrupt (void)
cir_input_last = now; cir_input_last = now;
ignore_input = 1; ignore_input = 1;
} }
/* Remove ADDRESS bits and filter COMMAND bits */
else if (cir_proto == CIR_PROTO_SONY) else if (cir_proto == CIR_PROTO_SONY)
{ {
if (cir_seq == 1 + 12) if (cir_seq != 1 + 12 && cir_seq != 1 + 15)
cir_data = cir_data & 0x007f;
else if (cir_seq == 1 + 15)
cir_data = cir_data & 0x00ff;
else
ignore_input = 1; ignore_input = 1;
} }
else if (cir_proto == CIR_PROTO_OTHER) else if (cir_proto == CIR_PROTO_OTHER)
@@ -551,10 +867,7 @@ cir_timer_interrupt (void)
if (cir_seq == 1 + 32) if (cir_seq == 1 + 32)
{ {
if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff)) if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff))
{ cir_proto = CIR_PROTO_NEC;
cir_proto = CIR_PROTO_NEC;
cir_data = (cir_data >> 16) & 0x00ff;
}
else else
ignore_input = 1; ignore_input = 1;
} }
@@ -569,10 +882,7 @@ cir_timer_interrupt (void)
^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f) ^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f)
^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f) ^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f)
^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f))) ^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f)))
{ cir_proto = CIR_PROTO_SHARP;
cir_proto = CIR_PROTO_SHARP;
cir_data = (cir_data >> 16) & 0x0fff;
}
else else
ignore_input = 1; ignore_input = 1;
} }
@@ -581,16 +891,12 @@ cir_timer_interrupt (void)
} }
else if (cir_proto == CIR_PROTO_RC6) else if (cir_proto == CIR_PROTO_RC6)
{ {
if (cir_seq == 16 || cir_seq == 32) if (cir_seq != 16 && cir_seq != 32)
cir_data &= 0x00ff;
else
ignore_input = 1; ignore_input = 1;
} }
else if (cir_proto == CIR_PROTO_RC5) else if (cir_proto == CIR_PROTO_RC5)
{ {
if (cir_seq == 14) if (cir_seq != 14)
cir_data &= 0x003f;
else
ignore_input = 1; ignore_input = 1;
} }
else else
@@ -603,7 +909,8 @@ cir_timer_interrupt (void)
{ {
cir_input_last = now; cir_input_last = now;
/* Notify thread */ /* Notify thread */
chEvtSignal (pin_thread, (eventmask_t)1); if (pin_thread)
chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE);
} }
#if defined(DEBUG_CIR) #if defined(DEBUG_CIR)

View File

@@ -117,21 +117,19 @@ blink_dp (void)
} }
static Thread *pin_thread; static Thread *pin_thread;
#define EV_SW_PUSH (eventmask_t)1
void void
dial_sw_interrupt (void) dial_sw_interrupt (void)
{ {
dial_sw_disable (); dial_sw_disable ();
chEvtSignalI (pin_thread, EV_SW_PUSH); chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE);
palClearPad (IOPORT1, GPIOA_LED2); palClearPad (IOPORT1, GPIOA_LED2);
} }
msg_t int
pin_main (void *arg) pinpad_getline (int msg_code, systime_t timeout)
{ {
int msg_code = (int)arg;
uint16_t count, count_prev; uint16_t count, count_prev;
uint8_t input_mode; uint8_t input_mode;
uint8_t sw_push_count; uint8_t sw_push_count;
@@ -150,7 +148,7 @@ pin_main (void *arg)
sw_push_count = 0; sw_push_count = 0;
sw_event = 0; sw_event = 0;
while (!chThdShouldTerminate ()) while (1)
{ {
eventmask_t m; eventmask_t m;
@@ -158,7 +156,7 @@ pin_main (void *arg)
dial_sw_enable (); dial_sw_enable ();
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_DISP_BLINK_INTERVAL0); 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) if (palReadPad (IOPORT2, GPIOB_BUTTON) == 0)
sw_push_count++; sw_push_count++;
@@ -218,5 +216,5 @@ pin_main (void *arg)
led_disp (OFF); led_disp (OFF);
TIM4->CR1 &= ~TIM_CR1_CEN; TIM4->CR1 &= ~TIM_CR1_CEN;
dial_sw_disable (); dial_sw_disable ();
return 0; return pin_input_len;
} }

372
src/pin-dnd.c Normal file
View 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);
}

View File

@@ -1,7 +1,7 @@
/* /*
* random.c -- get random bytes * random.c -- get random bytes
* *
* Copyright (C) 2010 Free Software Initiative of Japan * Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,47 +24,49 @@
#include "config.h" #include "config.h"
#include "ch.h" #include "ch.h"
#include "gnuk.h" #include "gnuk.h"
#include "neug.h"
#define RANDOM_BYTES_LENGTH 16
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
void
random_init (void)
{
int i;
neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
for (i = 0; i < NEUG_PRE_LOOP; i++)
(void)neug_get (NEUG_KICK_FILLING);
neug_prng_reseed ();
}
/*
* Return pointer to random 16-byte
*/
const uint8_t * const uint8_t *
random_bytes_get (void) random_bytes_get (void)
{ {
uint32_t addr, addr0; neug_wait_full ();
return (const uint8_t *)random_word;
addr = (uint32_t)&random_bits_start + ((hardclock () << 5) & 0x3e0);
addr0 = addr;
while (1)
{
if (*(uint32_t *)addr != 0 && *(uint32_t *)addr != 0xffffffff)
break;
addr += 32;
if (addr >= ((uint32_t)&random_bits_start) + 1024)
addr = ((uint32_t)&random_bits_start);
if (addr == addr0)
fatal (FATAL_RANDOM);
}
return (const uint8_t *)addr;
} }
/*
* Free pointer to random 16-byte
*/
void void
random_bytes_free (const uint8_t *p) random_bytes_free (const uint8_t *p)
{ {
int i; (void)p;
uint32_t addr = (uint32_t)p; neug_flush ();
for (i = 0; i < 16; i++)
flash_clear_halfword (addr+i*2);
} }
/*
* Return 4-byte salt
*/
uint32_t uint32_t
get_random (void) get_salt (void)
{ {
const uint32_t *p = (const uint32_t *)random_bytes_get (); return neug_get (NEUG_KICK_FILLING);
uint32_t r = *p;
random_bytes_free ((const uint8_t *)p);
return r;
} }

View File

@@ -26,7 +26,6 @@
#include "hal.h" #include "hal.h"
#include "gnuk.h" #include "gnuk.h"
#include "usb_lib.h" #include "usb_lib.h"
#include "usb_desc.h"
#include "usb_mem.h" #include "usb_mem.h"
#include "hw_config.h" #include "hw_config.h"
#include "usb_istr.h" #include "usb_istr.h"
@@ -170,12 +169,31 @@ void
EP2_OUT_Callback (void) EP2_OUT_Callback (void)
{ {
int len; 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_SIL_Read (EP2_OUT, icc_next_p);
if (len == 0)
{ /* Just ignore Zero Length Packet (ZLP), if any */
SetEPRxValid (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); SetEPRxValid (ENDP2);
if ((icc_next_p - icc_buffer) >= USB_BUF_SIZE) if ((icc_next_p - icc_buffer) >= USB_BUF_SIZE)
/* No room to receive any more */ /* No room to receive any more */
@@ -187,27 +205,18 @@ EP2_OUT_Callback (void)
* (and discard the whole block) * (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 */ else /* Finished */
{ {
struct icc_header *icc_header; icc_data_size = data_len_so_far;
int data_len; icc_seq = icc_header->seq; /* NOTE: We're little endian */
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;
if (icc_data_size != data_len) if (icc_data_size != data_len)
{ {
@@ -217,7 +226,7 @@ EP2_OUT_Callback (void)
icc_prepare_receive (0); icc_prepare_receive (0);
} }
else else
/* Notify icc_thread */ /* Notify myself */
chEvtSignalI (icc_thread, EV_RX_DATA_READY); chEvtSignalI (icc_thread, EV_RX_DATA_READY);
} }
} }
@@ -374,7 +383,7 @@ icc_power_off (void)
if (gpg_thread) if (gpg_thread)
{ {
chThdTerminate (gpg_thread); chThdTerminate (gpg_thread);
chEvtSignal (gpg_thread, (eventmask_t)1); chEvtSignal (gpg_thread, EV_NOP);
chThdWait (gpg_thread); chThdWait (gpg_thread);
gpg_thread = NULL; gpg_thread = NULL;
} }
@@ -497,7 +506,7 @@ icc_handle_data (void)
{ {
if (icc_header->param == 0) if (icc_header->param == 0)
{ /* Give this message to GPG thread */ { /* Give this message to GPG thread */
chEvtSignal (gpg_thread, (eventmask_t)1); chEvtSignal (gpg_thread, EV_CMD_AVAILABLE);
next_state = ICC_STATE_EXECUTE; next_state = ICC_STATE_EXECUTE;
} }
else if (icc_header->param == 1) else if (icc_header->param == 1)
@@ -524,7 +533,15 @@ icc_handle_data (void)
cmd_APDU[2] = icc_buffer[27]; cmd_APDU[2] = icc_buffer[27];
cmd_APDU[3] = icc_buffer[28]; cmd_APDU[3] = icc_buffer[28];
icc_data_size = 4; icc_data_size = 4;
chEvtSignal (gpg_thread, (eventmask_t)1); cmd_APDU[4] = 0; /* bConfirmPIN */
cmd_APDU[5] = icc_buffer[17]; /* bEntryValidationCondition */
cmd_APDU[6] = icc_buffer[18]; /* bNumberMessage */
cmd_APDU[7] = icc_buffer[19]; /* wLangId L */
cmd_APDU[8] = icc_buffer[20]; /* wLangId H */
cmd_APDU[9] = icc_buffer[21]; /* bMsgIndex, bMsgIndex1 */
cmd_APDU[10] = 0; /* bMsgIndex2 */
cmd_APDU[11] = 0; /* bMsgIndex3 */
chEvtSignal (gpg_thread, EV_VERIFY_CMD_AVAILABLE);
next_state = ICC_STATE_EXECUTE; next_state = ICC_STATE_EXECUTE;
} }
else if (icc_buffer[10] == 0x01) /* PIN Modification */ else if (icc_buffer[10] == 0x01) /* PIN Modification */
@@ -540,7 +557,18 @@ icc_handle_data (void)
cmd_APDU[2] = icc_buffer[29 + num_msgs]; cmd_APDU[2] = icc_buffer[29 + num_msgs];
cmd_APDU[3] = icc_buffer[30 + num_msgs]; cmd_APDU[3] = icc_buffer[30 + num_msgs];
icc_data_size = 4; icc_data_size = 4;
chEvtSignal (gpg_thread, (eventmask_t)1); cmd_APDU[4] = icc_buffer[19]; /* bConfirmPIN */
cmd_APDU[5] = icc_buffer[20]; /* bEntryValidationCondition */
cmd_APDU[6] = icc_buffer[21]; /* bNumberMessage */
cmd_APDU[7] = icc_buffer[22]; /* wLangId L */
cmd_APDU[8] = icc_buffer[23]; /* wLangId H */
cmd_APDU[9] = icc_buffer[24]; /* bMsgIndex, bMsgIndex1 */
cmd_APDU[10] = cmd_APDU[11] = 0;
if (num_msgs >= 2)
cmd_APDU[10] = icc_buffer[25]; /* bMsgIndex2 */
if (num_msgs == 3)
cmd_APDU[11] = icc_buffer[26]; /* bMsgIndex3 */
chEvtSignal (gpg_thread, EV_MODIFY_CMD_AVAILABLE);
next_state = ICC_STATE_EXECUTE; next_state = ICC_STATE_EXECUTE;
} }
else else
@@ -572,7 +600,7 @@ icc_handle_data (void)
icc_data_size = icc_next_p - icc_buffer - ICC_MSG_HEADER_SIZE; icc_data_size = icc_next_p - icc_buffer - ICC_MSG_HEADER_SIZE;
icc_chain_p = NULL; icc_chain_p = NULL;
next_state = ICC_STATE_EXECUTE; next_state = ICC_STATE_EXECUTE;
chEvtSignal (gpg_thread, (eventmask_t)1); chEvtSignal (gpg_thread, EV_CMD_AVAILABLE);
} }
else /* icc_header->param == 3 is not supported. */ else /* icc_header->param == 3 is not supported. */
{ {

View File

@@ -8,10 +8,14 @@
#ifndef __USB_CONF_H #ifndef __USB_CONF_H
#define __USB_CONF_H #define __USB_CONF_H
#ifdef ENABLE_VIRTUAL_COM_PORT #ifdef PINPAD_DND_SUPPORT
#define EP_NUM (6) # define EP_NUM (8)
#else #else
#define EP_NUM (3) # ifdef ENABLE_VIRTUAL_COM_PORT
# define EP_NUM (6)
# else
# define EP_NUM (3)
# endif
#endif #endif
#define BTABLE_ADDRESS (0x00) #define BTABLE_ADDRESS (0x00)
@@ -28,9 +32,14 @@
/* EP3 */ /* EP3 */
#define ENDP3_TXADDR (0x140) #define ENDP3_TXADDR (0x140)
/* EP4 */ /* EP4 */
#define ENDP4_TXADDR (0x180) #define ENDP4_TXADDR (0x150)
/* EP5 */ /* 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 ) #define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )

View File

@@ -15,7 +15,7 @@
static const uint8_t gnukDeviceDescriptor[] = { static const uint8_t gnukDeviceDescriptor[] = {
18, /* bLength */ 18, /* bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x00, 0x02, /* bcdUSB = 2.00 */ 0x10, 0x01, /* bcdUSB = 1.1 */
0x00, /* bDeviceClass: 0 means deferred to interface */ 0x00, /* bDeviceClass: 0 means deferred to interface */
0x00, /* bDeviceSubClass */ 0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */ 0x00, /* bDeviceProtocol */
@@ -29,14 +29,29 @@ static const uint8_t gnukDeviceDescriptor[] = {
0x01 /* bNumConfigurations */ 0x01 /* bNumConfigurations */
}; };
#define ICC_TOTAL_LENGTH (9+9+54+7+7)
#define ICC_NUM_INTERFACES 1
#ifdef ENABLE_VIRTUAL_COM_PORT #ifdef ENABLE_VIRTUAL_COM_PORT
#define W_TOTAL_LENGTH (9+9+54+7+7+9+5+5+4+5+7+9+7+7) #define VCOM_TOTAL_LENGTH (9+5+5+4+5+7+9+7+7)
#define NUM_INTERFACES 3 /* two for CDC, one for GPG */ #define VCOM_NUM_INTERFACES 2
#else #else
#define W_TOTAL_LENGTH (9+9+54+7+7) #define VCOM_TOTAL_LENGTH 0
#define NUM_INTERFACES 1 /* GPG only */ #define VCOM_NUM_INTERFACES 0
#endif #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 */ /* Configuation Descriptor */
static const uint8_t gnukConfigDescriptor[] = { static const uint8_t gnukConfigDescriptor[] = {
9, /* bLength: Configuation Descriptor size */ 9, /* bLength: Configuation Descriptor size */
@@ -105,7 +120,7 @@ static const uint8_t gnukConfigDescriptor[] = {
0xff, /* bClassEnvelope: */ 0xff, /* bClassEnvelope: */
0, 0, /* wLCDLayout: FIXED VALUE */ 0, 0, /* wLCDLayout: FIXED VALUE */
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
#if defined(PINPAD_CIR_SUPPORT) #if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DND_SUPPORT)
1, /* bPinSupport: with PIN pad (verify) */ 1, /* bPinSupport: with PIN pad (verify) */
#elif defined(PINPAD_DIAL_SUPPORT) #elif defined(PINPAD_DIAL_SUPPORT)
3, /* bPinSupport: with PIN pad (verify, modify) */ 3, /* bPinSupport: with PIN pad (verify, modify) */
@@ -193,7 +208,40 @@ static const uint8_t gnukConfigDescriptor[] = {
0x83, /* bEndpointAddress: (IN3) */ 0x83, /* bEndpointAddress: (IN3) */
0x02, /* bmAttributes: Bulk */ 0x02, /* bmAttributes: Bulk */
VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */ 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 #endif
}; };
@@ -224,6 +272,16 @@ static const uint8_t gnukStringProduct[] = {
' ', 0, 'T', 0, 'o', 0, 'k', 0, 'e', 0, 'n', 0 ' ', 0, 'T', 0, 'o', 0, 'k', 0, 'e', 0, 'n', 0
}; };
const uint8_t gnukStringSerial[] = {
13*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
'0', 0, '.', 0, '1', 0, '6', 0, /* Version number of Gnuk */
'-', 0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
const ONE_DESCRIPTOR Device_Descriptor = { const ONE_DESCRIPTOR Device_Descriptor = {
(uint8_t*)gnukDeviceDescriptor, (uint8_t*)gnukDeviceDescriptor,
sizeof (gnukDeviceDescriptor) sizeof (gnukDeviceDescriptor)
@@ -234,8 +292,9 @@ const ONE_DESCRIPTOR Config_Descriptor = {
sizeof (gnukConfigDescriptor) sizeof (gnukConfigDescriptor)
}; };
const ONE_DESCRIPTOR String_Descriptor[3] = { const ONE_DESCRIPTOR String_Descriptor[] = {
{(uint8_t*)gnukStringLangID, sizeof (gnukStringLangID)}, {(uint8_t*)gnukStringLangID, sizeof (gnukStringLangID)},
{(uint8_t*)gnukStringVendor, sizeof (gnukStringVendor)}, {(uint8_t*)gnukStringVendor, sizeof (gnukStringVendor)},
{(uint8_t*)gnukStringProduct, sizeof (gnukStringProduct)}, {(uint8_t*)gnukStringProduct, sizeof (gnukStringProduct)},
{(uint8_t*)gnukStringSerial, sizeof (gnukStringSerial)},
}; };

View File

@@ -18,5 +18,5 @@ EP3_IN_Callback(void)
void void
EP5_OUT_Callback(void) EP5_OUT_Callback(void)
{ {
SetEPRxValid (ENDP3); SetEPRxValid (ENDP5);
} }

567
src/usb_msc.c Normal file
View File

@@ -0,0 +1,567 @@
/*
* usb_msc.c -- USB Mass Storage Class protocol handling
*
* 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 "usb_lib.h"
#include "config.h"
#include "ch.h"
#include "gnuk.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_stall_transmit (void)
{
SetEPTxStatus (ENDP6, EP_TX_STALL);
}
static void usb_start_transmit (const uint8_t *p, size_t n)
{
size_t pkt_len = n > ENDP_MAX_SIZE ? ENDP_MAX_SIZE : n;
ep6_in.txbuf = p;
ep6_in.txsize = n;
ep6_in.txcnt = 0;
USB_SIL_Write (EP6_IN, (uint8_t *)ep6_in.txbuf, pkt_len);
SetEPTxValid (ENDP6);
}
/* "Data Transmitted" callback */
void EP6_IN_Callback (void)
{
size_t n = (size_t)GetEPTxCount (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_SIL_Write (EP6_IN, (uint8_t *)ep6_in.txbuf, n);
SetEPTxValid (ENDP6);
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_stall_receive (void)
{
SetEPRxStatus (ENDP7, EP_RX_STALL);
}
static void usb_start_receive (uint8_t *p, size_t n)
{
ep7_out.rxbuf = p;
ep7_out.rxsize = n;
ep7_out.rxcnt = 0;
if (n < ENDP_MAX_SIZE)
SetEPRxCount (ENDP7, n);
else
SetEPRxCount (ENDP7, ENDP_MAX_SIZE);
SetEPRxValid (ENDP7);
}
/* "Data Received" call back */
void EP7_OUT_Callback (void)
{
size_t n = (size_t)GetEPRxCount (ENDP7);
int err = 0;
if (n > ep7_out.rxsize)
{ /* buffer overflow */
err = 1;
SetEPRxCount (ENDP7, ep7_out.rxsize);
}
n = USB_SIL_Read (EP7_OUT, ep7_out.rxbuf);
ep7_out.rxbuf += n;
ep7_out.rxcnt += n;
ep7_out.rxsize -= n;
if (n == ENDP_MAX_SIZE && ep7_out.rxsize != 0)
{ /* More data to be received */
SetEPRxValid (ENDP7);
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_stall_receive ();
chSysUnlock ();
}
return;
}
n = ep7_out.rxcnt;
if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE))
{
msc_state = MSC_ERROR;
chSysLock ();
usb_stall_receive ();
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_stall_transmit ();
usb_stall_receive ();
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
View 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;

View File

@@ -36,30 +36,14 @@
#include "usb-cdc-vport.c" #include "usb-cdc-vport.c"
#endif #endif
static uint8_t gnukStringSerial[] = { #ifdef PINPAD_DND_SUPPORT
13*2+2, /* bLength */ #include "usb_msc.h"
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ #endif
'0', 0, '.', 0, '1', 0, '1', 0, /* Version number of Gnuk */
'-', 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
#define ID_OFFSET 12
static void static void
gnuk_device_init (void) gnuk_device_init (void)
{ {
const uint8_t *u = unique_device_id ();
int i;
for (i = 0; i < 4; i++)
{
gnukStringSerial[i*4+ID_OFFSET+0] = (u[i*2] >> 4) + 'A';
gnukStringSerial[i*4+ID_OFFSET+1] = 0;
gnukStringSerial[i*4+ID_OFFSET+2] = (u[i*2+1] & 0x0f) + 'A';
gnukStringSerial[i*4+ID_OFFSET+3] = 0;
}
pInformation->Current_Configuration = 0; pInformation->Current_Configuration = 0;
/* Connect the device */ /* Connect the device */
@@ -128,6 +112,20 @@ gnuk_device_reset (void)
SetEPTxStatus (ENDP5, EP_TX_DIS); SetEPTxStatus (ENDP5, EP_TX_DIS);
#endif #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);
SetEPRxStatus (ENDP7, EP_RX_STALL);
SetEPTxStatus (ENDP7, EP_TX_DIS);
#endif
/* Set this device to response on default address */ /* Set this device to response on default address */
SetDeviceAddress (0); SetDeviceAddress (0);
@@ -140,8 +138,14 @@ gnuk_device_SetConfiguration (void)
DEVICE_INFO *pInfo = &Device_Info; DEVICE_INFO *pInfo = &Device_Info;
if (pInfo->Current_Configuration != 0) if (pInfo->Current_Configuration != 0)
/* Device configured */ { /* Device configured */
bDeviceState = CONFIGURED; extern void *main_thread;
extern void chEvtSignalI (void *, unsigned long);
#define LED_STATUS_MODE (8)
bDeviceState = CONFIGURED;
chEvtSignalI (main_thread, LED_STATUS_MODE);
}
} }
static void static void
@@ -167,6 +171,21 @@ gnuk_device_SetInterface (void)
ClearDTOG_TX (ENDP3); ClearDTOG_TX (ENDP3);
} }
#endif #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 static void
@@ -205,28 +224,27 @@ static uint8_t *
gnuk_device_GetStringDescriptor (uint16_t Length) gnuk_device_GetStringDescriptor (uint16_t Length)
{ {
uint8_t wValue0 = pInformation->USBwValue0; uint8_t wValue0 = pInformation->USBwValue0;
uint32_t wOffset = pInformation->Ctrl_Info.Usb_wOffset;
if (wValue0 == 3) if (wValue0 >= (sizeof (String_Descriptor) / sizeof (ONE_DESCRIPTOR)))
/* Serial number is requested */
if (Length == 0)
{
pInformation->Ctrl_Info.Usb_wLength = sizeof gnukStringSerial - wOffset;
return 0;
}
else
return gnukStringSerial + wOffset;
else if (wValue0 > (sizeof (String_Descriptor) / sizeof (ONE_DESCRIPTOR)))
return NULL; return NULL;
else else
return Standard_GetDescriptorData (Length, return
(PONE_DESCRIPTOR)&String_Descriptor[wValue0]); Standard_GetDescriptorData (Length,
(PONE_DESCRIPTOR)&String_Descriptor[wValue0]);
} }
#ifdef ENABLE_VIRTUAL_COM_PORT #ifdef PINPAD_DND_SUPPORT
#define NUM_INTERFACES 3 /* two for CDC, one for CCID */ # 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 #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 #endif
static RESULT static RESULT
@@ -270,11 +288,26 @@ gnuk_data_rates (uint16_t len)
return (uint8_t *)data_rate_table; 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 static RESULT
gnuk_setup_with_data (uint8_t RequestNo) gnuk_setup_with_data (uint8_t RequestNo)
{ {
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
if (pInformation->USBwIndex0 == 0) /* Interface */ if (pInformation->USBwIndex0 == 0)
{ {
if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES) if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
{ {
@@ -293,23 +326,41 @@ gnuk_setup_with_data (uint8_t RequestNo)
else else
return USB_UNSUPPORT; 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) if (RequestNo == MSC_GET_MAX_LUN_COMMAND)
return Virtual_Com_Port_Data_Setup (RequestNo); {
#else pInformation->Ctrl_Info.CopyData = msc_lun_info;
return USB_UNSUPPORT; pInformation->Ctrl_Info.Usb_wOffset = 0;
#endif 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 else
return USB_UNSUPPORT; return USB_UNSUPPORT;
} }
static RESULT static RESULT
gnuk_setup_with_nodata (uint8_t RequestNo) gnuk_setup_with_nodata (uint8_t RequestNo)
{ {
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
if (pInformation->USBwIndex0 == 0) /* Interface */ if (pInformation->USBwIndex0 == 0)
{ {
if (RequestNo == USB_CCID_REQ_ABORT) if (RequestNo == USB_CCID_REQ_ABORT)
/* wValue: bSeq, bSlot */ /* wValue: bSeq, bSlot */
@@ -318,14 +369,29 @@ gnuk_setup_with_nodata (uint8_t RequestNo)
else else
return USB_UNSUPPORT; 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) if (RequestNo == MSC_MASS_STORAGE_RESET_COMMAND)
return Virtual_Com_Port_NoData_Setup (RequestNo); {
#else /* Should call resetting MSC thread, something like msc_reset() */
return USB_UNSUPPORT; return USB_SUCCESS;
#endif }
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 else
return USB_UNSUPPORT; return USB_UNSUPPORT;
} }

View File

@@ -4,7 +4,7 @@
dfuse.py - DFU (Device Firmware Upgrade) tool for STM32 Processor. dfuse.py - DFU (Device Firmware Upgrade) tool for STM32 Processor.
"SE" in DfuSe stands for "STmicroelectronics Extention". "SE" in DfuSe stands for "STmicroelectronics Extention".
Copyright (C) 2010 Free Software Initiative of Japan Copyright (C) 2010, 2011 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -208,10 +208,23 @@ class DFU_STM32:
# First, erase pages # First, erase pages
sys.stdout.write("Erasing: ") sys.stdout.write("Erasing: ")
sys.stdout.flush() sys.stdout.flush()
last_addr = 0
for start_addr in sorted(ih.memory.keys()): for start_addr in sorted(ih.memory.keys()):
data = ih.memory[start_addr] data = ih.memory[start_addr]
end_addr = start_addr + len(data) end_addr = start_addr + len(data)
addr = start_addr & 0xfffffc00 addr = start_addr & 0xfffffc00
if not last_addr == 0:
i = 0
if last_addr > addr:
addr = last_addr
else:
while last_addr < addr:
self.dfuse_erase(last_addr)
if i & 0x03 == 0x03:
sys.stdout.write(".")
sys.stdout.flush()
last_addr += 1024
i += 1
i = 0 i = 0
while addr < end_addr: while addr < end_addr:
self.dfuse_erase(addr) self.dfuse_erase(addr)
@@ -220,20 +233,32 @@ class DFU_STM32:
sys.stdout.flush() sys.stdout.flush()
addr += 1024 addr += 1024
i += 1 i += 1
last_addr = addr
sys.stdout.write("\n") sys.stdout.write("\n")
sys.stdout.flush() sys.stdout.flush()
# Then, write pages # Then, write pages
sys.stdout.write("Writing: ") sys.stdout.write("Writing: ")
sys.stdout.flush() sys.stdout.flush()
last_addr = 0
for start_addr in sorted(ih.memory.keys()): for start_addr in sorted(ih.memory.keys()):
data = ih.memory[start_addr] data = ih.memory[start_addr]
end_addr = start_addr + len(data) end_addr = start_addr + len(data)
addr = start_addr & 0xfffffc00 addr = start_addr & 0xfffffc00
# XXX: data should be 1-KiB aligned if not last_addr == 0:
if addr != start_addr: i = 0
raise ValueError, "padding is not supported yet" while last_addr < addr:
self.dfuse_set_address_pointer(addr) if i & 0x03 == 0x03:
sys.stdout.write(".")
sys.stdout.flush()
last_addr += 1024
i += 1
i = 0 i = 0
if addr != start_addr:
self.dfuse_set_address_pointer(start_addr)
self.dfuse_write_memory(data[0:(addr + 1024 - start_addr)])
data = data[(addr + 1024 - start_addr):]
addr += 1024
self.dfuse_set_address_pointer(addr)
while addr < end_addr: while addr < end_addr:
self.dfuse_write_memory(data[i*1024:(i+1)*1024]) self.dfuse_write_memory(data[i*1024:(i+1)*1024])
if i & 0x03 == 0x03: if i & 0x03 == 0x03:
@@ -241,6 +266,7 @@ class DFU_STM32:
sys.stdout.flush() sys.stdout.flush()
addr += 1024 addr += 1024
i += 1 i += 1
last_addr = addr
if self.__protocol == DFU_STM32PROTOCOL_0: if self.__protocol == DFU_STM32PROTOCOL_0:
# 0-length write at the end # 0-length write at the end
self.ll_download_block(self.__blocknum, None) self.ll_download_block(self.__blocknum, None)
@@ -268,13 +294,33 @@ class DFU_STM32:
# Read pages # Read pages
sys.stdout.write("Reading: ") sys.stdout.write("Reading: ")
sys.stdout.flush() sys.stdout.flush()
last_addr = 0
for start_addr in sorted(ih.memory.keys()): for start_addr in sorted(ih.memory.keys()):
data = ih.memory[start_addr] data = ih.memory[start_addr]
end_addr = start_addr + len(data) end_addr = start_addr + len(data)
addr = start_addr & 0xfffffc00 addr = start_addr & 0xfffffc00
# XXX: data should be 1-KiB aligned if not last_addr == 0:
i = 0
while last_addr < addr:
if i & 0x03 == 0x03:
sys.stdout.write(".")
sys.stdout.flush()
last_addr += 1024
i += 1
if addr != start_addr: if addr != start_addr:
raise ValueError, "padding is not supported yet" self.dfuse_set_address_pointer(addr)
self.ll_clear_status()
self.ll_clear_status()
block = self.dfuse_read_memory()
j = 0
for c in data[0:(addr + 1024 - start_addr)]:
if (ord(c)&0xff) != block[j + start_addr - addr]:
raise ValueError, "verify failed at %08x" % (addr + i*1024+j)
j += 1
data = data[(addr + 1024 - start_addr):]
addr += 1024
self.ll_clear_status()
self.ll_clear_status()
self.dfuse_set_address_pointer(addr) self.dfuse_set_address_pointer(addr)
self.ll_clear_status() self.ll_clear_status()
self.ll_clear_status() self.ll_clear_status()
@@ -282,7 +328,7 @@ class DFU_STM32:
while addr < end_addr: while addr < end_addr:
block = self.dfuse_read_memory() block = self.dfuse_read_memory()
j = 0 j = 0
for c in data[i*1024:i*1024+1024] for c in data[i*1024:(i+1)*1024]:
if (ord(c)&0xff) != block[j]: if (ord(c)&0xff) != block[j]:
raise ValueError, "verify failed at %08x" % (addr + i*1024+j) raise ValueError, "verify failed at %08x" % (addr + i*1024+j)
j += 1 j += 1
@@ -291,6 +337,7 @@ class DFU_STM32:
sys.stdout.flush() sys.stdout.flush()
addr += 1024 addr += 1024
i += 1 i += 1
last_addr = addr
self.ll_clear_status() self.ll_clear_status()
self.ll_clear_status() self.ll_clear_status()
self.ll_clear_status() self.ll_clear_status()
@@ -299,10 +346,19 @@ class DFU_STM32:
busses = usb.busses() busses = usb.busses()
# 0483: SGS Thomson Microelectronics
# df11: DfuSe
USB_VENDOR_STMICRO=0x0483
USB_PRODUCT_DFUSE=0xdf11
def get_device(): def get_device():
for bus in busses: for bus in busses:
devices = bus.devices devices = bus.devices
for dev in devices: for dev in devices:
if dev.idVendor != USB_VENDOR_STMICRO:
continue
if dev.idProduct != USB_PRODUCT_DFUSE:
continue
for config in dev.configurations: for config in dev.configurations:
for intf in config.interfaces: for intf in config.interfaces:
for alt in intf: for alt in intf:

View File

@@ -23,186 +23,66 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
from intel_hex import * import sys, os, binascii, string
from struct import *
import sys, time, os, binascii, string
# INPUT: binary file # INPUT: binary file
# Assume only single CCID device is attached to computer, and it's Gnuk Token # Assume only single CCID device is attached to computer and it's Gnuk Token
import usb from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.util import toHexString
# USB class, subclass, protocol def s2l(s):
CCID_CLASS = 0x0B return [ ord(c) for c in s ]
CCID_SUBCLASS = 0x00
CCID_PROTOCOL_0 = 0x00
def icc_compose(msg_type, data_len, slot, seq, param, data): class GnukToken(object):
return pack('<BiBBBH', msg_type, data_len, slot, seq, 0, param) + data def __init__(self):
cardtype = AnyCardType()
def iso7816_compose(ins, p1, p2, data): cardrequest = CardRequest(timeout=1, cardType=cardtype)
cls = 0x00 cardservice = cardrequest.waitforcard()
data_len = len(data) self.connection = cardservice.connection
if data_len == 0:
return pack('>BBBB', cls, ins, p1, p2)
else:
return pack('>BBBBBh', cls, ins, p1, p2, 0, data_len) + data
# This class only supports Gnuk (for now)
class gnuk_token:
def __init__(self, device, configuration, interface):
"""
__init__(device, configuration, interface) -> None
Initialize the device.
device: usb.Device object.
configuration: configuration number.
interface: usb.Interface object representing the interface and altenate setting.
"""
if interface.interfaceClass != CCID_CLASS:
raise ValueError, "Wrong interface class"
if interface.interfaceSubClass != CCID_SUBCLASS:
raise ValueError, "Wrong interface sub class"
self.__devhandle = device.open()
try:
self.__devhandle.setConfiguration(configuration)
except:
pass
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting
self.__conf = configuration
self.__bulkout = 2
self.__bulkin = 0x81
self.__timeout = 10000
self.__seq = 0
def icc_get_result(self):
msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout)
if len(msg) < 10:
print msg
raise ValueError, "icc_get_result"
msg_type = msg[0]
data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24)
slot = msg[5]
seq = msg[6]
status = msg[7]
error = msg[8]
chain = msg[9]
data = msg[10:]
# XXX: check msg_type, data_len, slot, seq, error
return (status, chain, data)
def icc_get_status(self):
msg = icc_compose(0x65, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check chain, data
return status
def icc_power_on(self):
msg = icc_compose(0x62, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check status, chain
return data # ATR
def icc_power_off(self):
msg = icc_compose(0x63, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check chain, data
return status
def icc_send_data_block(self, data):
msg = icc_compose(0x6f, len(data), 0, self.__seq, 0, data)
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
return self.icc_get_result()
def icc_send_cmd(self, data):
status, chain, data_rcv = self.icc_send_data_block(data)
if chain == 0:
return data_rcv
elif chain == 1:
d = data_rcv
while True:
msg = icc_compose(0x6f, 0, 0, self.__seq, 0x10, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data_rcv = self.icc_get_result()
# XXX: check status
d += data_rcv
if chain == 2:
break
elif chain == 3:
continue
else:
raise ValueError, "icc_send_cmd chain"
return d
else:
raise ValueError, "icc_send_cmd"
def cmd_verify(self, who, passwd): def cmd_verify(self, who, passwd):
cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd) apdu = [0x00, 0x20, 0x00, 0x80+who, 0, 0, len(passwd)] + s2l(passwd)
sw = self.icc_send_cmd(cmd_data) response, sw1, sw2 = self.connection.transmit(apdu)
if len(sw) != 2: if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, "cmd_verify"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_verify" raise ValueError, "cmd_verify"
def cmd_write_binary(self, fileid, data): def cmd_write_binary(self, fileid, data, is_update):
count = 0 count = 0
data_len = len(data) data_len = len(data)
if is_update:
ins = 0xd6
else:
ins = 0xd0
while count*256 < data_len: while count*256 < data_len:
if count == 0: if count == 0:
cmd_data = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:256]) d = data[:256]
apdu = [0x00, ins, 0x80+fileid, 0x00, 0, len(d)>>8, len(d)&0xff] + s2l(d)
else: else:
cmd_data = iso7816_compose(0xd0, count, 0x00, data[256*count:256*(count+1)]) d = data[256*count:256*(count+1)]
sw = self.icc_send_cmd(cmd_data) apdu = [0x00, ins, count, 0x00, 0, len(d)>>8, len(d)&0xff] + s2l(d)
if len(sw) != 2: response, sw1, sw2 = self.connection.transmit(apdu)
raise ValueError, "cmd_write_binary" if not (sw1 == 0x90 and sw2 == 0x00):
if not (sw[0] == 0x90 and sw[1] == 0x00): if is_update:
raise ValueError, "cmd_write_binary" raise ValueError, "cmd_update_binary"
count += 1 else:
raise ValueError, "cmd_write_binary"
def cmd_update_binary(self, fileid, data):
count = 0
data_len = len(data)
while count*256 < data_len:
if count == 0:
cmd_data = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:256])
else:
cmd_data = iso7816_compose(0xd6, count, 0x00, data[256*count:256*(count+1)])
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, "cmd_update_binary"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_update_binary"
count += 1 count += 1
def cmd_select_openpgp(self): def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01") apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
sw = self.icc_send_cmd(cmd_data) response, sw1, sw2 = self.connection.transmit(apdu)
if len(sw) != 2: if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, "cmd_select_openpgp"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_select_openpgp" raise ValueError, "cmd_select_openpgp"
def cmd_get_data(self, tagh, tagl): def cmd_get_data(self, tagh, tagl):
cmd_data = iso7816_compose(0xca, tagh, tagl, "") apdu = [0x00, 0xca, tagh, tagl]
result = self.icc_send_cmd(cmd_data) response, sw1, sw2 = self.connection.transmit(apdu)
sw = result[-2:] if not (sw1 == 0x90 and sw2 == 0x00):
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_get_data" raise ValueError, "cmd_get_data"
return result[:-2] return response
def compare(data_original, data_in_device): def compare(data_original, data_in_device):
i = 0 i = 0
@@ -211,44 +91,40 @@ def compare(data_original, data_in_device):
raise ValueError, "verify failed at %08x" % i raise ValueError, "verify failed at %08x" % i
i += 1 i += 1
def get_device(): DEFAULT_PW3 = "12345678"
busses = usb.busses() BY_ADMIN = 3
for bus in busses:
devices = bus.devices
for dev in devices:
for config in dev.configurations:
for intf in config.interfaces:
for alt in intf:
if alt.interfaceClass == CCID_CLASS and \
alt.interfaceSubClass == CCID_SUBCLASS and \
alt.interfaceProtocol == CCID_PROTOCOL_0:
return dev, config, alt
raise ValueError, "Device not found"
def main(fileid, is_update, data): def main(fileid, is_update, data, passwd):
dev, config, intf = get_device() gnuk = GnukToken()
print "Device: ", dev.filename
print "Configuration: ", config.value gnuk.connection.connect()
print "Interface: ", intf.interfaceNumber print "Token:", gnuk.connection.getReader()
icc = gnuk_token(dev, config, intf) print "ATR:", toHexString( gnuk.connection.getATR() )
if icc.icc_get_status() == 2:
raise ValueError, "No ICC present" gnuk.cmd_verify(BY_ADMIN, passwd)
elif icc.icc_get_status() == 1: gnuk.cmd_write_binary(fileid, data, is_update)
icc.icc_power_on()
icc.cmd_verify(3, "12345678")
if is_update:
icc.cmd_update_binary(fileid, data)
else:
icc.cmd_write_binary(fileid, data)
icc.cmd_select_openpgp()
if fileid == 0: if fileid == 0:
data = data[:-2] gnuk.cmd_select_openpgp()
data_in_device = icc.cmd_get_data(0x7f, 0x21) data_in_device = gnuk.cmd_get_data(0x7f, 0x21)
compare(data, data_in_device) compare(data[:-2], data_in_device)
icc.icc_power_off() elif fileid == 2:
gnuk.cmd_select_openpgp()
data_in_device = gnuk.cmd_get_data(0x00, 0x4f)
for d in data_in_device:
print "%02x" % d,
print
compare(data, data_in_device[8:])
gnuk.connection.disconnect()
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':
passwd = DEFAULT_PW3
if sys.argv[1] == '-p':
from getpass import getpass
passwd = getpass("Admin password:")
sys.argv.pop(1)
if sys.argv[1] == '-u': if sys.argv[1] == '-u':
is_update = True is_update = True
sys.argv.pop(1) sys.argv.pop(1)
@@ -291,4 +167,4 @@ if __name__ == '__main__':
print "%s: %d" % (filename, len(data)) print "%s: %d" % (filename, len(data))
data += "\x90\x00" data += "\x90\x00"
print "Updating card holder certificate" print "Updating card holder certificate"
main(fileid, is_update, data) main(fileid, is_update, data, passwd)

294
tool/gnuk_put_binary_libusb.py Executable file
View File

@@ -0,0 +1,294 @@
#! /usr/bin/python
"""
gnuk_put_binary.py - a tool to put binary to Gnuk Token
This tool is for importing certificate, updating random number, etc.
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/>.
"""
from intel_hex import *
from struct import *
import sys, time, os, binascii, string
# INPUT: binary file
# Assume only single CCID device is attached to computer, and it's Gnuk Token
import usb
# USB class, subclass, protocol
CCID_CLASS = 0x0B
CCID_SUBCLASS = 0x00
CCID_PROTOCOL_0 = 0x00
def icc_compose(msg_type, data_len, slot, seq, param, data):
return pack('<BiBBBH', msg_type, data_len, slot, seq, 0, param) + data
def iso7816_compose(ins, p1, p2, data):
cls = 0x00
data_len = len(data)
if data_len == 0:
return pack('>BBBB', cls, ins, p1, p2)
else:
return pack('>BBBBBh', cls, ins, p1, p2, 0, data_len) + data
# This class only supports Gnuk (for now)
class gnuk_token:
def __init__(self, device, configuration, interface):
"""
__init__(device, configuration, interface) -> None
Initialize the device.
device: usb.Device object.
configuration: configuration number.
interface: usb.Interface object representing the interface and altenate setting.
"""
if interface.interfaceClass != CCID_CLASS:
raise ValueError, "Wrong interface class"
if interface.interfaceSubClass != CCID_SUBCLASS:
raise ValueError, "Wrong interface sub class"
self.__devhandle = device.open()
try:
self.__devhandle.setConfiguration(configuration)
except:
pass
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting
self.__conf = configuration
self.__bulkout = 2
self.__bulkin = 0x81
self.__timeout = 10000
self.__seq = 0
def icc_get_result(self):
msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout)
if len(msg) < 10:
print msg
raise ValueError, "icc_get_result"
msg_type = msg[0]
data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24)
slot = msg[5]
seq = msg[6]
status = msg[7]
error = msg[8]
chain = msg[9]
data = msg[10:]
# XXX: check msg_type, data_len, slot, seq, error
return (status, chain, data)
def icc_get_status(self):
msg = icc_compose(0x65, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check chain, data
return status
def icc_power_on(self):
msg = icc_compose(0x62, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check status, chain
return data # ATR
def icc_power_off(self):
msg = icc_compose(0x63, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check chain, data
return status
def icc_send_data_block(self, data):
msg = icc_compose(0x6f, len(data), 0, self.__seq, 0, data)
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
return self.icc_get_result()
def icc_send_cmd(self, data):
status, chain, data_rcv = self.icc_send_data_block(data)
if chain == 0:
return data_rcv
elif chain == 1:
d = data_rcv
while True:
msg = icc_compose(0x6f, 0, 0, self.__seq, 0x10, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data_rcv = self.icc_get_result()
# XXX: check status
d += data_rcv
if chain == 2:
break
elif chain == 3:
continue
else:
raise ValueError, "icc_send_cmd chain"
return d
else:
raise ValueError, "icc_send_cmd"
def cmd_verify(self, who, passwd):
cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd)
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, "cmd_verify"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_verify"
def cmd_write_binary(self, fileid, data):
count = 0
data_len = len(data)
while count*256 < data_len:
if count == 0:
cmd_data = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:256])
else:
cmd_data = iso7816_compose(0xd0, count, 0x00, data[256*count:256*(count+1)])
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, "cmd_write_binary"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_write_binary"
count += 1
def cmd_update_binary(self, fileid, data):
count = 0
data_len = len(data)
while count*256 < data_len:
if count == 0:
cmd_data = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:256])
else:
cmd_data = iso7816_compose(0xd6, count, 0x00, data[256*count:256*(count+1)])
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, "cmd_update_binary"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_update_binary"
count += 1
def cmd_select_openpgp(self):
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"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_select_openpgp"
def cmd_get_data(self, tagh, tagl):
cmd_data = iso7816_compose(0xca, tagh, tagl, "")
result = self.icc_send_cmd(cmd_data)
sw = result[-2:]
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_get_data"
return result[:-2]
def compare(data_original, data_in_device):
i = 0
for d in data_original:
if ord(d) != data_in_device[i]:
raise ValueError, "verify failed at %08x" % i
i += 1
def get_device():
busses = usb.busses()
for bus in busses:
devices = bus.devices
for dev in devices:
for config in dev.configurations:
for intf in config.interfaces:
for alt in intf:
if alt.interfaceClass == CCID_CLASS and \
alt.interfaceSubClass == CCID_SUBCLASS and \
alt.interfaceProtocol == CCID_PROTOCOL_0:
return dev, config, alt
raise ValueError, "Device not found"
def main(fileid, is_update, data):
dev, config, intf = get_device()
print "Device: ", dev.filename
print "Configuration: ", config.value
print "Interface: ", intf.interfaceNumber
icc = gnuk_token(dev, config, intf)
if icc.icc_get_status() == 2:
raise ValueError, "No ICC present"
elif icc.icc_get_status() == 1:
icc.icc_power_on()
icc.cmd_verify(3, "12345678")
if is_update:
icc.cmd_update_binary(fileid, data)
else:
icc.cmd_write_binary(fileid, data)
icc.cmd_select_openpgp()
if fileid == 0:
data = data[:-2]
data_in_device = icc.cmd_get_data(0x7f, 0x21)
compare(data, data_in_device)
icc.icc_power_off()
return 0
if __name__ == '__main__':
if sys.argv[1] == '-u':
is_update = True
sys.argv.pop(1)
else:
is_update = False
if sys.argv[1] == '-s':
fileid = 2 # serial number
filename = sys.argv[2]
f = open(filename)
email = os.environ['EMAIL']
serial_data_hex = None
for line in f.readlines():
field = string.split(line)
if field[0] == email:
serial_data_hex = field[1].replace(':','')
f.close()
if not serial_data_hex:
print "No serial number"
exit(1)
print "Writing serial number"
data = binascii.unhexlify(serial_data_hex)
elif sys.argv[1] == '-r':
fileid = 1 # Random number bits
if len(sys.argv) == 3:
filename = sys.argv[2]
f = open(filename)
else:
filename = stdin
f = sys.stdin
data = f.read()
f.close()
print "%s: %d" % (filename, len(data))
print "Updating random bits"
else:
fileid = 0 # Card holder certificate
filename = sys.argv[1]
f = open(filename)
data = f.read()
f.close()
print "%s: %d" % (filename, len(data))
data += "\x90\x00"
print "Updating card holder certificate"
main(fileid, is_update, data)

256
tool/hub_ctrl.py Executable file
View File

@@ -0,0 +1,256 @@
#! /usr/bin/python
"""
hub_ctrl.py - a tool to control port power/led of USB hub
Copyright (C) 2006, 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/>.
"""
import usb
USB_RT_HUB = (usb.TYPE_CLASS | usb.RECIP_DEVICE)
USB_RT_PORT = (usb.TYPE_CLASS | usb.RECIP_OTHER)
USB_PORT_FEAT_RESET = 4
USB_PORT_FEAT_POWER = 8
USB_PORT_FEAT_INDICATOR = 22
USB_DIR_IN = 0x80 # device to host
COMMAND_SET_NONE = 0
COMMAND_SET_LED = 1
COMMAND_SET_POWER = 2
HUB_LED_GREEN = 2
def find_hubs(listing, verbose, busnum=None, devnum=None, hub=None):
number_of_hubs_with_feature = 0
hubs = []
busses = usb.busses()
if not busses:
raise ValueError, "can't access USB"
for bus in busses:
devices = bus.devices
for dev in devices:
if dev.deviceClass != usb.CLASS_HUB:
continue
printout_enable = 0
if (listing
or (verbose
and ((bus.dirname == busnum and dev.devnum == devnumd)
or hub == number_of_hubs_with_feature))):
printout_enable = 1
uh = dev.open()
desc = None
try:
# Get USB Hub descriptor
desc = uh.controlMsg(requestType = USB_DIR_IN | USB_RT_HUB,
request = usb.REQ_GET_DESCRIPTOR,
value = usb.DT_HUB << 8,
index = 0, buffer = 1024, timeout = 1000)
finally:
del uh
if not desc:
continue
# desc[3] is lower byte of wHubCharacteristics
if (desc[3] & 0x80) == 0 and (desc[3] & 0x03) >= 2:
# Hub doesn't have features of controling port power/indicator
continue
if printout_enable:
print "Hub #%d at %s:%03d" % (number_of_hubs_with_feature,
bus.dirname, dev.devnum)
if (desc[3] & 0x03) == 0:
print " INFO: ganged power switching."
elif (desc[3] & 0x03) == 1:
print " INFO: individual power switching."
elif (desc[3] & 0x03) == 2 or (desc[3] & 0x03) == 3:
print " WARN: no power switching."
if (desc[3] & 0x80) == 0:
print " WARN: Port indicators are NOT supported."
hubs.append({ 'busnum' : bus.dirname, 'devnum' : dev.devnum,
'indicator_support' : (desc[3] & 0x80) == 0x80,
'dev' : dev, 'num_ports' : desc[2] })
number_of_hubs_with_feature += 1
return hubs
def hub_port_status(handle, num_ports):
print " Hub Port Status:"
for i in range(num_ports):
port = i + 1
status = handle.controlMsg(requestType = USB_RT_PORT | usb.ENDPOINT_IN,
request = usb.REQ_GET_STATUS,
value = 0,
index = port, buffer = 4,
timeout = 1000)
print " Port %d: %02x%02x.%02x%02x" % (port, status[3], status[2],
status[1], status[0]),
if status[1] & 0x10:
print " indicator",
if status[1] & 0x08:
print " test" ,
if status[1] & 0x04:
print " highspeed",
if status[1] & 0x02:
print " lowspeed",
if status[1] & 0x01:
print " power",
if status[0] & 0x10:
print " RESET",
if status[0] & 0x08:
print " oc",
if status[0] & 0x04:
print " suspend",
if status[0] & 0x02:
print " enable",
if status[0] & 0x01:
print " connect",
print
import sys
COMMAND_SET_NONE = 0
COMMAND_SET_LED = 1
COMMAND_SET_POWER = 2
HUB_LED_GREEN = 2
def usage(progname):
print >> sys.stderr, """Usage: %s [{-h HUBNUM | -b BUSNUM -d DEVNUM}]
[-P PORT] [{-p [VALUE]|-l [VALUE]}]
""" % progname
def exit_with_usage(progname):
usage(progname)
exit(1)
if __name__ == '__main__':
busnum = None
devnum = None
listing = False
verbose = False
hub = None
port = 1
cmd = COMMAND_SET_NONE
if len(sys.argv) == 1:
listing = True
else:
try:
while len(sys.argv) >= 2:
option = sys.argv[1]
sys.argv.pop(1)
if option == '-h':
if bunum != None or devnum != None:
exit_with_usage(sys.argv[0])
hub = int(sys.argv[1])
sys.argv.pop(1)
elif option == '-b':
busnum = int(sys.argv[1])
sys.argv.pop(1)
elif option == '-d':
devnum = int(sys.argv[1])
sys.argv.pop(1)
elif option == '-P':
port = int(sys.argv[1])
sys.argv.pop(1)
elif option == '-l':
if cmd != COMMAND_SET_NONE:
exit_with_usage(sys.argv[0])
if len(sys.argv) > 1:
value = int(sys.argv[1])
sys.argv.pop(1)
else:
value = HUB_LED_GREEN
cmd = COMMAND_SET_LED
elif option == '-p':
if cmd != COMMAND_SET_NONE:
exit_with_usage(sys.argv[0])
if len(sys.argv) > 1:
value = int(sys.argv[1])
sys.argv.pop(1)
else:
value = 0
cmd = COMMAND_SET_POWER
elif option == '-v':
verbose = True
if len(sys.argv) == 1:
listing = True
else:
exit_with_usage(sys.argv[0])
except:
exit_with_usage(sys.argv[0])
if ((busnum != None and devnum == None)
or (busnum == None and devnum != None)):
exit_with_usage(sys.argv[0])
if hub == None and busnum == None:
hub = 0 # Default hub = 0
if cmd == COMMAND_SET_NONE:
cmd = COMMAND_SET_POWER
hubs = find_hubs(listing, verbose, busnum, devnum, hub)
if len(hubs) == 0:
print >> sys.stderr, "No hubs found."
exit(1)
if listing:
exit(0)
if hub == None:
for h in hubs:
if h['busnum'] == busnum and h['devnum'] == devnum:
dev_hub = h['dev']
nports = h['num_ports']
else:
dev_hub = hubs[hub]['dev']
nports = hubs[hub]['num_ports']
uh = dev_hub.open()
if cmd == COMMAND_SET_POWER:
feature = USB_PORT_FEAT_POWER
index = port
if value:
request = usb.REQ_SET_FEATURE
else:
request = usb.REQ_CLEAR_FEATURE
else:
request = usb.REQ_SET_FEATURE
feature = USB_PORT_FEAT_INDICATOR
index = (value << 8) | port
if verbose:
print "Send control message (REQUEST=%d, FEATURE=%d, INDEX=%d) " % (request, feature, index)
uh.controlMsg(requestType = USB_RT_PORT, request = request, value = feature,
index = index, buffer = None, timeout = 1000)
if verbose:
hub_port_status(uh,nports)
del uh

View File

@@ -0,0 +1,6 @@
init
reset
halt
stm32x lock 0
reset
exit

View File

@@ -0,0 +1,5 @@
init
reset
halt
stm32x options_read 0
exit

View File

@@ -0,0 +1,6 @@
init
reset
halt
stm32x unlock 0
reset
exit

View File

@@ -0,0 +1,5 @@
init
reset
halt
flash write_image erase gnuk.elf
exit

291
tool/pinpad-test.py Executable file
View File

@@ -0,0 +1,291 @@
#! /usr/bin/python
"""
pinpad-test.py - a tool to test pinpad support by card reader.
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/>.
"""
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
CM_IOCTL_GET_FEATURE_REQUEST = (0x42000000 + 3400)
FEATURE_VERIFY_PIN_DIRECT = 0x06
FEATURE_MODIFY_PIN_DIRECT = 0x07
BY_ADMIN = 3
BY_USER = 1
PIN_MAX_DEFAULT = 15 # max of VASCO DIGIPASS 920
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, pinmax):
cardtype = AnyCardType()
cardrequest = CardRequest(timeout=1, cardType=cardtype)
cardservice = cardrequest.waitforcard()
self.connection = cardservice.connection
self.verify_ioctl = -1
self.modify_ioctl = -1
self.another_byte = add_a_byte
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)
1, # wPINMaxExtraDigit High (PINmin)
0x02, # bEntryValidationCondition
0x01, # bNumberMessage
0x00, # wLangId Low
0x00, # wLangId High
0x00, # bMsgIndex
0x00, # bTeoPrologue[0]
0x00, # bTeoPrologue[1]
0x00 # bTeoPrologue[2]
]
pin_verify += [ len(apdu), 0, 0, 0 ] + apdu + self.possibly_add_dummy_byte()
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)
1, # 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]
]
pin_modify += [ len(apdu), 0, 0, 0 ] + apdu + self.possibly_add_dummy_byte()
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))
# 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
else:
apdu = [0x00, 0x2c, 0x00, 0x81] # BY_USER with resetcode
self.send_modify_pinpad(apdu, False, "cmd_reset_retry_counter_pinpad")
# 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")
# "Vasco DIGIPASS 920 [CCID] 00 00"
# "FSIJ Gnuk (0.16-34006F06) 00 00"
def main(who, method, add_a_byte, pinmax, change_by_two_steps):
card = Card(add_a_byte, pinmax)
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":
# It's always by single step
if who == BY_USER:
print "Please input reset code"
print "and New User's PIN twice"
else:
print "Please input Admin's PIN"
print "and New User's PIN twice"
card.cmd_reset_retry_counter_pinpad(who)
elif method == "put":
# It's always by two steps
print "Please input Admin's PIN"
card.cmd_verify_pinpad(BY_ADMIN)
print "Please input New Reset Code twice"
card.cmd_put_resetcode_pinpad()
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--put:\t\tsetup resetcode (admin PIN, new PIN twice)"
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--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
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 == '--add':
add_a_byte = True
elif option == '--pinmax':
pinmax = int(sys.argv[1])
sys.argv.pop(1)
elif option == '--put':
method = "put"
elif option == "verify":
method = "verify"
elif option == '--help':
print_usage()
exit(0)
else:
raise ValueError, option
main(who, method, add_a_byte, pinmax, change_by_two_steps)
# 69 82: Security status not satisfied: pin doesn't match
# 69 85: Conditions of use not satisfied
# 6b 00: Wrong parameters P1-P2