Compare commits

...

88 Commits

Author SHA1 Message Date
NIIBE Yutaka
3da8a3b326 version 0.18 2012-06-06 09:05:24 +09:00
NIIBE Yutaka
808cb61b9a doc/firmware-update 2012-06-06 09:02:17 +09:00
NIIBE Yutaka
75bfa6068a improve regnual 2012-06-06 08:39:23 +09:00
NIIBE Yutaka
37b1992f10 fix gnuk_put_binary 2012-06-05 11:18:41 +09:00
NIIBE Yutaka
bfa4952f31 use RBIT instruction of Thumb-2 2012-06-05 10:33:50 +09:00
NIIBE Yutaka
1164ac4d28 CertDO bug fixes 2012-06-04 18:13:35 +09:00
NIIBE Yutaka
f73634d17c Implement CRC32 check 2012-06-04 16:31:40 +09:00
NIIBE Yutaka
07b1266727 bug fix 2012-06-04 11:34:10 +09:00
NIIBE Yutaka
961b808adb fix 2012-06-04 11:30:04 +09:00
NIIBE Yutaka
879b8b9966 firmware update using public key 2012-06-01 13:23:00 +09:00
NIIBE Yutaka
78d9a56277 firmware update key registration 2012-06-01 13:20:47 +09:00
NIIBE Yutaka
75b480f2c2 fix gnuk_put_binary 2012-06-01 13:19:10 +09:00
NIIBE Yutaka
19d9e55613 update regnual 2012-06-01 13:18:34 +09:00
NIIBE Yutaka
441051a485 ifdef-out USB strings for reGNUal 2012-06-01 13:15:13 +09:00
NIIBE Yutaka
42f9c16fd8 Bug fixes for USB protocol stack. 2012-06-01 09:36:02 +09:00
NIIBE Yutaka
7860f1e729 buffer size of rsa_verify 2012-05-31 18:19:39 +09:00
NIIBE Yutaka
5cafb8a84f fix 2012-05-31 15:06:25 +09:00
NIIBE Yutaka
41633871fe update 2012-05-31 15:03:31 +09:00
NIIBE Yutaka
fa2ae42e69 SHA1 for external authentication 2012-05-31 13:09:57 +09:00
NIIBE Yutaka
2215a6dd2c challenge/response definition change 2012-05-31 12:34:11 +09:00
NIIBE Yutaka
95f328f94f update tools 2012-05-31 12:10:08 +09:00
NIIBE Yutaka
34bd069743 invalidating all update keys, flash_erase_page will be called 2012-05-31 12:06:33 +09:00
NIIBE Yutaka
c5762e7891 firmware update keys handling 2012-05-31 11:58:14 +09:00
NIIBE Yutaka
ab51c5421d revice system service, version string 2012-05-31 08:58:26 +09:00
NIIBE Yutaka
093c98bb0f external authenticate implemented 2012-05-30 18:50:22 +09:00
NIIBE Yutaka
6ba65c8d8b rsa_verify function 2012-05-29 12:14:10 +09:00
NIIBE Yutaka
f8bb88227a fix API of RSA 2012-05-29 11:55:08 +09:00
NIIBE Yutaka
cc95fff074 support revision detail and configure options in USB strings 2012-05-29 11:28:00 +09:00
NIIBE Yutaka
7ae467f874 fix board name 2012-05-29 10:58:00 +09:00
NIIBE Yutaka
01de6a74c5 DFU support for reGNUal upgrade 2012-05-29 10:07:23 +09:00
NIIBE Yutaka
08563d5a65 improve sys interface for flash_erase_all_and_exec 2012-05-29 09:41:25 +09:00
NIIBE Yutaka
e2ab8c9183 improve DFU_SUPPORT 2012-05-29 09:20:38 +09:00
NIIBE Yutaka
8d8e67f1ad support DFU board 2012-05-29 08:37:36 +09:00
NIIBE Yutaka
1576b8303e flash write range check 2012-05-28 13:00:58 +09:00
NIIBE Yutaka
ba8609be41 DFU Support 2012-05-28 12:53:58 +09:00
NIIBE Yutaka
3588fbd97a AES data .sys works now 2012-05-28 12:04:27 +09:00
NIIBE Yutaka
54f52838ef cleanup hwinit0 2012-05-28 11:48:35 +09:00
NIIBE Yutaka
f072de436b better usage of .sys section 2012-05-28 11:46:49 +09:00
NIIBE Yutaka
cb1dc21b61 Update by reGNUal works now 2012-05-28 11:29:51 +09:00
NIIBE Yutaka
4e8af02ac0 fix regnual/sys.c 2012-05-28 11:03:26 +09:00
NIIBE Yutaka
95fd3711d8 Merge branch 'master' of www.gniibe.org:git/gnuk 2012-05-28 09:42:24 +09:00
NIIBE Yutaka
0bda48c985 disable systick 2012-05-26 20:15:07 +09:00
NIIBE Yutaka
ded02a6808 fix 2012-05-26 16:01:55 +09:00
NIIBE Yutaka
8538ac19d0 fix 2012-05-26 13:36:55 +09:00
NIIBE Yutaka
cdc9d441a6 fix sys.h 2012-05-26 13:29:59 +09:00
NIIBE Yutaka
7dd703c28b SCR->VCR 2012-05-26 12:50:23 +09:00
NIIBE Yutaka
1e9b73de49 sys section at non-writable area 2012-05-25 17:06:14 +09:00
NIIBE Yutaka
2113d5b751 boards changes 2012-05-25 15:36:09 +09:00
NIIBE Yutaka
6b47ee56b8 use functions in sys 2012-05-25 15:20:08 +09:00
NIIBE Yutaka
8c6ffaa167 fix sys.c 2012-05-25 09:12:37 +09:00
NIIBE Yutaka
37f82b6026 fix 2012-05-24 21:59:11 +09:00
NIIBE Yutaka
1c910fc3e2 clear CR_MER 2012-05-24 19:09:05 +09:00
NIIBE Yutaka
e99d129c97 fix mass erase on SRAM 2012-05-24 09:07:00 +09:00
NIIBE Yutaka
94e38ae1bc reset device 2012-05-24 09:03:51 +09:00
NIIBE Yutaka
0c721d6e10 remove space 2012-05-24 09:03:22 +09:00
NIIBE Yutaka
21053abc51 fix main 2012-05-23 17:50:47 +09:00
NIIBE Yutaka
4a59c73bc3 main.c 2012-05-23 17:07:30 +09:00
NIIBE Yutaka
b02c6a480d support stm8s-discovery 2012-05-23 16:02:02 +09:00
NIIBE Yutaka
dec12d4b15 fix 2012-05-23 15:48:49 +09:00
NIIBE Yutaka
b1cc1ec6f6 protection 2012-05-23 15:25:20 +09:00
NIIBE Yutaka
d31b2211c6 mass erase 2012-05-23 14:55:04 +09:00
NIIBE Yutaka
365b59cd56 follow change of regnual protocol 2012-05-23 12:17:56 +09:00
NIIBE Yutaka
80e2d33a51 fix 2012-05-23 12:17:11 +09:00
NIIBE Yutaka
8e4775ab4a improve regnual 2012-05-23 12:16:31 +09:00
NIIBE Yutaka
d3af289b3c add -m flags for linking 2012-05-22 19:51:52 +09:00
NIIBE Yutaka
84e3a5c1a6 regnual: flash write support 2012-05-22 17:02:54 +09:00
NIIBE Yutaka
6c205c3111 main cleanup 2012-05-22 16:38:02 +09:00
NIIBE Yutaka
244cdbff3f set data_p->addr=NULL 2012-05-22 16:37:30 +09:00
NIIBE Yutaka
b202f95376 add flash and reset routines 2012-05-22 16:36:23 +09:00
NIIBE Yutaka
86b1c1848a Makefile.in for usb_ctrl.c rename 2012-05-22 16:35:13 +09:00
NIIBE Yutaka
ab4e0c2167 configure support for regnual 2012-05-22 12:26:49 +09:00
NIIBE Yutaka
cc80c3e433 rename to usb_ctrl.c 2012-05-22 12:07:02 +09:00
NIIBE Yutaka
11be169187 improve regnual config 2012-05-22 11:20:16 +09:00
NIIBE Yutaka
abfe779728 add regnual 2012-05-22 11:14:22 +09:00
NIIBE Yutaka
12c94c1f22 Gnuk change to support reGNUal 2012-05-22 10:53:23 +09:00
NIIBE Yutaka
449b3c35ba update regnual 2012-05-22 10:44:37 +09:00
NIIBE Yutaka
dc85bcfb92 testing regnual 2012-05-19 02:07:31 +09:00
NIIBE Yutaka
f95cf8942b upgrade: gnuk side working now 2012-05-19 02:05:31 +09:00
NIIBE Yutaka
810b0d9a5b bug fix for control_read 2012-05-19 01:40:44 +09:00
NIIBE Yutaka
b7599feb4f more upgrade 2012-05-18 19:03:09 +09:00
NIIBE Yutaka
48f143aa31 more upgrade 2012-05-18 19:02:53 +09:00
NIIBE Yutaka
0c4fb96c1a bug fix for control_write 2012-05-18 19:02:26 +09:00
NIIBE Yutaka
c723df0841 more regnual 2012-05-18 16:54:17 +09:00
NIIBE Yutaka
87d36deeb9 more changes for upgrade feature and USB API 2012-05-18 11:39:04 +09:00
NIIBE Yutaka
ce338a9727 implement downloading program 2012-05-17 17:02:49 +09:00
NIIBE Yutaka
e2e2e1a045 disable all endpoints when configure(0) 2012-05-17 13:29:39 +09:00
NIIBE Yutaka
f2afeacdcb fix usb_lld.c 2012-05-17 12:45:51 +09:00
NIIBE Yutaka
429c6f3d8b fileid change/cleanup 2012-05-17 12:25:52 +09:00
55 changed files with 3302 additions and 1136 deletions

13
.gitignore vendored
View File

@@ -1,14 +1,19 @@
# generated files by 'configure'
src/Makefile
src/config.h
src/gnuk.ld
*.lst
*.o
*.pyc
src/.dep
src/Makefile
src/config.h
src/gnuk.ld
src/gnuk.bin
src/gnuk.dmp
src/gnuk.elf
src/gnuk.hex
src/gnuk.map
src/*.inc
regnual/sys.h
regnual/regnual.bin
regnual/regnual.hex
regnual/regnual.elf
regnual/usb_lld.c
regnual/usb_lld.h

43
AUTHORS
View File

@@ -37,32 +37,39 @@ NIIBE Yutaka:
Wrote a tool for Gnuk:
tool/gnuk_put_binary.py
tool/gnuk_put_binary_libusb.py
tool/gnuk_remove_keys.py
tool/gnuk_upgrade.py
Wrote a tool for USB Hub:
tool/hub_ctrl.py
Wrote:
Wrote a tool for testing card reader with pinpad:
tool/pinpadtest.py
Wrote reGNUal implementation:
regnual/regnual.c
regnual/sys.c
Wrote Gnuk implementation:
gnuk.svg
src/configure
src/ac.c
src/main.c
src/usb_lld.h
src/gnuk.h
src/usb_lld.c
src/usb-icc.c
src/openpgp-do.c
src/flash.c
src/debug.c
src/usb_desc.c
src/usb-cdc-vport.c
src/hardclock.c
src/openpgp.h
src/openpgp.c
src/call-rsa.c
src/random.c
src/debug.c
src/flash.c
src/gnuk.h
src/main.c
src/neug.c
src/openpgp-do.c
src/openpgp.c
src/openpgp.h
src/pin-cir.c
src/pin-dial.c
src/pin-dnd.c
src/usb_msc.c
src/usb_msc.h
src/neug.c
src/random.c
src/sys.c
src/usb-icc.c
src/usb-msc.c
src/usb-msc.h
src/usb_ctrl.c
src/usb_desc.c
src/usb_lld.c
src/usb_lld.h
*
and others.

344
ChangeLog
View File

@@ -1,3 +1,347 @@
2012-06-06 Niibe Yutaka <gniibe@fsij.org>
* Version 0.19.
* src/usb_desc.c (gnukStringSerial): Updated.
* regnual/regnual.c (fetch): Better implementation.
2012-06-05 Niibe Yutaka <gniibe@fsij.org>
Firmware update key handling.
* tool/gnuk_put_binary.py (GnukToken.cmd_get_response): Handle
larger data such as card holder certificate.
(GnukToken.cmd_write_binary): Bug fix for cert do write.
(GnukToken.cmd_read_binary): New.
(main): Support firmware update key.
Take advantage of the Thumb-2 "rbit" instruction.
* regnual/regnual.c (fetch): Reverse bits.
* src/usb_ctrl.c (rbit): New. Deleted reverse32.
(download_check_crc32): Use rbit.
* tool/gnuk_upgrade.py (crc32): Just use binascii.crc32.
(crctab): Remove.
2012-06-04 Niibe Yutaka <gniibe@fsij.org>
Card holder certificate data object bug fixes.
* tool/gnuk_put_binary_libusb.py (gnuk_token.cmd_get_response):
Handle larger data such as card holder certificate.
* src/flash.c (flash_write_binary): Bug fix. Call
flash_check_blank with p + offset.
* src/gnuk.h (FLASH_CH_CERTIFICATE_SIZE): Define here (was: flash.c).
Implement CRC32 check for firmware update.
* src/usb_ctrl.c (download_check_crc32): New.
* regnual/regnual.c (calc_crc32): New.
(regnual_ctrl_write_finish): Call calc_crc32.
* tool/gnuk_upgrade.py (crc32): New.
(regnual.download): Check crc32code.
* regnual/regnual.c (regnual_ctrl_write_finish): Bug fix.
2012-06-01 Niibe Yutaka <gniibe@fsij.org>
Support firmware update with public key authentication.
* tool/gnuk_upgrade.py (gpg_sign): New.
* tool/gnuk_put_binary_libusb.py (main): Support firmware update
key registration.
Update of reGNUal.
* regnual/regnual.c (main): Follow the change of usb_lld_init.
(regnual_config_desc): Include interface descriptor.
(usb-strings.c.inc): Change the file name.
* regnual/Makefile (regnual.o): Depend on sys.h.
* src/configure (usb-strings.c.inc): ifdef-out
gnuk_revision_detail and gnuk_config_options (for reGNUal).
* src/usb_desc.c (USB_STRINGS_FOR_GNUK): Define.
USB bug fixes.
* src/usb_ctrl.c (gnuk_usb_event): Bug fix for handling
USB_EVENT_CONFIG. Do nothing when current_conf == value.
* src/usb_lld.c (std_clear_feature): Bug fix. Always clear DTOG.
(usb_lld_init): New argument for FEATURE.
2012-05-31 Niibe Yutaka <gniibe@fsij.org>
* polarssl-0.14.0/library/rsa.c (rsa_pkcs1_verify): BUF size is
256 (was: 1024).
* src/call-rsa.c (rsa_verify): It's SIG_RSA_SHA1.
* src/openpgp.c (cmd_external_authenticate): Follow the change of
rsa_verify.
Support "firmware update" keys.
* src/flash.c (flash_write_binary): Support update keys.
* src/gnuk.h (FILEID_UPDATE_KEY_0, FILEID_UPDATE_KEY_1)
(FILEID_UPDATE_KEY_2,FILEID_UPDATE_KEY_3): New.
* src/gnuk.ld.in (_updatekey_store): New.
* src/openpgp.c (FILE_EF_UPDATE_KEY_0, FILE_EF_UPDATE_KEY_1)
(FILE_EF_UPDATE_KEY_2, FILE_EF_UPDATE_KEY_3): New.
(gpg_get_firmware_update_key): New.
(cmd_read_binary): Support update keys and certificate.
(modify_binary): New.
(cmd_update_binary, cmd_write_binary): Use modify_binary.
(cmd_external_authenticate): Support up to four keys.
Version string of system service is now USB string.
* src/sys.h (unique_device_id): Define here, not as system
service.
* src/sys.c (sys_version): Version string for system service.
* src/usb_desc.c (String_Descriptors): Add sys_version.
* src/usb_conf.h (NUM_STRING_DESC): 7 (was: 6).
* src/gnuk.ld.in (.sys.version): New section.
2012-05-30 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp.c (CHALLENGE_LEN): New.
(cmd_external_authenticate): Authentication by response with
public key.
(cmd_get_challenge): 16-byte is enough for challenge.
2012-05-29 Niibe Yutaka <gniibe@fsij.org>
* src/call-rsa.c (rsa_verify): New function.
* polarssl-0.14.0/include/polarssl/rsa.h (rsa_pkcs1_verify)
* polarssl-0.14.0/library/rsa.c (rsa_pkcs1_verify): Fix API.
* src/usb_conf.h (NUM_STRING_DESC): Incremented to 6 (was: 4).
* src/configure: Generate strings for revision detail and config
options.
* src/usb_desc.c (gnuk_revision_detail, gnuk_config_options): New.
* src/main.c (main) [DFU_SUPPORT]: Kill DFU and install .sys.
* src/config.h.in (FLASH_PAGE_SIZE): New.
* src/configure: Support FLASH_PAGE_SIZE for config.h
* boards/*/board.h (FLASH_PAGE_SIZE): Remove.
* src/flash.c (FLASH_PAGE_SIZE): Remove.
* src/sys.c (reset): Don't depend if DFU_SUPPORT or not.
(flash_erase_all_and_exec): Rename and change the argument.
* src/gnuk.ld.in (__flash_start__): Real flash ROM address,
regardless of DFU_SUPPORT.
* src/main.c (main): Call flash_erase_all_and_exec with SRAM
address.
* polarssl-0.14.0/library/aes.c (FT0, FT1, FT2): Specify sections
in detail, so that addresses won't be affected by compiler.
* src/gnuk.ld.in (.sys): Define sections in detail.
* boards/STBEE_MINI/board.h (SET_USB_CONDITION, GPIO_USB)
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
(FLASH_PAGE_SIZE): New.
* boards/STBEE_MINI/board.c (USB_Cable_Config, set_led): Remove.
* boards/STBEE/board.h (SET_USB_CONDITION, GPIO_USB, IOPORT_USB)
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
* boards/STBEE/board.c (USB_Cable_Config, set_led): Remove.
* boards/CQ_STARM/board.h (SET_USB_CONDITION)
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
* boards/CQ_STARM/board.c (USB_Cable_Config, set_led): Remove.
2012-05-28 Niibe Yutaka <gniibe@fsij.org>
* boards/*/board.c (hwinit0): Removed...
* boards/common/hwinit.c (hwinit0): ... and define here.
(hwinit0) [DFU_SUPPORT]: Don't set SCB->VTOR here.
* src/sys.c (reset) [DFU_SUPPORT]: Set SCB->VTOR here.
(flash_write): Range check.
* polarssl-0.14.0/library/aes.c (FT0, FT1, FT2): Specify the
section ".sys", so that we will have more room for flash ROM.
* src/gnuk.ld.in (.sys): Add alignment settings.
* tool/gnuk_upgrade.py (main): First 4096-byte of Gnuk is system
block. Don't send it to reGNUal.
* regnual/sys.c (entry): Fix clearing BSS. It is called with all
interrupts disabled.
* regnual/regnual.ld (_flash_start): It's 0x08001000 now, because
there is system block now (was: 0x08000000).
2012-05-26 Niibe Yutaka <gniibe@fsij.org>
* src/sys.c (reset): Set SCR->VCR here.
2012-05-25 Niibe Yutaka <gniibe@fsij.org>
* src/gnuk.ld.in (.sys): New section.
* boards/OLIMEX_STM32_H103/board.h (SET_USB_CONDITION, GPIO_USB)
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
(FLASH_PAGE_SIZE): New.
* boards/OLIMEX_STM32_H103/board.c (USB_Cable_Config, set_led):
Remove.
* boards/STM32_PRIMER2/board.h (SET_USB_CONDITION, GPIO_USB)
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
(FLASH_PAGE_SIZE): New.
* boards/STM32_PRIMER2/board.c (USB_Cable_Config, set_led):
Remove.
* boards/FST_01_00/board.h (SET_USB_CONDITION, GPIO_USB)
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
(FLASH_PAGE_SIZE): New.
* boards/FST_01_00/board.c (USB_Cable_Config, set_led): Remove.
* boards/FST_01/board.h (SET_USB_CONDITION, GPIO_USB, IOPORT_USB)
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
* boards/FST_01/board.c (USB_Cable_Config, set_led): Remove.
* regnual/sys-stm8s-discovery.h, sys-stbee.h: Remove.
* boards/STM8S_DISCOVERY/board.h (SET_USB_CONDITION)
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
* boards/STM8S_DISCOVERY/board.c (USB_Cable_Config, set_led):
Remove.
* regnual/Makefile: Add -I ../src to CFLAGS.
* regnual/regnual.ld (vector): New.
* regnual/sys.c: Remove implementation, but jump to vector by sys.h.
* src/Makefile.in: Follow change of files.
* src/configure: Undo changes of 2012-05-22.
* boards/common/hw_config.c: Remove. Mov function to sys.c.
* src/flash.c: Move functions to sys.c.
* src/sys.c: New.
* src/main.c (main): Call flash_mass_erase_and_exec.
* src/usb_lld.c: Include sys.h.
* src/usb_lld_sys.c: Remove. Move interrupt handler to...
* src/usb_ctrl.c: ... this file.
* regnual/sys.c (clock_init, gpio_init, flash_unlock): Removed.
(entry): Rename (was: reset).
2012-05-24 Niibe Yutaka <gniibe@fsij.org>
* src/main.c (good_bye): Care LSB of function pointer.
(flash_mass_erase_and_exec): Implemented in C.
2012-05-23 Niibe Yutaka <gniibe@fsij.org>
* regnual/sys-stm8s-discovery.h: New.
* src/main.c (flash_mass_erase_and_exec, good_bye): New.
(main): Call good_bye.
* tool/gnuk_upgrade.py (regnual.protect): New.
(main): Call regnual.protect().
* regnual/regnual.c (regnual_setup): Don't call flash_write here.
(regnual_ctrl_write_finish): But call here.
(USB_REGNUAL_RESULT): New.
* regnual/sys.c (flash_protect): New.
2012-05-22 Niibe Yutaka <gniibe@fsij.org>
* src/configure (../regnual/sys.h): Create symblic link.
* src/usb_ctrl.c: Rename (was: usb_prop.c).
* regnual/types.h, regnual/sys.c, regnual/regnual.ld: New.
* regnual/regnual.c, regnual/Makefile: New.
* regnual/sys-stbee.h: New.
* src/usb_lld.c: Support FREE_STANDING environment as well as
under ChibiOS/RT.
(usb_lld_init): Call usb_lld_sys_init. Don't call user defined
method. Call usb_lld_set_configuration.
(usb_lld_shutdown): Call usb_lld_sys_shutdown.
(Vector90): Move to usb_lld_sys.c.
(usb_interrupt_handler): Export to global.
* src/usb_lld_sys.c: New.
* src/usb_prop.c (Device_Method): Remove gnuk_device_init.
(gnuk_device_init): Remove.
2012-05-19 Niibe Yutaka <gniibe@fsij.org>
* src/usb_lld.c (handle_datastage_in): Bug fix, erable RX when
sending ZLP. It will be possible to get OUT transaction soon
after IN transaction.
2012-05-18 Niibe Yutaka <gniibe@fsij.org>
* src/usb_lld.c (handle_datastage_out): Fix rx copying.
(handle_setup0): Bug fix not stalling TX, it will be possible
to go IN transaction, soon after OUT transaction.
* src/usb_lld.h (USB_SETUP_SET, USB_SETUP_GET): New.
(usb_device_method.ctrl_write_finish): New.
(usb_device_method.setup): Merge setup_with_data, and
setup_with_nodata.
* src/usb_lld.c (usb_lld_shutdown, usb_lld_prepare_shutdown): New.
(handle_setup0): Call ->setup.
(handle_in0): Call ->ctrl_write_finish.
* src/usb_prop.c (vcom_port_data_setup): Merge
vcom_port_setup_with_nodata.
(download_check_crc32): New.
(gnuk_setup): Merge gnuk_setup_with_data and
gnuk_setup_with_nodata.
(gnuk_ctrl_write_finish): New.
2012-05-17 Niibe Yutaka <gniibe@fsij.org>
* tool/gnuk_upgrade.py: New tool.
* src/gnuk.h (ICC_STATE_EXITED, ICC_STATE_EXEC_REQUESTED): New.
* src/openpgp.c (INS_EXTERNAL_AUTHENTICATE)
(cmd_external_authenticate): New.
(INS_GET_CHALLENGE, cmd_get_challenge): New.
* src/usb-icc.c (USBthread): Finish the thread with
ICC_STATE_EXITED, after EXTERNAL_AUTHENTICATE.
* src/usb_prop.c (gnuk_setup_endpoints_for_interface): Add STOP
argument.
(gnuk_usb_event): Disable all endpoints when configure(0).
(vcom_port_data_setup): Check direction and support
USB_CDC_REQ_SET_LINE_CODING.
(vcom_port_setup_with_nodata): Check direction.
(gnuk_setup_with_data): Check direction and add FSIJ_GNUK device
requests.
(gnuk_setup_with_nodata): Likewise.
* src/usb_lld.c (LAST_OUT_DATA): Remove.
(handle_datastage_out): Cleanup and call st103_ep_set_rxtx_status.
(handle_datastage_in): Call st103_ep_set_rxtx_status and
st103_ep_set_tx_status.
(handle_setup0): Likewise.
(handle_out0): Remove LAST_OUT_DATA.
(std_none, std_get_status, std_clear_feature, std_set_feature)
(std_set_address, std_get_descriptor, std_get_configuration)
(std_set_configuration, std_get_interface, std_set_interface):
Check direction.
(handle_setup0): Add length for setup_with_data.
2012-05-16 Niibe Yutaka <gniibe@fsij.org>
* tool/gnuk_put_binary.py (main): Fix fileid.
* tool/gnuk_put_binary_libusb.py: Ditto.
* src/openpgp.c (FILE_EF_RANDOM): Remove.
(cmd_update_binary, cmds): ifdef CERTDO_SUPPORT.
(cmd_write_binary): Fix fileid.
* src/flash.c (flash_check_blank): Always enable.
(flash_erase_binary): ifdef CERTDO_SUPPORT.
(flash_write_binary): Call flash_check_blank.
2012-05-15 Niibe Yutaka <gniibe@fsij.org>
* Version 0.18.

28
NEWS
View File

@@ -1,5 +1,31 @@
Gnuk NEWS - User visible changes
* Major changes in Gnuk 0.19
Released 2012-06-06, by NIIBE Yutaka
** Firmware upgrade feature
Firmware upgrade is now possible after the public key authentication
using EXTERNAL AUTHENTICATE command of ISO 7816. Firmware upgrade is
done together with reGNUal, the firmware upgrade program.
** System service blocks at the beginning of flash ROM.
Once flash ROM is protected, first 4-KiB cannot be modified. Gnuk
use this area for "system service". Note that this area will not
be able to be modified by firmware upgrade (or by any method).
** New tool: gnuk_upgrade.py
The tool gnuk_upgrade.py is to do public key authentication using
gpg-agent and send reGNUal to Gnuk. Then, we put new Gnuk binary
into the device with reGNUal.
** USB strings for revision detail, configure options, and system service.
USB strings now have more information. There are revision detail
string, configure options string, system service version string, as
well as vendor string and product string. These strings could be
examined to check Gnuk Token.
* Major changes in Gnuk 0.18
Released 2012-05-15, by NIIBE Yutaka
@@ -22,7 +48,7 @@ original implementation. Hopefully, size and quality are improved.
Released 2012-02-02, by NIIBE Yutaka
** USB CCID/ICCD protocol implementation change
Gnuk now only supports short APDU level exchange, not support.
Gnuk now only supports short APDU level exchange, not supporting
extended APDU level exchange. Thus, Gnuk could be compatible to older
host side software implementation.

55
README
View File

@@ -1,7 +1,7 @@
Gnuk - software for GnuPG USB Token
Version 0.18
2012-05-15
Version 0.19
2012-06-06
Niibe Yutaka
Free Software Initiative of Japan
@@ -106,16 +106,16 @@ Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
"GPG Password Agent" and "SSH Key Agent".
Qc: Do you know a good SWD debugger to connect FST-01 or something?
Ac: Perhaps, you can use a part of STM32F4 Discovery Kit as SWD
debugger. It seems that there is a free software tool for that.
Ac: STLink v2 is cheap one. See http://code.google.com/p/arm-utilities/
for a control program.
Release notes
=============
This is nineteenth release of Gnuk. In this release, the usage of USB
device ID by FSIJ is clarified. While it works well for specific
usages and it is considered stable, it is still somewhat experimental.
This is twentieth release of Gnuk. In this release, firmware upgrade
feature is added. While it is daily use, some features (including
firmware upgrade) are still considered experimental.
Tested features are:
@@ -157,7 +157,7 @@ With DfuSe support, CQ STARM, STBee, and STBee Mini are also our
targets. But those targets with DfuSe are basically not for normal
use but for experiments, because it would be impossible for DfuSe to
disable read from flash. For real use, please consider killing DfuSe
and enable read protection using JTAG debugger.
and enabling read protection using JTAG debugger.
I think that it could run on Olimex STM32-P103, or other boards with
STM32F103. Besides, we are porting it to STM32 Primer 2.
@@ -174,15 +174,17 @@ Another PIN-pad support is connecting rotary encoder, push switch and
7-segment LED display. Both of PIN verification and PIN modification
are supported for this circuit extension.
Recently, "DnDpinentry" support is added. This is using usual file
Also, there is "DnDpinentry" support. 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.
However, this will be removed in future version, as it found it's
not that useful.
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.
Note that you need pinpad support for GnuPG to use PIN-pad enabled
Gnuk. The pinpad support for GnuPG is 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
@@ -203,7 +205,7 @@ Please read relevant licenses for external source code, too.
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
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 access everything on the Token, regardless of its
protections. Private keys, and other information should be protected
properly.
@@ -228,6 +230,9 @@ Gnuk is distributed with external source code.
The file include/polarssl/bn_mul.h is heavily modified for ARM
Cortex-M3.
The file library/aes.c is modified so that some constants can
go to .sys section.
USB vendor ID and product ID (USB device ID)
============================================
@@ -235,7 +240,7 @@ USB vendor ID and product ID (USB device ID)
When you have a vender ID and assign a product ID for Gnuk, edit the
file GNUK_USB_DEVICE_ID and add an entry for yours. In this case,
please contact Niibe, so that it is listed to the file in the official
release of source code.
release of the source code.
When you are modifing Gnuk and installing the binary to device, you
should replace "FSIJ" in the string gnukStringSerial (usb_desc.c) to
@@ -264,14 +269,16 @@ with Gnuk under one of following conditions:
please use that number for your device.
(There a file 'GNUK_SERIAL_NUMBER' in the official release.)
FSIJ could permit companies or business entities to use USB device ID
of FSIJ for devices with unmodified version of Gnuk, provided they
support Free Software and respect users' freedom for computing.
Please ask FSIJ for permission.
FSIJ could give companies or business entities "second source
manufacturer" license to use USB device ID of FSIJ for devices with
unmodified version of Gnuk, provided they support Free Software and
respect users' freedom for computing. Please ask FSIJ for the
license.
Otherwise, companies which want to distribute Gnuk devices, please use
your own USB vendor ID and product ID. When you modify Gnuk, please
replace "FSIJ" in the string gnukStringSerial (usb_desc.c) to yours.
your own USB vendor ID and product ID. Note that please replace
"FSIJ" in the string gnukStringSerial (usb_desc.c) to yours, when you
modify Gnuk.
Host Requirements
@@ -615,6 +622,12 @@ You can observe the traffic of USB using "usbmon". See the file:
linux/Documentation/usb/usbmon.txt
Firmware update
===============
See doc/firmware-update.
Read-only Git Repository
========================

View File

@@ -4,34 +4,8 @@
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
hwinit1_common ();
}
void
USB_Cable_Config (FunctionalState NewState)
{
/* CQ STARM has no functionality to stop USB. */
/*
* It seems that users can add the functionality with USB_DC (PD9)
* though
*/
(void)NewState;
}
void
set_led (int value)
{
if (value)
palSetPad (IOPORT3, GPIOC_LED);
else
palClearPad (IOPORT3, GPIOC_LED);
}

View File

@@ -30,6 +30,10 @@
/*
* Setup for the CQ STARM board.
*/
#undef SET_USB_CONDITION /* No functionality to disconnect USB */
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
#define GPIO_LED GPIOC_LED
#define IOPORT_LED GPIOC
/*
* Board identifier.

View File

@@ -4,12 +4,6 @@
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
@@ -48,24 +42,6 @@ hwinit1 (void)
#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)

View File

@@ -30,6 +30,12 @@
/*
* Setup for the FST-01 board.
*/
#define SET_USB_CONDITION(en) en /* To connect USB, call palSetPad */
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
#define GPIO_USB GPIOA_USB_ENABLE
#define IOPORT_USB GPIOA
#define GPIO_LED GPIOB_LED
#define IOPORT_LED GPIOB
/*
* Board identifier.

View File

@@ -4,33 +4,8 @@
#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);
}

View File

@@ -30,6 +30,12 @@
/*
* Setup for the FST-01 board (experimental version 00).
*/
#define SET_USB_CONDITION(en) en /* To connect USB, call palSetPad */
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
#define GPIO_USB GPIOA_USB_ENABLE
#define IOPORT_USB GPIOA
#define GPIO_LED GPIOA_LED
#define IOPORT_LED GPIOA
/*
* Board identifier.

View File

@@ -4,32 +4,8 @@
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
hwinit1_common ();
}
void
USB_Cable_Config (FunctionalState NewState)
{
if (NewState != DISABLE)
palClearPad (IOPORT3, GPIOC_DISC);
else
palSetPad (IOPORT3, GPIOC_DISC);
}
void
set_led (int value)
{
if (value)
palClearPad (IOPORT3, GPIOC_LED);
else
palSetPad (IOPORT3, GPIOC_LED);
}

View File

@@ -30,6 +30,12 @@
/*
* Setup for the Olimex STM32-H103 proto board.
*/
#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
#define GPIO_USB GPIOC_DISC
#define IOPORT_USB GPIOC
#define GPIO_LED GPIOC_LED
#define IOPORT_LED GPIOC
/*
* Board identifier.

View File

@@ -4,12 +4,6 @@
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
@@ -70,24 +64,6 @@ hwinit1 (void)
#endif
}
void
USB_Cable_Config (FunctionalState NewState)
{
if (NewState != DISABLE)
palClearPad (IOPORT4, GPIOD_USB_ENABLE);
else
palSetPad (IOPORT4, GPIOD_USB_ENABLE);
}
void
set_led (int value)
{
if (value)
palClearPad (IOPORT4, GPIOD_LED1);
else
palSetPad (IOPORT4, GPIOD_LED1);
}
#if defined(PINPAD_CIR_SUPPORT)
void
cir_ext_disable (void)

View File

@@ -31,6 +31,12 @@
/*
* Setup for the STBee board.
*/
#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
#define GPIO_USB GPIOD_USB_ENABLE
#define IOPORT_USB GPIOD
#define GPIO_LED GPIOD_LED1
#define IOPORT_LED GPIOD
/*
* Board identifier.

View File

@@ -4,12 +4,6 @@
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
@@ -83,24 +77,6 @@ hwinit1 (void)
palSetPad (IOPORT1, GPIOA_LED2);
}
void
USB_Cable_Config (FunctionalState NewState)
{
if (NewState != DISABLE)
palSetPad (IOPORT1, GPIOA_USB_ENABLE);
else
palClearPad (IOPORT1, GPIOA_USB_ENABLE);
}
void
set_led (int value)
{
if (value)
palClearPad (IOPORT1, GPIOA_LED1);
else
palSetPad (IOPORT1, GPIOA_LED1);
}
#if defined(PINPAD_CIR_SUPPORT)
void
cir_ext_disable (void)

View File

@@ -31,6 +31,12 @@
/*
* Setup for the STBee Mini board.
*/
#define SET_USB_CONDITION(en) (en) /* To connect USB, call palSetPad */
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
#define GPIO_USB GPIOA_USB_ENABLE
#define IOPORT_USB GPIOA
#define GPIO_LED GPIOA_LED1
#define IOPORT_LED GPIOA
/*
* Board identifier.

View File

@@ -4,12 +4,6 @@
#include "../common/hwinit.c"
void
hwinit0(void)
{
hwinit0_common ();
}
void
hwinit1(void)
{
@@ -21,21 +15,3 @@ hwinit1(void)
palClearPad (IOPORT5, GPIOE_LED);
palClearPad (IOPORT3, GPIOC_SHUTDOWN);
}
void
USB_Cable_Config (FunctionalState NewState)
{
if (NewState != DISABLE)
palClearPad (IOPORT4, GPIOD_DISC);
else
palSetPad (IOPORT4, GPIOD_DISC);
}
void
set_led (int value)
{
if (value)
palClearPad (IOPORT5, GPIOE_LEDR);
else
palSetPad (IOPORT5, GPIOE_LEDR);
}

View File

@@ -30,6 +30,12 @@
/*
* Setup for the STM32 Primer2.
*/
#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
#define GPIO_USB GPIOD_DISC
#define IOPORT_USB GPIOD
#define GPIO_LED GPIOE_LEDR
#define IOPORT_LED GPIOE
/*
* Board identifier.

View File

@@ -4,12 +4,6 @@
#include "../common/hwinit.c"
void
hwinit0 (void)
{
hwinit0_common ();
}
void
hwinit1 (void)
{
@@ -46,22 +40,6 @@ hwinit1 (void)
AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_PARTIALREMAP;
}
void
USB_Cable_Config (FunctionalState NewState)
{
/* No functionality to stop USB. */
(void)NewState;
}
void
set_led (int value)
{
if (value)
palSetPad (IOPORT1, GPIOA_LED);
else
palClearPad (IOPORT1, GPIOA_LED);
}
#if defined(PINPAD_CIR_SUPPORT)
void
cir_ext_disable (void)

View File

@@ -32,11 +32,16 @@
* Setup for the ST-Link part of STM8S-Discovery board.
*/
#undef SET_USB_CONDITION /* No functionality to disconnect USB */
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
#define GPIO_LED GPIOA_LED
#define IOPORT_LED GPIOA
/*
* Board identifier.
*/
#define BOARD_ST_DISCOVERY
#define BOARD_NAME "ST-Link"
#define BOARD_NAME "STM8S Discovery"
#define CPU_WITH_NO_GPIOE 1
/*

View File

@@ -1,14 +0,0 @@
/* Hardware specific function */
#include "ch.h"
#include "hal.h"
#include "board.h"
const uint8_t *
unique_device_id (void)
{
/* STM32F103 has 96-bit unique device identifier */
const uint8_t *addr = (const uint8_t *)0x1ffff7e8;
return addr;
}

View File

@@ -29,15 +29,9 @@
* This initialization is performed just after reset before BSS and DATA
* segments initialization.
*/
/*
* Common code for hwinit0
*/
static void hwinit0_common (void)
void
hwinit0 (void)
{
#ifdef DFU_SUPPORT
SCB->VTOR = 0x08003000;
#endif
stm32_clock_init();
}

128
doc/firmware-update Normal file
View File

@@ -0,0 +1,128 @@
Firmware update feature
=======================
The firmware update feature of Gnuk is experimental. Please be
careful using that.
Note that updating firmware, all data objects and keys will be
removed. There is _no way_ to preserve those data.
Preparation
===========
In addition to settings of Gnuk, I create a file
/etc/udev/rules.d/92-gnuk.rules::
# For updating firmware, permission settings are needed.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
While I am a member of group "pcscd" in /etc/group.
This is needed for reGNUal, the firmware update program.
Registering a public key for firmware update
============================================
You need to register a public key to update the firmware. It should
be RSA 2048-bit.
One way to extract public key data is by using "gpg-connect-agent"
command connecting gpg-agent.
We can examine key information of gpg-agent by "KEYINFO" command.
Here is my example::
$ gpg-connect-agent "KEYINFO --list" /bye
S KEYINFO 4970A0D537CA2EF7CE6A106E47AD89B0EFB684C8 D - - - - -
S KEYINFO 65F67E742101C7FE6D5B33FCEFCF4F65EAF0688C T D276000124010200F517000000010000 OPENPGP.2 - - -
S KEYINFO 5D6C89682D07CCFC034AF508420BF2276D8018ED T D276000124010200F517000000010000 OPENPGP.3 - - -
S KEYINFO 7D180C0C2A991B25204110A92F5F92A5A509845B D - - - - -
S KEYINFO 101DE7B639FE29F4636BDEECF442A9273AFA6565 T D276000124010200F517000000010000 OPENPGP.1 - - -
OK
I have two local keys (in my PC) and three keys in my token.
With the script below, I extract public key of the keygrip
5D6C89682D07CCFC034AF508420BF2276D8018ED into the file: 5D6C8968.bin::
$ ./get_public_key.py 5D6C89682D07CCFC034AF508420BF2276D8018ED
Here is the script, get_public_key.py::
#! /usr/bin/python
import sys, binascii
from subprocess import check_output
def get_gpg_public_key(keygrip):
result = check_output(["gpg-connect-agent", "READKEY %s" % keygrip, "/bye"])
key = ""
while True:
i = result.find('%')
if i < 0:
key += result
break
hex_str = result[i+1:i+3]
key += result[0:i]
key += chr(int(hex_str,16))
result = result[i+3:]
pos = key.index("D (10:public-key(3:rsa(1:n257:") + 31 # skip NUL too
key = key[pos:-17] # )(1:e3:XYZ)))\nOK\n
if len(key) != 256:
raise ValueError, binascii.hexlify(key)
return key
if __name__ == '__main__':
keygrip = sys.argv[1]
k = get_gpg_public_key(keygrip)
shorthand = keygrip[0:8] + ".bin"
f = open(shorthand,"w")
f.write(k)
f.close()
Then, we can put the data of public key into token by::
$ tool/gnuk_put_binary_libusb.py -k 0 5D6C8968.bin
Invoking firmware update
========================
We specify the keygrip to authenticate, reGNUal binary, and Gnuk binary.
$ ../tool/gnuk_upgrade.py 5D6C89682D07CCFC034AF508420BF2276D8018ED ../regnual/regnual.bin gnuk.bin
Two or more tokens
==================
Currently, GnuPG doesn't support multiple devices connected to the
host.
In order to update the firmware of a token TARGET, we use GnuPG to
authenticate with public key. If it is on another token AUTH, it is
somewhat complicated.
What I do is:
(1) Don't run PC/SC daemon::
# /etc/init.d/pcscd stop
(2) To make sure, kill scdaemon::
$ killall -9 scdaemon
(3) Connect the token of AUTH, and use it::
$ gpg --card-status
(4) Connect TARGET, and invoke gnuk_update.py
--

View File

@@ -330,7 +330,7 @@ int rsa_pkcs1_verify( rsa_context *ctx,
int hash_id,
int hashlen,
const unsigned char *hash,
unsigned char *sig );
const unsigned char *sig );
/**
* \brief Free the components of an RSA key

View File

@@ -172,15 +172,15 @@ static const unsigned char FSb[256] =
V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
#define V(a,b,c,d) 0x##a##b##c##d
static const unsigned long FT0[256] = { FT };
static const unsigned long FT0[256] __attribute__((section(".sys.0"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
static const unsigned long FT1[256] = { FT };
static const unsigned long FT1[256] __attribute__((section(".sys.1"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
static const unsigned long FT2[256] = { FT };
static const unsigned long FT2[256] __attribute__((section(".sys.2"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##d##a##b##c

View File

@@ -538,11 +538,11 @@ int rsa_pkcs1_verify( rsa_context *ctx,
int hash_id,
int hashlen,
const unsigned char *hash,
unsigned char *sig )
const unsigned char *sig )
{
int ret, len, siglen;
unsigned char *p, c;
unsigned char buf[1024];
unsigned char buf[256];
siglen = ctx->len;

51
regnual/Makefile Normal file
View File

@@ -0,0 +1,51 @@
# Makefile for reGNUal
PROJECT = regnual
SRCS = regnual.c usb_lld.c sys.c
OBJS = regnual.o usb_lld.o sys.o
LDSCRIPT= regnual.ld
###################################
MCU = cortex-m3
TRGT = arm-none-eabi-
CC = $(TRGT)gcc
LD = $(TRGT)ld
OBJCOPY = $(TRGT)objcopy
OBJDUMP = $(TRGT)objdump
# THUMB-specific options here
TOPT = -mthumb -DTHUMB -mno-thumb-interwork
# Define C warning options here
CWARN = -Wall -Wextra -Wstrict-prototypes
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
DEFS = -DFREE_STANDING
CFLAGS = -O2 -g
CFLAGS += $(CWARN) -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
LDFLAGS = -T$(LDSCRIPT) -nostartfiles $(MCFLAGS) $(TOPT)
####################
all: regnual.hex
regnual.o: regnual.c ../src/sys.h
regnual.hex: regnual.elf
$(OBJCOPY) -Obinary regnual.elf regnual.bin
$(OBJCOPY) -Oihex regnual.elf regnual.hex
usb_lld.c: ../src/usb_lld.c
cp -p ../src/usb_lld.c .
regnual.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS)
clean:
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin
distclean: clean
-rm -f usb_lld.c

355
regnual/regnual.c Normal file
View File

@@ -0,0 +1,355 @@
/*
* regnual.c -- Firmware installation for STM32F103 Flash ROM
*
* Copyright (C) 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* ReGNUal
*/
#include "types.h"
#include "usb_lld.h"
#include "sys.h"
extern void *memset (void *s, int c, size_t n);
extern void set_led (int);
extern uint8_t _flash_start, _flash_end;
extern int flash_write (uint32_t dst_addr, const uint8_t *src, size_t len);
extern int flash_protect (void);
extern void nvic_system_reset (void);
#define ENDP0_RXADDR (0x40)
#define ENDP0_TXADDR (0x80)
/* USB Standard Device Descriptor */
static const uint8_t regnual_device_desc[] = {
18, /* bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x10, 0x01, /* bcdUSB = 1.1 */
0xFF, /* bDeviceClass: VENDOR */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */
#include "../src/usb-vid-pid-ver.c.inc"
1, /* Index of string descriptor describing manufacturer */
2, /* Index of string descriptor describing product */
3, /* Index of string descriptor describing the device's serial number */
0x01 /* bNumConfigurations */
};
static const uint8_t regnual_config_desc[] = {
9,
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
18, 0, /* wTotalLength: no of returned bytes */
1, /* bNumInterfaces: single vender interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: None */
#if defined(USB_SELF_POWERED)
0xC0, /* bmAttributes: self powered */
#else
0x80, /* bmAttributes: bus powered */
#endif
50, /* MaxPower 100 mA */
/* Interface Descriptor */
9,
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
0, /* bInterfaceNumber: Index of this interface */
0, /* Alternate setting for this interface */
0, /* bNumEndpoints: None */
0xFF,
0,
0,
0, /* string index for interface */
};
static const uint8_t regnual_string_lang_id[] = {
4, /* bLength */
USB_STRING_DESCRIPTOR_TYPE,
0x09, 0x04 /* LangID = 0x0409: US-English */
};
#include "../src/usb-strings.c.inc"
static const uint8_t regnual_string_serial[] = {
8*2+2,
USB_STRING_DESCRIPTOR_TYPE,
/* FSIJ-0.0 */
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
'0', 0, '.', 0, '0', 0,
};
const struct Descriptor device_desc = {
regnual_device_desc,
sizeof (regnual_device_desc)
};
const struct Descriptor config_desc = {
regnual_config_desc,
sizeof (regnual_config_desc)
};
const struct Descriptor string_descs[] = {
{regnual_string_lang_id, sizeof (regnual_string_lang_id)},
{gnukStringVendor, sizeof (gnukStringVendor)},
{gnukStringProduct, sizeof (gnukStringProduct)},
{regnual_string_serial, sizeof (regnual_string_serial)},
};
#define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
static void
regnual_device_reset (void)
{
/* Set DEVICE as not configured */
usb_lld_set_configuration (0);
/* Current Feature initialization */
usb_lld_set_feature (config_desc.Descriptor[7]);
usb_lld_reset ();
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
64);
}
#define USB_REGNUAL_MEMINFO 0
#define USB_REGNUAL_SEND 1
#define USB_REGNUAL_RESULT 2
#define USB_REGNUAL_FLASH 3
#define USB_REGNUAL_PROTECT 4
#define USB_REGNUAL_FINISH 5
static uint8_t mem[256];
static uint32_t result;
static const uint8_t *const mem_info[] = { &_flash_start, &_flash_end, };
static uint32_t rbit (uint32_t v)
{
uint32_t r;
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
return r;
}
static uint32_t fetch (int i)
{
uint32_t v;
v = *(uint32_t *)(&mem[i*4]);
return rbit (v);
}
struct CRC {
__IO uint32_t DR;
__IO uint8_t IDR;
uint8_t RESERVED0;
uint16_t RESERVED1;
__IO uint32_t CR;
};
#define CRC_CR_RESET 0x01
static uint32_t calc_crc32 (void)
{
struct CRC *CRC = (struct CRC *)0x40023000;
int i;
CRC->CR = CRC_CR_RESET;
for (i = 0; i < 256/4; i++)
CRC->DR = fetch (i);
return rbit (CRC->DR);
}
static void regnual_ctrl_write_finish (uint8_t req, uint8_t req_no,
uint16_t value, uint16_t index,
uint16_t len)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
{
if (req_no == USB_REGNUAL_SEND && value == 0)
result = calc_crc32 ();
else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
{
uint32_t dst_addr = (0x08000000 + value * 0x100);
result = flash_write (dst_addr, mem, 256);
}
else if (req_no == USB_REGNUAL_PROTECT && len == 0
&& value == 0 && index == 0)
result = flash_protect ();
else if (req_no == USB_REGNUAL_FINISH && len == 0
&& value == 0 && index == 0)
nvic_system_reset ();
}
}
static int
regnual_setup (uint8_t req, uint8_t req_no,
uint16_t value, uint16_t index, uint16_t len)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
{
if (USB_SETUP_GET (req))
{
if (req_no == USB_REGNUAL_MEMINFO)
{
usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
return USB_SUCCESS;
}
else if (req_no == USB_REGNUAL_RESULT)
{
usb_lld_set_data_to_send (&result, sizeof (uint32_t));
return USB_SUCCESS;
}
}
else /* SETUP_SET */
{
if (req_no == USB_REGNUAL_SEND)
{
if (value != 0 || index + len > 256)
return USB_UNSUPPORT;
if (index + len < 256)
memset (mem + index + len, 0xff, 256 - (index + len));
usb_lld_set_data_to_recv (mem + index, len);
return USB_SUCCESS;
}
else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
{
uint32_t dst_addr = (0x08000000 + value * 0x100);
if (dst_addr + 256 <= (uint32_t)&_flash_end)
return USB_SUCCESS;
}
else if (req_no == USB_REGNUAL_PROTECT && len == 0
&& value == 0 && index == 0)
return USB_SUCCESS;
else if (req_no == USB_REGNUAL_FINISH && len == 0
&& value == 0 && index == 0)
return USB_SUCCESS;
}
}
return USB_UNSUPPORT;
}
static int
regnual_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
{
(void)index;
if (desc_type == DEVICE_DESCRIPTOR)
{
usb_lld_set_data_to_send (device_desc.Descriptor,
device_desc.Descriptor_Size);
return USB_SUCCESS;
}
else if (desc_type == CONFIG_DESCRIPTOR)
{
usb_lld_set_data_to_send (config_desc.Descriptor,
config_desc.Descriptor_Size);
return USB_SUCCESS;
}
else if (desc_type == STRING_DESCRIPTOR)
{
uint8_t desc_index = value & 0xff;
if (desc_index < NUM_STRING_DESC)
{
usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
string_descs[desc_index].Descriptor_Size);
return USB_SUCCESS;
}
}
return USB_UNSUPPORT;
}
static int regnual_usb_event (uint8_t event_type, uint16_t value)
{
(void)value;
switch (event_type)
{
case USB_EVENT_ADDRESS:
case USB_EVENT_CONFIG:
return USB_SUCCESS;
default:
break;
}
return USB_UNSUPPORT;
}
static int regnual_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
{
(void)cmd; (void)interface; (void)alt;
return USB_UNSUPPORT;
}
const struct usb_device_method Device_Method = {
regnual_device_reset,
regnual_ctrl_write_finish,
regnual_setup,
regnual_get_descriptor,
regnual_usb_event,
regnual_interface,
};
static void wait (int count)
{
int i;
for (i = 0; i < count; i++)
asm volatile ("" : : "r" (i) : "memory");
}
#define WAIT 2400000
int
main (int argc, char *argv[])
{
(void)argc; (void)argv;
set_led (0);
usb_lld_init (regnual_config_desc[7]);
while (1)
{
set_led (1);
wait (WAIT);
set_led (0);
wait (WAIT);
}
}

98
regnual/regnual.ld Normal file
View File

@@ -0,0 +1,98 @@
/*
* ST32F103 memory setup.
*/
__main_stack_size__ = 0x0400;
__process_stack_size__ = 0x0200;
__stacks_total_size__ = __main_stack_size__ + __process_stack_size__;
MEMORY
{
ram0 : org = 0x20000000, len = 0x1400
ram1 : org = 0x20001400, len = 20k - 0x1400
}
vector = 0x08000000;
_flash_start = 0x08001000;
_flash_end = 0x08020000;
__ram_start__ = ORIGIN(ram0);
__ram_size__ = 20k;
__ram_end__ = __ram_start__ + __ram_size__;
SECTIONS
{
. = 0;
.bss :
{
_bss_start = .;
*(.bss)
. = ALIGN(4);
*(.bss.*)
. = ALIGN(4);
*(COMMON)
. = ALIGN(4);
_bss_end = .;
} > ram0
.text : ALIGN(16) SUBALIGN(16)
{
_text = .;
KEEP(*(.vectors))
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
} > ram1
.ctors :
{
PROVIDE(_ctors_start_ = .);
KEEP(*(SORT(.ctors.*)))
KEEP(*(.ctors))
PROVIDE(_ctors_end_ = .);
} > ram1
.dtors :
{
PROVIDE(_dtors_start_ = .);
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
PROVIDE(_dtors_end_ = .);
} > ram1
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)}
__exidx_start = .;
.ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > ram1
__exidx_end = .;
.eh_frame_hdr : {*(.eh_frame_hdr)}
.eh_frame : ONLY_IF_RO {*(.eh_frame)}
. = ALIGN(4);
_etext = .;
_textdata = _etext;
.data :
{
_data = .;
*(.data)
. = ALIGN(4);
*(.data.*)
. = ALIGN(4);
*(.ramtext)
. = ALIGN(4);
_edata = .;
} > ram1
PROVIDE(end = .);
_end = .;
}
__heap_base__ = _end;
__heap_end__ = __ram_end__ - __stacks_total_size__;

60
regnual/sys.c Normal file
View File

@@ -0,0 +1,60 @@
#include "types.h"
static void fatal (void)
{
for (;;);
}
static void none (void)
{
}
/* Note: it is not reset */
static __attribute__ ((naked))
void entry (void)
{
asm volatile ("ldr r0, =__ram_end__\n\t"
"ldr r1, =__main_stack_size__\n\t"
"sub r0, r0, r1\n\t"
"mov sp, r0\n\t"
"mov r0, #0\n\t"
"ldr r1, =_bss_start\n\t"
"ldr r2, =_bss_end\n"
"0:\n\t"
"str r0, [r1], #4\n\t"
"cmp r2, r1\n\t"
"bhi 0b\n\t"
"cpsie i\n\t" /* Enable interrupts */
"mov r0, #0\n\t"
"mov r1, r0\n\t"
"bl main\n"
"1:\n\t"
"b 1b\n"
: /* no output */ : /* no input */ : "memory");
}
typedef void (*handler)(void);
extern uint8_t __ram_end__;
extern void usb_interrupt_handler (void);
handler vector_table[] __attribute__ ((section(".vectors"))) = {
(handler)&__ram_end__,
entry,
fatal, /* nmi */
fatal, /* hard fault */
/* 10 */
fatal, /* mem manage */
fatal, /* bus fault */
fatal, /* usage fault */
none,
/* 20 */
none, none, none, none, none, none, none, none,
/* 40 */
none, none, none, none, none, none, none, none,
/* 60 */
none, none, none, none, none, none, none, none,
/* 80 */
none, none, none, none,
/* 90 */
usb_interrupt_handler,
};

12
regnual/types.h Normal file
View File

@@ -0,0 +1,12 @@
typedef unsigned long size_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define TRUE 1
#define FALSE 0
#define NULL 0
#define __IO volatile

View File

@@ -76,16 +76,14 @@ CSRC = $(PORTSRC) \
$(HALSRC) \
$(PLATFORMSRC) \
$(BOARDSRC) \
../boards/common/hw_config.c \
$(BOARD_DIR)/board.c \
$(CHIBIOS)/os/various/evtimer.c \
$(CHIBIOS)/os/various/syscalls.c \
$(VCOMSRC) \
$(CRYPTSRC) \
main.c usb_lld.c \
usb_desc.c usb_prop.c \
usb_desc.c usb_ctrl.c \
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c \
random.c neug.c
random.c neug.c sys.c
ifneq ($(ENABLE_DEBUG),)
CSRC += debug.c
@@ -195,13 +193,6 @@ ULIBS =
# End of user defines
##############################################################################
ifeq ($(USE_FWLIB),yes)
include $(CHIBIOS)/ext/stm32lib/stm32lib.mk
CSRC += $(STM32SRC)
INCDIR += $(STM32INC)
USE_OPT += -DUSE_STDPERIPH_DRIVER
endif
include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd

View File

@@ -183,3 +183,31 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
return 0;
}
}
int
rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
{
int r;
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
rsa_ctx.len = KEY_CONTENT_LEN;
mpi_read_string (&rsa_ctx.E, 16, "10001");
mpi_read_binary (&rsa_ctx.N, pubkey, KEY_CONTENT_LEN);
DEBUG_INFO ("RSA verify...");
r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA1, 20, hash, sig);
rsa_free (&rsa_ctx);
if (r < 0)
{
DEBUG_INFO ("fail:");
DEBUG_SHORT (r);
return r;
}
else
{
DEBUG_INFO ("verified.\r\n");
return 0;
}
}

View File

@@ -6,3 +6,4 @@
@PINPAD_DEFINE@
@PINPAD_MORE_DEFINE@
@CERTDO_DEFINE@
#define FLASH_PAGE_SIZE @FLASH_PAGE_SIZE@

80
src/configure vendored
View File

@@ -103,35 +103,6 @@ if test "$vidpid" = "none"; then
exit 1
fi
if !(IFS=" "
while read VIDPID VERSION PRODUCT VENDOR; do
if test "$vidpid" = "$VIDPID"; then
(echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\n 0x\4, 0x\3, /* idProduct */%p"
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
) > usb-vid-pid-ver.c.inc
(echo 'static const uint8_t gnukStringVendor[] = {'
echo " ${#VENDOR}*2+2, /* bLength */"
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
echo " /* Manufacturer: \"$VENDOR\" */"
echo $VENDOR | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
echo '};'
echo
echo 'static const uint8_t gnukStringProduct[] = {'
echo " ${#PRODUCT}*2+2, /* bLength */"
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
echo " /* Product name: \"$PRODUCT\" */"
echo $PRODUCT | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
echo '};'
) >usb-string-vendor-product.c.inc
exit 0
fi
done; exit 1) < ../GNUK_USB_DEVICE_ID
then
echo "Please specify valid Vendor ID and Product ID."
echo "Check ../GNUK_USB_DEVICE_ID."
exit 1
fi
BOARD_DIR=../boards/$target
if test -d $BOARD_DIR; then
echo "Configured for target: $target"
@@ -186,6 +157,7 @@ if test "$with_dfu" = "yes"; then
FLASH_SIZE=`expr $FLASH_SIZE - 12`
DFU_DEFINE="#define DFU_SUPPORT 1"
else
with_dfu=no
echo "Configured for bare system (no-DFU)"
ORIGIN=0x08000000
DFU_DEFINE="#undef DFU_SUPPORT"
@@ -198,6 +170,7 @@ if test "$pinpad" = "no"; then
PINPAD_MORE_DEFINE=""
echo "PIN pad option disabled"
elif test "$pinpad" = "yes"; then
pinpad=dnd
PINPAD_MAKE_OPTION="ENABLE_PINPAD=dnd"
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
PINPAD_MORE_DEFINE="#define PINPAD_DND_SUPPORT 1"
@@ -218,6 +191,54 @@ else
echo "CERT.3 Data Object is not supported"
fi
REVISION=`git describe --dirty="-modified"`
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo"
if !(IFS=" "
while read VIDPID VERSION PRODUCT VENDOR; do
if test "$vidpid" = "$VIDPID"; then
(echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\n 0x\4, 0x\3, /* idProduct */%p"
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
) > usb-vid-pid-ver.c.inc
(echo 'static const uint8_t gnukStringVendor[] = {'
echo " ${#VENDOR}*2+2, /* bLength */"
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
echo " /* Manufacturer: \"$VENDOR\" */"
echo $VENDOR | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
echo '};'
echo
echo 'static const uint8_t gnukStringProduct[] = {'
echo " ${#PRODUCT}*2+2, /* bLength */"
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
echo " /* Product name: \"$PRODUCT\" */"
echo $PRODUCT | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
echo '};'
echo
echo '#ifdef USB_STRINGS_FOR_GNUK'
echo 'static const uint8_t gnuk_revision_detail[] = {'
echo " ${#REVISION}*2+2, /* bLength */"
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
echo " /* revision detail: \"$REVISION\" */"
echo $REVISION | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
echo '};'
echo
echo 'static const uint8_t gnuk_config_options[] = {'
echo " ${#CONFIG}*2+2, /* bLength */"
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
echo " /* configure options: \"$CONFIG\" */"
echo $CONFIG | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
echo '};'
echo '#endif'
) >usb-strings.c.inc
exit 0
fi
done; exit 1) < ../GNUK_USB_DEVICE_ID
then
echo "Please specify valid Vendor ID and Product ID."
echo "Check ../GNUK_USB_DEVICE_ID."
exit 1
fi
sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
@@ -238,5 +259,6 @@ sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
< config.h.in > config.h
exit 0

View File

@@ -32,108 +32,9 @@
#include "config.h"
#include "ch.h"
#include "hal.h"
#include "sys.h"
#include "gnuk.h"
#define FLASH_KEY1 0x45670123UL
#define FLASH_KEY2 0xCDEF89ABUL
enum flash_status
{
FLASH_BUSY = 1,
FLASH_ERROR_PG,
FLASH_ERROR_WRP,
FLASH_COMPLETE,
FLASH_TIMEOUT
};
void
flash_unlock (void)
{
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
static int
flash_get_status (void)
{
int status;
if ((FLASH->SR & FLASH_SR_BSY) != 0)
status = FLASH_BUSY;
else if ((FLASH->SR & FLASH_SR_PGERR) != 0)
status = FLASH_ERROR_PG;
else if((FLASH->SR & FLASH_SR_WRPRTERR) != 0 )
status = FLASH_ERROR_WRP;
else
status = FLASH_COMPLETE;
return status;
}
static int
flash_wait_for_last_operation (uint32_t timeout)
{
int status;
do
if (--timeout == 0)
return FLASH_TIMEOUT;
else
status = flash_get_status ();
while (status == FLASH_BUSY);
return status;
}
#define FLASH_PROGRAM_TIMEOUT 0x00010000
#define FLASH_ERASE_TIMEOUT 0x01000000
static int
flash_program_halfword (uint32_t addr, uint16_t data)
{
int status;
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
chSysLock ();
if (status == FLASH_COMPLETE)
{
FLASH->CR |= FLASH_CR_PG;
*(volatile uint16_t *)addr = data;
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
if (status != FLASH_TIMEOUT)
FLASH->CR &= ~FLASH_CR_PG;
}
chSysUnlock ();
return status;
}
static int
flash_erase_page (uint32_t addr)
{
int status;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
chSysLock ();
if (status == FLASH_COMPLETE)
{
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = addr;
FLASH->CR |= FLASH_CR_STRT;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
if (status != FLASH_TIMEOUT)
FLASH->CR &= ~FLASH_CR_PER;
}
chSysUnlock ()
return status;
}
/*
* Flash memory map
*
@@ -155,11 +56,6 @@ flash_erase_page (uint32_t addr)
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3)
*/
#define FLASH_DATA_POOL_HEADER_SIZE 2
#if defined(STM32F10X_HD)
#define FLASH_PAGE_SIZE 2048
#else
#define FLASH_PAGE_SIZE 1024
#endif
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
#define FLASH_KEYSTORE_SIZE (512*3)
@@ -294,14 +190,14 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
addr = (uint32_t)p;
hw = nr | (len << 8);
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
addr += 2;
for (i = 0; i < len/2; i++)
{
hw = data[i*2] | (data[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
addr += 2;
}
@@ -309,7 +205,7 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
if ((len & 1))
{
hw = data[i*2] | 0xff00;
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
}
}
@@ -359,19 +255,19 @@ flash_do_release (const uint8_t *do_data)
/* Fill zero for content and pad */
for (i = 0; i < len/2; i ++)
{
if (flash_program_halfword (addr, 0) != FLASH_COMPLETE)
if (flash_program_halfword (addr, 0) != 0)
flash_warning ("fill-zero failure");
addr += 2;
}
if ((len & 1))
{
if (flash_program_halfword (addr, 0) != FLASH_COMPLETE)
if (flash_program_halfword (addr, 0) != 0)
flash_warning ("fill-zero pad failure");
}
/* Fill 0x0000 for "tag_number and length" word */
if (flash_program_halfword (addr_tag, 0) != FLASH_COMPLETE)
if (flash_program_halfword (addr_tag, 0) != 0)
flash_warning ("fill-zero tag_nr failure");
}
@@ -399,7 +295,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
for (i = 0; i < KEY_CONTENT_LEN/2; i ++)
{
hw = key_data[i*2] | (key_data[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
if (flash_program_halfword (addr, hw) != 0)
return -1;
addr += 2;
}
@@ -407,7 +303,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
for (i = 0; i < KEY_CONTENT_LEN/2; i ++)
{
hw = modulus[i*2] | (modulus[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
if (flash_program_halfword (addr, hw) != 0)
return -1;
addr += 2;
}
@@ -580,24 +476,9 @@ flash_cnt123_clear (const uint8_t **addr_p)
#if defined(CERTDO_SUPPORT)
static int
flash_check_blank (const uint8_t *page, int size)
{
const uint8_t *p;
for (p = page; p < page + size; p++)
if (*p != 0xff)
return 0;
return 1;
}
#endif
#define FLASH_CH_CERTIFICATE_SIZE 2048
int
flash_erase_binary (uint8_t file_id)
{
#if defined(CERTDO_SUPPORT)
if (file_id == FILEID_CH_CERTIFICATE)
{
const uint8_t *p = &ch_certificate_start;
@@ -611,12 +492,10 @@ flash_erase_binary (uint8_t file_id)
return 0;
}
else
#else
(void)file_id;
#endif
return -1;
return -1;
}
#endif
int
@@ -626,19 +505,23 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
uint16_t maxsize;
const uint8_t *p;
#if defined(CERTDO_SUPPORT)
if (file_id == FILEID_CH_CERTIFICATE)
{
maxsize = FLASH_CH_CERTIFICATE_SIZE;
p = &ch_certificate_start;
}
else
#endif
if (file_id == FILEID_SERIAL_NO)
{
maxsize = 6;
p = &openpgpcard_aid[8];
}
else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
{
maxsize = KEY_CONTENT_LEN;
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
}
#if defined(CERTDO_SUPPORT)
else if (file_id == FILEID_CH_CERTIFICATE)
{
maxsize = FLASH_CH_CERTIFICATE_SIZE;
p = &ch_certificate_start;
}
#endif
else
return -1;
@@ -650,11 +533,14 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
uint32_t addr;
int i;
if (flash_check_blank (p + offset, len) == 0)
return -1;
addr = (uint32_t)p + offset;
for (i = 0; i < len/2; i++)
{
hw = data[i*2] | (data[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
addr += 2;
}

View File

@@ -76,6 +76,9 @@ enum icc_state
ICC_STATE_EXECUTE, /* Busy4 */
ICC_STATE_RECEIVE, /* APDU Received Partially */
ICC_STATE_SEND, /* APDU Sent Partially */
ICC_STATE_EXITED, /* ICC Thread Terminated */
ICC_STATE_EXEC_REQUESTED, /* Exec requested */
};
extern enum icc_state *icc_state_p;
@@ -118,6 +121,7 @@ extern void gpg_do_get_data (uint16_t tag, int with_tag);
extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
extern void gpg_do_public_key (uint8_t kk_byte);
extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
enum kind_of_key {
@@ -126,7 +130,6 @@ enum kind_of_key {
GPG_KEY_FOR_AUTHENTICATION,
};
extern void flash_unlock (void);
extern const uint8_t *flash_init (void);
extern void flash_do_release (const uint8_t *);
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
@@ -137,12 +140,17 @@ extern void flash_clear_halfword (uint32_t addr);
extern void flash_increment_counter (uint8_t counter_tag_nr);
extern void flash_reset_counter (uint8_t counter_tag_nr);
#define FILEID_CH_CERTIFICATE 0
#define FILEID_RANDOM 1
#define FILEID_SERIAL_NO 2
#define FILEID_SERIAL_NO 0
#define FILEID_UPDATE_KEY_0 1
#define FILEID_UPDATE_KEY_1 2
#define FILEID_UPDATE_KEY_2 3
#define FILEID_UPDATE_KEY_3 4
#define FILEID_CH_CERTIFICATE 5
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);
#define FLASH_CH_CERTIFICATE_SIZE 2048
/* Linker set these two symbols */
extern uint8_t ch_certificate_start;
extern uint8_t random_bits_start;
@@ -224,6 +232,8 @@ extern int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *);
extern const uint8_t *modulus_calc (const uint8_t *, int);
extern void modulus_free (const uint8_t *);
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
const uint8_t *signature);
extern const uint8_t *gpg_do_read_simple (uint8_t);
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);
@@ -320,8 +330,6 @@ extern uint32_t get_salt (void);
extern uint32_t hardclock (void);
extern void set_led (int);
#define NUM_ALL_PRV_KEYS 3 /* SIG, DEC and AUT */
extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
@@ -349,7 +357,6 @@ 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_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)
@@ -386,3 +393,5 @@ extern uint8_t pin_input_len;
extern int pinpad_getline (int msg_code, systime_t timeout);
#endif
extern uint8_t _regnual_start, __heap_end__;

View File

@@ -33,10 +33,15 @@ __stacks_total_size__ = __main_stack_size__ + __process_stack_size__;
MEMORY
{
flash : org = @ORIGIN@, len = @FLASH_SIZE@k
flash0 : org = @ORIGIN@, len = 4k
flash : org = @ORIGIN@+0x1000, len = @FLASH_SIZE@k - 4k
ram : org = 0x20000000, len = 20k
}
/* __flash_start__: flash ROM start address regardless of DFU_SUPPORT */
__flash_start__ = 0x08001000;
__flash_end__ = ORIGIN(flash) + LENGTH(flash);
__ram_start__ = ORIGIN(ram);
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
@@ -45,6 +50,22 @@ SECTIONS
{
. = 0;
.sys : ALIGN(16) SUBALIGN(16)
{
_sys = .;
KEEP(*(.vectors))
. = ALIGN(16);
*(.sys.version)
sys.o(.text)
sys.o(.text.*)
sys.o(.rodata)
sys.o(.rodata.*)
. = ALIGN(1024);
*(.sys.0)
*(.sys.1)
*(.sys.2)
} > flash0
.text : ALIGN(16) SUBALIGN(16)
{
_text = .;
@@ -114,6 +135,8 @@ SECTIONS
PROVIDE(end = .);
_end = .;
. = ALIGN(512);
_regnual_start = .;
@CERTDO_SUPPORT_START@
.gnuk_ch_certificate :
@@ -136,6 +159,9 @@ SECTIONS
_keystore_pool = .;
. += 512*3;
. = ALIGN(@FLASH_PAGE_SIZE@);
_updatekey_store = .;
. += 1024;
. = ALIGN(@FLASH_PAGE_SIZE@);
} > flash =0xffffffff
}

View File

@@ -23,6 +23,8 @@
#include "config.h"
#include "ch.h"
#include "hal.h"
#include "sys.h"
#include "gnuk.h"
#include "usb_lld.h"
#include "usb-cdc.h"
@@ -368,6 +370,7 @@ led_blink (int spec)
chEvtSignal (main_thread, LED_TWOSHOT);
}
/*
* Entry point.
*
@@ -375,7 +378,7 @@ led_blink (int spec)
* See the hwinit1_common function.
*/
int
main (int argc, char **argv)
main (int argc, char *argv[])
{
int count = 0;
@@ -386,7 +389,7 @@ main (int argc, char **argv)
flash_unlock ();
device_initialize_once ();
usb_lld_init ();
usb_lld_init (Config_Descriptor.Descriptor[7]);
random_init ();
while (1)
@@ -418,6 +421,9 @@ main (int argc, char **argv)
{
eventmask_t m;
if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED)
break;
count++;
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL);
switch (m)
@@ -469,6 +475,41 @@ main (int argc, char **argv)
#endif
}
set_led (1);
usb_lld_shutdown ();
/* Disable SysTick */
SysTick->CTRL = 0;
/* Disable all interrupts */
port_disable ();
/* Set vector */
SCB->VTOR = (uint32_t)&_regnual_start;
#ifdef DFU_SUPPORT
#define FLASH_SYS_START_ADDR 0x08000000
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
{
extern uint8_t _sys;
uint32_t addr;
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10];
/* Kill DFU */
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
addr += FLASH_PAGE_SIZE)
flash_erase_page (addr);
/* copy system service routines */
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
/* Leave Gnuk to exec reGNUal */
(*func) (*((void (**)(void))(&_regnual_start+4)));
for (;;);
}
#else
/* Leave Gnuk to exec reGNUal */
flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
#endif
/* Never reached */
return 0;
}

View File

@@ -25,6 +25,7 @@
#include "config.h"
#include "ch.h"
#include "sys.h"
#include "gnuk.h"
#include "openpgp.h"

View File

@@ -1,7 +1,7 @@
/*
* openpgp.c -- OpenPGP card protocol support
*
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -25,6 +25,7 @@
#include "ch.h"
#include "hal.h"
#include "gnuk.h"
#include "sys.h"
#include "openpgp.h"
#include "polarssl/config.h"
#include "polarssl/sha1.h"
@@ -39,6 +40,8 @@
#define INS_PSO 0x2a
#define INS_RESET_RETRY_COUNTER 0x2c
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47
#define INS_EXTERNAL_AUTHENTICATE 0x82
#define INS_GET_CHALLENGE 0x84
#define INS_INTERNAL_AUTHENTICATE 0x88
#define INS_SELECT_FILE 0xa4
#define INS_READ_BINARY 0xb0
@@ -48,6 +51,9 @@
#define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb /* For key import */
#define CHALLENGE_LEN 16
static const uint8_t *challenge; /* Random bytes */
static const uint8_t
select_file_TOP_result[] __attribute__ ((aligned (1))) = {
0x00, 0x00, /* unused */
@@ -76,9 +82,12 @@ set_res_sw (uint8_t sw1, uint8_t sw2)
#define FILE_DF_OPENPGP 1
#define FILE_MF 2
#define FILE_EF_DIR 3
#define FILE_EF_SERIAL 4
#define FILE_EF_CH_CERTIFICATE 5
#define FILE_EF_RANDOM 6
#define FILE_EF_SERIAL_NO 4
#define FILE_EF_UPDATE_KEY_0 5
#define FILE_EF_UPDATE_KEY_1 6
#define FILE_EF_UPDATE_KEY_2 7
#define FILE_EF_UPDATE_KEY_3 8
#define FILE_EF_CH_CERTIFICATE 9
static uint8_t file_selection;
@@ -480,23 +489,95 @@ cmd_pgp_gakp (void)
}
}
const uint8_t *
gpg_get_firmware_update_key (uint8_t keyno)
{
extern uint8_t _updatekey_store;
const uint8_t *p;
p = &_updatekey_store + keyno * KEY_CONTENT_LEN;
return p;
}
#ifdef CERTDO_SUPPORT
#define FILEID_CH_CERTIFICATE_IS_VALID 1
#else
#define FILEID_CH_CERTIFICATE_IS_VALID 0
#endif
static void
cmd_read_binary (void)
{
int is_short_EF = (P1 (apdu) & 0x80) != 0;
uint8_t file_id;
const uint8_t *p;
uint16_t offset;
DEBUG_INFO (" - Read binary\r\n");
if (file_selection == FILE_EF_SERIAL)
if (is_short_EF)
file_id = (P1 (apdu) & 0x1f);
else
file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO;
if ((!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE)
|| file_id > FILEID_CH_CERTIFICATE)
{
if (P2 (apdu) >= 6)
GPG_BAD_P0_P1 ();
else
{
gpg_do_get_data (0x004f, 1); /* AID */
res_APDU[0] = 0x5a;
}
GPG_NO_FILE ();
return;
}
if (is_short_EF)
{
file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
offset = P2 (apdu);
}
else
GPG_NO_RECORD();
offset = (P1 (apdu) << 8) | P2 (apdu);
if (file_id == FILEID_SERIAL_NO)
{
if (offset != 0)
GPG_BAD_P1_P2 ();
else
{
gpg_do_get_data (0x004f, 1); /* Get AID... */
res_APDU[0] = 0x5a; /* ... and overwrite the first byte of data. */
}
return;
}
if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
{
if (offset != 0)
GPG_MEMORY_FAILURE ();
else
{
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
res_APDU_size = KEY_CONTENT_LEN;
memcpy (res_APDU, p, KEY_CONTENT_LEN);
GPG_SUCCESS ();
}
}
#if defined(CERTDO_SUPPORT)
else /* file_id == FILEID_CH_CERTIFICATE */
{
uint16_t len = 256;
p = &ch_certificate_start;
if (offset >= FLASH_CH_CERTIFICATE_SIZE)
GPG_MEMORY_FAILURE ();
else
{
if (offset + len >= FLASH_CH_CERTIFICATE_SIZE)
len = FLASH_CH_CERTIFICATE_SIZE - offset;
res_APDU_size = len;
memcpy (res_APDU, p + offset, len);
GPG_SUCCESS ();
}
}
#endif
}
static void
@@ -539,7 +620,7 @@ cmd_select_file (void)
* MF.EF-GDO -- Serial number of the card and name of the owner
*/
GPG_SUCCESS ();
file_selection = FILE_EF_SERIAL;
file_selection = FILE_EF_SERIAL_NO;
}
else if (apdu.cmd_apdu_data_len == 2
&& apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00)
@@ -700,16 +781,17 @@ cmd_internal_authenticate (void)
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#define MBD_OPRATION_WRITE 0
#define MBD_OPRATION_UPDATE 1
static void
cmd_update_binary (void)
modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
{
int len = apdu.cmd_apdu_data_len;
uint8_t file_id;
uint16_t offset;
int is_short_EF = (p1 & 0x80) != 0;
int r;
DEBUG_INFO (" - UPDATE BINARY\r\n");
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
{
DEBUG_INFO ("security error.");
@@ -717,42 +799,52 @@ cmd_update_binary (void)
return;
}
if ((P1 (apdu) & 0x80))
if ((P1 (apdu) & 0x7f) <= FILEID_RANDOM)
{
file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f);
r = flash_erase_binary (file_selection - FILE_EF_CH_CERTIFICATE);
if (r < 0)
{
DEBUG_INFO ("memory error.\r\n");
GPG_MEMORY_FAILURE ();
return;
}
offset = 0;
}
else
{
GPG_NO_FILE ();
return;
}
if (is_short_EF)
file_id = (p1 & 0x1f);
else
{
if (file_selection != FILE_EF_CH_CERTIFICATE
&& file_selection != FILE_EF_RANDOM)
{
GPG_COMMAND_NOT_ALLOWED ();
return;
}
file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO;
offset = (P1 (apdu) << 8) | P2 (apdu);
if (!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE)
{
GPG_NO_FILE ();
return;
}
if (op == MBD_OPRATION_UPDATE && file_id != FILEID_CH_CERTIFICATE)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (file_id > FILEID_CH_CERTIFICATE)
{
GPG_NO_FILE ();
return;
}
if (is_short_EF)
{
file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
offset = p2;
if (op == MBD_OPRATION_UPDATE)
{
r = flash_erase_binary (file_id);
if (r < 0)
{
DEBUG_INFO ("memory error.\r\n");
GPG_MEMORY_FAILURE ();
return;
}
}
}
else
offset = (p1 << 8) | p2;
DEBUG_SHORT (len);
DEBUG_SHORT (offset);
r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
apdu.cmd_apdu_data, len, offset);
r = flash_write_binary (file_id, apdu.cmd_apdu_data, len, offset);
if (r < 0)
{
DEBUG_INFO ("memory error.\r\n");
@@ -761,64 +853,105 @@ cmd_update_binary (void)
}
GPG_SUCCESS ();
}
#if defined(CERTDO_SUPPORT)
static void
cmd_update_binary (void)
{
int len = apdu.cmd_apdu_data_len;
DEBUG_INFO (" - UPDATE BINARY\r\n");
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("UPDATE BINARY done.\r\n");
}
#endif
static void
cmd_write_binary (void)
{
int len = apdu.cmd_apdu_data_len;
uint16_t offset;
int r;
int i;
const uint8_t *p;
DEBUG_INFO (" - WRITE BINARY\r\n");
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
for (i = 0; i < 4; i++)
{
p = gpg_get_firmware_update_key (i);
if (p[0] != 0x00 || p[1] != 0x00) /* still valid */
break;
}
if (i == 4) /* all update keys are removed */
{
p = gpg_get_firmware_update_key (0);
flash_erase_page ((uint32_t)p);
}
DEBUG_INFO ("WRITE BINARY done.\r\n");
}
static void
cmd_external_authenticate (void)
{
const uint8_t *pubkey;
const uint8_t *signature = apdu.cmd_apdu_data;
uint8_t *hash = apdu.cmd_apdu_data + 256;
int len = apdu.cmd_apdu_data_len;
uint8_t keyno = P2 (apdu);
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
if (keyno > 4)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
pubkey = gpg_get_firmware_update_key (keyno);
if (len != 256
|| (pubkey[0] == 0xff && pubkey[1] == 0xff) /* not registered */
|| (pubkey[0] == 0x00 && pubkey[1] == 0x00) /* removed */)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
memcpy (hash, unique_device_id (), 4);
memcpy (hash+4, challenge, CHALLENGE_LEN);
random_bytes_free (challenge);
challenge = NULL;
if (rsa_verify (pubkey, hash, signature) < 0)
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
if ((P1 (apdu) & 0x80))
if ((P1 (apdu) & 0x7f) <= FILEID_SERIAL_NO)
{
file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f);
offset = 0;
}
else
{
GPG_NO_FILE ();
return;
}
else
{
if (file_selection != FILE_EF_CH_CERTIFICATE
&& file_selection != FILE_EF_RANDOM
&& file_selection != FILE_EF_SERIAL)
{
GPG_COMMAND_NOT_ALLOWED ();
return;
}
chThdTerminate (chThdSelf ());
set_res_sw (0xff, 0xff);
DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n");
}
offset = (P1 (apdu) << 8) | P2 (apdu);
}
static void
cmd_get_challenge (void)
{
DEBUG_INFO (" - GET CHALLENGE\r\n");
DEBUG_SHORT (len);
DEBUG_SHORT (offset);
r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
apdu.cmd_apdu_data, len, offset);
if (r < 0)
{
DEBUG_INFO ("memory error.\r\n");
GPG_MEMORY_FAILURE ();
return;
}
if (challenge)
random_bytes_free (challenge);
challenge = random_bytes_get ();
memcpy (res_APDU, unique_device_id (), 4);
memcpy (res_APDU+4, challenge, CHALLENGE_LEN);
res_APDU_size = CHALLENGE_LEN + 4;
GPG_SUCCESS ();
DEBUG_INFO ("WRITE BINARY done.\r\n");
DEBUG_INFO ("GET CHALLENGE done.\r\n");
}
@@ -834,12 +967,17 @@ const struct command cmds[] = {
{ INS_PSO, cmd_pso },
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
{ INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
{ INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */
cmd_external_authenticate },
{ INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */
{ INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
{ INS_SELECT_FILE, cmd_select_file },
{ INS_READ_BINARY, cmd_read_binary },
{ INS_GET_DATA, cmd_get_data },
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
#if defined(CERTDO_SUPPORT)
{ INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */
#endif
{ INS_PUT_DATA, cmd_put_data },
{ INS_PUT_DATA_ODD, cmd_put_data },
};

View File

@@ -6,7 +6,7 @@
#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81)
#define GPG_NO_FILE() set_res_sw (0x6a, 0x82)
#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88)
#define GPG_BAD_P0_P1() set_res_sw (0x6b, 0x00)
#define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00)
#define GPG_NO_INS() set_res_sw (0x6d, 0x00)
#define GPG_ERROR() set_res_sw (0x6f, 0x00)
#define GPG_SUCCESS() set_res_sw (0x90, 0x00)

307
src/sys.c Normal file
View File

@@ -0,0 +1,307 @@
/*
* sys.c - system services at the first flash ROM blocks
*
* Copyright (C) 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "ch.h"
#include "hal.h"
#include "board.h"
#include "usb_lld.h"
extern uint8_t __flash_start__, __flash_end__;
static void
usb_cable_config (int enable)
{
#if defined(SET_USB_CONDITION)
if (SET_USB_CONDITION (enable))
palSetPad (IOPORT_USB, GPIO_USB);
else
palClearPad (IOPORT_USB, GPIO_USB);
#else
(void)enable;
#endif
}
static void
set_led (int on)
{
if (SET_LED_CONDITION (on))
palSetPad (IOPORT_LED, GPIO_LED);
else
palClearPad (IOPORT_LED, GPIO_LED);
}
#define FLASH_KEY1 0x45670123UL
#define FLASH_KEY2 0xCDEF89ABUL
static void
flash_unlock (void)
{
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
static int
flash_wait_for_last_operation (uint32_t timeout)
{
int status;
do
{
status = FLASH->SR;
if (--timeout == 0)
break;
}
while ((status & FLASH_SR_BSY) != 0);
return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR);
}
#define FLASH_PROGRAM_TIMEOUT 0x00010000
#define FLASH_ERASE_TIMEOUT 0x01000000
static int
flash_program_halfword (uint32_t addr, uint16_t data)
{
int status;
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
port_disable ();
if (status == 0)
{
FLASH->CR |= FLASH_CR_PG;
*(volatile uint16_t *)addr = data;
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
FLASH->CR &= ~FLASH_CR_PG;
}
port_enable ();
return status;
}
static int
flash_erase_page (uint32_t addr)
{
int status;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
port_disable ();
if (status == 0)
{
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = addr;
FLASH->CR |= FLASH_CR_STRT;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
FLASH->CR &= ~FLASH_CR_PER;
}
port_enable ();
return status;
}
static int
flash_check_blank (const uint8_t *p_start, size_t size)
{
const uint8_t *p;
for (p = p_start; p < p_start + size; p++)
if (*p != 0xff)
return 0;
return 1;
}
static int
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
{
int status;
uint32_t flash_start = (uint32_t)&__flash_start__;
uint32_t flash_end = (uint32_t)&__flash_end__;
if (dst_addr < flash_start || dst_addr + len > flash_end)
return 0;
while (len)
{
uint16_t hw = *src++;
hw |= (*src++ << 8);
status = flash_program_halfword (dst_addr, hw);
if (status != 0)
return 0; /* error return */
dst_addr += 2;
len -= 2;
}
return 1;
}
#define OPTION_BYTES_ADDR 0x1ffff800
static int
flash_protect (void)
{
int status;
uint32_t option_bytes_value;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
port_disable ();
if (status == 0)
{
FLASH->OPTKEYR = FLASH_KEY1;
FLASH->OPTKEYR = FLASH_KEY2;
FLASH->CR |= FLASH_CR_OPTER;
FLASH->CR |= FLASH_CR_STRT;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
FLASH->CR &= ~FLASH_CR_OPTER;
}
port_enable ();
if (status != 0)
return 0;
option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR;
return (option_bytes_value & 0xff) == 0xff ? 1 : 0;
}
static void __attribute__((naked))
flash_erase_all_and_exec (void (*entry)(void))
{
uint32_t addr = (uint32_t)&__flash_start__;
uint32_t end = (uint32_t)&__flash_end__;
int r;
while (addr < end)
{
r = flash_erase_page (addr);
if (r != 0)
break;
addr += FLASH_PAGE_SIZE;
}
if (addr >= end)
(*entry) ();
for (;;);
}
static void
nvic_enable_vector (uint32_t n, uint32_t prio)
{
unsigned int sh = (n & 3) << 3;
NVIC_IPR (n >> 2) = (NVIC_IPR(n >> 2) & ~(0xFF << sh)) | (prio << sh);
NVIC_ICPR (n >> 5) = 1 << (n & 0x1F);
NVIC_ISER (n >> 5) = 1 << (n & 0x1F);
}
static void
usb_lld_sys_init (void)
{
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
/*
* Note that we also have other IRQ(s):
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
* USBWakeUp_IRQn (suspend/resume)
*/
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0;
usb_cable_config (1);
}
static void
usb_lld_sys_shutdown (void)
{
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
usb_cable_config (0);
}
#define SYSRESETREQ 0x04
static void
nvic_system_reset (void)
{
SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ);
asm volatile ("dsb");
}
static void __attribute__ ((naked))
reset (void)
{
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
"mov.w r0, #0xed00\n\t" /* r0 = SCR */
"movt r0, #0xe000\n\t"
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
"mov r2, #0x1000\n\t"
"add r1, r1, r2\n\t"
"sub r2, r2, #1\n\t"
"bic r1, r1, r2\n\t"
"str r1, [r0, #8]\n\t" /* Set SCR->VCR */
"ldr r0, [r1], #4\n\t"
"msr MSP, r0\n\t" /* Main (exception handler) stack. */
"ldr r0, [r1]\n\t" /* Reset handler. */
"bx r0\n"
: /* no output */ : /* no input */ : "memory");
}
typedef void (*handler)(void);
extern uint8_t __ram_end__;
handler vector[] __attribute__ ((section(".vectors"))) = {
(handler)&__ram_end__,
reset,
(handler)set_led,
flash_unlock,
(handler)flash_program_halfword,
(handler)flash_erase_page,
(handler)flash_check_blank,
(handler)flash_write,
(handler)flash_protect,
(handler)flash_erase_all_and_exec,
usb_lld_sys_init,
usb_lld_sys_shutdown,
nvic_system_reset,
};
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
3*2+2, /* bLength */
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/
/* sys version: "1.0" */
'1', 0, '.', 0, '0', 0,
};

95
src/sys.h Normal file
View File

@@ -0,0 +1,95 @@
extern const uint8_t sys_version[8];
typedef void (*handler)(void);
extern handler vector[14];
static inline const uint8_t *
unique_device_id (void)
{
/* STM32F103 has 96-bit unique device identifier */
const uint8_t *addr = (const uint8_t *)0x1ffff7e8;
return addr;
}
static inline void
set_led (int on)
{
void (*func) (int) = (void (*)(int))vector[2];
return (*func) (on);
}
static inline void
flash_unlock (void)
{
(*vector[3]) ();
}
static inline int
flash_program_halfword (uint32_t addr, uint16_t data)
{
int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4];
return (*func) (addr, data);
}
static inline int
flash_erase_page (uint32_t addr)
{
int (*func) (uint32_t) = (int (*)(uint32_t))vector[5];
return (*func) (addr);
}
static inline int
flash_check_blank (const uint8_t *p_start, size_t size)
{
int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6];
return (*func) (p_start, size);
}
static inline int
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
{
int (*func) (uint32_t, const uint8_t *, size_t)
= (int (*)(uint32_t, const uint8_t *, size_t))vector[7];
return (*func) (dst_addr, src, len);
}
static inline int
flash_protect (void)
{
int (*func) (void) = (int (*)(void))vector[8];
return (*func) ();
}
static inline void __attribute__((noreturn))
flash_erase_all_and_exec (void (*entry)(void))
{
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9];
(*func) (entry);
for (;;);
}
static inline void
usb_lld_sys_init (void)
{
(*vector[10]) ();
}
static inline void
usb_lld_sys_shutdown (void)
{
(*vector[11]) ();
}
static inline void
nvic_system_reset (void)
{
(*vector[12]) ();
}

View File

@@ -1273,6 +1273,7 @@ icc_handle_timeout (struct ccid *c)
static struct ccid ccid;
#define GPG_THREAD_TERMINATED 0xffff
msg_t
USBthread (void *arg)
@@ -1303,6 +1304,16 @@ USBthread (void *arg)
else if (m == EV_EXEC_FINISHED)
if (c->icc_state == ICC_STATE_EXECUTE)
{
if (c->a->sw == GPG_THREAD_TERMINATED)
{
c->sw1sw2[0] = 0x90;
c->sw1sw2[1] = 0x00;
c->state = APDU_STATE_RESULT;
icc_send_data_block (c, 0);
c->icc_state = ICC_STATE_EXITED;
break;
}
c->a->cmd_apdu_data_len = 0;
c->sw1sw2[0] = c->a->sw >> 8;
c->sw1sw2[1] = c->a->sw & 0xff;

View File

@@ -3,7 +3,7 @@
#ifndef __USB_CONF_H
#define __USB_CONF_H
#define NUM_STRING_DESC 4
#define NUM_STRING_DESC 7
/* Control pipe */
/* EP0 */

455
src/usb_ctrl.c Normal file
View File

@@ -0,0 +1,455 @@
/*
* usb_ctrl.c - USB control pipe device specific code for Gnuk
*
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* 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/>.
*
*/
/* Packet size of USB Bulk transfer for full speed */
#define GNUK_MAX_PACKET_SIZE 64
#include "config.h"
#include "ch.h"
#include "hal.h"
#include "usb_lld.h"
#include "usb_conf.h"
#include "gnuk.h"
#ifdef ENABLE_VIRTUAL_COM_PORT
#include "usb-cdc.h"
struct line_coding
{
uint32_t bitrate;
uint8_t format;
uint8_t paritytype;
uint8_t datatype;
};
static struct line_coding line_coding = {
115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */
0x00, /* parity: none */
0x08 /* bits: 8 */
};
static int
vcom_port_data_setup (uint8_t req, uint8_t req_no)
{
if (USB_SETUP_GET (req))
{
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
{
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
return USB_SUCCESS;
}
}
else /* USB_SETUP_SET (req) */
{
if (req_no == USB_CDC_REQ_SET_LINE_CODING)
{
usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
return USB_SUCCESS;
}
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
/* Do nothing and success */
return USB_SUCCESS;
}
return USB_UNSUPPORT;
}
#define VCOM_NUM_INTERFACES 2
#else
#define VCOM_NUM_INTERFACES 0
#endif
#ifdef PINPAD_DND_SUPPORT
#include "usb-msc.h"
#define MSC_NUM_INTERFACES 1
#else
#define MSC_NUM_INTERFACES 0
#endif
#define NUM_INTERFACES (1+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
#define MSC_INTERFACE_NO (1+VCOM_NUM_INTERFACES)
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
static void
gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
{
if (interface == 0)
{
if (!stop)
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, ENDP1_TXADDR,
GNUK_MAX_PACKET_SIZE);
else
{
usb_lld_stall_rx (ENDP1);
usb_lld_stall_tx (ENDP1);
}
}
#ifdef ENABLE_VIRTUAL_COM_PORT
else if (interface == 1)
{
if (!stop)
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
else
usb_lld_stall_tx (ENDP4);
}
else if (interface == 2)
{
if (!stop)
{
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
VIRTUAL_COM_PORT_DATA_SIZE);
}
else
{
usb_lld_stall_tx (ENDP3);
usb_lld_stall_rx (ENDP5);
}
}
#endif
#ifdef PINPAD_DND_SUPPORT
else if (interface == MSC_INTERFACE_NO)
{
if (!stop)
{
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
ENDP6_RXADDR, ENDP6_TXADDR, 64);
usb_lld_stall_rx (ENDP6);
}
else
{
usb_lld_stall_tx (ENDP6);
usb_lld_stall_rx (ENDP6);
}
}
#endif
}
static void
gnuk_device_reset (void)
{
int i;
/* Set DEVICE as not configured */
usb_lld_set_configuration (0);
/* Current Feature initialization */
usb_lld_set_feature (Config_Descriptor.Descriptor[7]);
usb_lld_reset ();
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
GNUK_MAX_PACKET_SIZE);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 0);
bDeviceState = ATTACHED;
}
#define USB_CCID_REQ_ABORT 0x01
#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02
#define USB_CCID_REQ_GET_DATA_RATES 0x03
static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
#if defined(PINPAD_DND_SUPPORT)
static const uint8_t lun_table[] = { 0, 0, 0, 0, };
#endif
static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, };
#define USB_FSIJ_GNUK_MEMINFO 0
#define USB_FSIJ_GNUK_DOWNLOAD 1
#define USB_FSIJ_GNUK_EXEC 2
static uint32_t rbit (uint32_t v)
{
uint32_t r;
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
return r;
}
/* After calling this function, CRC module remain enabled. */
static int download_check_crc32 (const uint32_t *end_p)
{
uint32_t crc32 = *end_p;
const uint32_t *p;
RCC->AHBENR |= RCC_AHBENR_CRCEN;
CRC->CR = CRC_CR_RESET;
for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
CRC->DR = rbit (*p);
if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
return USB_SUCCESS;
return USB_UNSUPPORT;
}
static int
gnuk_setup (uint8_t req, uint8_t req_no,
uint16_t value, uint16_t index, uint16_t len)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
{
if (USB_SETUP_GET (req))
{
if (req_no == USB_FSIJ_GNUK_MEMINFO)
{
usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
return USB_SUCCESS;
}
}
else /* SETUP_SET */
{
uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
{
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
return USB_UNSUPPORT;
if (addr < &_regnual_start || addr + len > &__heap_end__)
return USB_UNSUPPORT;
if (index + len < 256)
memset (addr + index + len, 0, 256 - (index + len));
usb_lld_set_data_to_recv (addr, len);
return USB_SUCCESS;
}
else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
{
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
return USB_UNSUPPORT;
if (((uint32_t)addr & 0x03))
return USB_UNSUPPORT;
return download_check_crc32 ((uint32_t *)addr);
}
}
}
else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
if (index == 0)
{
if (USB_SETUP_GET (req))
{
if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
{
usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
return USB_SUCCESS;
}
else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
{
usb_lld_set_data_to_send (data_rate_table,
sizeof (data_rate_table));
return USB_SUCCESS;
}
}
else
{
if (req_no == USB_CCID_REQ_ABORT)
/* wValue: bSeq, bSlot */
/* Abortion is not supported in Gnuk */
return USB_UNSUPPORT;
}
}
#ifdef ENABLE_VIRTUAL_COM_PORT
else if (index == 1)
return vcom_port_data_setup (req, req_no);
#endif
#ifdef PINPAD_DND_SUPPORT
else if (index == MSC_INTERFACE_NO)
{
if (USB_SETUP_GET (req))
{
if (req_no == MSC_GET_MAX_LUN_COMMAND)
{
usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
return USB_SUCCESS;
}
}
else
if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
/* Should call resetting MSC thread, something like msc_reset() */
return USB_SUCCESS;
}
#endif
return USB_UNSUPPORT;
}
static void gnuk_ctrl_write_finish (uint8_t req, uint8_t req_no,
uint16_t value, uint16_t index,
uint16_t len)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
&& USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
{
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
return;
(void)value; (void)index;
usb_lld_prepare_shutdown (); /* No further USB communication */
*icc_state_p = ICC_STATE_EXEC_REQUESTED;
}
}
static int
gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
{
(void)index;
if (desc_type == DEVICE_DESCRIPTOR)
{
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
Device_Descriptor.Descriptor_Size);
return USB_SUCCESS;
}
else if (desc_type == CONFIG_DESCRIPTOR)
{
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
Config_Descriptor.Descriptor_Size);
return USB_SUCCESS;
}
else if (desc_type == STRING_DESCRIPTOR)
{
uint8_t desc_index = value & 0xff;
if (desc_index < NUM_STRING_DESC)
{
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
String_Descriptors[desc_index].Descriptor_Size);
return USB_SUCCESS;
}
}
return USB_UNSUPPORT;
}
static int gnuk_usb_event (uint8_t event_type, uint16_t value)
{
int i;
uint8_t current_conf;
switch (event_type)
{
case USB_EVENT_ADDRESS:
bDeviceState = ADDRESSED;
return USB_SUCCESS;
case USB_EVENT_CONFIG:
current_conf = usb_lld_current_configuration ();
if (current_conf == 0)
{
if (value != 1)
return USB_UNSUPPORT;
usb_lld_set_configuration (value);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 0);
bDeviceState = CONFIGURED;
chEvtSignalI (main_thread, LED_STATUS_MODE);
}
else if (current_conf != value)
{
if (value != 0)
return USB_UNSUPPORT;
usb_lld_set_configuration (0);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 1);
bDeviceState = ADDRESSED;
}
/* Do nothing when current_conf == value */
return USB_SUCCESS;
default:
break;
}
return USB_UNSUPPORT;
}
static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
{
static uint8_t zero = 0;
if (interface >= NUM_INTERFACES)
return USB_UNSUPPORT;
switch (cmd)
{
case USB_SET_INTERFACE:
if (alt != 0)
return USB_UNSUPPORT;
else
{
gnuk_setup_endpoints_for_interface (interface, 0);
return USB_SUCCESS;
}
case USB_GET_INTERFACE:
usb_lld_set_data_to_send (&zero, 1);
return USB_SUCCESS;
default:
case USB_QUERY_INTERFACE:
return USB_SUCCESS;
}
}
/*
* Interface to USB core
*/
const struct usb_device_method Device_Method = {
gnuk_device_reset,
gnuk_ctrl_write_finish,
gnuk_setup,
gnuk_get_descriptor,
gnuk_usb_event,
gnuk_interface,
};
CH_IRQ_HANDLER (Vector90)
{
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
usb_interrupt_handler ();
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
}

View File

@@ -4,6 +4,7 @@
#include "config.h"
#include "ch.h"
#include "sys.h"
#include "usb_lld.h"
#include "usb_conf.h"
#include "usb-cdc.h"
@@ -253,20 +254,20 @@ static const uint8_t gnukStringLangID[] = {
0x09, 0x04 /* LangID = 0x0409: US-English */
};
#include "usb-string-vendor-product.c.inc"
#define USB_STRINGS_FOR_GNUK 1
#include "usb-strings.c.inc"
const uint8_t gnukStringSerial[] = {
18*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
/* FSIJ-0.18 */
/* FSIJ-0.19 */
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
'0', 0, '.', 0, '1', 0, '8', 0, /* Version number of Gnuk */
'0', 0, '.', 0, '1', 0, '9', 0, /* Version number of Gnuk */
'-', 0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
const struct Descriptor Device_Descriptor = {
gnukDeviceDescriptor,
sizeof (gnukDeviceDescriptor)
@@ -282,4 +283,7 @@ const struct Descriptor String_Descriptors[NUM_STRING_DESC] = {
{gnukStringVendor, sizeof (gnukStringVendor)},
{gnukStringProduct, sizeof (gnukStringProduct)},
{gnukStringSerial, sizeof (gnukStringSerial)},
{gnuk_revision_detail, sizeof (gnuk_revision_detail)},
{gnuk_config_options, sizeof (gnuk_config_options)},
{sys_version, sizeof (sys_version)},
};

View File

@@ -1,11 +1,14 @@
#ifdef FREE_STANDING
#include "types.h"
#else
#include "ch.h"
#include "hal.h"
#endif
#include "sys.h"
#include "usb_lld.h"
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
#define RECIPIENT 0x1F /* Mask to get recipient */
enum STANDARD_REQUESTS
{
GET_STATUS = 0,
@@ -27,16 +30,15 @@ enum STANDARD_REQUESTS
/* The state machine states of a control pipe */
enum CONTROL_STATE
{
WAIT_SETUP, /* 0 */
SETTING_UP, /* 1 */
IN_DATA, /* 2 */
OUT_DATA, /* 3 */
LAST_IN_DATA, /* 4 */
LAST_OUT_DATA, /* 5 */
WAIT_STATUS_IN, /* 7 */
WAIT_STATUS_OUT, /* 8 */
STALLED, /* 9 */
PAUSE /* 10 */
WAIT_SETUP,
SETTING_UP,
IN_DATA,
OUT_DATA,
LAST_IN_DATA,
WAIT_STATUS_IN,
WAIT_STATUS_OUT,
STALLED,
PAUSE
};
enum FEATURE_SELECTOR
@@ -69,9 +71,15 @@ struct DEVICE_INFO
uint8_t state;
};
static struct CONTROL_INFO *ctrl_p;
static struct DEVICE_INFO *dev_p;
static struct DATA_INFO *data_p;
static struct CONTROL_INFO control_info;
static struct DEVICE_INFO device_info;
static struct DATA_INFO data_info;
extern const struct usb_device_method Device_Method;
static struct CONTROL_INFO *const ctrl_p = &control_info;
static struct DEVICE_INFO *const dev_p = &device_info;
static struct DATA_INFO *const data_p = &data_info;
static const struct usb_device_method *const method_p = &Device_Method;
#define REG_BASE (0x40005C00UL) /* USB_IP Peripheral Registers base address */
#define PMA_ADDR (0x40006000UL) /* USB_IP Packet Memory Area base address */
@@ -350,9 +358,37 @@ static void st103_ep_clear_dtog_tx (uint8_t ep_num)
}
}
static const struct usb_device_method* method_p;
void usb_lld_init (uint8_t feature)
{
usb_lld_sys_init ();
static void
dev_p->state = IN_DATA;
usb_lld_set_configuration (0);
usb_lld_set_feature (feature);
/* Reset USB */
st103_set_cntr (CNTR_FRES);
st103_set_cntr (0);
/* Clear Interrupt Status Register, and enable interrupt for USB */
st103_set_istr (0);
st103_set_cntr (CNTR_CTRM | CNTR_RESETM);
}
void usb_lld_prepare_shutdown (void)
{
st103_set_istr (0);
st103_set_cntr (0);
}
void usb_lld_shutdown (void)
{
st103_set_cntr (CNTR_PDWN);
usb_lld_sys_shutdown ();
}
void
usb_interrupt_handler (void)
{
uint16_t istr_value = st103_get_istr ();
@@ -373,51 +409,33 @@ usb_interrupt_handler (void)
st103_set_istr (CLR_ERR);
}
CH_IRQ_HANDLER (Vector90) {
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
usb_interrupt_handler ();
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
}
static void handle_datastage_out (void)
{
if (data_p->addr && data_p->len)
{
uint8_t *buf;
uint32_t len = USB_MAX_PACKET_SIZE;
uint32_t len = st103_get_rx_count (ENDP0);
if (len > data_p->len)
len = data_p->len;
buf = data_p->addr + data_p->offset;
usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len);
data_p->len -= len;
data_p->offset += len;
usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len);
}
if (data_p->len != 0)
if (data_p->len == 0)
{
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
dev_p->state = WAIT_STATUS_IN;
st103_set_tx_count (ENDP0, 0);
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
}
if (data_p->len >= USB_MAX_PACKET_SIZE)
dev_p->state = OUT_DATA;
else
if (data_p->len > 0)
dev_p->state = LAST_OUT_DATA;
else if (data_p->len == 0)
{
dev_p->state = WAIT_STATUS_IN;
st103_set_tx_count (ENDP0, 0);
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
}
{
dev_p->state = OUT_DATA;
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
}
}
static void handle_datastage_in (void)
@@ -433,14 +451,15 @@ static void handle_datastage_in (void)
/* No more data to send. Send empty packet */
st103_set_tx_count (ENDP0, 0);
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID);
}
else
{
/* No more data to send. Thus, STALL the TX Status*/
/* No more data to send, proceed to receive OUT acknowledge.*/
dev_p->state = WAIT_STATUS_OUT;
st103_ep_set_tx_status (ENDP0, EP_TX_STALL);
st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_STALL);
}
return;
}
@@ -451,32 +470,33 @@ static void handle_datastage_in (void)
buf = (const uint8_t *)data_p->addr + data_p->offset;
usb_lld_to_pmabuf (buf, st103_get_tx_addr (ENDP0), len);
st103_set_tx_count (ENDP0, len);
data_p->len -= len;
data_p->offset += len;
st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID);
st103_set_tx_count (ENDP0, len);
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
}
typedef int (*HANDLER) (uint8_t rcp,
typedef int (*HANDLER) (uint8_t req,
uint16_t value, uint16_t index, uint16_t length);
static int std_none (uint8_t rcp,
static int std_none (uint8_t req,
uint16_t value, uint16_t index, uint16_t length)
{
(void)rcp; (void)value; (void)index; (void)length;
(void)req; (void)value; (void)index; (void)length;
return USB_UNSUPPORT;
}
static int std_get_status (uint8_t rcp,
static int std_get_status (uint8_t req,
uint16_t value, uint16_t index, uint16_t length)
{
static uint16_t status_info;
uint8_t rcp = req & RECIPIENT;
status_info = 0; /* Reset Status Information */
data_p->addr = (uint8_t *)&status_info;
if (value != 0 || length != 2 || (index >> 8) != 0)
if (value != 0 || length != 2 || (index >> 8) != 0
|| (req & REQUEST_DIR) == 0)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT)
@@ -548,9 +568,14 @@ static int std_get_status (uint8_t rcp,
return USB_UNSUPPORT;
}
static int std_clear_feature (uint8_t rcp, uint16_t value,
static int std_clear_feature (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT)
{
if (length != 0 || index != 0)
@@ -582,22 +607,10 @@ static int std_clear_feature (uint8_t rcp, uint16_t value,
if (status == 0) /* Disabled */
return USB_UNSUPPORT;
if (index & 0x80)
{ /* IN endpoint */
if (st103_ep_get_tx_status (endpoint) == EP_TX_STALL)
{
st103_ep_clear_dtog_tx (endpoint);
st103_ep_set_tx_status (endpoint, EP_TX_VALID);
}
}
else
{ /* OUT endpoint */
if (st103_ep_get_rx_status (endpoint) == EP_RX_STALL)
{
st103_ep_clear_dtog_rx (endpoint);
st103_ep_set_rx_status (endpoint, EP_RX_VALID);
}
}
if (index & 0x80) /* IN endpoint */
st103_ep_clear_dtog_tx (endpoint);
else /* OUT endpoint */
st103_ep_clear_dtog_rx (endpoint);
// event??
return USB_SUCCESS;
@@ -606,9 +619,14 @@ static int std_clear_feature (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT;
}
static int std_set_feature (uint8_t rcp, uint16_t value,
static int std_set_feature (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT)
{
if (length != 0 || index != 0)
@@ -654,9 +672,14 @@ static int std_set_feature (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT;
}
static int std_set_address (uint8_t rcp, uint16_t value,
static int std_set_address (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT)
{
if (length == 0 && value <= 127 && index == 0
@@ -667,9 +690,14 @@ static int std_set_address (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT;
}
static int std_get_descriptor (uint8_t rcp, uint16_t value,
static int std_get_descriptor (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 0)
return USB_UNSUPPORT;
(void)length;
if (rcp == DEVICE_RECIPIENT)
return (*method_p->get_descriptor) ((value >> 8), index, value);
@@ -677,9 +705,14 @@ static int std_get_descriptor (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT;
}
static int std_get_configuration (uint8_t rcp, uint16_t value,
static int std_get_configuration (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 0)
return USB_UNSUPPORT;
(void)value; (void)index; (void)length;
if (rcp == DEVICE_RECIPIENT)
{
@@ -691,9 +724,14 @@ static int std_get_configuration (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT;
}
static int std_set_configuration (uint8_t rcp, uint16_t value,
static int std_set_configuration (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0)
{
int r;
@@ -706,9 +744,14 @@ static int std_set_configuration (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT;
}
static int std_get_interface (uint8_t rcp, uint16_t value,
static int std_get_interface (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 0)
return USB_UNSUPPORT;
if (rcp == INTERFACE_RECIPIENT)
{
if (value != 0 || (index >> 8) != 0 || length != 1)
@@ -723,9 +766,14 @@ static int std_get_interface (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT;
}
static int std_set_interface (uint8_t rcp, uint16_t value,
static int std_set_interface (uint8_t req, uint16_t value,
uint16_t index, uint16_t length)
{
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == INTERFACE_RECIPIENT)
{
int r;
@@ -767,7 +815,6 @@ static void handle_setup0 (void)
uint8_t req;
int r = USB_UNSUPPORT;
HANDLER handler;
uint8_t type_rcp;
pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2));
w = *pw++;
@@ -781,44 +828,28 @@ static void handle_setup0 (void)
pw++;
ctrl_p->wLength = *pw;
dev_p->state = STALLED;
data_p->addr = NULL;
data_p->len = 0;
data_p->offset = 0;
type_rcp = (ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT));
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) /* Interface */
|| (ctrl_p->bmRequestType & REQUEST_TYPE) == VENDOR_REQUEST)
{
if (ctrl_p->wLength == 0)
r = (*method_p->setup_with_nodata) (type_rcp, req, ctrl_p->wIndex);
else
{
(*method_p->setup_with_data) (type_rcp, req, ctrl_p->wIndex);
if (data_p->len != 0)
r = USB_SUCCESS;
}
}
else if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
{
if (req < TOTAL_REQUEST)
{
handler = std_request_handler[req];
r = (*handler) (ctrl_p->bmRequestType & RECIPIENT,
r = (*handler) (ctrl_p->bmRequestType,
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
}
}
else
r = (*method_p->setup) (ctrl_p->bmRequestType, req,
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
if (r != USB_SUCCESS)
dev_p->state = STALLED;
else
{
if (ctrl_p->wLength == 0)
{
dev_p->state = WAIT_STATUS_IN;
st103_set_tx_count (ENDP0, 0);
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
}
else if (ctrl_p->bmRequestType & 0x80)
if (USB_SETUP_GET (ctrl_p->bmRequestType))
{
uint32_t len = ctrl_p->wLength;
@@ -831,13 +862,19 @@ static void handle_setup0 (void)
else
data_p->require_zlp = FALSE;
dev_p->state = IN_DATA;
handle_datastage_in ();
}
else
else if (ctrl_p->wLength == 0)
{
dev_p->state = WAIT_STATUS_IN;
st103_set_tx_count (ENDP0, 0);
st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
}
else
{
dev_p->state = OUT_DATA;
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
/* enable for next data reception */
}
}
}
@@ -855,6 +892,11 @@ static void handle_in0 (void)
st103_set_daddr (ctrl_p->wValue);
(*method_p->event) (USB_EVENT_ADDRESS, ctrl_p->wValue);
}
else
(*method_p->ctrl_write_finish) (ctrl_p->bmRequestType,
ctrl_p->bRequest, ctrl_p->wValue,
ctrl_p->wIndex, ctrl_p->wLength);
dev_p->state = STALLED;
}
else
@@ -866,7 +908,7 @@ static void handle_out0 (void)
if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
/* host aborts the transfer before finish */
dev_p->state = STALLED;
else if (dev_p->state == OUT_DATA || dev_p->state == LAST_OUT_DATA)
else if (dev_p->state == OUT_DATA)
handle_datastage_out ();
else if (dev_p->state == WAIT_STATUS_OUT)
dev_p->state = STALLED;
@@ -879,7 +921,7 @@ static void nop_proc (void)
{
}
#define WEAK __attribute__ ((weak))
#define WEAK __attribute__ ((weak, alias ("nop_proc")))
void WEAK EP1_IN_Callback (void);
void WEAK EP2_IN_Callback (void);
void WEAK EP3_IN_Callback (void);
@@ -896,22 +938,6 @@ void WEAK EP5_OUT_Callback (void);
void WEAK EP6_OUT_Callback (void);
void WEAK EP7_OUT_Callback (void);
#pragma weak EP1_IN_Callback = nop_proc
#pragma weak EP2_IN_Callback = nop_proc
#pragma weak EP3_IN_Callback = nop_proc
#pragma weak EP4_IN_Callback = nop_proc
#pragma weak EP5_IN_Callback = nop_proc
#pragma weak EP6_IN_Callback = nop_proc
#pragma weak EP7_IN_Callback = nop_proc
#pragma weak EP1_OUT_Callback = nop_proc
#pragma weak EP2_OUT_Callback = nop_proc
#pragma weak EP3_OUT_Callback = nop_proc
#pragma weak EP4_OUT_Callback = nop_proc
#pragma weak EP5_OUT_Callback = nop_proc
#pragma weak EP6_OUT_Callback = nop_proc
#pragma weak EP7_OUT_Callback = nop_proc
void (*const ep_intr_handler_IN[7]) (void) = {
EP1_IN_Callback,
EP2_IN_Callback,
@@ -994,46 +1020,12 @@ usb_handle_transfer (void)
}
}
static struct CONTROL_INFO Control_Info;
static struct DEVICE_INFO Device_Info;
static struct DATA_INFO Data_Info;
void usb_lld_reset (void)
{
st103_set_btable ();
st103_set_daddr (0);
}
void usb_lld_init (void)
{
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
NVICEnableVector (USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
/*
* Note that we also have other IRQ(s):
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
* USBWakeUp_IRQn (suspend/resume)
*/
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0;
dev_p = &Device_Info;
ctrl_p = &Control_Info;
data_p = &Data_Info;
dev_p->state = IN_DATA;
method_p = &Device_Method;
method_p->init();
/* Reset USB */
st103_set_cntr (CNTR_FRES);
st103_set_cntr (0);
/* Clear Interrupt Status Register, and enable interrupt for USB */
st103_set_istr (0);
st103_set_cntr (CNTR_CTRM | CNTR_RESETM);
}
void usb_lld_txcpy (const void *src,
int ep_num, int offset, size_t len)
{

View File

@@ -39,10 +39,15 @@ enum DESCRIPTOR_TYPE
ENDPOINT_DESCRIPTOR
};
#define REQUEST_DIR 0x80 /* Mask to get request dir */
#define REQUEST_TYPE 0x60 /* Mask to get request type */
#define STANDARD_REQUEST 0x00 /* Standard request */
#define CLASS_REQUEST 0x20 /* Class request */
#define VENDOR_REQUEST 0x40 /* Vendor request */
#define RECIPIENT 0x1F /* Mask to get recipient */
#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0)
#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0)
struct Descriptor
{
@@ -58,17 +63,17 @@ enum
struct usb_device_method
{
void (*init) (void);
void (*reset) (void);
void (*setup_with_data) (uint8_t rcp, uint8_t req_no, uint16_t index);
int (*setup_with_nodata) (uint8_t rcp, uint8_t req_no, uint16_t index);
void (*ctrl_write_finish) (uint8_t req, uint8_t req_no,
uint16_t value, uint16_t index, uint16_t len);
int (*setup) (uint8_t req, uint8_t req_no,
uint16_t value, uint16_t index, uint16_t len);
int (*get_descriptor) (uint8_t desc_type, uint16_t index, uint16_t value);
int (*event) (uint8_t event_type, uint16_t value);
int (*interface) (uint8_t cmd, uint16_t interface, uint16_t value);
};
enum {
USB_EVENT_RESET,
USB_EVENT_ADDRESS,
USB_EVENT_CONFIG,
USB_EVENT_SUSPEND,
@@ -104,7 +109,7 @@ extern uint32_t bDeviceState;
#define STM32_USB_IRQ_PRIORITY 11
extern void usb_lld_init (void);
extern void usb_lld_init (uint8_t feature);
extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
@@ -141,3 +146,13 @@ extern uint8_t usb_lld_current_configuration (void);
extern void usb_lld_set_feature (uint8_t feature);
extern void usb_lld_set_data_to_send (const void *p, size_t len);
extern inline void usb_lld_set_data_to_recv (void *p, size_t len)
{
usb_lld_set_data_to_send ((const void *)p, len);
}
extern void usb_lld_prepare_shutdown (void);
extern void usb_lld_shutdown (void);
extern void usb_interrupt_handler (void);

View File

@@ -1,342 +0,0 @@
/*
* usb_prop.c - interface code between Gnuk and USB
*
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* 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/>.
*
*/
/* Packet size of USB Bulk transfer for full speed */
#define GNUK_MAX_PACKET_SIZE 64
#include "config.h"
#include "ch.h"
#include "usb_lld.h"
#include "usb_conf.h"
#ifdef ENABLE_VIRTUAL_COM_PORT
#include "usb-cdc.h"
struct line_coding
{
uint32_t bitrate;
uint8_t format;
uint8_t paritytype;
uint8_t datatype;
};
static const struct line_coding line_coding = {
115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */
0x00, /* parity: none */
0x08 /* bits: 8 */
};
static void
vcom_port_data_setup (uint8_t RequestNo)
{
if (RequestNo != USB_CDC_REQ_GET_LINE_CODING)
return;
/* RequestNo == USB_CDC_REQ_SET_LINE_CODING is not supported */
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
}
static int
vcom_port_setup_with_nodata (uint8_t RequestNo)
{
if (RequestNo == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
/* Do nothing and success */
return USB_SUCCESS;
return USB_UNSUPPORT;
}
#define VCOM_NUM_INTERFACES 2
#else
#define VCOM_NUM_INTERFACES 0
#endif
#ifdef PINPAD_DND_SUPPORT
#include "usb-msc.h"
#define MSC_NUM_INTERFACES 1
#else
#define MSC_NUM_INTERFACES 0
#endif
#define NUM_INTERFACES (1+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
#define MSC_INTERFACE_NO (1+VCOM_NUM_INTERFACES)
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
static void
gnuk_device_init (void)
{
usb_lld_set_configuration (0);
USB_Cable_Config (1);
bDeviceState = UNCONNECTED;
}
static void
gnuk_setup_endpoints_for_interface (uint16_t interface)
{
if (interface == 0)
{
/* Initialize Endpoint 1 */
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, ENDP1_TXADDR,
GNUK_MAX_PACKET_SIZE);
}
#ifdef ENABLE_VIRTUAL_COM_PORT
else if (interface == 1)
{
/* Initialize Endpoint 4 */
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
}
else if (interface == 2)
{
/* Initialize Endpoint 3 */
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
/* Initialize Endpoint 5 */
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
VIRTUAL_COM_PORT_DATA_SIZE);
}
#endif
#ifdef PINPAD_DND_SUPPORT
else if (interface == MSC_INTERFACE_NO)
{
/* Initialize Endpoint 6 */
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0, ENDP6_RXADDR, ENDP6_TXADDR,
64);
usb_lld_stall_rx (ENDP6);
}
#endif
}
static void
gnuk_device_reset (void)
{
int i;
/* Set DEVICE as not configured */
usb_lld_set_configuration (0);
/* Current Feature initialization */
usb_lld_set_feature (Config_Descriptor.Descriptor[7]);
usb_lld_reset ();
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
GNUK_MAX_PACKET_SIZE);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i);
bDeviceState = ATTACHED;
}
#define USB_CCID_REQ_ABORT 0x01
#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02
#define USB_CCID_REQ_GET_DATA_RATES 0x03
static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
#if defined(PINPAD_DND_SUPPORT)
static const uint8_t lun_table[] = { 0, 0, 0, 0, };
#endif
static void
gnuk_setup_with_data (uint8_t recipient, uint8_t RequestNo, uint16_t index)
{
if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
{
if (index == 0)
{
if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES)
usb_lld_set_data_to_send (data_rate_table, sizeof (data_rate_table));
}
#ifdef ENABLE_VIRTUAL_COM_PORT
else if (index == 1)
vcom_port_data_setup (RequestNo);
#endif
#ifdef PINPAD_DND_SUPPORT
else if (index == MSC_INTERFACE_NO)
{
if (RequestNo == MSC_GET_MAX_LUN_COMMAND)
usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
}
#endif
}
}
static int
gnuk_setup_with_nodata (uint8_t recipient, uint8_t RequestNo, uint16_t index)
{
if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
if (index == 0)
{
if (RequestNo == USB_CCID_REQ_ABORT)
/* wValue: bSeq, bSlot */
/* Abortion is not supported in Gnuk */
return USB_UNSUPPORT;
else
return USB_UNSUPPORT;
}
#ifdef ENABLE_VIRTUAL_COM_PORT
else if (index == 1)
return vcom_port_setup_with_nodata (RequestNo);
#endif
#ifdef PINPAD_DND_SUPPORT
else if (index == MSC_INTERFACE_NO)
{
if (RequestNo == MSC_MASS_STORAGE_RESET_COMMAND)
{
/* Should call resetting MSC thread, something like msc_reset() */
return USB_SUCCESS;
}
else
return USB_UNSUPPORT;
}
#endif
else
return USB_UNSUPPORT;
else
return USB_UNSUPPORT;
}
static int
gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
{
(void)index;
if (desc_type == DEVICE_DESCRIPTOR)
{
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
Device_Descriptor.Descriptor_Size);
return USB_SUCCESS;
}
else if (desc_type == CONFIG_DESCRIPTOR)
{
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
Config_Descriptor.Descriptor_Size);
return USB_SUCCESS;
}
else if (desc_type == STRING_DESCRIPTOR)
{
uint8_t desc_index = value & 0xff;
if (desc_index < NUM_STRING_DESC)
{
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
String_Descriptors[desc_index].Descriptor_Size);
return USB_SUCCESS;
}
}
return USB_UNSUPPORT;
}
static int gnuk_usb_event (uint8_t event_type, uint16_t value)
{
switch (event_type)
{
case USB_EVENT_RESET:
break;
case USB_EVENT_ADDRESS:
bDeviceState = ADDRESSED;
break;
case USB_EVENT_CONFIG:
if (usb_lld_current_configuration () == 0)
{
int i;
extern void *main_thread;
#define LED_STATUS_MODE (8)
if (value != 1)
return USB_UNSUPPORT;
usb_lld_set_configuration (value);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i);
bDeviceState = CONFIGURED;
chEvtSignalI (main_thread, LED_STATUS_MODE);
return USB_SUCCESS;
}
else
{
if (value != 0)
return USB_UNSUPPORT;
usb_lld_set_configuration (0);
// Disable all endpoints???
bDeviceState = ADDRESSED;
}
default:
break;
}
return USB_UNSUPPORT;
}
static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
{
static uint8_t zero = 0;
if (interface >= NUM_INTERFACES)
return USB_UNSUPPORT;
switch (cmd)
{
case USB_SET_INTERFACE:
if (alt != 0)
return USB_UNSUPPORT;
else
{
gnuk_setup_endpoints_for_interface (interface);
return USB_SUCCESS;
}
case USB_GET_INTERFACE:
usb_lld_set_data_to_send (&zero, 1);
return USB_SUCCESS;
default:
case USB_QUERY_INTERFACE:
return USB_SUCCESS;
}
}
/*
* Interface to USB core
*/
const struct usb_device_method Device_Method = {
gnuk_device_init,
gnuk_device_reset,
gnuk_setup_with_data,
gnuk_setup_with_nodata,
gnuk_get_descriptor,
gnuk_usb_event,
gnuk_interface,
};

View File

@@ -4,7 +4,7 @@
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
Copyright (C) 2011, 2012 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -44,11 +44,17 @@ class GnukToken(object):
self.connection = cardservice.connection
def cmd_get_response(self, expected_len):
apdu = [0x00, 0xc0, 0x00, 0x00, expected_len]
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%02x%02x" % (sw1, sw2))
return response
result = []
while True:
apdu = [0x00, 0xc0, 0x00, 0x00, expected_len]
response, sw1, sw2 = self.connection.transmit(apdu)
result += response
if sw1 == 0x90 and sw2 == 0x00:
return result
elif sw1 != 0x61:
raise ValueError, ("%02x%02x" % (sw1, sw2))
else:
expected_len = sw2
def cmd_verify(self, who, passwd):
apdu = [0x00, 0x20, 0x00, 0x80+who, len(passwd)] + s2l(passwd)
@@ -56,6 +62,15 @@ class GnukToken(object):
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%02x%02x" % (sw1, sw2))
def cmd_read_binary(self, fileid):
apdu = [0x00, 0xb0, 0x80+fileid, 0x00]
response, sw1, sw2 = self.connection.transmit(apdu)
if sw1 == 0x61:
response = self.cmd_get_response(sw2)
elif not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%02x%02x" % (sw1, sw2))
return response
def cmd_write_binary(self, fileid, data, is_update):
count = 0
data_len = len(data)
@@ -66,7 +81,7 @@ class GnukToken(object):
while count*256 < data_len:
if count == 0:
d = data[:256]
if len(d) <= 255:
if len(d) <= 255:
apdu = [0x00, ins, 0x80+fileid, 0x00, len(d)] + s2l(d)
else:
apdu0 = [0x10, ins, 0x80+fileid, 0x00, 255] + s2l(d[:255])
@@ -74,18 +89,18 @@ class GnukToken(object):
apdu = [0x00, ins, 0x80+fileid, 0x00, 1 ] + s2l(d[255:])
else:
d = data[256*count:256*(count+1)]
if len(d) <= 255:
if len(d) <= 255:
apdu = [0x00, ins, count, 0x00, len(d)] + s2l(d)
else:
apdu0 = [0x10, ins, count, 0x00, 255] + s2l(d[:255])
response, sw1, sw2 = self.connection.transmit(apdu0)
apdu = [0x00, ins, 0x80+fileid, 0x00, 1] + s2l(d[255:])
apdu = [0x00, ins, count, 0x00, 1] + s2l(d[255:])
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
if is_update:
raise ValueError, ("%02x%02x" % (sw1, sw2))
raise ValueError, ("update failure: %02x%02x" % (sw1, sw2))
else:
raise ValueError, ("%02x%02x" % (sw1, sw2))
raise ValueError, ("write failure: %02x%02x" % (sw1, sw2))
count += 1
def cmd_select_openpgp(self):
@@ -124,17 +139,19 @@ def main(fileid, is_update, data, passwd):
gnuk.cmd_verify(BY_ADMIN, passwd)
gnuk.cmd_write_binary(fileid, data, is_update)
gnuk.cmd_select_openpgp()
if fileid == 0:
gnuk.cmd_select_openpgp()
data_in_device = gnuk.cmd_get_data(0x7f, 0x21)
compare(data[:-2], data_in_device)
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:])
elif fileid >= 1 and fileid <= 4:
data_in_device = gnuk.cmd_read_binary(fileid)
compare(data, data_in_device)
elif fileid == 5:
data_in_device = gnuk.cmd_get_data(0x7f, 0x21)
compare(data, data_in_device)
gnuk.connection.disconnect()
return 0
@@ -152,7 +169,7 @@ if __name__ == '__main__':
else:
is_update = False
if sys.argv[1] == '-s':
fileid = 2 # serial number
fileid = 0 # serial number
filename = sys.argv[2]
f = open(filename)
email = os.environ['EMAIL']
@@ -167,8 +184,15 @@ if __name__ == '__main__':
exit(1)
print "Writing serial number"
data = binascii.unhexlify(serial_data_hex)
elif sys.argv[1] == '-k': # firmware update key
keyno = sys.argv[2]
fileid = 1 + int(keyno)
filename = sys.argv[3]
f = open(filename)
data = f.read()
f.close()
else:
fileid = 0 # Card holder certificate
fileid = 5 # Card holder certificate
filename = sys.argv[1]
f = open(filename)
data = f.read()

View File

@@ -4,7 +4,7 @@
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
Copyright (C) 2011, 2012 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -41,13 +41,12 @@ 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
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
return pack('>BBBBB', cls, ins, p1, p2, data_len) + data
# This class only supports Gnuk (for now)
class gnuk_token:
@@ -75,7 +74,7 @@ class gnuk_token:
self.__alt = interface.alternateSetting
self.__conf = configuration
self.__bulkout = 2
self.__bulkout = 1
self.__bulkin = 0x81
self.__timeout = 10000
@@ -150,59 +149,88 @@ class gnuk_token:
else:
raise ValueError, "icc_send_cmd"
def cmd_get_response(self, expected_len):
result = []
while True:
cmd_data = iso7816_compose(0xc0, 0x00, 0x00, '') + pack('>B', expected_len)
response = self.icc_send_cmd(cmd_data)
result += response[:-2]
sw = response[-2:]
if sw[0] == 0x90 and sw[1] == 0x00:
return result
elif sw[0] != 0x61:
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
else:
expected_len = sw[1]
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"
raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_verify"
raise ValueError, sw
def cmd_write_binary(self, fileid, data):
def cmd_read_binary(self, fileid):
cmd_data = iso7816_compose(0xb0, 0x80+fileid, 0x00, '')
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if sw[0] != 0x61:
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_write_binary(self, fileid, data, is_update):
count = 0
data_len = len(data)
if is_update:
ins = 0xd6
else:
ins = 0xd0
while count*256 < data_len:
if count == 0:
cmd_data = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:256])
if len(data) < 128:
cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128], 0x10)
cmd_data1 = iso7816_compose(ins, 0x80+fileid, 0x00, data[128:256])
else:
cmd_data = iso7816_compose(0xd0, count, 0x00, data[256*count:256*(count+1)])
sw = self.icc_send_cmd(cmd_data)
if len(data[256*count:256*count+128]) < 128:
cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128], 0x10)
cmd_data1 = iso7816_compose(ins, count, 0x00, data[256*count+128:256*(count+1)])
sw = self.icc_send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError, "cmd_write_binary"
raise ValueError, "cmd_write_binary 0"
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"
raise ValueError, "cmd_write_binary 0"
if cmd_data1:
sw = self.icc_send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError, "cmd_write_binary 1"
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_write_binary 1"
count += 1
def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x00, "\xD2\x76\x00\x01\x24\x01")
cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, "cmd_select_openpgp"
raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, "cmd_select_openpgp"
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
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]
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if sw[0] != 0x61:
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def compare(data_original, data_in_device):
i = 0
@@ -211,7 +239,7 @@ def compare(data_original, data_in_device):
raise ValueError, "verify failed at %08x" % i
i += 1
def get_device():
def gnuk_devices():
busses = usb.busses()
for bus in busses:
devices = bus.devices
@@ -222,40 +250,57 @@ def get_device():
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"
yield dev, config, alt
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)
DEFAULT_PW3 = "12345678"
BY_ADMIN = 3
def main(fileid, is_update, data, passwd):
icc = None
for (dev, config, intf) in gnuk_devices():
try:
icc = gnuk_token(dev, config, intf)
print "Device: ", dev.filename
print "Configuration: ", config.value
print "Interface: ", intf.interfaceNumber
break
except:
pass
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_verify(BY_ADMIN, passwd)
icc.cmd_write_binary(fileid, data, is_update)
icc.cmd_select_openpgp()
if fileid == 0:
data = data[:-2]
data_in_device = icc.cmd_get_data(0x00, 0x4f)
for d in data_in_device:
print "%02x" % d,
print
compare(data, data_in_device[8:])
elif fileid >= 1 and fileid <= 4:
data_in_device = icc.cmd_read_binary(fileid)
compare(data, data_in_device)
else:
data_in_device = icc.cmd_get_data(0x7f, 0x21)
compare(data, data_in_device)
icc.icc_power_off()
return 0
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':
is_update = True
sys.argv.pop(1)
else:
is_update = False
if sys.argv[1] == '-s':
fileid = 2 # serial number
fileid = 0 # serial number
filename = sys.argv[2]
f = open(filename)
email = os.environ['EMAIL']
@@ -270,24 +315,19 @@ if __name__ == '__main__':
exit(1)
print "Writing serial number"
data = binascii.unhexlify(serial_data_hex)
elif sys.argv[1] == '-r':
fileid = 1 # Random number bits
if len(sys.argv) == 3:
filename = sys.argv[2]
f = open(filename)
else:
filename = stdin
f = sys.stdin
elif sys.argv[1] == '-k': # firmware update key
keyno = sys.argv[2]
fileid = 1 + int(keyno)
filename = sys.argv[3]
f = open(filename)
data = f.read()
f.close()
print "%s: %d" % (filename, len(data))
print "Updating random bits"
else:
fileid = 0 # Card holder certificate
fileid = 5 # Card holder certificate
filename = sys.argv[1]
f = open(filename)
data = f.read()
f.close()
print "%s: %d" % (filename, len(data))
print "Updating card holder certificate"
main(fileid, is_update, data)
main(fileid, is_update, data, passwd)

491
tool/gnuk_upgrade.py Executable file
View File

@@ -0,0 +1,491 @@
#! /usr/bin/python
"""
gnuk_upgrade.py - a tool to upgrade firmware of Gnuk Token
Copyright (C) 2012 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
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('>BBBBB', cls, ins, p1, p2, data_len) + data
class regnual:
def __init__(self, dev):
conf = dev.configurations[0]
intf_alt = conf.interfaces[0]
intf = intf_alt[0]
if intf.interfaceClass != 0xff:
raise ValueError, "Wrong interface class"
self.__devhandle = dev.open()
try:
self.__devhandle.setConfiguration(conf)
except:
pass
self.__devhandle.claimInterface(intf)
self.__devhandle.setAltInterface(intf)
def mem_info(self):
mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0,
value = 0, index = 0, buffer = 8,
timeout = 10000)
start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0]
end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4]
return (start, end)
def download(self, start, data):
addr = start
addr_end = (start + len(data)) & 0xffffff00
i = (addr - 0x08000000) / 0x100
j = 0
print "start %08x" % addr
print "end %08x" % addr_end
while addr < addr_end:
print "# %08x: %d: %d : %d" % (addr, i, j, 256)
self.__devhandle.controlMsg(requestType = 0x40, request = 1,
value = 0, index = 0,
buffer = data[j*256:j*256+256],
timeout = 10000)
crc32code = crc32(data[j*256:j*256+256])
res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2,
value = 0, index = 0, buffer = 4,
timeout = 10000)
r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0]
if (crc32code ^ r_value) != 0xffffffff:
print "failure"
self.__devhandle.controlMsg(requestType = 0x40, request = 3,
value = i, index = 0,
buffer = None,
timeout = 10000)
time.sleep(0.010)
res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2,
value = 0, index = 0, buffer = 4,
timeout = 10000)
r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0]
if r_value == 0:
print "failure"
i = i+1
j = j+1
addr = addr + 256
residue = len(data) % 256
if residue != 0:
print "# %08x: %d : %d" % (addr, i, residue)
self.__devhandle.controlMsg(requestType = 0x40, request = 1,
value = 0, index = 0,
buffer = data[j*256:],
timeout = 10000)
crc32code = crc32(data[j*256:].ljust(256,chr(255)))
res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2,
value = 0, index = 0, buffer = 4,
timeout = 10000)
r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0]
if (crc32code ^ r_value) != 0xffffffff:
print "failure"
self.__devhandle.controlMsg(requestType = 0x40, request = 3,
value = i, index = 0,
buffer = None,
timeout = 10000)
time.sleep(0.010)
res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2,
value = 0, index = 0, buffer = 4,
timeout = 10000)
r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0]
if r_value == 0:
print "failure"
def protect(self):
self.__devhandle.controlMsg(requestType = 0x40, request = 4,
value = 0, index = 0, buffer = None,
timeout = 10000)
time.sleep(0.100)
res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2,
value = 0, index = 0, buffer = 4,
timeout = 10000)
r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0]
if r_value == 0:
print "protection failure"
def finish(self):
self.__devhandle.controlMsg(requestType = 0x40, request = 5,
value = 0, index = 0, buffer = None,
timeout = 10000)
def reset_device(self):
try:
self.__devhandle.reset()
except:
pass
# 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 = 1
self.__bulkin = 0x81
self.__timeout = 10000
self.__seq = 0
def reset_device(self):
try:
self.__devhandle.reset()
except:
pass
def stop_gnuk(self):
self.__devhandle.releaseInterface()
self.__devhandle.setConfiguration(0)
return
def mem_info(self):
mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0,
value = 0, index = 0, buffer = 8,
timeout = 10)
start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0]
end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4]
return (start, end)
def download(self, start, data):
addr = start
addr_end = (start + len(data)) & 0xffffff00
i = (addr - 0x20000000) / 0x100
j = 0
print "start %08x" % addr
print "end %08x" % addr_end
while addr < addr_end:
print "# %08x: %d : %d" % (addr, i, 256)
self.__devhandle.controlMsg(requestType = 0x40, request = 1,
value = i, index = 0,
buffer = data[j*256:j*256+256],
timeout = 10)
i = i+1
j = j+1
addr = addr + 256
residue = len(data) % 256
if residue != 0:
print "# %08x: %d : %d" % (addr, i, residue)
self.__devhandle.controlMsg(requestType = 0x40, request = 1,
value = i, index = 0,
buffer = data[j*256:],
timeout = 10)
def execute(self, last_addr):
i = (last_addr - 0x20000000) / 0x100
o = (last_addr - 0x20000000) % 0x100
self.__devhandle.controlMsg(requestType = 0x40, request = 2,
value = i, index = o, buffer = None,
timeout = 10)
def icc_get_result(self):
msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout)
if len(msg) < 10:
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_get_response(self, expected_len):
cmd_data = iso7816_compose(0xc0, 0x00, 0x00, '') + pack('>B', expected_len)
response = self.icc_send_cmd(cmd_data)
return response[:-2]
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, sw
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, sw
def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
def cmd_external_authenticate(self, signed):
cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed[0:128], cls=0x10)
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed[128:])
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
def cmd_get_challenge(self):
cmd_data = iso7816_compose(0x84, 0x00, 0x00, '')
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if sw[0] != 0x61:
raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
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 ccid_devices():
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:
yield dev, config, alt
USB_VENDOR_FSIJ=0x234b
USB_PRODUCT_GNUK=0x0000
def gnuk_devices():
busses = usb.busses()
for bus in busses:
devices = bus.devices
for dev in devices:
if dev.idVendor != USB_VENDOR_FSIJ:
continue
if dev.idProduct != USB_PRODUCT_GNUK:
continue
yield dev
def to_string(t):
result = ""
for c in t:
result += chr(c)
return result
from subprocess import check_output
def gpg_sign(keygrip, hash):
result = check_output(["gpg-connect-agent",
"SIGKEY %s" % keygrip,
"SETHASH --hash=sha1 %s" % hash,
"PKSIGN", "/bye"])
signed = ""
while True:
i = result.find('%')
if i < 0:
signed += result
break
hex_str = result[i+1:i+3]
signed += result[0:i]
signed += chr(int(hex_str,16))
result = result[i+3:]
pos = signed.index("D (7:sig-val(3:rsa(1:s256:") + 26
signed = signed[pos:-7]
if len(signed) != 256:
raise ValueError, binascii.hexlify(signed)
return signed
def UNSIGNED(n):
return n & 0xffffffff
def crc32(bytestr):
crc = binascii.crc32(bytestr)
return UNSIGNED(crc)
def main(keygrip, data_regnual, data_upgrade):
l = len(data_regnual)
if (l & 0x03) != 0:
data_regnual = data_regnual.ljust(l + 4 - (l & 0x03), chr(0))
crc32code = crc32(data_regnual)
print "CRC32: %04x\n" % crc32code
data_regnual += pack('<I', crc32code)
for (dev, config, intf) in ccid_devices():
try:
icc = gnuk_token(dev, config, intf)
print "Device: ", dev.filename
print "Configuration: ", config.value
print "Interface: ", intf.interfaceNumber
break
except:
icc = None
if icc.icc_get_status() == 2:
raise ValueError, "No ICC present"
elif icc.icc_get_status() == 1:
icc.icc_power_on()
icc.cmd_select_openpgp()
challenge = icc.cmd_get_challenge()
signed = gpg_sign(keygrip, binascii.hexlify(to_string(challenge)))
icc.cmd_external_authenticate(signed)
icc.stop_gnuk()
mem_info = icc.mem_info()
print "%08x:%08x" % mem_info
print "Downloading flash upgrade program..."
icc.download(mem_info[0], data_regnual)
print "Run flash upgrade program..."
icc.execute(mem_info[0] + len(data_regnual) - 4)
#
time.sleep(3)
icc.reset_device()
del icc
icc = None
#
print "Wait 3 seconds..."
time.sleep(3)
# Then, send upgrade program...
reg = None
for dev in gnuk_devices():
try:
reg = regnual(dev)
print "Device: ", dev.filename
break
except:
pass
mem_info = reg.mem_info()
print "%08x:%08x" % mem_info
print "Downloading the program"
reg.download(mem_info[0], data_upgrade)
reg.protect()
reg.finish()
reg.reset_device()
return 0
if __name__ == '__main__':
keygrip = sys.argv[1]
filename_regnual = sys.argv[2]
filename_upgrade = sys.argv[3]
f = open(filename_regnual)
data_regnual = f.read()
f.close()
print "%s: %d" % (filename_regnual, len(data_regnual))
f = open(filename_upgrade)
data_upgrade = f.read()
f.close()
print "%s: %d" % (filename_upgrade, len(data_upgrade))
main(keygrip, data_regnual, data_upgrade[4096:])