Compare commits

...

83 Commits

Author SHA1 Message Date
NIIBE Yutaka
83414a747a Version 1.2.5. 2017-08-11 22:12:09 +09:00
NIIBE Yutaka
8a615d087b Update .gitignore. 2017-08-11 22:11:49 +09:00
NIIBE Yutaka
967b949967 Tweak process size of gpg. 2017-08-11 22:00:01 +09:00
NIIBE Yutaka
11afbdde14 src/config.mk generation. 2017-08-11 21:06:59 +09:00
NIIBE Yutaka
328766af12 Merge branch 'master' of git.gniibe.org:gnuk/gnuk 2017-08-04 08:33:46 +09:00
NIIBE Yutaka
2b340ee1c5 Fix factory-reset for admin-less mode.
Reported-by: Stanislas Bach <sbach@0g.re>
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-04 08:32:39 +09:00
NIIBE Yutaka
86e6adf47e Fix factory-reset for admin-less mode.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-03 21:35:20 +09:00
Jeremy Drake
eea011fe70 Allow compile-time override of detected flash size.
On the STM32F103C8, as used in the "blue pill" boards, it has been
determined that, despite these only officially having 64KiB flash, it is
possible to actually use 128KiB of flash.

This commit allows for a preprocessor define
STM32F103_OVERRIDE_FLASH_SIZE which, when set, is used as the size of
flash in KiB instead of reading it from the FLASH_SIZE_REG.
2017-08-03 21:20:47 +09:00
Jeremy Drake
e736227de7 Erase CERTDO on terminate.
When both certdo and lifecycle support are enabled, flash_terminate
neglected to erase the certdo pages.  It now does so.
2017-08-02 11:13:02 +09:00
NIIBE Yutaka
22156ea7f9 Fix factory-reset. 2017-08-01 13:30:02 +09:00
Anthony Romano
db45e62ebe configure: sanitize for shellcheck
Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-20 12:25:24 +09:00
Anthony Romano
3270740631 docker: source checking container
Includes shellcheck and scan-build

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-20 12:24:44 +09:00
NIIBE Yutaka
e4e72a29ae Initialize TMP to avoid confusion by static analysis.
--

The computation using TMP is keeping it constant-time only, but
it is better not to confuse static analysis.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-19 11:55:20 +09:00
NIIBE Yutaka
25d3f021c1 Support no git situation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-19 11:25:38 +09:00
NIIBE Yutaka
ae76d66d53 Fix accessing garbage on error path.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Reported-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-19 10:48:16 +09:00
NIIBE Yutaka
10c5010141 Git is assumed for the source with .git.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-18 14:12:20 +09:00
Anthony Romano
d12483c3c9 Support building with docker.
Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:38:46 +09:00
Anthony Romano
67acb670d1 call fatal if mem_head size is corrupted.
Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:31:06 +09:00
Anthony Romano
a44244b27e avoid null dereference when openpgp algo goes from !rsa2k to rsa2k.
Detected with scan-build.

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:27:12 +09:00
Anthony Romano
2622840e27 remove unused calculations from mod_reduce.
Detected with scan-build.

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:19:42 +09:00
Anthony Romano
a51ac8593b call-rsa: free modulus buffers on error paths.
* MPI_CHK jumps to cleanup on ret != 0, so p_q_modulus is never freed if
  rsa_gen_key fails (detected via scan-build).
* modulus_calc never freed its modulus buffer on error.

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:15:42 +09:00
NIIBE Yutaka
de81caba3e Update Chopstx.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-18 12:58:23 +09:00
NIIBE Yutaka
fa69a85826 Version 1.2.4.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-12 17:22:20 +09:00
NIIBE Yutaka
5c3c3e3001 usbip list -r 127.0.0.1 now works.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-12 14:13:53 +09:00
NIIBE Yutaka
6dcb4dd027 Add usb-emu.c.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-02 15:05:15 +09:00
NIIBE Yutaka
fa08f44cac Fix old documentation (note) for firmware update.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-01 14:58:15 +09:00
NIIBE Yutaka
4c2294ea6c Portability change.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-28 16:14:30 +09:00
NIIBE Yutaka
86eaa26d32 New: src/mcu-stm32f103.c.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-28 15:49:38 +09:00
NIIBE Yutaka
9e52789203 Fix long standing buf of digital signature counter.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-28 14:54:15 +09:00
NIIBE Yutaka
702bc8cbde Move data objects at the end of flash.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-27 15:23:25 +09:00
NIIBE Yutaka
2cfce76d91 [SECURITY] Flash memory usage change.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-27 14:36:32 +09:00
NIIBE Yutaka
207652246a emulation: USB device emulation by USBIP protocol. 2017-04-18 15:45:25 +09:00
NIIBE Yutaka
32779b6f96 Version 1.2.3. 2017-02-02 16:33:30 +09:00
NIIBE Yutaka
55c1015faa Increase CCID thread stack size by 0x20 for newer GCC. 2017-02-02 14:11:11 +09:00
NIIBE Yutaka
0932465f0b Update Chopstx to 1.3. 2017-02-02 13:07:35 +09:00
NIIBE Yutaka
4417799a51 Update README 2017-02-01 17:16:54 +09:00
Szczepan Zalega
b424cecf1e Regnual update tool: do not allow other than binary formats (upgrade_by_passwd)
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2017-02-01 15:40:56 +09:00
NIIBE Yutaka
7ef417ae36 tool: Improve tool/*.py.
--

Szczepan Zalega's idea of using the file GNUK_USB_DEVICE_ID would
good, but not merged yet.  Because it makes difficult to distribute
the scripts.  We need to consider installing tools and the file
like GNUK_USB_DEVICE_ID altogether.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-02-01 12:34:35 +09:00
NIIBE Yutaka
d4469c24ec fix NIST P-256 / secp256k1 key generation. 2016-10-21 15:30:07 +09:00
NIIBE Yutaka
e4333c6580 Version 1.2.2 2016-10-15 20:18:20 +09:00
NIIBE Yutaka
d2261d53e3 fix scripts 2016-10-15 20:14:18 +09:00
NIIBE Yutaka
27bd37781a Fix flash initialization 2016-10-15 19:29:23 +09:00
NIIBE Yutaka
bed43d4049 Add tests/ accessing DO 6E 2016-10-15 19:28:57 +09:00
NIIBE Yutaka
f7d857b527 fix stack usage of CCID 2016-10-15 18:37:22 +09:00
NIIBE Yutaka
350528e1f4 tests/ update for signature counter 2016-10-15 18:35:21 +09:00
NIIBE Yutaka
4de605ed63 Add pubkey tests 2016-10-15 16:55:22 +09:00
NIIBE Yutaka
ffa9bf1f94 support factory_reset. 2016-10-14 08:45:01 +09:00
NIIBE Yutaka
34d0b34144 add factory reset support (not-full yet) 2016-10-13 15:06:19 +09:00
NIIBE Yutaka
5795dc9877 rename status-code.h 2016-10-13 11:03:50 +09:00
NIIBE Yutaka
c8b17a8759 Update to Chopstx 1.2 2016-10-13 10:35:22 +09:00
NIIBE Yutaka
38d70e277b Fix difference between original OpenPGP card 2016-10-13 10:33:02 +09:00
NIIBE Yutaka
b00bab8dbf tests/ update 2016-10-13 10:04:27 +09:00
NIIBE Yutaka
3c91dce8b7 fix tests/ 2016-10-12 19:42:22 +09:00
NIIBE Yutaka
f1773c146b fix test/ 2016-10-12 15:32:51 +09:00
NIIBE Yutaka
979992c046 fix test/ 2016-10-12 14:56:57 +09:00
NIIBE Yutaka
50700e3887 more tests (incomplete) 2016-10-12 10:22:57 +09:00
NIIBE Yutaka
b0ee8b4452 TPDU reader works now 2016-10-07 16:39:20 +09:00
NIIBE Yutaka
a73f8cf4fd implement TPDU card reader 2016-10-05 20:00:22 +09:00
NIIBE Yutaka
c1cc75f5b0 New test suite for OpenPGP card 2016-09-30 16:38:27 +09:00
NIIBE Yutaka
47150b5c98 minor fix for configure 2016-09-30 16:20:19 +09:00
NIIBE Yutaka
f46880d2a8 Add Gnuk logo of PNG 2016-09-02 11:01:55 +09:00
NIIBE Yutaka
23bbc9c755 Fix test setup 2016-08-24 10:39:27 +09:00
NIIBE Yutaka
2b784cb3b9 Upgrade tool/hub_ctrl.py 2016-08-03 21:19:34 +09:00
NIIBE Yutaka
452c15c908 Version 1.2.1 2016-07-11 16:20:55 +09:00
NIIBE Yutaka
dc568422b1 Cleanup openpgp_thread. 2016-07-11 13:06:30 +09:00
NIIBE Yutaka
5edcf32bb7 Update document 2016-07-11 12:55:09 +09:00
NIIBE Yutaka
2647797348 Fix for PIN DND 2016-07-11 12:47:06 +09:00
NIIBE Yutaka
9697694e45 pin CIR fixes 2016-07-11 11:32:14 +09:00
NIIBE Yutaka
f5cbc71a54 doc fix 2016-07-11 11:28:08 +09:00
NIIBE Yutaka
5099bfee88 Update chopstx to 1.1 2016-07-01 13:09:42 +09:00
NIIBE Yutaka
691e16c605 doc update 2016-06-21 14:44:51 +09:00
Niibe Yutaka
eabcec107e Update to Chopstx 1.0 2016-06-17 14:54:52 +09:00
Niibe Yutaka
73c698c67e tweak thread size 2016-06-15 15:14:03 +09:00
Niibe Yutaka
d035c53b9c update chopstx 2016-06-14 16:48:31 +09:00
Niibe Yutaka
a96a3eefe6 Update Chopstx, follow the change of USB API 2016-06-14 14:29:17 +09:00
NIIBE Yutaka
fd08a853fd Fix regnual for new Chopstx 2016-06-02 11:03:59 +09:00
NIIBE Yutaka
f882acc1b4 Fix USB usage in tool/ 2016-06-01 09:49:28 +09:00
NIIBE Yutaka
907d8c7a8e Add ccid_notify_slot_change for the interrupt transfer 2016-06-01 07:52:56 +09:00
NIIBE Yutaka
d636bf314c Remove sys, adc and usb (use Chopstx's) 2016-05-31 21:18:08 +09:00
NIIBE Yutaka
0212328a6a USB handling improvement 2016-05-31 20:29:31 +09:00
NIIBE Yutaka
eb90074e11 ICC->CCID 2016-05-31 19:51:07 +09:00
NIIBE Yutaka
38d164360c Update to Chopstx 0.12 2016-05-31 18:16:51 +09:00
NIIBE Yutaka
ff190a8053 Fix LED blinking protocol. 2016-05-21 10:56:49 +09:00
93 changed files with 4657 additions and 4440 deletions

5
.gitignore vendored
View File

@@ -2,7 +2,7 @@
*.o
*.pyc
src/.dep
src/Makefile
src/config.mk
src/config.h
src/gnuk.ld
src/board.h
@@ -12,3 +12,6 @@ regnual/regnual.bin
regnual/regnual.hex
regnual/regnual.elf
doc/_build
tests/.cache
tests/__pycache__
emulation/gnuk_emulation

10
AUTHORS
View File

@@ -1,3 +1,13 @@
Anthony Romano:
Modified:
src/call-rsa.c
src/main.c
src/mod.c
Jeremy Drake:
Modified:
regnual/regnual.c
Kaz Kojima:
Added STM32 Primer2 support.

347
ChangeLog
View File

@@ -1,3 +1,350 @@
2017-08-11 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.5.
* chopstx: Update to 1.4.
* src/gnuk.ld.in (__process3_stack_size__): Tweak the size.
* src/configure: Define STM32F103_OVERRIDE_FLASH_SIZE_KB for
BULE_PILL.
* src/configure: Let generate src/config.mk.
* src/Makefile: Rename from src/Makefile.in.
* regnual/Makefile: Use src/config.mk.
2017-08-03 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_terminate_df): Fix for admin-less mode.
2017-08-03 Jeremy Drake <jeremydrake+gnuk@eacceleration.com>
* regnual/regnual.c (main): Allow compile time
flash size definition by STM32F103_OVERRIDE_FLASH_SIZE_KB.
2017-08-02 Jeremy Drake <jeremydrake+gnuk@eacceleration.com>
* src/flash.c (flash_terminate): Erase Certificate DO, too.
2017-08-01 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (FILE_CARD_TERMINATED_OPENPGP): Remove.
(cmd_select_file): Don't change file_selection.
2017-07-19 NIIBE Yutaka <gniibe@fsij.org>
* src/mod.c (mod_inv): Clear TMP.
* src/configure (REVISION): Generate even when no git.
* polarssl/library/bignum.c (mpi_exp_mod): Call mpi_grow for X
after the initialization of RR.
2017-07-18 NIIBE Yutaka <gniibe@fsij.org>
* src/configure: Bark when no git available.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* docker: New.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/main.c (MEMORY_SIZE, MEM_HEAD_IS_CORRUPT, MEM_HEAD_CHECK):
New.
(gnuk_malloc, gnuk_free): Add calls to MEM_HEAD_CHECK.
* src/gnuk.h (FATAL_HEAP): New.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/openpgp-do.c (gpg_reset_algo_attr): New.
(rw_algorithm_attr): Use gpg_reset_algo_attr.
Fix null dereference.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/mod.c (mod_reduce): Clean up unused code.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/call-rsa.c (modulus_calc): Free modulus on error.
(rsa_genkey): Remove bogus check, and call chopstx_cleanup_pop
with 1 to release p_q_modulus on error. Assign NULL to clp.arg
when it's goes with no error.
* src/main.c (gnuk_free): Allow NULL.
2017-07-18 NIIBE Yutaka <gniibe@fsij.org>
* Update chopstx (with USBIP emulation).
2017-05-12 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.4.
2017-04-28 NIIBE Yutaka <gniibe@fsij.org>
* src/mcu-stm32f103.c: New.
(check_crc32, sram_address): New.
* src/usb_ctrl.c (download_check_crc32): Use check_crc32 and
sram_address.
* src/openpgp-do.c (gpg_write_digital_signature_counter): Fix
writing lower 10-bit.
2017-04-27 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.ld.in (_data_pool): Move to the end.
* src/flash.c (flash_init): Return address of end of data object.
* src/openpgp.c (gpg_init): Get address of end of data object.
* src/openpgp-do.c (gpg_data_scan): Check the end address.
2017-02-02 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.3.
* src/gnuk.ld.in (__process1_stack_size__): Increase by 0x20.
* chopstx: Update to 1.3.
* src/configure: Add BLUE_PILL in the help message.
2017-02-01 NIIBE Yutaka <gniibe@fsij.org>
* README: Update README. Thanks to Paul Fertser.
2017-01-02 Szczepan Zalega <szczepan@nitrokey.com>
* tool/upgrade_by_passwd.py: Add file extention check.
2017-02-01 NIIBE Yutaka <gniibe@fsij.org>
* tool/upgrade_by_passwd.py (main): More verbose messages
suggested by Szczepan Zalega <szczepan@nitrokey.com>.
* tool/gnuk_token.py (USB_PRODUCT_LIST): New.
(gnuk_devices_by_vidpid): Support searching by USB_PRODUCT_LIST.
Thanks to Szczepan Zalega <szczepan@nitrokey.com>.
* tool/usb_strings.py: Use gnuk_token.py.
2016-10-21 Niibe Yutaka <gniibe@fsij.org>
* src/ecc.c (check_secret): Fix condition.
2016-10-15 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.2.
* tool/gnuk_put_binary_libusb.py (main): Likewise.
* tool/upgrade_by_passwd.py (main): Add call of cmd_select_openpgp
method.
* src/openpgp.c (gpg_init): flash_init_keys shoule be after
gpg_data_scan since flash_init_keys accesses Data Object for
key attributes.
* src/usb-ccid.c (ccid_power_on): Don't waste stack.
2016-10-14 Niibe Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_power_on) [LIFE_CYCLE_MANAGEMENT_SUPPORT]:
Change LCS value in ATR at run time.
* src/openpgp.c (gpg_init): Handle FILE_CARD_TERMINATED.
(cmd_select_file): Don't return AID.
(cmd_activate_file, cmd_terminate_df): New.
(process_command_apdu): Let return GPG_NO_RECORD() when
not selected.
* src/openpgp-do.c (gpg_do_terminate): New.
(gpg_data_scan): Handle p_start is NULL.
(do_hist_bytes): Remove.
* src/flash.c (flash_data): Change the value from 0x0000.
(flash_init): Support termination state. Fix handling
of the boundary case where gen0 is 0xfffe.
(flash_terminate, flash_activate): New.
(flash_copying_gc): Skip 0xffff for generation number.
2016-10-13 Niibe Yutaka <gniibe@fsij.org>
* src/status-code.h: Rename from openpgp.h.
* chopstx: Update to 1.2.
* tests: New test suite for OpenPGP card with PyTest.
* src/configure (factory_reset): New.
* src/usb-ccid.c (ccid_power_on): Use ATR_head and historical
bytes.
* src/openpgp-do.c (rw_algorithm_attr): Clear fingerprint, timestamp,
and possibly ds_counter.
2016-10-12 Niibe Yutaka <gniibe@fsij.org>
* test/features/steps.py (cmd_reset_retry_counter): Fix.
* tool/gnuk_token.py (gnuk_token.cmd_reset_retry_counter): Fix.
(gnuk_token.cmd_select_openpgp): Fix P2.
2016-09-02 Niibe Yutaka <gniibe@fsij.org>
* src/configure (REVISION): Fix the detection of .git.
It may be a regular file (if it's created by worktree).
2016-08-24 Niibe Yutaka <gniibe@fsij.org>
* test/features/steps.py (ini): Use GLC (the global context),
instead of FTC (the feature context), so that token only is
opened once.
2016-08-03 Niibe Yutaka <gniibe@fsij.org>
* tool/hub_ctrl.py: Port to Python 3.
2016-07-11 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.1.
* src/usb-ccid.c (ccid_power_on): Fix call of chopstx_create.
* src/usb-msc.c (msc_init): Ditto.
* src/pin-cir.c (cir_init): Ditto.
* src/neug.c (neug_init): Ditto.
* src/main.c (main): Ditto.
* src/usb-ccid.c (struct ccid): Arrange for smaller footprint.
* src/gnuk.h (struct apdu): Likewise.
* src/usb-ccid.c (ccid_card_change_signal): Don't touch ccid_state_p.
(ccid_state_p): This is constant.
* src/configure (output_vendor_product_serial_strings): Add const
qualifier.
* src/usb-ccid.c (epo_init, epi_init): Simplify without notify method.
(EP1_IN_Callback, EP1_OUT_Callback): Call notify_tx and notify_icc
directly.
2016-07-09 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (openpgp_card_thread): Don't need to get SELF.
2016-07-06 NIIBE Yutaka <gniibe@fsij.org>
* src/pin-cir.c (cir_getchar): Use chopstx_poll.
* src/usb-ccid.c (usb_tx_done): Fix ifdef condition.
* src/usb_ctrl.c (usb_ctrl_write_finish): Fix ifdef nesting.
2016-07-04 NIIBE Yutaka <gniibe@fsij.org>
* doc/conf.py: Remove 'sphinx.ext.pngmath' and 'sphinx.ext.mathjax'.
Reported by Kenji Rikitake.
2016-07-01 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.1.
* src/usb-ccid.c (poll_event_intr, ccid_thread): Follow the
change.
2016-06-21 Niibe Yutaka <gniibe@fsij.org>
* doc/index.rst: Update documentation by an example
Ed25519/cv25519.
2016-06-17 Niibe Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.0.
2016-06-15 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.ld.in (__process2_stack_size__): Update
thread size for rng by examining NeuG.
* src/usb-ccid.c (poll_event_intr): New.
2016-06-14 Niibe Yutaka <gniibe@fsij.org>
* regnual/regnual.c (usb_device_reset): Rename from
usb_cb_device_reset.
(usb_ctrl_write_finish): Rename from usb_cb_ctrl_write_finish.
(usb_setup): Rename from usb_cb_setup.
(usb_get_descriptor): Rename from usb_cb_get_descriptor.
(usb_set_configuration): New.
(usb_interrupt_handler): New.
* src/usb-ccid.c (usb_tx_done): Rename from usb_cb_tx_done.
(usb_rx_ready): Rename from usb_cb_rx_ready.
(usb_event_handle): New.
(ccid_thread): Use usb_event_handle.
* src/usb-msc.c (EP6_IN_Callback): Update to new USB API.
(EP6_OUT_Callback): Likewise.
* src/usb_ctrl.c (usb_device_reset): Rename from
usb_cb_device_reset.
(vcom_port_data_setup): Update to new USB API.
(usb_ctrl_write_finish): Rename from usb_cb_ctrl_write_finish.
(usb_setup): Rename from usb_cb_setup.
(usb_set_configuration): New, based on usb_cb_handle_event.
(usb_set_interface): Rename from usb_cb_interface.
(usb_get_interface): New.
(usb_get_status_interface): New.
* src/usb_desc.c (usb_get_descriptor): Rename from
usb_cb_get_descriptor.
2016-06-02 Niibe Yutaka <gniibe@fsij.org>
* regnual/regnual.c (usb_cb_tx_done): Follow the change of USB
API.
* regnual/reset.c: Rename from sys.c.
2016-06-01 Niibe Yutaka <gniibe@fsij.org>
* tool/stlinkv2.py (stlinkv2.__init__): Don't
call setConfiguration.
* tool/gnuk_token.py (gnuk_token, regnual): Don't
call setAltInterface, it's not needed.
* src/usb-ccid.c (ccid_notify_slot_change): New.
(ccid_thread): Call ccid_notify_slot_change at
interface_reset and EV_CARD_CHANGE.
2016-05-31 NIIBE Yutaka <gniibe@fsij.org>
* src/usb_stm32f103.c, src/stm32f103.h: Remove.
* src/adc_stm32f103.c, src/sys.c: Remove.
* src/usb_ctrl.c (usb_cb_interface): call ccid_usb_reset.
(usb_cb_handle_event): Likewise.
* src/usb-ccid.c (ccid_thread): Handle RESET->CONFIGURE process
correctly.
(ccid_thread): Handle SET_INTERFACE correctly.
* polarssl/library/aes.c (FT0, FT1, FT2): Add "weak" flag.
* src/neug.c: Update from NeuG.
* src/usb_desc.c (usb_cb_get_descriptor): Only valid if USE_SYS3.
* src/Makefile.in (USE_SYS, USE_USB, USE_ADC): Enabled.
(CHIP): Add.
* src/sys.c, src/sys.h: Remove.
* src/usb_stm32f103.c, src/usb_lld.h: Remove.
* src/adc_stm32f103.c, src/adc.h: Remove.
* chopstx: Update to 0.12.
2016-05-21 Niibe Yutaka <gniibe@fsij.org>
* src/main.c (led_blink, main): Fix LED blink protocol.
2016-05-20 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.0.

59
NEWS
View File

@@ -1,5 +1,64 @@
Gnuk NEWS - User visible changes
* Major changes in Gnuk 1.2.5
Released 2017-08-11, by NIIBE Yutaka
** "factory-reset" fix
Gnuk's behavior was implemented by referring the gpg implementation.
It found that gpg implementation was not good from the viewpoint of
the OpenPGP card specification. GnuPG was fixed to match the OpenPGP
card specification already. Thus, Gnuk is now fixed.
** Upgrade of Chopstx
We use Chopstx 1.4.
* Major changes in Gnuk 1.2.4
Released 2017-05-12, by NIIBE Yutaka
** Flash ROM security fix
The partial content of flash ROM might be exposed when scanning of
data object had a problem. Added boundary check and changed layout of
flash ROM.
* Major changes in Gnuk 1.2.3
Released 2017-02-02, by NIIBE Yutaka
** ECC key generation on the device
Bug fixed.
** Upgrade of Chopstx
We use Chopstx 1.3.
* Major changes in Gnuk 1.2.2
Released 2016-10-15, by NIIBE Yutaka
** Change of SELECT FILE behavior
Gnuk used to reply AID upon SELECT FILE command. Now, to be compatible
to original OpenPGP card, it returns nothing but status code of 9000.
** Added feature of Factory Reset as compile time option
Original OpenPGP card has the feature, and Gnuk is now configurable to
support the feature.
** Upgrade of Chopstx
We use Chopstx 1.2.
* Major changes in Gnuk 1.2.1
Released 2016-07-11, by NIIBE Yutaka
** Upgrade of Chopstx
We use Chopstx 1.1.
* Major changes in Gnuk 1.2.0
Released 2016-05-20, by NIIBE Yutaka

93
README
View File

@@ -1,23 +1,23 @@
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 1.2.0
2016-05-20
Version 1.2.5
2017-08-11
Niibe Yutaka
Free Software Initiative of Japan
Release Notes
=============
This is new release of Gnuk, version 1.2.0, which has major
This is the release of Gnuk, version 1.2.5, which has major
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
overriding key import, but importing keys (or generating keys) results
password reset. Please update your documentation for Gnuk Token, so
that the instruction of importing keys won't cause any confusion.
It has supports of EdDSA, ECDSA (with NIST P256 and secp256k1), and
ECDH (with NIST P256, secp256k1, and X25519), but this ECC feature is
somehow experimental, and it requires modern GnuPG 2.1.x with
libgcrypt 1.7.0 or later.
ECDH (with X25519, NIST P256 and secp256k1), but this ECC feature is
somehow experimental, and it requires modern GnuPG 2.1 with libgcrypt
1.7.0 or later.
It also supports RSA-4096, but users should know that it takes more
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
@@ -47,7 +47,7 @@ FAQ
Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
card 2.0, YubiKey, etc.) ?
http://www.g10code.de/p-card.html
https://www.g10code.de/p-card.html
https://www.yubico.com/
A0: Good points of Gnuk are:
* If you have skill of electronics and like DIY, you can build
@@ -62,8 +62,8 @@ A0: Good points of Gnuk are:
Q1: What kind of key algorithm is supported?
A1: Gnuk version 1.0 only supports RSA-2048.
Gnuk version 1.2.x supports 256-bit EdDSA and ECDSA, as well as
RSA-4096. But it takes long time to sign with RSA-4096.
Gnuk version 1.2.x supports 255-bit EdDSA, as well as RSA-4096.
(Note that it takes long time to sign with RSA-4096.)
Q2: How long does it take for digital signing?
A2: It takes a second and a half or so for RSA-2048.
@@ -77,12 +77,12 @@ A3: Orthodox choice is Olimex STM32-H103.
choice for experiment.
Q4: What's version of GnuPG are you using?
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.12 in
experimental.
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.18 in
unstable.
Q5: What's version of pcscd and libccid are you using?
A5: I don't use them, pcscd and libccid are optional, you can use Gnuk
without them.
Token without them.
I tested pcscd 1.5.5-4 and libccid 1.3.11-2 which were in Debian
squeeze.
@@ -248,7 +248,7 @@ External source code
Gnuk is distributed with external source code.
* chopstx/ -- Chopstx 0.11
* chopstx/ -- Chopstx 1.3
We use Chopstx as the kernel for Gnuk.
@@ -361,10 +361,10 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
On Debian we can install the packages of gcc-arm-none-eabi,
gdb-arm-none-eabi and its friends. I'm using:
binutils-arm-none-eabi 2.26-4+8
gcc-arm-none-eabi 15:4.9.3+svn231177-1
gdb-arm-none-eabi 7.10-1+9
libnewlib-arm-none-eabi 2.2.0+git20150830.5a3d536-1
binutils-arm-none-eabi 2.28-4+9+b2
gcc-arm-none-eabi 15:5.4.1+svn241155-1
gdb-arm-none-eabi 7.12-6+9+b2
libnewlib-arm-none-eabi 2.4.0.20160527-2
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
GNU Toolchain for 'arm-none-eabi' target.
@@ -395,18 +395,14 @@ How to install
Olimex STM32-H103 board
-----------------------
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD:
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD
and write "gnuk.elf" to Flash ROM:
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg -f board/olimex_stm32_h103.cfg
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \
-f board/olimex_stm32_h103.cfg \
-c "program build/gnuk.elf verify reset exit"
Then, with another terminal, type following to write "gnuk.elf" to Flash ROM:
$ telnet localhost 4444
> reset halt
> flash write_image erase gnuk.elf
> reset
> exit
$
Command invocation is assumed in src/ directory.
Flying Stone Tiny 01
@@ -414,9 +410,10 @@ Flying Stone Tiny 01
If you are using Flying Stone Tiny 01, you need a SWD writer.
OpenOCD 0.9 now supports ST-Link/V2. We can use it:
OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x_stlink.cfg
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
-c "program build/gnuk.elf verify reset exit"
@@ -435,20 +432,24 @@ Then, reset the board.
How to protect flash ROM
========================
Invoke your OpenOCD and type:
To protect, invoke OpenOCD like (for FST-01):
$ telnet localhost 4444
> reset halt
> stm32f1x lock 0
> reset
> shutdown
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
-c init -c "reset halt" -c "stm32f1x lock 0" -c reset -c exit
After power-off / power-on sequence, the contents of flash ROM cannot
be accessible from JTAG debugger.
Unprotecting is:
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
-c init -c "reset halt" -c "stm32f1x unlock 0" -c reset -c exit
Upon unprotection, flash is erased.
Note that it would be still possible for some implementation of DfuSe
to access the contents. If you want to protect, killing DfuSe and
accessing by JTAG debugger is recommended.
to access the contents, even if it's protected. If you really want to
protect, killing DfuSe and accessing by JTAG debugger is recommended.
(Optional) Configure serial number and X.509 certificate
@@ -551,6 +552,10 @@ Inside GDB, we can connect OpenOCD by:
(gdb) target remote localhost:3333
or
(gdb) target extended-remote localhost:3333
You can see the output of PCSCD:
@@ -582,14 +587,14 @@ You can browse at: http://git.gniibe.org/gitweb?p=gnuk/gnuk.git;a=summary
I put Chopstx as a submodule of Git. Please do this:
$ git submodule init
$ git submodule update
$ git submodule update --init
We have migrated from ChibiOS/RT to Chopstx in Gnuk 1.1. If you have
old code of ChibiOS/RT, you need:
Gnuk 1.0 uses ChibiOS/RT, and then, we have migrated from to Chopstx
in the development phase of Gnuk 1.1. If you have old code of
ChibiOS/RT, you need:
Edit .git/config to remove chibios reference
git rm --cached chibios
Edit .git/config to remove chibios reference and
$ git rm --cached chibios
Information on the Web
@@ -599,7 +604,7 @@ Please visit: http://www.fsij.org/gnuk/
Please see the FST-01 support pages:
http://www.gniibe.org/category/fst-01.html
https://www.gniibe.org/category/fst-01.html
Please consider to join Gnuk-users mailing list:

6
THANKS
View File

@@ -11,14 +11,17 @@ Achim Pietig achim@pietig.com
Aidan Thornton
Anibal Monsalve Salazar anibal@debian.org
Andre Zepezauer andre.zepezauer@student.uni-halle.de
Anthony Romano anthony.romano@coreos.com
Bertrand Jacquin bertrand@jacquin.bzh
Clint Adams clint@softwarefreedom.org
Daniel Kahn Gillmor dkg@fifthhorseman.net
Elliott Mitchell
Hironobu SUZUKI hironobu@h2np.net
Jan Suhr jan@suhr.info
Jeremy Drake jeremydrake+gnuk@eacceleration.com
Jonathan McDowell noodles@earth.li
Kaz Kojima kkojima@rr.iij4u.or.jp
Kenji Rikitake
Ludovic Rousseau ludovic.rousseau@free.fr
Luis Felipe R. Murillo luisfelipe@ucla.edu
Mateusz Zalega mateusz@nitrokey.com
@@ -28,9 +31,12 @@ NAGAMI Takeshi nagami-takeshi@aist.go.jp
Nguyễn Hồng Quân quannguyen@mbm.vn
Nico Rikken nico@nicorikken.eu
NOKUBI Takatsugu knok@daionet.gr.jp
Paul Fertser
Paul Bakker polarssl_maintainer@polarssl.org
Santiago Ruano Rincón santiago@debian.org
Shane Coughlan scoughlan@openinventionnetwork.com
Stanislas Bach sbach@0g.re
Szczepan Zalega szczepan@nitrokey.com
Vasily Evseenko
Werner Koch wk@gnupg.org
Yuji Imai ug@xcast.jp

View File

@@ -1 +1 @@
release/1.2.0
release/1.2.5

Submodule chopstx updated: 5458b77d36...d8df82badf

View File

@@ -25,7 +25,7 @@ import sys, os
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode']
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View File

@@ -22,24 +22,19 @@ tool/stlinkv2.py.
OpenOCD
-------
For JTAG/SWD debugger, we can use OpenOCD somehow.
Note that ST-Link/V2 was *not* supported by OpenOCD 0.5.0.
It is supported by version 0.6 or later somehow, but still, you can't
enable protection of flash ROM with OpenOCD using ST-Link/V2.
For JTAG/SWD debugger, we can use OpenOCD.
GNU Toolchain
-------------
You need GNU toolchain and newlib for 'arm-none-eabi' target.
In Debian, we can just apt-get packages of: gcc-arm-none-eabi, binutils-arm-none-eabi, gdb-arm-none-eabi and libnewlib-arm-none-eabi.
There is "gcc-arm-embedded" project. See:
For other distributiions, there is "gcc-arm-embedded" project. See:
https://launchpad.net/gcc-arm-embedded/
It is based on GCC 4.8 (as of December, 2013). We are using "-O3 -Os"
for compiler option.
We are using "-O3 -Os" for compiler option.
Building Gnuk

View File

@@ -1,313 +0,0 @@
============================
Generating 2048-bit RSA keys
============================
In this section, we describe how to generate 2048-bit RSA keys.
Key length of RSA
=================
In 2005, NIST (National Institute of Standards and Technology, USA)
has issued the first revision of NIST Special Publication 800-57,
"Recommendation for Key Management".
In 800-57, NIST advises that 1024-bit RSA keys will no longer be
viable after 2010 and advises moving to 2048-bit RSA keys. NIST
advises that 2048-bit keys should be viable until 2030.
As of 2010, GnuPG's default for generating RSA key is 2048-bit.
Some people have preference on RSA 4096-bit keys, considering
"longer is better".
However, "longer is better" is not always true. When it's long, it
requires more computational resource, memory and storage, and it
consumes more power for nomal usages. These days, many people has
enough computational resource, that would be true, but less is better
for power consumption.
For security, the key length is just a single factor. We had and will have
algorithm issues, too. It is true that it's difficult to update
our public keys, but this problem wouldn't be solved by just have
longer keys.
We deliberately support only RSA 2048-bit keys for Gnuk, considering
device computation power and host software constraints.
Thus, the key size is 2048-bit in the examples below.
Generating keys on host PC
==========================
Here is the example session to generate main key and a subkey for encryption.
I invoke GnuPG with ``--gen-key`` option. ::
$ gpg --gen-key
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
and GnuPG asks kind of key. Select ``RSA and RSA``. ::
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
and select 2048-bit (as Gnuk Token only supports this). ::
What keysize do you want? (2048)
Requested keysize is 2048 bits
and select expiration of the key. ::
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Confirm key types, bitsize and expiration. ::
Is this correct? (y/N) y
Then enter user ID. ::
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
Real name: Niibe Yutaka
Email address: gniibe@fsij.org
Comment:
You selected this USER-ID:
"Niibe Yutaka <gniibe@fsij.org>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
and enter passphrase for this **key on host PC**.
Note that this is a passphrase for the key on host PC.
It is different thing to the passphrase of Gnuk Token.
We enter two same inputs two times
(once for passphrase input, and another for confirmation). ::
You need a Passphrase to protect your secret key.
<PASSWORD-KEY-ON-PC>
Then, GnuPG generate keys. It takes some time. ::
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
...+++++
+++++
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
..+++++
Not enough random bytes available. Please do some other work to give
the OS a chance to collect more entropy! (Need 15 more bytes)
...+++++
gpg: key 4CA7BABE marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
pub 2048R/4CA7BABE 2010-10-15
Key fingerprint = 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE
uid Niibe Yutaka <gniibe@fsij.org>
sub 2048R/084239CF 2010-10-15
$
Done.
Then, we create authentication subkey.
Authentication subkey is not that common,
but very useful (for SSH authentication).
As it is not that common, we need ``--expert`` option for GnuPG. ::
$ gpg --expert --edit-key 4CA7BABE
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
[ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
gpg>
Here, it displays that there are main key and a subkey.
It prompts sub-command with ``gpg>`` .
Here, we enter ``addkey`` sub-command.
Then, we enter the passphrase of **key on host PC**.
It's the one we entered above as <PASSWORD-KEY-ON-PC>. ::
gpg> addkey
Key is protected.
You need a passphrase to unlock the secret key for
user: "Niibe Yutaka <gniibe@fsij.org>"
2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
<PASSWORD-KEY-ON-PC>
gpg: gpg-agent is not available in this session
GnuPG asks kind of key. We select ``RSA (set your own capabilities)``. ::
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection? 8
And select ``Authenticate`` for the capabilities for this key.
Initially, it's ``Sign`` and ``Encrypt``.
I need to deselect ``Sign`` and ``Encrypt``, and select ``Authenticate``.
To do that, I enter ``s``, ``e``, and ``a``. ::
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? e
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions:
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? a
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
OK, we set the capability of ``Authenticate``.
We enter ``q`` to finish setting capabilities. ::
Your selection? q
GnuPG asks bitsize and expiration, we enter 2048 for bitsize and no expiration.
Then, we confirm that we really create the key. ::
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
Then, GnuPG generate the key. ::
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
.......+++++
+++++
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
[ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
gpg>
We save the key (to the storage of the host PC. ::
gpg> save
$
Now, we have three keys (one primary key for signature and certification,
subkey for encryption, and another subkey for authentication).
Publishing public key
=====================
We make a file for the public key by ``--export`` option of GnuPG. ::
$ gpg --armor --output <YOUR-KEY>.asc --export <YOUR-KEY-ID>
We can publish the file by web server. Or we can publish the key
to a keyserver, by invoking GnuPG with ``--send-keys`` option. ::
$ gpg --keyserver pool.sks-keyservers.net --send-keys <YOUR-KEY-ID>
Here, pool.sks-keyservers.net is a keyserver, which is widely used.
Backup the private key
======================
There are some ways to back up private key, such that backup .gnupg
directory entirely, or use of paperkey, etc.
Here, we describe backup by ASCII file.
ASCII file is good, because it has less risk on transfer.
Binary file has a risk to be modified on transfer.
Note that the key on host PC is protected by passphrase (which
is <PASSWORD-KEY-ON-PC> in the example above). Using the key
from the backup needs this passphrase. It is common that
people will forget passphrase for backup. Never forget it.
You have been warned.
To make ASCII backup for private key,
invokde GnuPG with ``--armor`` option and ``--export-secret-keys``
specifying the key identifier. ::
$ gpg --armor --output <YOUR-SECRET>.asc --export-secret-keys <YOUR-KEY-ID>
From the backup,
we can recover privet key by invoking GnuPG with ``--import`` option. ::
$ gpg --import <YOUR-SECRET>.asc

487
doc/generating-key.rst Normal file
View File

@@ -0,0 +1,487 @@
====================
Generating key pairs
====================
In this section, we describe how to generate 2048-bit RSA keys.
You would like to use newer ECC keys instead of RSA keys. It is also described.
Key length of RSA
=================
In 2005, NIST (National Institute of Standards and Technology, USA)
issued the first revision of NIST Special Publication 800-57,
"Recommendation for Key Management".
In 800-57, NIST advises that 1024-bit RSA keys will no longer be
viable after 2010 and advises moving to 2048-bit RSA keys. NIST
advises that 2048-bit keys should be viable until 2030.
As of 2016, GnuPG's default for generating RSA key is 2048-bit.
Some people have preference on RSA 4096-bit keys, considering "longer is better".
However, "longer is better" is not always true. When it's long, it
requires more computational resource, memory, and storage. Further,
it consumes more power for nomal usages. These days, many people has
enough computational resource, that would be true, but less is better
for power consumption, isn't it?
For security, the key length is just a single factor. We had and will have
algorithm issues, too. It is true that it's difficult to update
our public keys, but this problem wouldn't be solved by just having
longer keys.
We deliberately recommend use of RSA 2048-bit keys for Gnuk,
considering device computation power and host software constraints.
Thus, the key size is 2048-bit in the examples below.
When/If your environment allows use of newer ECC keys, newer ECC keys are recommended.
Generating RSA keys on host PC
==============================
Here is the example session to generate main key and a subkey for encryption.
I invoke GnuPG with ``--quick-gen-key`` option. ::
$ gpg --quick-gen-key "Niibe Yutaka <gniibe@fsij.org>"
About to create a key for:
"Niibe Yutaka <gniibe@fsij.org>"
Continue? (Y/n) y
It askes passphrase for this **key on host PC**.
Note that this is a passphrase for the key on host PC.
It is different thing to the passphrase of Gnuk Token.
We enter two same inputs two times
(once for passphrase input, and another for confirmation),
<PASSWORD-KEY-ON-PC>.
Then, GnuPG generate keys. It takes some time. ::
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 76A9392B02CD15D1 marked as ultimately trusted
gpg: revocation certificate stored as '/home/gniibe.gnupg/openpgp-revocs.d/36CE0B8408CFE5CD07F94ACF76A9392B02CD15D1.rev'
public and secret key created and signed.
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub rsa2048 2016-06-20 [S]
36CE0B8408CFE5CD07F94ACF76A9392B02CD15D1
uid [ultimate] Niibe Yutaka <gniibe@fsij.org>
sub rsa2048 2016-06-20 []
Done.
Then, we create authentication subkey.
Authentication subkey is not that common,
but very useful (for SSH authentication).
As it is not that common, we need ``--expert`` option for GnuPG. ::
gpg (GnuPG) 2.1.13; Copyright (C) 2016 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec rsa2048/76A9392B02CD15D1
created: 2016-06-20 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa2048/4BD1EB26F0E607E6
created: 2016-06-20 expires: never usage: E
[ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
gpg>
Here, it displays that there are main key and a subkey.
It prompts sub-command with ``gpg>`` .
Here, we enter ``addkey`` sub-command.
gpg> addkey
GnuPG asks kind of key. We select ``RSA (set your own capabilities)``. ::
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
Your selection? 8
And select ``Authenticate`` for the capabilities for this key.
Initially, it's ``Sign`` and ``Encrypt``.
I need to deselect ``Sign`` and ``Encrypt``, and select ``Authenticate``.
To do that, I enter ``s``, ``e``, and ``a``. ::
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? e
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions:
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? a
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
OK, we set the capability of ``Authenticate``.
We enter ``q`` to finish setting capabilities. ::
Your selection? q
GnuPG asks bitsize and expiration, we enter 2048 for bitsize and no expiration.
Then, we confirm that we really create the key. ::
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
Then, it askes the passphrase, it is the passphrase of **key on host PC**.
It's the one we entered above as <PASSWORD-KEY-ON-PC>.
Then, GnuPG generate the key. ::
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec rsa2048/76A9392B02CD15D1
created: 2016-06-20 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa2048/4BD1EB26F0E607E6
created: 2016-06-20 expires: never usage: E
ssb rsa2048/F3BA52C64012198D
created: 2016-06-20 expires: never usage: A
[ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
gpg>
We save the key (to the storage of the host PC). ::
gpg> save
$
Now, we have three keys (one primary key for signature and certification,
subkey for encryption, and another subkey for authentication).
Publishing public key
=====================
We make a file for the public key by ``--export`` option of GnuPG. ::
$ gpg --armor --output <YOUR-KEY>.asc --export <YOUR-KEY-ID>
We can publish the file by web server. Or we can publish the key
to a keyserver, by invoking GnuPG with ``--send-keys`` option. ::
$ gpg --keyserver pool.sks-keyservers.net --send-keys <YOUR-KEY-ID>
Here, pool.sks-keyservers.net is a keyserver, which is widely used.
Backup the private key
======================
There are some ways to back up private key, such that backup .gnupg
directory entirely, or use of paperkey, etc.
Here, we describe backup by ASCII file.
ASCII file is good, because it has less risk on transfer.
Binary file has a risk to be modified on transfer.
Note that the key on host PC is protected by passphrase (which
is <PASSWORD-KEY-ON-PC> in the example above). Using the key
from the backup needs this passphrase. It is common that
people will forget passphrase for backup. Never forget it.
You have been warned.
To make ASCII backup for private key,
invokde GnuPG with ``--armor`` option and ``--export-secret-keys``
specifying the key identifier. ::
$ gpg --armor --output <YOUR-SECRET>.asc --export-secret-keys <YOUR-KEY-ID>
From the backup,
we can recover privet key by invoking GnuPG with ``--import`` option. ::
$ gpg --import <YOUR-SECRET>.asc
Generating ECC keys on host PC
==============================
Here is an example session log to create newer ECC keys. You need
libgcrypt 1.7 or newer and GnuPG 2.1.8 or newer.
Next, we invoke gpg frontend with ``--expert`` and ``--full-gen-key`` option. ::
$ gpg --expert --full-gen-key
gpg (GnuPG) 2.1.13; Copyright (C) 2016 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Then, we input ``9`` to select ECC primary key and ECC encryption subkey. ::
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC and ECC
(10) ECC (sign only)
(11) ECC (set your own capabilities)
Your selection? 9
Next is the important selection. We input ``1`` to select "Curve25519". ::
Please select which elliptic curve you want:
(1) Curve 25519
(2) NIST P-256
(3) NIST P-384
(4) NIST P-521
(5) Brainpool P-256
(6) Brainpool P-384
(7) Brainpool P-512
(8) secp256k1
Your selection? 1
You may see WARNING (it depends on version of GnuPG) and may been asked. Since it is what you want, please answer with 'y'. ::
gpg: WARNING: Curve25519 is not yet part of the OpenPGP standard.
Use this curve anyway? (y/N) y
It asks about expiration of key. ::
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
Then, it asks about a user ID. ::
GnuPG needs to construct a user ID to identify your key.
Real name: Kunisada Chuji
Email address: chuji@gniibe.org
Comment:
You selected this USER-ID:
"Kunisada Chuji <chuji@gniibe.org>"
Lastly, it asks confirmation. ::
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
Then, it goes like this. ::
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
It asks the passphrase for keys by pop-up window, and then, finishes. ::
gpg: key 17174C1A7C406DB5 marked as ultimately trusted
gpg: revocation certificate stored as '/home/gniibe.gnupg/openpgp-revocs.d/1719874a4fe5a1d8c465277d5a1bb27e3000f4ff.rev'
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 6 signed: 67 trust: 0-, 0q, 0n, 0m, 0f, 6u
gpg: depth: 1 valid: 67 signed: 40 trust: 67-, 0q, 0n, 0m, 0f, 0u
gpg: next trustdb check due at 2016-10-05
pub ed25519 2016-07-08
F478770235B60A230BE78005006A236C292C31D7
uid [ultimate] Kunisada Chuji <chuji@gniibe.org>
sub cv25519 2016-07-08
$
We have the primary key with ed25519, and encryption subkey with cv25519.
Next, we add authentication subkey which can be used with OpenSSH.
We invoke gpg frontend with ``--edit-key`` and the key ID. ::
$ gpg2 --expert --edit-key 17174C1A7C406DB5
gpg (GnuPG) 2.1.13; Copyright (C) 2016 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec ed25519/17174C1A7C406DB5
created: 2016-07-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/37A03183DF7B31B1
created: 2016-07-08 expires: never usage: E
[ultimate] (1). Kunisada Chuji <chuji@gniibe.org>
We invoke ``addkey`` subcommand. ::
gpg> addkey
It asks a kind of key, we input ``11`` to select ECC for authentication. ::
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
Your selection? 11
and then, we specify "Authenticate" capability. ::
Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Sign
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? a
Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Sign Authenticate
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
Then, it asks which curve. We input ``1`` for "Curve25519". ::
Please select which elliptic curve you want:
(1) Curve 25519
(2) NIST P-256
(3) NIST P-384
(4) NIST P-521
(5) Brainpool P-256
(6) Brainpool P-384
(7) Brainpool P-512
(8) secp256k1
Your selection? 1
It may ask confirmation with WARNING (depends on version). We say ``y``. ::
gpg: WARNING: Curve25519 is not yet part of the OpenPGP standard.
Use this curve anyway? (y/N) y
It asks expiration of the key. ::
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
And the confirmation. ::
Really create? (y/N) y
It goes. ::
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
It asks the passphrase. And done. ::
sec ed25519/17174C1A7C406DB5
created: 2016-09-08 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/37A03183DF7B31B1
created: 2016-09-08 expires: never usage: E
ssb ed25519/4AD7D2428679DF5F
created: 2016-09-08 expires: never usage: A
[ultimate] (1). Kunisada Chuji <chuji@gniibe.org>
We type ``save`` to exit form gpg. ::
gpg> save
$

View File

@@ -1,42 +0,0 @@
===========================================
GnuPG settings for GNOME 3.1x and GNOME 3.0
===========================================
In the section `GnuPG settings`_, I wrote how I disable GNOME-keyrings for SSH.
It was for GNOME 2. The old days was good, we just disabled GNOME-keyrings
interference to SSH and customizing our desktop was easy for GNU and UNIX users.
.. _GnuPG settings: gpg-settings
GNOME keyrings in GNOME 3.1x
============================
In the files /etc/xdg/autostart/gnome-keyring-ssh.desktop
and /etc/xdg/autostart/gnome-keyring-gpg.desktop,
we have a line something like: ::
OnlyShowIn=GNOME;Unity;MATE;
Please edit this line to: ::
OnlyShowIn=
Then, no desktop environment invokes gnome-keyring for ssh and gpg. I think that it is The Right Thing.
GNOME keyrings in GNOME 3.0 by GNOME-SESSION-PROPERTIES
=======================================================
We can't use GNOME configuration tool (like GNOME 2) to disable interference by
GNOME keyrings in GNOME 3.0.
It is GNOME-SESSION-PROPERTIES to disable the interference. Invoking::
$ gnome-session-properties
and at the tab of "Startup Programs", I removed radio check buttons
for "GPG Password Agent" and "SSH Key Agent".
Then, I can use proper gpg-agent for GnuPG Agent Service and SSH Agent Service with Gnuk Token in GNOME 3.0.

View File

@@ -10,7 +10,7 @@ I don't save changes on PC after keytocard.
For the steps before the last step, please see `keytocard with removing keys on PC`_.
.. _keytocard removing keys: gnuk-keytocard
.. _keytocard with removing keys on PC: gnuk-keytocard
Here is the session log of the last step.
@@ -22,4 +22,4 @@ Lastly, I quit GnuPG. Note that I **don't** save changes. ::
$
All keys are imported to Gnuk Token now.
Still, secret keys are available on PC.
Still, secret keys are available on PC, too.

View File

@@ -24,31 +24,29 @@ After personalization, I put my keys into the Token.
Here is the session log.
I invoke GnuPG with my key (4ca7babe). ::
I invoke GnuPG with my key (249CB3771750745D5CDD323CE267B052364F028D). ::
$ gpg --edit-key 4ca7babe
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
$ gpg --edit-key 249CB3771750745D5CDD323CE267B052364F028D
gpg (GnuPG) 2.1.13; Copyright (C) 2016 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@debian.org>
[ultimate] (2) NIIBE Yutaka <gniibe@fsij.org>
gpg>
Then, GnuPG enters its own command interaction mode. The prompt is ``gpg>``.
To enable ``keytocard`` command, I type ``toggle`` command. ::
gpg> toggle
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
ssb 2048R/084239CF created: 2010-10-15 expires: never
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
(1) NIIBE Yutaka <gniibe@fsij.org>
Firstly, I import my primary key into Gnuk Token.
I type ``keytocard`` command, answer ``y`` to confirm keyimport,
@@ -56,135 +54,129 @@ and type ``1`` to say it's signature key. ::
gpg> keytocard
Really move the primary key? (y/N) y
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
Then, GnuPG asks two passwords. One is the passphrase of **keys on PC**
and another is the password of **Gnuk Token**. Note that the password of
the token and the password of the keys on PC are different things,
Then, GnuPG asks two kinds of passphrases. One is the passphrase of **keys on PC**
and another is the passphrase of **Gnuk Token**. Note that the passphrase of
the token and the passphrase of the keys on PC are different things,
although they can be same.
Here, I assume that Gnuk Token's admin password of factory setting (12345678).
Here, I assume that Gnuk Token's admin passphrase of factory setting (12345678).
I enter these passwords. ::
I enter these passphrases. ::
You need a passphrase to unlock the secret key for
user: "NIIBE Yutaka <gniibe@fsij.org>"
2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
<PASSWORD-KEY-4CA7BABE>
gpg: writing new key
gpg: 3 Admin PIN attempts remaining before card is permanently locked
Please enter your passphrase, so that the secret key can be unlocked for this session
<PASSWORD-KEY-ON-PC>
Please enter the Admin PIN
Enter Admin PIN: 12345678
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb 2048R/084239CF created: 2010-10-15 expires: never
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
(1) NIIBE Yutaka <gniibe@fsij.org>
The primary key is now on the Token and GnuPG says its card-no (F517 00000001),
where F517 is the vendor ID of FSIJ.
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
Secondly, I import my subkey of encryption. I select key number '1'. ::
gpg> key 1
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb* 2048R/084239CF created: 2010-10-15 expires: never
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
(1) NIIBE Yutaka <gniibe@fsij.org>
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
You can see that the subkey is marked by '*'.
I type ``keytocard`` command to import this subkey to Gnuk Token.
I select ``2`` as it's encryption key. ::
gpg> keytocard
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
Please select where to store the key:
(2) Encryption key
Your selection? 2
Then, GnuPG asks the passphrase of **keys on PC** again. I enter. ::
You need a passphrase to unlock the secret key for
user: "NIIBE Yutaka <gniibe@fsij.org>"
2048-bit RSA key, ID 084239CF, created 2010-10-15
<PASSWORD-KEY-4CA7BABE>
gpg: writing new key
Please enter your passphrase, so that the secret key can be unlocked for this session
<PASSWORD-KEY-ON-PC>
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb* 2048R/084239CF created: 2010-10-15 expires: never
card-no: F517 00000001
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
(1) NIIBE Yutaka <gniibe@fsij.org>
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
The sub key is now on the Token.
The sub key is now on the Token and GnuPG says its card-no for it.
I type ``key 1`` to deselect key number '1'. ::
gpg> key 1
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb 2048R/084239CF created: 2010-10-15 expires: never
card-no: F517 00000001
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
(1) NIIBE Yutaka <gniibe@fsij.org>
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
Thirdly, I select sub key of authentication which has key number '2'. ::
gpg> key 2
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb 2048R/084239CF created: 2010-10-15 expires: never
card-no: F517 00000001
ssb* 2048R/5BB065DC created: 2010-10-22 expires: never
(1) NIIBE Yutaka <gniibe@fsij.org>
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb* ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
You can see that the subkey number '2' is marked by '*'.
I type ``keytocard`` command to import this subkey to Gnuk Token.
I select ``3`` as it's authentication key. ::
gpg> keytocard
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
Please select where to store the key:
(3) Authentication key
Your selection? 3
Then, GnuPG asks the passphrase of **keys on PC** again. I enter. ::
You need a passphrase to unlock the secret key for
user: "NIIBE Yutaka <gniibe@fsij.org>"
2048-bit RSA key, ID 5BB065DC, created 2010-10-22
<PASSWORD-KEY-4CA7BABE>
gpg: writing new key
Please enter your passphrase, so that the secret key can be unlocked for this session
<PASSWORD-KEY-ON-PC>
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb 2048R/084239CF created: 2010-10-15 expires: never
card-no: F517 00000001
ssb* 2048R/5BB065DC created: 2010-10-22 expires: never
card-no: F517 00000001
(1) NIIBE Yutaka <gniibe@fsij.org>
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb* ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
The sub key is now on the Token and GnuPG says its card-no for it.
The sub key is now on the Token.
Lastly, I save changes of **keys on PC** and quit GnuPG. ::

View File

@@ -22,41 +22,40 @@ Besides, some people sometimes prefer the word "passphrase" to
same thing and it just refer user-password or admin-password.
Set up PW1, PW3 and reset code
==============================
Set up PW1 and PW3
==================
Invoke GnuPG with the option ``--card-edit``. ::
$ gpg --card-edit
Application ID ...: D276000124010200F517000000010000
Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
Application ID ...: D276000124010200FFFE871930590000
Version ..........: 2.0
Manufacturer .....: FSIJ
Serial number ....: 00000001
Manufacturer .....: unmanaged S/N range
Serial number ....: 87193059
Name of cardholder: Yutaka Niibe
Language prefs ...: ja
Sex ..............: male
URL of public key : http://www.gniibe.org/gniibe.asc
URL of public key : http://www.gniibe.org/gniibe-20150813.asc
Login data .......: gniibe
Signature PIN ....: not forced
Key attributes ...: 2048R 2048R 2048R
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE
created ....: 2010-10-15 06:46:33
Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF
created ....: 2010-10-15 06:46:33
Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC
created ....: 2010-10-22 06:06:36
General key info..:
pub 2048R/4CA7BABE 2010-10-15 NIIBE Yutaka <gniibe@fsij.org>
sec> 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb> 2048R/084239CF created: 2010-10-15 expires: never
card-no: F517 00000001
ssb> 2048R/5BB065DC created: 2010-10-22 expires: never
card-no: F517 00000001
Signature key ....: 249C B377 1750 745D 5CDD 323C E267 B052 364F 028D
created ....: 2015-08-12 07:10:48
Encryption key....: E228 AB42 0F73 3B1D 712D E50C 850A F040 D619 F240
created ....: 2015-08-12 07:10:48
Authentication key: E63F 31E6 F203 20B5 D796 D266 5F91 0521 FAA8 05B1
created ....: 2015-08-12 07:16:14
General key info..: pub ed25519/E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
sec> ed25519/E267B052364F028D created: 2015-08-12 expires: never
card-no: FFFE 87193059
ssb> cv25519/850AF040D619F240 created: 2015-08-12 expires: never
card-no: FFFE 87193059
ssb> ed25519/5F910521FAA805B1 created: 2015-08-12 expires: never
card-no: FFFE 87193059
gpg/card>
It shows the status of the card (as same as the output of ``gpg --card-status``).
@@ -71,7 +70,7 @@ Note that *the length of PIN should be more than (or equals to) 8* for
"admin less mode". ::
gpg/card> passwd
gpg: OpenPGP card no. D276000124010200F517000000010000 detected
gpg: OpenPGP card no. D276000124010200FFFE871930590000 detected
Please enter the PIN
Enter PIN: 123456
@@ -94,15 +93,24 @@ please change admin-password at first.
Then, the token works as same as OpenPGPcard specification
with regards to PW1 and PW3.)
Lastly, I setup reset code, entering admin mode.
Having reset code, you can unblock PIN when the token will be blocked
(by wrong attempt to entering PIN). This is optional step. ::
Set up of reset code (optional)
===============================
Lastly, we can setup reset code, entering admin mode.
Having reset code, we can unblock the token when the token will be blocked
(by wrong attempts to entering passphrase). Note that this is optional step.
When reset code is known to someone, that person can try to guess your passphrase of PW1 more times by unblocking the token. So, I don't use this feature by myself.
If we do, here is the interaction. ::
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. D276000124010200F517000000010000 detected
gpg: OpenPGP card no. D276000124010200FFFE871930590000 detected
1 - change PIN
2 - unblock PIN
@@ -135,4 +143,4 @@ Then, I quit. ::
gpg/card> quit
That's all.
That's all in this step.

View File

@@ -9,17 +9,19 @@ Personalize your Gnuk Token
Invoke GnuPG with the option ``--card-edit``. ::
$ gpg --card-edit
Application ID ...: D276000124010200FFFE330069060000
Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
Application ID ...: D276000124010200FFFE871930590000
Version ..........: 2.0
Manufacturer .....: unmanaged S/N range
Serial number ....: 33006906
Serial number ....: 87193059
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: 2048R 2048R 2048R
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
@@ -58,7 +60,7 @@ login, and URL. URL specifies the place where I put my public keys. ::
Sex ((M)ale, (F)emale or space): m
gpg/card> url
URL to retrieve public key: http://www.gniibe.org/gniibe.asc
URL to retrieve public key: http://www.gniibe.org/gniibe-20150813.asc
gpg/card> login
Login data (account name): gniibe
@@ -72,4 +74,4 @@ Then, I quit. ::
gpg/card> quit
That's all.
That's all in this step.

View File

@@ -27,13 +27,15 @@ Make sure there is no ``scdaemon`` for configuring Gnuk Token. You can kill ``
Serial Number (optional)
========================
Note that this is completely optional step. I don't know anyone other than me, do this. Even for me, I only do that for a single device among multiple devices I use. I do that to test the feature.
In the file ``GNUK_SERIAL_NUMBER``, each line has email and 6-byte serial number. The first two bytes are organization number (F5:17 is for FSIJ). Last four bytes are number for tokens.
The tool ``../tool/gnuk_put_binary_libusb.py`` examines environment variable of ``EMAIL``, and writes corresponding serial number to Gnuk Token. ::
$ ../tool/gnuk_put_binary_libusb.py -s ../GNUK_SERIAL_NUMBER
Writing serial number
Device: 006
Device:
Configuration: 1
Interface: 0
d2 76 00 01 24 01 02 00 f5 17 00 00 00 01 00 00

View File

@@ -12,35 +12,38 @@ Here is my GnuPG settings.
I create ``.gnupg/gpg.conf`` file with the following content. ::
use-agent
personal-digest-preferences SHA256
cert-digest-algo SHA256
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
default-key 0xE267B052364F028D
default-key 0x4ca7babe
In addition to the ``use-agent`` option, set preferences on algorithms, and specify my default key.
In addition to the ``use-agent`` option, I specify my default key.
The ``use-agent`` option is for GnuPG 1.4.x and it means using gpg-agent if available.
If no option, GnuPG 1.4.x directly connects to Gnuk Token by itself, instead of through scdaemon. When GnuPG 1.4.x tries to access Gnuk Token and scdaemon is running, there are conflicts.
We recommend to specify the ``use-agent`` option for GnuPG 1.4.x to access Gnuk Token through gpg-agent and scdaemon.
For GnuPG 2.0.x, gpg-agent is always used, so there is no need to specify the ``use-agent`` option, but having this option is no harm, anyway.
For GnuPG 2.0 and 2.1, gpg-agent is always used, so, there is no need to specify the ``use-agent`` option, but having this option is no harm, anyway.
Let gpg-agent manage SSH key
============================
I deactivate seahorse-agent. Also, for GNOME 2, I deactivate gnome-keyring managing SSH key. ::
$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
I edit the file /etc/X11/Xsession.options and comment out use-ssh-agent line.
Then, I create ``.gnupg/gpg-agent.conf`` file with the following content. ::
I create ``.gnupg/gpg-agent.conf`` file with the following content. ::
enable-ssh-support
I edit the file /etc/X11/Xsession.options and comment out use-ssh-agent line,
so that Xsession doesn't invoke original ssh-agent. We use gpg-agent as ssh-agent.
In the files /etc/xdg/autostart/gnome-keyring-ssh.desktop,
I have a line something like: ::
OnlyShowIn=GNOME;Unity;MATE;
I edit this line to: ::
OnlyShowIn=
So that no desktop environment enables gnome-keyring for ssh.
References
==========

View File

@@ -2,8 +2,8 @@
sphinx-quickstart on Wed Jul 4 15:29:05 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Copyright (C) 2012, 2013 NIIBE Yutaka
Copyright (C) 2012, 2013 Free Software Initiative of Japan
Copyright (C) 2012, 2013, 2016 NIIBE Yutaka
Copyright (C) 2012, 2013, 2016 Free Software Initiative of Japan
This document is licensed under a CC-BY-SA 3.0 Unported License
Gnuk Documentation
@@ -20,12 +20,11 @@ Contents:
udev-rules.rst
gnuk-token-initial-configuration.rst
gnuk-personalization.rst
generating-2048-RSA-key.rst
generating-key.rst
gnuk-keytocard.rst
gnuk-keytocard-noremoval.rst
gnuk-passphrase-setting.rst
using-gnuk-token-with-another-computer.rst
gnome3-gpg-settings.rst
development.rst

View File

@@ -9,6 +9,8 @@ Gnuk is an implementation of USB cryptographic token for GNU Privacy
Guard. Gnuk supports OpenPGP card protocol version 2, and it runs on
STM32F103 processor.
This document explains about Gnuk 1.2, which comes with ECC algorithm.
Cryptographic token and feature of Gnuk
---------------------------------------
@@ -31,15 +33,15 @@ Target boards for running Gnuk
------------------------------
Hardware requirement for Gnuk is the micro controller STM32F103.
In version 1.1.x, Gnuk supports following boards.
In version 1.2, Gnuk supports following boards.
* FST-01 (Flying Stone Tiny ZERO-ONE)
* Olimex STM32-H103
* STM32 part of STM8S Discovery Kit
* ST Nucleo F103
* STBee
* Nitrokey Start
Host prerequisites for using Gnuk Token
@@ -49,11 +51,9 @@ Host prerequisites for using Gnuk Token
* libusb
* [Optional] PC/SC lite (pcscd, libccid)
* [Optional] SSH: openssh
* [optional] Web: scute, firefox
* [experimental] Web: scute, firefox
Usages
@@ -62,4 +62,4 @@ Usages
* Sign with GnuPG
* Decrypt with GnuPG
* Use with OpenSSH through gpg-agent (as ssh-agent)
* Use with Firefox through Scute for X.509 client certificate authentication
* [experimental] Use with Firefox through Scute for X.509 client certificate authentication

View File

@@ -50,39 +50,9 @@ With the script below, I extract public key of the keygrip
$ ./get_raw_public_key.py 5D6C89682D07CCFC034AF508420BF2276D8018ED
Here is the script, get_raw_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()
(The script is available in the directory gnuk/tool. Please note that
it was written in the early stage of the development. The quality of
the code is somewhat questionable.)
Then, we can put the data of public key into token by::

View File

@@ -28,10 +28,16 @@ To stop SCDAEMON and let it exit, type::
Then, you can confirm that there is no SCDAEMON any more by ``ps``
command.
Or, you can use ``gpgconf`` command. Type::
$ gpgconf --reload scdameon
will do the samething.
Let GPG-AGENT/SCDAEMON learn
============================
To let gpg-agent/scdaemon learn from Gnuk Token, type::
To let gpg-agent/scdaemon "learn" from Gnuk Token, type::
$ gpg-connect-agent learn /bye

View File

@@ -10,10 +10,13 @@ PC/SC Lite, as it has its own device configuration.
udev rules for Gnuk Token
=========================
In case of Debian, there is a file /lib/udev/rules.d/60-gnupg.rules,
when you install "gnupg" package. This is the place we need to
change, if your installation is older (than jessie). Newer "gnupg"
package (1.4.15-1 or later) has already supported Gnuk Token.
In case of Debian, there is a file /lib/udev/rules.d/60-gnupg.rules
(or /lib/udev/rules.d/60-scdamon.rules for newer version),
when you install "gnupg" package (or "scdaemon" package).
This is the place we need to
change, if your installation is older than jessie. Newer "gnupg"
package (1.4.15-1 or later) or "scdaemon" package has already
supported Gnuk Token.
If needed, please add lines for Gnuk Token to give a desktop user the
permission to use the device. We specify USB ID of Gnuk Token (by
@@ -30,7 +33,7 @@ FSIJ)::
+
LABEL="gnupg_rules_end"
When we install "gnupg2" package only (with no "gnupg" package),
When we only install "gnupg2" package for 2.0 (with no "gnupg" package),
there will be no udev rules (there is a bug report #543217 for this issue).
In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules::

View File

@@ -12,90 +12,90 @@ while ``.gnupg`` directory contains keyrings and trustdb, too.
Fetch the public key and connect it to the Token
================================================
Using the Token, we need to put the public key and the secret
key reference (to the token) in ``.gnupg``.
In order to use the Token, we need to put the public key and the secret
key references (to the token) under ``.gnupg`` directory.
To do that, invoke GnuPG with ``--card-edit`` option. ::
$ gpg --card-edit
Application ID ...: D276000124010200F517000000010000
Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
Application ID ...: D276000124010200FFFE871930590000
Version ..........: 2.0
Manufacturer .....: FSIJ
Serial number ....: 00000001
Manufacturer .....: unmanaged S/N range
Serial number ....: 87193059
Name of cardholder: Yutaka Niibe
Language prefs ...: ja
Sex ..............: male
URL of public key : http://www.gniibe.org/gniibe.asc
URL of public key : http://www.gniibe.org/gniibe-20150813.asc
Login data .......: gniibe
Signature PIN ....: not forced
Key attributes ...: 2048R 2048R 2048R
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 6
Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE
created ....: 2010-10-15 06:46:33
Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF
created ....: 2010-10-15 06:46:33
Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC
created ....: 2010-10-22 06:06:36
Signature counter : 0
Signature key ....: 249C B377 1750 745D 5CDD 323C E267 B052 364F 028D
created ....: 2015-08-12 07:10:48
Encryption key....: E228 AB42 0F73 3B1D 712D E50C 850A F040 D619 F240
created ....: 2015-08-12 07:10:48
Authentication key: E63F 31E6 F203 20B5 D796 D266 5F91 0521 FAA8 05B1
created ....: 2015-08-12 07:16:14
General key info..: [none]
gpg/card>
It says, there is no key info related to this token on your PC (``[none]``).
Here, the secret key references (to the token) are created under ``.gnupg/private-keys-v1.d`` directory. It can be also created when I do ``--card-status`` by GnuPG.
Fetch the public key from URL specified in the Token. ::
Still, it says that there is no key info related to this token on my PC (``[none]`` for General key info), because I don't have the public key on this PC yet.
So, I fetch the public key from URL specified in the Token. ::
gpg/card> fetch
gpg: requesting key 4CA7BABE from http server www.gniibe.org
gpg: key 4CA7BABE: public key "NIIBE Yutaka <gniibe@fsij.org>" imported
gpg: no ultimately trusted keys found
gpg: requesting key E267B052364F028D from http server www.gniibe.org
gpg: key E267B052364F028D: public key "NIIBE Yutaka <gniibe@fsij.org>" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
gpg: imported: 1
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 6 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 6u
gpg/card>
Good. The public key is now in ``.gnupg``. We can examine by ``gpg --list-keys``.
Good. The public key is now under ``.gnupg`` directory. We can examine by ``gpg --list-keys``.
However, the secret key reference (to the token) is not in ``.gnupg`` yet.
When I type return at the ``gpg/card>`` prompt, now, I can see: ::
It will be generated when I do ``--card-status`` by GnuPG with
correspoinding public key in ``.gnupg``, or just type return
at the ``gpg/card>`` prompt. ::
gpg/card>
Application ID ...: D276000124010200F517000000010000
Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
Application ID ...: D276000124010200FFFE871930590000
Version ..........: 2.0
Manufacturer .....: FSIJ
Serial number ....: 00000001
Manufacturer .....: unmanaged S/N range
Serial number ....: 87193059
Name of cardholder: Yutaka Niibe
Language prefs ...: ja
Sex ..............: male
URL of public key : http://www.gniibe.org/gniibe.asc
URL of public key : http://www.gniibe.org/gniibe-20150813.asc
Login data .......: gniibe
Signature PIN ....: not forced
Key attributes ...: 2048R 2048R 2048R
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 6
Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE
created ....: 2010-10-15 06:46:33
Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF
created ....: 2010-10-15 06:46:33
Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC
created ....: 2010-10-22 06:06:36
General key info..:
pub 2048R/4CA7BABE 2010-10-15 NIIBE Yutaka <gniibe@fsij.org>
sec> 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb> 2048R/084239CF created: 2010-10-15 expires: never
card-no: F517 00000001
ssb> 2048R/5BB065DC created: 2010-10-22 expires: never
card-no: F517 00000001
Signature counter : 0
Signature key ....: 249C B377 1750 745D 5CDD 323C E267 B052 364F 028D
created ....: 2015-08-12 07:10:48
Encryption key....: E228 AB42 0F73 3B1D 712D E50C 850A F040 D619 F240
created ....: 2015-08-12 07:10:48
Authentication key: E63F 31E6 F203 20B5 D796 D266 5F91 0521 FAA8 05B1
created ....: 2015-08-12 07:16:14
General key info..: pub ed25519/E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
sec> ed25519/E267B052364F028D created: 2015-08-12 expires: never
card-no: FFFE 87193059
ssb> cv25519/850AF040D619F240 created: 2015-08-12 expires: never
card-no: FFFE 87193059
ssb> ed25519/5F910521FAA805B1 created: 2015-08-12 expires: never
card-no: FFFE 87193059
gpg/card>
Note that, it displays the information about "General key info".
OK, now I can use the Token on this computer.
@@ -103,33 +103,43 @@ Update trustdb for the key on Gnuk Token
========================================
Yes, I can use the Token by the public key and the secret
key reference to the card. More, I need to update the trustdb.
key references to the card. More, I need to update the trustdb.
To do that I do: ::
To do that, I do: ::
$ gpg --edit-key 4ca7babe
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
$ ./gpg --edit-key E267B052364F028D
gpg (GnuPG) 2.1.13; Copyright (C) 2016 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
trust: unknown validity: unknown
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
card-no: FFFE 87193059
trust: unknown validity: unknown
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
card-no: FFFE 87193059
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
card-no: FFFE 87193059
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
gpg>
See, the key is ``unknown`` state. Add trust for that. ::
See, the key is ``unknown`` state. Add trust for that, because it's the key under my control. ::
gpg> trust
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
trust: unknown validity: unknown
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
card-no: FFFE 87193059
trust: unknown validity: unknown
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
card-no: FFFE 87193059
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
card-no: FFFE 87193059
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
@@ -146,32 +156,49 @@ See, the key is ``unknown`` state. Add trust for that. ::
Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
trust: ultimate validity: unknown
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
card-no: FFFE 87193059
trust: ultimate validity: unknown
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
card-no: FFFE 87193059
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
card-no: FFFE 87193059
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
$
gpg>
Next time I invoke GnuPG, it will be ``ultimate`` key. Let's see: ::
And I quit from gpg. Then, when I invoke GnuPG, it will be ``ultimate`` key. Let's see: ::
$ gpg --edit-key 4ca7babe
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
$ ./gpg --edit-key E267B052364F028D
gpg (GnuPG) 2.1.13; Copyright (C) 2016 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 7 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 7u
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
card-no: FFFE 87193059
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
card-no: FFFE 87193059
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
card-no: FFFE 87193059
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
gpg> quit
$
$
OK, all set. I'm ready to use my Gnuk Token on this PC.

7
docker/Dockerfile.check Normal file
View File

@@ -0,0 +1,7 @@
FROM gnuk:latest
LABEL Description="Image for checking gnuK"
RUN apt install -y shellcheck
RUN apt install -y clang libfindbin-libs-perl
RUN apt clean

4
docker/Dockerfile.debug Normal file
View File

@@ -0,0 +1,4 @@
FROM gnuk:latest
LABEL Description="Image for building gnuK with debugging"
RUN apt install -y gdb-arm-none-eabi && apt clean

View File

@@ -0,0 +1,6 @@
FROM debian:latest
LABEL Description="Image for building gnuK"
RUN apt update -y && apt install -y make gcc-arm-none-eabi && apt clean
CMD ["/bin/sh", "-c", "cd /gnuk/src && make clean && ./configure $GNUK_CONFIG && make"]

36
docker/Makefile Normal file
View File

@@ -0,0 +1,36 @@
ifndef GNUK_CONFIG
$(warning configuration flags not set in GNUK_CONFIG)
endif
all: ../chopstx docker-build-release
docker run --user=`id -u` --env GNUK_CONFIG --rm -v `pwd`/..:/gnuk/ -t gnuk:latest
clean: docker-build-release
docker run --user=`id -u` --env GNUK_CONFIG --rm -v `pwd`/..:/gnuk/ -w /gnuk/src -t gnuk:latest make clean
gdb: docker-build-debug
docker run --net host --rm -i -v `pwd`/..:/gnuk/ -t gnuk:latest-debug arm-none-eabi-gdb /gnuk/src/build/gnuk.elf
shellcheck: docker-build-check
docker run --rm -v `pwd`/..:/gnuk/ -t gnuk:latest-check shellcheck /gnuk/src/configure
CHECKERS=security optin nullability core deadcode alpha.core alpha.security
scan-build: clean docker-build-check
docker run --user=`id -u` --rm -v `pwd`/..:/gnuk/ -w /gnuk/src -t gnuk:latest-check scan-build -o scan-build \
-analyze-headers -stats $(addprefix -enable-checker ,$(CHECKERS)) -k \
--use-cc=arm-none-eabi-gcc \
make
../chopstx:
git submodule update --init
docker-build-release:
docker build -t gnuk:latest -f `pwd`/Dockerfile.release ..
docker-build-debug: docker-build-release
docker build -t gnuk:latest-debug -f `pwd`/Dockerfile.debug ..
docker-build-check: docker-build-release
docker build -t gnuk:latest-check -f `pwd`/Dockerfile.check ..
.PHONY: all clean gdb shellcheck scan-build \
docker-build-release docker-build-debug docker-build-check

31
emulation/Makefile Normal file
View File

@@ -0,0 +1,31 @@
SRCS = usbip-server.c usb-emu.c glue.c
OBJS = $(SRCS:.c=.o)
TARGET=gnuk_emulation
GNUKDIR=../src
GNUK_SRCS = main.c call-rsa.c \
usb-ccid.c openpgp.c ac.c openpgp-do.c flash.c \
bn.c mod.c \
modp256r1.c jpc_p256r1.c ec_p256r1.c call-ec_p256r1.c \
modp256k1.c jpc_p256k1.c ec_p256k1.c call-ec_p256k1.c \
mod25638.c ecc-edwards.c ecc-mont.c sha512.c \
random.c neug.c sha256.c
USB_SRCS=usb_desc.c usb_ctrl.c
GNUK_CSRC = $(addprefix $(GNUKDIR)/, $(GNUK_SRCS))
GNUK_OBJS = $(notdir $(GNUK_CSRC:.c=.o))
USB_CSRC = $(addprefix $(GNUKDIR)/, $(USB_SRCS))
USB_OBJS = $(notdir $(USB_CSRC:.c=.o))
# all:
# echo $(GNUK_OBJS)
$(TARGET): $(OBJS) $(USB_OBJS) Makefile
$(CC) -o $(TARGET) $(OBJS) $(USB_OBJS)
$(GNUK_OBJS): %.o : $(GNUKDIR)/%.c Makefile
$(CC) -c $(CFLAGS) -I. -I$(GNUKDIR) -I../chopstx $< -o $@
$(USB_OBJS): %.o : $(GNUKDIR)/%.c Makefile
$(CC) -c $(CFLAGS) -I. -I$(GNUKDIR) -I../chopstx $< -o $@

54
emulation/glue.c Normal file
View File

@@ -0,0 +1,54 @@
#include <stdint.h>
uint8_t _regnual_start;
uint8_t __heap_end__;
int
check_crc32 (const uint32_t *start_p, const uint32_t *end_p)
{
return 0;
}
uint8_t *
sram_address (uint32_t offset)
{
return ((uint8_t *)0x20000000) + offset;
}
const uint8_t sys_version[8] = {
3*2+2, /* bLength */
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
/* sys version: "3.0" */
'3', 0, '.', 0, '0', 0,
};
void
led_blink (int spec)
{
}
void
ccid_usb_reset (int full)
{
}
void
ccid_card_change_signal (int how)
{
}
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
/* Busy1, Busy2, Busy3, Busy5 */
CCID_STATE_EXECUTE, /* Busy4 */
CCID_STATE_RECEIVE, /* APDU Received Partially */
CCID_STATE_SEND, /* APDU Sent Partially */
CCID_STATE_EXITED, /* ICC Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
};
static enum ccid_state ccid_state;
enum ccid_state *const ccid_state_p = &ccid_state;

103
emulation/usb-emu.c Normal file
View File

@@ -0,0 +1,103 @@
/*
* usb-emu.c - USB driver for USBIP emulation
*
* Copyright (C) 2017 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx 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.
*
* Chopstx 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 <stdint.h>
#include <stdlib.h>
#include "../chopstx/usb_lld.h"
int
usb_lld_ctrl_ack (struct usb_dev *dev)
{
return 0;
}
int
usb_lld_ctrl_recv (struct usb_dev *dev, void *p, size_t len)
{
return 0;
}
int
usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
{
return 0;
}
uint8_t
usb_lld_current_configuration (struct usb_dev *dev)
{
return 0;
}
void
usb_lld_prepare_shutdown (void)
{
}
void
usb_lld_ctrl_error (struct usb_dev *dev)
{
}
void
usb_lld_reset (struct usb_dev *dev, uint8_t feature)
{
}
void
usb_lld_set_configuration (struct usb_dev *dev, uint8_t config)
{
}
void
usb_lld_shutdown (void)
{
}
void
usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
int ep_rx_addr, int ep_tx_addr,
int ep_rx_memory_size)
{
}
void
usb_lld_stall (int ep_num)
{
}
void
usb_lld_stall_tx (int ep_num)
{
usb_lld_stall (ep_num);
}
void
usb_lld_stall_rx (int ep_num)
{
usb_lld_stall (ep_num);
}

278
emulation/usbip-server.c Normal file
View File

@@ -0,0 +1,278 @@
/*
* usbip-server.c - USB Device Emulation by USBIP Protocol
*
* Copyright (C) 2017 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx 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.
*
* Chopstx 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 <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#define USBIP_PORT 3240
#define CMD_REQ_LIST 0x01118005
#define CMD_REQ_ATTACH 0x01118003
#define CMD_URB 0x00000001
#define CMD_DETACH 0x00000002
struct usbip_msg_head {
uint32_t cmd;
uint32_t seq;
};
#define USBIP_REPLY_HEADER_SIZE 12
#define DEVICE_INFO_SIZE (256+32+12+6+6)
#define INTERFACE_INFO_SIZE 4
#define DEVICE_LIST_SIZE (USBIP_REPLY_HEADER_SIZE+DEVICE_INFO_SIZE*1+INTERFACE_INFO_SIZE*1)
#define USBIP_REPLY_DEVICE_LIST "\x01\x11\x00\x05"
#define NETWORK_UINT32_ZERO "\x00\x00\x00\x00"
#define NETWORK_UINT32_ONE "\x00\x00\x00\x01"
#define NETWORK_UINT32_TWO "\x00\x00\x00\x02"
#define NETWORK_UINT16_FSIJ "\x23\x4b"
#define NETWORK_UINT16_ZERO "\x00\x00"
#define NETWORK_UINT16_ONE_ONE "\x01\x01"
static char *
list_devices (size_t *len_p)
{
char *p0, *p;
*len_p = 0;
p0 = malloc (DEVICE_LIST_SIZE);
if (p0 == NULL)
return NULL;
*len_p = DEVICE_LIST_SIZE;
p = p0;
memcpy (p, USBIP_REPLY_DEVICE_LIST, 4);
p += 4;
memcpy (p, NETWORK_UINT32_ZERO, 4);
p += 4;
memcpy (p, NETWORK_UINT32_ONE, 4);
p += 4;
memset (p, 0, 256);
strcpy (p, "/sys/devices/pci0000:00/0000:00:01.1/usb1/1-1");
p += 256;
memset (p, 0, 32);
strcpy (p, "1-1");
p += 32;
memcpy (p, NETWORK_UINT32_ONE, 4); /* Bus */
p += 4;
memcpy (p, NETWORK_UINT32_TWO, 4); /* Dev */
p += 4;
memcpy (p, NETWORK_UINT32_ONE, 4); /* Speed */
p += 4;
memcpy (p, NETWORK_UINT16_FSIJ, 2);
p += 2;
memcpy (p, NETWORK_UINT16_ZERO, 2); /* Gnuk */
p += 2;
memcpy (p, NETWORK_UINT16_ONE_ONE, 2); /* USB 1.1 */
p += 2;
*p++ = 0; /* bDeviceClass */
*p++ = 0; /* bDeviceSubClass */
*p++ = 0; /* bDeviceProtocol */
*p++ = 0; /* bConfigurationValue */
*p++ = 1; /* bConfigurationValue */
*p++ = 1; /* bNumInterfaces */
*p++ = 11; /* bInterfaceClass */
*p++ = 0; /* bInterfaceSubClass */
*p++ = 0; /* bInterfaceProtocol */
*p++ = 0; /* ----pad----------- */
return p0;
}
static char *
attach_device (char busid[32], size_t *len_p)
{
*len_p = 0;
return NULL;
}
static int
handle_urb (int fd)
{
return 0;
}
static void
run_server (void)
{
int sock;
struct sockaddr_in v4addr;
const int one = 1;
if ((sock = socket (PF_INET, SOCK_STREAM, 0)) < 0)
{
perror ("socket");
exit (1);
}
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
(const char*)&one, sizeof (int)) < 0)
perror ("WARN: setsockopt");
memset (&v4addr, 0, sizeof (v4addr));
v4addr.sin_family = AF_INET;
v4addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
v4addr.sin_port = htons (USBIP_PORT);
if (bind (sock, (const struct sockaddr *)&v4addr, sizeof (v4addr)) < 0)
{
perror ("bind");
exit (1);
}
/* We only accept a connection from a single client. */
if (listen (sock, 1) < 0)
{
perror ("listen");
exit (1);
}
for (;;)
{
int fd;
int attached = 0;
/* We don't care who is connecting. */
if ((fd = accept (sock, NULL, NULL)) < 0)
{
perror ("accept");
exit (1);
}
for (;;)
{
struct usbip_msg_head msg;
if (recv (fd, (char *)&msg, sizeof (msg), 0) != sizeof (msg))
{
perror ("msg recv");
break;
}
msg.cmd = ntohl (msg.cmd);
msg.seq = ntohl (msg.seq);
if (msg.cmd == CMD_REQ_LIST)
{
char *device_list;
size_t device_list_size;
if (attached)
{
fprintf (stderr, "REQ list while attached\n");
break;
}
device_list = list_devices (&device_list_size);
if (send (fd, device_list, device_list_size, 0) != device_list_size)
{
perror ("list send");
break;
}
free (device_list);
}
else if (msg.cmd == CMD_REQ_ATTACH)
{
char busid[32];
char *attach;
size_t attach_size;
if (attached)
{
fprintf (stderr, "REQ attach while attached\n");
break;
}
if (recv (fd, busid, 32, 0) != 32)
{
perror ("attach recv");
break;
}
attach = attach_device (busid, &attach_size);
if (send (fd, attach, attach_size, 0) != attach_size)
{
perror ("list send");
break;
}
free (attach);
attached = 1;
}
else if (msg.cmd == CMD_URB)
{
if (!attached)
{
fprintf (stderr, "URB while attached\n");
break;
}
if (handle_urb (fd) < 0)
{
fprintf (stderr, "URB handling failed\n");
break;
}
}
else if(msg.cmd == CMD_DETACH)
{
if (!attached)
{
fprintf (stderr, "DETACH while attached\n");
break;
}
/* send reply??? */
break;
}
else
{
fprintf (stderr, "Unknown command %08x, disconnecting.\n", msg.cmd);
break;
}
}
close (fd);
}
}
int
main (int argc, const char *argv[])
{
run_server ();
return 0;
}

BIN
gnuk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -179,15 +179,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
const uint32_t FT0[256] __attribute__((section(".sys.0"))) = { FT };
const uint32_t FT0[256] __attribute__((weak,section(".sys.0"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
const uint32_t FT1[256] __attribute__((section(".sys.1"))) = { FT };
const uint32_t FT1[256] __attribute__((weak,section(".sys.1"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
const uint32_t FT2[256] __attribute__((section(".sys.2"))) = { FT };
const uint32_t FT2[256] __attribute__((weak,section(".sys.2"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##d##a##b##c

View File

@@ -1632,7 +1632,6 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
* Init temps and window size
*/
mpi_montg_init( &mm, N );
MPI_CHK( mpi_grow( X, N->n ) );
/*
* If 1st call, pre-compute R^2 mod N
@@ -1658,6 +1657,8 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
memset (d, 0, N->n * ciL); /* Set lower half of D zero. */
}
MPI_CHK( mpi_grow( X, N->n ) );
/*
* W[1] = A * R^2 * R^-1 mod N = A * R mod N
*/

View File

@@ -2,9 +2,11 @@
PROJECT = regnual
OBJS = regnual.o usb_stm32f103.o sys.o
OBJS = regnual.o usb-stm32f103.o reset.o
LDSCRIPT= regnual.ld
include ../src/config.mk
###################################
MCU = cortex-m3
@@ -19,11 +21,11 @@ TOPT = -mthumb -DTHUMB -mno-thumb-interwork
# Define C warning options here
CWARN = -Wall -Wextra -Wstrict-prototypes
MCFLAGS= -mcpu=$(MCU)
DEFS = -DFREE_STANDING
DEFS += -DFREE_STANDING
CFLAGS = -O2 -g
CFLAGS += -Wa,-alms=$(notdir $(<:.c=.lst)) -fpie
CFLAGS += $(CWARN) -I . -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
CFLAGS += $(CWARN) -I . -I ../chopstx -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
LDFLAGS = -T$(LDSCRIPT) -nostartfiles $(MCFLAGS) $(TOPT)
@@ -32,19 +34,19 @@ LDFLAGS = -T$(LDSCRIPT) -nostartfiles $(MCFLAGS) $(TOPT)
all: regnual.hex
regnual.o: regnual.c ../src/sys.h ../src/usb_lld.h
regnual.o: regnual.c ../chopstx/sys.h ../chopstx/usb_lld.h
regnual.hex: regnual.elf
$(OBJCOPY) -Obinary regnual.elf regnual.bin
$(OBJCOPY) -Oihex regnual.elf regnual.hex
usb_stm32f103.o: ../src/usb_stm32f103.c
$(CC) $(CFLAGS) -c -o usb_stm32f103.o ../src/usb_stm32f103.c
usb-stm32f103.o: ../chopstx/mcu/usb-stm32f103.c
$(CC) $(CFLAGS) -c -o usb-stm32f103.o ../chopstx/mcu/usb-stm32f103.c
regnual.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS)
clean:
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin *.lst
distclean: clean

View File

@@ -1,7 +1,7 @@
/*
* regnual.c -- Firmware installation for STM32F103 Flash ROM
*
* Copyright (C) 2012, 2013, 2015, 2016
* Copyright (C) 2012, 2013, 2015, 2016, 2017
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -109,10 +109,10 @@ static const uint8_t regnual_string_serial[] = {
};
void
usb_cb_device_reset (void)
static void
usb_device_reset (struct usb_dev *dev)
{
usb_lld_reset (REGNUAL_FEATURE_INIT);
usb_lld_reset (dev, REGNUAL_FEATURE_INIT);
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
@@ -169,95 +169,101 @@ static uint32_t calc_crc32 (void)
}
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no,
struct req_args *arg)
static void
usb_ctrl_write_finish (struct usb_dev *dev)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
&& USB_SETUP_SET (arg->type))
{
if (req_no == USB_REGNUAL_SEND && arg->value == 0)
if (arg->request == USB_REGNUAL_SEND && arg->value == 0)
result = calc_crc32 ();
else if (req_no == USB_REGNUAL_FLASH)
else if (arg->request == USB_REGNUAL_FLASH)
{
uint32_t dst_addr = (0x08000000 + arg->value * 0x100);
result = flash_write (dst_addr, (const uint8_t *)mem, 256);
}
else if (req_no == USB_REGNUAL_PROTECT && arg->value == 0)
else if (arg->request == USB_REGNUAL_PROTECT && arg->value == 0)
result = flash_protect ();
else if (req_no == USB_REGNUAL_FINISH && arg->value == 0)
else if (arg->request == USB_REGNUAL_FINISH && arg->value == 0)
nvic_system_reset ();
}
}
int
usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
static int
usb_setup (struct usb_dev *dev)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
{
if (USB_SETUP_GET (req))
if (USB_SETUP_GET (arg->type))
{
if (req_no == USB_REGNUAL_MEMINFO)
if (arg->request == USB_REGNUAL_MEMINFO)
{
const uint8_t *mem_info[2];
mem_info[0] = (const uint8_t *)FLASH_START;
mem_info[1] = (const uint8_t *)flash_end;
return usb_lld_reply_request (mem_info, sizeof (mem_info), arg);
return usb_lld_ctrl_send (dev, mem_info, sizeof (mem_info));
}
else if (req_no == USB_REGNUAL_RESULT)
return usb_lld_reply_request (&result, sizeof (uint32_t), arg);
else if (arg->request == USB_REGNUAL_RESULT)
return usb_lld_ctrl_send (dev, &result, sizeof (uint32_t));
}
else /* SETUP_SET */
{
if (req_no == USB_REGNUAL_SEND)
if (arg->request == USB_REGNUAL_SEND)
{
if (arg->value != 0 || arg->index + arg->len > 256)
return USB_UNSUPPORT;
return -1;
if (arg->index + arg->len < 256)
memset ((uint8_t *)mem + arg->index + arg->len, 0xff,
256 - (arg->index + arg->len));
usb_lld_set_data_to_recv (mem + arg->index, arg->len);
return USB_SUCCESS;
return usb_lld_ctrl_recv (dev, mem + arg->index, arg->len);
}
else if (req_no == USB_REGNUAL_FLASH && arg->len == 0
else if (arg->request == USB_REGNUAL_FLASH && arg->len == 0
&& arg->index == 0)
{
uint32_t dst_addr = (0x08000000 + arg->value * 0x100);
if (dst_addr + 256 <= flash_end)
return USB_SUCCESS;
return usb_lld_ctrl_ack (dev);
}
else if (req_no == USB_REGNUAL_PROTECT && arg->len == 0
else if (arg->request == USB_REGNUAL_PROTECT && arg->len == 0
&& arg->value == 0 && arg->index == 0)
return USB_SUCCESS;
else if (req_no == USB_REGNUAL_FINISH && arg->len == 0
return usb_lld_ctrl_ack (dev);
else if (arg->request == USB_REGNUAL_FINISH && arg->len == 0
&& arg->value == 0 && arg->index == 0)
return USB_SUCCESS;
return usb_lld_ctrl_ack (dev);
}
}
return USB_UNSUPPORT;
return -1;
}
int
usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
struct req_args *arg)
static int
usb_get_descriptor (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
uint8_t desc_type = (arg->value >> 8);
uint8_t desc_index = (arg->value & 0xff);
if (rcp != DEVICE_RECIPIENT)
return USB_UNSUPPORT;
return -1;
if (desc_type == DEVICE_DESCRIPTOR)
return usb_lld_reply_request (regnual_device_desc,
sizeof (regnual_device_desc), arg);
return usb_lld_ctrl_send (dev, regnual_device_desc,
sizeof (regnual_device_desc));
else if (desc_type == CONFIG_DESCRIPTOR)
return usb_lld_reply_request (regnual_config_desc,
sizeof (regnual_config_desc), arg);
return usb_lld_ctrl_send (dev, regnual_config_desc,
sizeof (regnual_config_desc));
else if (desc_type == STRING_DESCRIPTOR)
{
const uint8_t *str;
@@ -282,46 +288,40 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
size = sizeof (regnual_string_serial);
break;
default:
return USB_UNSUPPORT;
return -1;
}
return usb_lld_reply_request (str, size, arg);
return usb_lld_ctrl_send (dev, str, size);
}
return USB_UNSUPPORT;
return -1;
}
int usb_cb_handle_event (uint8_t event_type, uint16_t value)
static int
usb_set_configuration (struct usb_dev *dev)
{
(void)value;
uint8_t current_conf;
switch (event_type)
current_conf = usb_lld_current_configuration (dev);
if (current_conf == 0)
{
case USB_EVENT_ADDRESS:
case USB_EVENT_CONFIG:
return USB_SUCCESS;
default:
break;
if (dev->dev_req.value != 1)
return -1;
usb_lld_set_configuration (dev, 1);
}
else if (current_conf != dev->dev_req.value)
{
if (dev->dev_req.value != 0)
return -1;
usb_lld_set_configuration (dev, 0);
}
return USB_UNSUPPORT;
/* Do nothing when current_conf == value */
return usb_lld_ctrl_ack (dev);
}
int usb_cb_interface (uint8_t cmd, struct req_args *arg)
{
(void)cmd; (void)arg;
return USB_UNSUPPORT;
}
void usb_cb_rx_ready (uint8_t ep_num)
{
(void)ep_num;
}
void usb_cb_tx_done (uint8_t ep_num)
{
(void)ep_num;
}
static void wait (int count)
{
@@ -356,6 +356,7 @@ static void nvic_enable_intr (uint8_t irq_num)
}
#define USB_LP_CAN1_RX0_IRQn 20
static struct usb_dev dev;
int
main (int argc, char *argv[])
@@ -364,14 +365,18 @@ main (int argc, char *argv[])
set_led (0);
#if defined(STM32F103_OVERRIDE_FLASH_SIZE_KB)
flash_end = FLASH_START_ADDR + STM32F103_OVERRIDE_FLASH_SIZE_KB*1024;
#else
flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
#endif
/*
* NVIC interrupt priority was set by Gnuk.
* USB interrupt is disabled by NVIC setting.
* We enable the interrupt again by nvic_enable_intr.
*/
usb_lld_init (REGNUAL_FEATURE_INIT);
usb_lld_init (&dev, REGNUAL_FEATURE_INIT);
nvic_enable_intr (USB_LP_CAN1_RX0_IRQn);
while (1)
@@ -382,3 +387,69 @@ main (int argc, char *argv[])
wait (WAIT);
}
}
void
usb_interrupt_handler (void)
{
uint8_t ep_num;
int e;
e = usb_lld_event_handler (&dev);
ep_num = USB_EVENT_ENDP (e);
if (ep_num == 0)
switch (USB_EVENT_ID (e))
{
case USB_EVENT_DEVICE_RESET:
usb_device_reset (&dev);
break;
case USB_EVENT_DEVICE_ADDRESSED:
break;
case USB_EVENT_GET_DESCRIPTOR:
if (usb_get_descriptor (&dev) < 0)
usb_lld_ctrl_error (&dev);
break;
case USB_EVENT_SET_CONFIGURATION:
if (usb_set_configuration (&dev) < 0)
usb_lld_ctrl_error (&dev);
break;
case USB_EVENT_SET_INTERFACE:
usb_lld_ctrl_error (&dev);
break;
case USB_EVENT_CTRL_REQUEST:
/* Device specific device request. */
if (usb_setup (&dev) < 0)
usb_lld_ctrl_error (&dev);
break;
case USB_EVENT_GET_STATUS_INTERFACE:
usb_lld_ctrl_error (&dev);
break;
case USB_EVENT_GET_INTERFACE:
usb_lld_ctrl_error (&dev);
break;
case USB_EVENT_SET_FEATURE_DEVICE:
case USB_EVENT_SET_FEATURE_ENDPOINT:
case USB_EVENT_CLEAR_FEATURE_DEVICE:
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
usb_lld_ctrl_ack (&dev);
break;
case USB_EVENT_CTRL_WRITE_FINISH:
/* Control WRITE transfer finished. */
usb_ctrl_write_finish (&dev);
break;
case USB_EVENT_OK:
case USB_EVENT_DEVICE_SUSPEND:
default:
break;
}
}

View File

@@ -8,15 +8,14 @@ CHOPSTX = ../chopstx
# Define linker script file here
LDSCRIPT= gnuk.ld
CSRC = main.c usb_stm32f103.c adc_stm32f103.c \
CSRC = main.c call-rsa.c mcu-stm32f103.c \
usb_desc.c usb_ctrl.c \
call-rsa.c \
usb-ccid.c openpgp.c ac.c openpgp-do.c flash.c \
bn.c mod.c \
modp256r1.c jpc_p256r1.c ec_p256r1.c call-ec_p256r1.c \
modp256k1.c jpc_p256k1.c ec_p256k1.c call-ec_p256k1.c \
mod25638.c ecc-edwards.c ecc-mont.c sha512.c \
random.c neug.c sha256.c sys.c
random.c neug.c sha256.c
INCDIR =
@@ -28,9 +27,7 @@ CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/aes.c
CSRC += $(CRYPTSRC)
INCDIR += $(CRYPTINCDIR)
@PINPAD_MAKE_OPTION@
@DEBUG_MAKE_OPTION@
@HEXOUTPUT_MAKE_OPTION@
include config.mk
USE_EVENTFLAG = yes
@@ -46,6 +43,11 @@ ifeq ($(ENABLE_PINPAD),dnd)
CSRC += usb-msc.c
endif
CHIP=stm32f103
USE_SYS = yes
USE_USB = yes
USE_ADC = yes
###################################
CROSS = arm-none-eabi-
CC = $(CROSS)gcc
@@ -54,8 +56,6 @@ OBJCOPY = $(CROSS)objcopy
MCU = cortex-m3
CWARN = -Wall -Wextra -Wstrict-prototypes
# DEFS: Add
DEFS = @HAVE_SYS_H@
OPT = -O3 -Os -g
LIBS =
@@ -71,5 +71,5 @@ sys.c: board.h
build/bignum.o: OPT = -O3 -g
distclean: clean
-rm -f gnuk.ld config.h board.h Makefile \
-rm -f gnuk.ld config.h board.h config.mk \
usb-strings.c.inc usb-vid-pid-ver.c.inc

View File

@@ -1,8 +0,0 @@
void adc_init (void);
void adc_start (void);
void adc_stop (void);
extern uint32_t adc_buf[64];
void adc_start_conversion (int offset, int count);
int adc_wait_completion (chopstx_intr_t *intr);

View File

@@ -1,319 +0,0 @@
/*
* adc_stm32f103.c - ADC driver for STM32F103
* In this ADC driver, there are NeuG specific parts.
* You need to modify to use this as generic ADC driver.
*
* Copyright (C) 2011, 2012, 2013, 2015
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of NeuG, a True Random Number Generator
* implementation based on quantization error of ADC (for STM32F103).
*
* NeuG is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NeuG 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 <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include "neug.h"
#include "stm32f103.h"
#include "adc.h"
#define NEUG_CRC32_COUNTS 4
#define STM32_ADC_ADC1_DMA_PRIORITY 2
#define ADC_SMPR1_SMP_VREF(n) ((n) << 21)
#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18)
#define ADC_SMPR1_SMP_AN10(n) ((n) << 0)
#define ADC_SMPR1_SMP_AN11(n) ((n) << 3)
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0)
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3)
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6)
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27)
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
#define ADC_SQR3_SQ1_N(n) ((n) << 0)
#define ADC_SQR3_SQ2_N(n) ((n) << 5)
#define ADC_SQR3_SQ3_N(n) ((n) << 10)
#define ADC_SQR3_SQ4_N(n) ((n) << 15)
#define ADC_SAMPLE_1P5 0
#define ADC_CHANNEL_IN0 0
#define ADC_CHANNEL_IN1 1
#define ADC_CHANNEL_IN2 2
#define ADC_CHANNEL_IN9 9
#define ADC_CHANNEL_IN10 10
#define ADC_CHANNEL_IN11 11
#define ADC_CHANNEL_SENSOR 16
#define ADC_CHANNEL_VREFINT 17
#define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
#define DELIBARATELY_DO_IT_WRONG_START_STOP
#ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
#define ADC_SAMPLE_VREF ADC_SAMPLE_1P5
#define ADC_SAMPLE_SENSOR ADC_SAMPLE_1P5
#else
#define ADC_SAMPLE_VREF ADC_SAMPLE_239P5
#define ADC_SAMPLE_SENSOR ADC_SAMPLE_239P5
#endif
#define NEUG_DMA_CHANNEL STM32_DMA1_STREAM1
#define NEUG_DMA_MODE \
( STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY) \
| STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD \
| STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE \
| STM32_DMA_CR_TEIE )
#define NEUG_ADC_SETTING1_SMPR1 ADC_SMPR1_SMP_VREF(ADC_SAMPLE_VREF) \
| ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_SENSOR)
#define NEUG_ADC_SETTING1_SMPR2 0
#define NEUG_ADC_SETTING1_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) \
| ADC_SQR3_SQ3_N(ADC_CHANNEL_SENSOR) \
| ADC_SQR3_SQ4_N(ADC_CHANNEL_VREFINT)
#define NEUG_ADC_SETTING1_NUM_CHANNELS 4
/*
* Do calibration for both of ADCs.
*/
void adc_init (void)
{
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
RCC->APB2RSTR = (RCC_APB2RSTR_ADC1RST | RCC_APB2RSTR_ADC2RST);
RCC->APB2RSTR = 0;
ADC1->CR1 = 0;
ADC1->CR2 = ADC_CR2_ADON;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC1->CR2 & ADC_CR2_CAL) != 0)
;
ADC1->CR2 = 0;
ADC2->CR1 = 0;
ADC2->CR2 = ADC_CR2_ADON;
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0)
;
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC2->CR2 & ADC_CR2_CAL) != 0)
;
ADC2->CR2 = 0;
RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
}
#include "sys.h"
#if defined(HAVE_SYS_H)
# define SYS_BOARD_ID sys_board_id
#else
# include "board.h"
# define SYS_BOARD_ID BOARD_ID
#endif
static void
get_adc_config (uint32_t config[4])
{
config[2] = ADC_SQR1_NUM_CH(2);
switch (SYS_BOARD_ID)
{
case BOARD_ID_FST_01:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9);
break;
case BOARD_ID_OLIMEX_STM32_H103:
case BOARD_ID_STBEE:
config[0] = ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5)
| ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5);
config[1] = 0;
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11);
break;
case BOARD_ID_STBEE_MINI:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN2(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2);
break;
case BOARD_ID_CQ_STARM:
case BOARD_ID_FST_01_00:
case BOARD_ID_MAPLE_MINI:
case BOARD_ID_STM32_PRIMER2:
case BOARD_ID_STM8S_DISCOVERY:
case BOARD_ID_ST_DONGLE:
case BOARD_ID_ST_NUCLEO_F103:
case BOARD_ID_NITROKEY_START:
default:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1);
break;
}
}
void adc_start (void)
{
uint32_t config[4];
get_adc_config (config);
/* Use DMA channel 1. */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel1->CCR = STM32_DMA_CCR_RESET_VALUE;
DMA1->IFCR = 0xffffffff;
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
| ADC_CR1_SCAN);
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
ADC1->SMPR1 = NEUG_ADC_SETTING1_SMPR1;
ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2;
ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS);
ADC1->SQR2 = 0;
ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3;
ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
| ADC_CR1_SCAN);
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC2->SMPR1 = config[0];
ADC2->SMPR2 = config[1];
ADC2->SQR1 = config[2];
ADC2->SQR2 = 0;
ADC2->SQR3 = config[3];
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
/*
* We could just let ADC run continuously always and only enable DMA
* to receive stable data from ADC. But our purpose is not to get
* correct data but noise. In fact, we can get more noise when we
* start/stop ADC each time.
*/
ADC2->CR2 = 0;
ADC1->CR2 = 0;
#else
/* Start conversion. */
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
#endif
}
uint32_t adc_buf[64];
void adc_start_conversion (int offset, int count)
{
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
DMA1_Channel1->CMAR = (uint32_t)&adc_buf[offset]; /* SetMemory0 */
DMA1_Channel1->CNDTR = count; /* Counter */
DMA1_Channel1->CCR = NEUG_DMA_MODE | DMA_CCR1_EN; /* Mode */
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
/* Power on */
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
/*
* Start conversion. tSTAB is 1uS, but we don't follow the spec, to
* get more noise.
*/
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
#endif
}
static void adc_stop_conversion (void)
{
DMA1_Channel1->CCR &= ~DMA_CCR1_EN;
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
ADC2->CR2 = 0;
ADC1->CR2 = 0;
#endif
}
void adc_stop (void)
{
ADC1->CR1 = 0;
ADC1->CR2 = 0;
ADC2->CR1 = 0;
ADC2->CR2 = 0;
RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
}
static uint32_t adc_err;
/*
* Return 0 on success.
* Return 1 on error.
*/
int adc_wait_completion (chopstx_intr_t *intr)
{
uint32_t flags;
while (1)
{
chopstx_intr_wait (intr);
flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause. */
/*
* Clear interrupt cause of channel 1.
*
* Note that CGIFx=0, as CGIFx=1 clears all of GIF, HTIF, TCIF
* and TEIF.
*/
DMA1->IFCR = (flags & ~1);
if ((flags & STM32_DMA_ISR_TEIF) != 0) /* DMA errors */
{
/* Should never happened. If any, it's coding error. */
/* Access an unmapped address space or alignment violation. */
adc_err++;
adc_stop_conversion ();
return 1;
}
else if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
{
adc_stop_conversion ();
return 0;
}
}
}

View File

@@ -30,7 +30,7 @@
#include "config.h"
#include "gnuk.h"
#include "openpgp.h"
#include "status-code.h"
#include "random.h"
#include "polarssl/config.h"
#include "polarssl/rsa.h"
@@ -130,9 +130,11 @@ modulus_calc (const uint8_t *p, int len)
cleanup:
mpi_free (&P); mpi_free (&Q); mpi_free (&N);
if (ret != 0)
return NULL;
else
return modulus;
{
free (modulus);
return NULL;
}
return modulus;
}
@@ -261,23 +263,14 @@ rsa_genkey (int pubkey_len)
cs = chopstx_setcancelstate (0); /* Allow cancellation. */
MPI_CHK( rsa_gen_key (&rsa_ctx, random_gen, &index, pubkey_len * 8,
RSA_EXPONENT) );
if (ret != 0)
{
chopstx_setcancelstate (cs);
chopstx_cleanup_pop (0);
free (p_q_modulus);
rsa_free (&rsa_ctx);
return NULL;
}
MPI_CHK( mpi_write_binary (&rsa_ctx.P, p, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.Q, q, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.N, modulus, pubkey_len) );
clp.arg = NULL;
cleanup:
chopstx_setcancelstate (cs);
chopstx_cleanup_pop (0);
rsa_free (&rsa_ctx);
chopstx_cleanup_pop (1);
if (ret != 0)
return NULL;
else

View File

@@ -8,3 +8,4 @@
@CERTDO_DEFINE@
@HID_CARD_CHANGE_DEFINE@
@SERIALNO_STR_LEN_DEFINE@
@LIFE_CYCLE_MANAGEMENT_DEFINE@

102
src/configure vendored
View File

@@ -6,7 +6,7 @@ nl=$'\n'
#
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
# Free Software Initiative of Japan
#
# This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -36,33 +36,38 @@ fi
help=no
vidpid=none
target=FST_01
verbose=no
with_dfu=default
debug=no
sys1_compat=yes
pinpad=no
certdo=no
hid_card_change=no
factory_reset=no
flash_override=""
# Revision number
if test -d ../.git; then
REVISION=`git describe --dirty="-modified"`
if test -e ../.git; then
if type git >/dev/null 2>&1; then
REVISION=$(git describe --dirty="-modified")
else
# echo 'No git available, please install git'
GIT_REVISION=$(sed -e 's/^\(.......\).*$/g\1/' "../.git/$(sed -e 's/^ref: //' ../.git/HEAD)")
REVISION=$(cat ../VERSION)-$GIT_REVISION
fi
else
REVISION=`cat ../VERSION`
REVISION=$(cat ../VERSION)
fi
# Process each option
for option; do
case $option in
*=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;;
*=*) optarg=$(expr "X$option" : '[^=]*=\(.*\)') ;;
*) optarg=yes ;;
esac
case $option in
-h | --help)
help=yes ;;
-v | --verbose)
verbose=yes ;;
--vidpid=*)
vidpid=$optarg ;;
--target=*)
@@ -87,6 +92,10 @@ for option; do
sys1_compat=yes ;;
--disable-sys1-compat)
sys1_compat=no ;;
--enable-factory-reset)
factory_reset=yes ;;
--disable-factory-reset)
factory_reset=no ;;
--with-dfu)
with_dfu=yes ;;
--without-dfu)
@@ -111,15 +120,17 @@ Configuration:
--target=TARGET specify target [FST_01]
supported targets are:
FST_01
FST_01G
OLIMEX_STM32_H103
STM32_PRIMER2
STBEE
STBEE_MINI
MAPLE_MINI
ST_DONGLE
ST_NUCLEO_F103
NITROKEY_START
BLUE_PILL
CQ_STARM
STM32_PRIMER2
STBEE
STBEE_MINI
FST_01_00 (unreleased version with 8MHz XTAL)
--enable-debug debug with virtual COM port [no]
--enable-pinpad=cir
@@ -130,6 +141,8 @@ Configuration:
--disable-sys1-compat disable SYS 1.0 compatibility [no]
executable is target independent
but requires SYS 2.0 or newer
--enable-factory-reset
support life cycle management [no]
--with-dfu build image for DFU [<target specific>]
EOF
exit 0
@@ -140,9 +153,9 @@ if test "$vidpid" = "none"; then
exit 1
fi
BOARD_HEADER_FILE=board-`echo $target | tr '_[:upper:]' '-[:lower:]'`.h
echo Header file is: $BOARD_HEADER_FILE
ln -sf ../chopstx/board/$BOARD_HEADER_FILE board.h
BOARD_HEADER_FILE=board-$(echo $target | tr '_[:upper:]' '-[:lower:]').h
echo "Header file is: $BOARD_HEADER_FILE"
ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h
# Flash page size in byte
FLASH_PAGE_SIZE=1024
@@ -153,6 +166,8 @@ MEMORY_SIZE=20
# Settings for TARGET
case $target in
BLUE_PILL)
flash_override="-DSTM32F103_OVERRIDE_FLASH_SIZE_KB" ;;
CQ_STARM|STBEE_MINI)
if test "$with_dfu" = "default"; then
with_dfu=yes;
@@ -189,13 +204,14 @@ fi
# --with-dfu option
if test "$with_dfu" = "yes"; then
if test "$target" = "FST_01" -o "$target" = "FST_01_00"; then
if test "$target" = "FST_01" -o "$target" = "FST_01G" \
-o "$target" = "FST_01_00"; then
echo "FST-01 doesn't have DFU loader, you should not use --with-dfu." >&2
exit 1
fi
echo "Configured for DFU"
ORIGIN=0x08003000
FLASH_SIZE=`expr $FLASH_SIZE - 12`
FLASH_SIZE=$((FLASH_SIZE - 12))
DFU_DEFINE="#define DFU_SUPPORT 1"
HEXOUTPUT_MAKE_OPTION="ENABLE_OUTPUT_HEX=yes"
else
@@ -246,8 +262,17 @@ else
echo "Card insert/removal by HID device is NOT supported"
fi
# --enable-factory-reset option
if test "$factory_reset" = "yes"; then
LIFE_CYCLE_MANAGEMENT_DEFINE="#define LIFE_CYCLE_MANAGEMENT_SUPPORT 1"
echo "Life cycle management is supported"
else
LIFE_CYCLE_MANAGEMENT_DEFINE="#undef LIFE_CYCLE_MANAGEMENT_SUPPORT"
echo "Life cycle management is NOT supported"
fi
### !!! Replace following string of "FSIJ" to yours !!! ####
SERIALNO="FSIJ-`cat ../VERSION | sed -e 's%^[^/]*/%%'`-"
SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
SERIALNO_STR_LEN_DEFINE="#define SERIALNO_STR_LEN ${#SERIALNO}"
@@ -267,8 +292,8 @@ else
fi
output_vid_pid_version () {
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 */\\${nl} 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"
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 */\\${nl} 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"
}
output_vendor_product_serial_strings () {
@@ -278,23 +303,23 @@ output_vendor_product_serial_strings () {
echo " ${#VENDOR}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Manufacturer: \"$VENDOR\" */"
echo $VENDOR | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo "$VENDOR" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};'
echo
echo "static const uint8_t ${prefix}string_product[] = {"
echo " ${#PRODUCT}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Product name: \"$PRODUCT\" */"
echo $PRODUCT | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo "$PRODUCT" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};'
if test -n "$prefix"; then
echo
echo "uint8_t ${prefix}string_serial[] = {"
echo "const uint8_t ${prefix}string_serial[] = {"
echo " ${#SERIALNO}*2+2+16, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Serial number: \"$SERIALNO\" */"
echo $SERIALNO | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo "$SERIALNO" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
echo '};'
@@ -304,7 +329,7 @@ output_vendor_product_serial_strings () {
echo " ${#REVISION}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* revision detail: \"$REVISION\" */"
echo $REVISION | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo "$REVISION" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};'
echo
echo "static const uint8_t ${prefix}config_options[] = {"
@@ -317,8 +342,8 @@ output_vendor_product_serial_strings () {
fi
}
if !(IFS=" "
while read VIDPID VERSION PRODUCT VENDOR; do
if ! (IFS=" "
while read -r VIDPID VERSION PRODUCT VENDOR; do
if test "$vidpid" = "$VIDPID"; then
output_vid_pid_version > usb-vid-pid-ver.c.inc
output_vendor_product_serial_strings gnuk_ >usb-strings.c.inc
@@ -332,21 +357,23 @@ then
fi
if test "$sys1_compat" = "no"; then
# Disable when you are sure that it's sys version 2.1.
# Note that Gnuk 1.0 and NeuG (until 0.06) uses sys version 1.0.
# Disabling the compatibility, executable will be target independent,
# assuming the clock initialization will be done by SYS (before entry).
have_sys_h="-DHAVE_SYS_H"
# Disable when you are sure that it's sys version 3.0 or later.
# Note that Gnuk 1.0 and NeuG (until 0.06) uses sys version 1.0.
# Disabling the compatibility, executable will be target independent,
# assuming the clock initialization will be done by clock_init in
# SYS.
use_sys3="-DUSE_SYS3"
else
have_sys_h=""
use_sys3=""
fi
sed -e "s%@HAVE_SYS_H@%$have_sys_h%" \
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
-e "s%@HEXOUTPUT_MAKE_OPTION@%$HEXOUTPUT_MAKE_OPTION%" \
< Makefile.in > Makefile
echo -e "DEFS=$use_sys3 $flash_override" '\n' \
"$DEBUG_MAKE_OPTION" '\n' \
"$PINPAD_MAKE_OPTION" '\n' \
"$HEXOUTPUT_MAKE_OPTION" \
> config.mk
if test "$certdo" = "yes"; then
sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \
-e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
@@ -372,6 +399,7 @@ sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
< config.h.in > config.h
exit 0

View File

@@ -384,7 +384,7 @@ FUNC(check_secret) (const bn256 *d0, bn256 *d1)
{
ac Q0[1], Q1[1];
if (bn256_is_zero (d0) || bn256_sub (d1, N, d0) <= 0)
if (bn256_is_zero (d0) || bn256_sub (d1, N, d0) != 0)
/* == 0 or >= N, it's not valid. */
return 0;

View File

@@ -1,7 +1,7 @@
/*
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -75,7 +75,7 @@ static uint8_t *last_p;
/* The first halfword is generation for the data page (little endian) */
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
0x01, 0x00, 0xff, 0xff
0x00, 0x00, 0xff, 0xff
};
/* Linker set this symbol */
@@ -102,8 +102,8 @@ static int key_available_at (const uint8_t *k, int key_size)
#define CHIP_ID_REG ((uint32_t *)0xe0042000)
const uint8_t *
flash_init (void)
void
flash_init (const uint8_t **p_do_start, const uint8_t **p_do_end)
{
uint16_t gen0, gen1;
uint16_t *gen0_p = (uint16_t *)&_data_pool;
@@ -114,22 +114,60 @@ flash_init (void)
flash_page_size = 2048;
gen1_p = (uint16_t *)(&_data_pool + flash_page_size);
data_pool = &_data_pool;
/* Check data pool generation and choose the page */
gen0 = *gen0_p;
gen1 = *gen1_p;
if (gen0 == 0xffff && gen1 == 0xffff)
{
/* It's terminated. */
*p_do_start = *p_do_end = NULL;
return;
}
if (gen0 == 0xffff)
/* Use another page if a page is erased. */
data_pool = &_data_pool + flash_page_size;
else if (gen1 == 0xffff)
/* Or use different page if another page is erased. */
data_pool = &_data_pool;
else if (gen1 > gen0)
else if ((gen0 == 0xfffe && gen1 == 0) || gen1 > gen0)
/* When both pages have valid header, use newer page. */
data_pool = &_data_pool + flash_page_size;
else
data_pool = &_data_pool;
return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
*p_do_start = data_pool + FLASH_DATA_POOL_HEADER_SIZE;
*p_do_end = data_pool + flash_page_size;
}
static uint8_t *flash_key_getpage (enum kind_of_key kk);
void
flash_terminate (void)
{
int i;
for (i = 0; i < 3; i++)
flash_erase_page ((uint32_t)flash_key_getpage (i));
flash_erase_page ((uint32_t)&_data_pool);
flash_erase_page ((uint32_t)(&_data_pool + flash_page_size));
data_pool = &_data_pool;
last_p = &_data_pool + FLASH_DATA_POOL_HEADER_SIZE;
#if defined(CERTDO_SUPPORT)
flash_erase_page ((uint32_t)&ch_certificate_start);
if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size)
flash_erase_page ((uint32_t)(&ch_certificate_start + flash_page_size));
#endif
}
void
flash_activate (void)
{
flash_program_halfword ((uint32_t)&_data_pool, 0);
}
void
flash_init_keys (void)
{
@@ -209,8 +247,12 @@ flash_copying_gc (void)
generation = *(uint16_t *)src;
data_pool = dst;
gpg_data_copy (data_pool + FLASH_DATA_POOL_HEADER_SIZE);
if (generation == 0xfffe)
generation = 0;
else
generation++;
flash_program_halfword ((uint32_t)dst, generation);
flash_erase_page ((uint32_t)src);
flash_program_halfword ((uint32_t)dst, generation+1);
return 0;
}

View File

@@ -12,8 +12,8 @@ struct apdu {
/* response APDU */
uint16_t sw;
uint8_t *res_apdu_data;
uint16_t res_apdu_data_len;
uint8_t *res_apdu_data;
};
extern struct apdu apdu;
@@ -22,14 +22,15 @@ extern struct apdu apdu;
#define CARD_CHANGE_REMOVE 1
#define CARD_CHANGE_TOGGLE 2
void ccid_card_change_signal (int how);
void ccid_usb_reset (void);
void ccid_usb_reset (int);
/* CCID thread */
#define EV_RX_DATA_READY 1 /* USB Rx data available */
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */
#define EV_TX_FINISHED 4 /* CCID Tx finished */
#define EV_CARD_CHANGE 8
#define EV_USB_RESET 16
#define EV_CARD_CHANGE 8
#define EV_USB_SET_INTERFACE 16
#define EV_USB_DEVICE_RESET 32
/* OpenPGPcard thread */
#define EV_PINPAD_INPUT_DONE 1
@@ -43,7 +44,7 @@ void ccid_usb_reset (void);
/* Maximum res apdu data is public key 5+9+512 (gpg_do_public_key) */
#define MAX_RES_APDU_DATA_SIZE (5+9+512) /* without trailer */
#define ICC_MSG_HEADER_SIZE 10
#define CCID_MSG_HEADER_SIZE 10
#define res_APDU apdu.res_apdu_data
#define res_APDU_size apdu.res_apdu_data_len
@@ -51,22 +52,21 @@ void ccid_usb_reset (void);
/* USB buffer size of LL (Low-level): size of single Bulk transaction */
#define USB_LL_BUF_SIZE 64
enum icc_state {
ICC_STATE_NOCARD, /* No card available */
ICC_STATE_START, /* Initial */
ICC_STATE_WAIT, /* Waiting APDU */
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
/* Busy1, Busy2, Busy3, Busy5 */
ICC_STATE_EXECUTE, /* Busy4 */
ICC_STATE_RECEIVE, /* APDU Received Partially */
ICC_STATE_SEND, /* APDU Sent Partially */
CCID_STATE_EXECUTE, /* Busy4 */
CCID_STATE_RECEIVE, /* APDU Received Partially */
CCID_STATE_SEND, /* APDU Sent Partially */
ICC_STATE_EXITED, /* ICC Thread Terminated */
ICC_STATE_EXEC_REQUESTED, /* Exec requested */
CCID_STATE_EXITED, /* ICC Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
};
#define CCID_CARD_INIT CARD_CHANGE_INSERT
extern enum icc_state *icc_state_p;
extern enum ccid_state *const ccid_state_p;
extern volatile uint8_t auth_status;
#define AC_NONE_AUTHORIZED 0x00
@@ -100,12 +100,15 @@ void ac_fini (void);
void set_res_sw (uint8_t sw1, uint8_t sw2);
extern uint8_t file_selection;
extern const uint8_t historical_bytes[];
extern uint16_t data_objects_number_of_bytes;
#define CHALLENGE_LEN 32
void gpg_data_scan (const uint8_t *p);
void gpg_data_scan (const uint8_t *start, const uint8_t *end);
void gpg_data_copy (const uint8_t *p);
void gpg_do_terminate (void);
void gpg_do_get_data (uint16_t tag, int with_tag);
void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
void gpg_do_public_key (uint8_t kk_byte);
@@ -136,7 +139,9 @@ enum size_of_key {
int gpg_get_algo_attr (enum kind_of_key kk);
int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
const uint8_t *flash_init (void);
void flash_init (const uint8_t **, const uint8_t **);
void flash_terminate (void);
void flash_activate (void);
void flash_init_keys (void);
void flash_do_release (const uint8_t *);
const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
@@ -233,6 +238,7 @@ int gpg_change_keystring (int who_old, const uint8_t *old_ks,
extern struct key_data kd[3];
#ifdef DEBUG
void stdout_init (void);
#define DEBUG_MORE 1
/*
* Debug functions in debug.c
@@ -295,6 +301,7 @@ void gpg_increment_digital_signature_counter (void);
void fatal (uint8_t code) __attribute__ ((noreturn));
#define FATAL_FLASH 1
#define FATAL_RANDOM 2
#define FATAL_HEAP 3
extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
extern uint8_t admin_authorized;
@@ -421,10 +428,11 @@ extern const uint8_t gnuk_string_serial[];
#define LED_ONESHOT 1
#define LED_TWOSHOTS 2
#define LED_SHOW_STATUS 4
#define LED_START_COMMAND 8
#define LED_FINISH_COMMAND 16
#define LED_FATAL 32
#define LED_GNUK_EXEC 64
#define LED_FATAL 8
#define LED_SYNC 16
#define LED_GNUK_EXEC 32
#define LED_START_COMMAND 64
#define LED_FINISH_COMMAND 128
void led_blink (int spec);
#if defined(PINPAD_SUPPORT)
@@ -452,3 +460,6 @@ int pinpad_getline (int msg_code, uint32_t timeout_usec);
#endif
extern uint8_t _regnual_start, __heap_end__[];
int check_crc32 (const uint32_t *start_p, const uint32_t *end_p);
uint8_t * sram_address (uint32_t offset);

View File

@@ -3,9 +3,9 @@
*/
__main_stack_size__ = 0x0080; /* Exception handlers */
__process0_stack_size__ = 0x0100; /* main */
__process1_stack_size__ = 0x0180; /* ccid */
__process2_stack_size__ = 0x0160; /* rng */
__process3_stack_size__ = 0x1640; /* gpg */
__process1_stack_size__ = 0x01a0; /* ccid */
__process2_stack_size__ = 0x0180; /* rng */
__process3_stack_size__ = 0x1660; /* gpg */
__process4_stack_size__ = 0; /* --- */
__process5_stack_size__ = @MSC_SIZE@; /* msc */
__process6_stack_size__ = @TIM_SIZE@; /* intr: timer */
@@ -34,10 +34,10 @@ SECTIONS
KEEP(*(.sys.version))
KEEP(*(.sys.board_id))
KEEP(*(.sys.board_name))
build/sys.o(.text)
build/sys.o(.text.*)
build/sys.o(.rodata)
build/sys.o(.rodata.*)
build/sys-*.o(.text)
build/sys-*.o(.text.*)
build/sys-*.o(.rodata)
build/sys-*.o(.rodata.*)
. = ALIGN(1024);
*(.sys.0)
*(.sys.1)
@@ -171,10 +171,6 @@ SECTIONS
.gnuk_flash :
{
. = ALIGN (@FLASH_PAGE_SIZE@);
_data_pool = .;
KEEP(*(.gnuk_data))
. = ALIGN(@FLASH_PAGE_SIZE@);
. += @FLASH_PAGE_SIZE@;
_keystore_pool = .;
. += 512;
. = ALIGN(@FLASH_PAGE_SIZE@);
@@ -185,6 +181,10 @@ SECTIONS
_updatekey_store = .;
. += 1024;
. = ALIGN(@FLASH_PAGE_SIZE@);
_data_pool = .;
KEEP(*(.gnuk_data))
. = ALIGN(@FLASH_PAGE_SIZE@);
. += @FLASH_PAGE_SIZE@;
} > flash =0xffffffff
}

View File

@@ -35,7 +35,7 @@
#include "usb_lld.h"
#include "usb-cdc.h"
#include "random.h"
#include "stm32f103.h"
#include "mcu/stm32f103.h"
/*
@@ -130,9 +130,9 @@ static void emit_led (int on_time, int off_time)
static void display_status_code (void)
{
enum icc_state icc_state = *icc_state_p;
enum ccid_state ccid_state = *ccid_state_p;
if (icc_state == ICC_STATE_START)
if (ccid_state == CCID_STATE_START)
emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
else
/* OpenPGP card thread is running */
@@ -144,12 +144,12 @@ static void display_status_code (void)
emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_INTERVAL);
if (icc_state == ICC_STATE_WAIT)
if (ccid_state == CCID_STATE_WAIT)
chopstx_usec_wait (LED_TIMEOUT_STOP * 2);
else
{
chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
emit_led (icc_state == ICC_STATE_RECEIVE?
emit_led (ccid_state == CCID_STATE_RECEIVE?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
}
}
@@ -158,6 +158,12 @@ static void display_status_code (void)
void
led_blink (int spec)
{
if (spec == LED_START_COMMAND || spec == LED_FINISH_COMMAND)
{
led_inverted = (spec == LED_START_COMMAND);
spec = LED_SYNC;
}
eventflag_signal (&led_event, spec);
}
@@ -178,9 +184,9 @@ calculate_regnual_entry_address (const uint8_t *addr)
return v;
}
extern uint8_t __process1_stack_base__, __process1_stack_size__;
const uint32_t __stackaddr_ccid = (uint32_t)&__process1_stack_base__;
const size_t __stacksize_ccid = (size_t)&__process1_stack_size__;
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
#define STACK_ADDR_CCID ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_CCID ((uint32_t)__process1_stack_size__)
#define PRIO_CCID 3
#define PRIO_MAIN 5
@@ -219,7 +225,7 @@ main (int argc, char *argv[])
stdout_init ();
#endif
ccid_thd = chopstx_create (PRIO_CCID, __stackaddr_ccid, __stacksize_ccid,
ccid_thd = chopstx_create (PRIO_CCID, STACK_ADDR_CCID, STACK_SIZE_CCID,
ccid_thread, NULL);
#ifdef PINPAD_CIR_SUPPORT
@@ -256,18 +262,12 @@ main (int argc, char *argv[])
case LED_SHOW_STATUS:
display_status_code ();
break;
case LED_START_COMMAND:
set_led (1);
led_inverted = 1;
chopstx_usec_wait (LED_TIMEOUT_STOP);
break;
case LED_FINISH_COMMAND:
led_inverted = 0;
set_led (0);
break;
case LED_FATAL:
display_fatal_code ();
break;
case LED_SYNC:
set_led (led_inverted);
break;
case LED_GNUK_EXEC:
goto exec;
default:
@@ -354,6 +354,7 @@ extern uint8_t __heap_end__[];
#define MEMORY_END (__heap_end__)
#define MEMORY_ALIGNMENT 16
#define MEMORY_ALIGN(n) (((n) + MEMORY_ALIGNMENT - 1) & ~(MEMORY_ALIGNMENT - 1))
#define MEMORY_SIZE ((uintptr_t)__heap_end__ - (uintptr_t)__heap_base__)
static uint8_t *heap_p;
static chopstx_mutex_t malloc_mtx;
@@ -365,6 +366,10 @@ struct mem_head {
struct mem_head *neighbor; /* backlink to neighbor */
};
#define MEM_HEAD_IS_CORRUPT(x) \
((x)->size != MEMORY_ALIGN((x)->size) || (x)->size > MEMORY_SIZE)
#define MEM_HEAD_CHECK(x) if (MEM_HEAD_IS_CORRUPT(x)) fatal (FATAL_HEAP)
static struct mem_head *free_list;
static void
@@ -421,7 +426,7 @@ gnuk_malloc (size_t size)
m->size = size;
break;
}
MEM_HEAD_CHECK (m);
if (m->size == size)
{
remove_from_free_list (m);
@@ -457,15 +462,20 @@ gnuk_free (void *p)
struct mem_head *m = (struct mem_head *)((void *)p - sizeof (uint32_t));
struct mem_head *m0;
if (p == NULL)
return;
chopstx_mutex_lock (&malloc_mtx);
m0 = free_list;
DEBUG_INFO ("free: ");
DEBUG_SHORT (m->size);
DEBUG_WORD ((uint32_t)p);
MEM_HEAD_CHECK (m);
m->neighbor = NULL;
while (m0)
{
MEM_HEAD_CHECK (m0);
if ((void *)m + m->size == (void *)m0)
m0->neighbor = m;
else if ((void *)m0 + m0->size == (void *)m)
@@ -481,6 +491,7 @@ gnuk_free (void *p)
heap_p -= m->size;
while (mn)
{
MEM_HEAD_CHECK (mn);
heap_p -= mn->size;
remove_from_free_list (mn);
mn = mn->neighbor;

56
src/mcu-stm32f103.c Normal file
View File

@@ -0,0 +1,56 @@
/*
* mcu-stm32f103.c - STM32F103 specific routines
*
* Copyright (C) 2017
* 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 <stdint.h>
#include "mcu/stm32f103.h"
static uint32_t
rbit (uint32_t v)
{
uint32_t r;
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
return r;
}
int
check_crc32 (const uint32_t *start_p, 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 = start_p; p < end_p; p++)
CRC->DR = rbit (*p);
return (rbit (CRC->DR) ^ crc32) == 0xffffffff;
}
uint8_t *
sram_address (uint32_t offset)
{
return ((uint8_t *)0x20000000) + offset;
}

View File

@@ -36,7 +36,6 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
bn512 q_big[1], tmp[1];
uint32_t carry;
#define borrow carry
uint32_t borrow_next;
memset (q, 0, sizeof (bn256));
q->word[0] = A->word[15];
@@ -110,9 +109,7 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
= tmp->word[11] = tmp->word[10] = tmp->word[9] = 0;
borrow = bn256_sub (X, (bn256 *)&q_big->word[0], (bn256 *)&tmp->word[0]);
borrow_next = (q_big->word[8] < borrow);
q_big->word[8] -= borrow;
borrow_next += (q_big->word[8] < tmp->word[8]);
q_big->word[8] -= tmp->word[8];
carry = q_big->word[8];
@@ -122,7 +119,7 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
bn256_sub (q, X, B);
if (carry)
carry -= bn256_sub (X, X, B);
bn256_sub (X, X, B);
else
bn256_sub (q, X, B);
@@ -159,6 +156,7 @@ mod_inv (bn256 *C, const bn256 *X, const bn256 *N)
#define borrow carry
int n = MAX_GCD_STEPS_BN256;
memset (tmp, 0, sizeof (bn256));
memset (C, 0, sizeof (bn256));
memcpy (u, X, sizeof (bn256));
memcpy (v, N, sizeof (bn256));

View File

@@ -1,7 +1,8 @@
/*
* neug.c - true random number generation
*
* Copyright (C) 2011, 2012, 2013 Free Software Initiative of Japan
* Copyright (C) 2011, 2012, 2013, 2016
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of NeuG, a True Random Number Generator
@@ -28,19 +29,13 @@
#include "sys.h"
#include "neug.h"
#include "stm32f103.h"
#include "mcu/stm32f103.h"
#include "adc.h"
#include "sha256.h"
static chopstx_mutex_t mode_mtx;
static chopstx_cond_t mode_cond;
/*
* ADC finish interrupt
*/
#define INTR_REQ_DMA1_Channel1 11
static sha256_context sha256_ctx_data;
static uint32_t sha256_output[SHA256_DIGEST_SIZE/sizeof (uint32_t)];
@@ -574,7 +569,6 @@ static void *
rng (void *arg)
{
struct rng_rb *rb = (struct rng_rb *)arg;
chopstx_intr_t adc_intr;
int mode = neug_mode;
rng_should_terminate = 0;
@@ -582,7 +576,6 @@ rng (void *arg)
chopstx_cond_init (&mode_cond);
/* Enable ADCs */
chopstx_claim_irq (&adc_intr, INTR_REQ_DMA1_Channel1);
adc_start ();
ep_init (mode);
@@ -591,7 +584,7 @@ rng (void *arg)
int err;
int n;
err = adc_wait_completion (&adc_intr);
err = adc_wait_completion ();
chopstx_mutex_lock (&mode_mtx);
if (err || mode != neug_mode)
@@ -647,9 +640,9 @@ rng (void *arg)
static struct rng_rb the_ring_buffer;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
const uint32_t __stackaddr_rng = (uint32_t)&__process2_stack_base__;
const size_t __stacksize_rng = (size_t)&__process2_stack_size__;
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
#define STACK_ADDR_RNG ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_RNG ((uint32_t)__process2_stack_size__)
#define PRIO_RNG 2
/**
@@ -675,7 +668,7 @@ neug_init (uint32_t *buf, uint8_t size)
neug_mode = NEUG_MODE_CONDITIONED;
rb_init (rb, buf, size);
rng_thread = chopstx_create (PRIO_RNG, __stackaddr_rng, __stacksize_rng,
rng_thread = chopstx_create (PRIO_RNG, STACK_ADDR_RNG, STACK_SIZE_RNG,
rng, rb);
}

View File

@@ -1,7 +1,7 @@
/*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -30,7 +30,7 @@
#include "sys.h"
#include "gnuk.h"
#include "openpgp.h"
#include "status-code.h"
#include "random.h"
#include "polarssl/config.h"
#include "polarssl/aes.h"
@@ -40,7 +40,7 @@
#define CLEAN_PAGE_FULL 1
#define CLEAN_SINGLE 0
static void gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full);
static void gpg_reset_digital_signature_counter (void);
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
static const uint8_t *pw_err_counter_p[3];
@@ -90,11 +90,11 @@ uint16_t data_objects_number_of_bytes;
/*
* Compile time vars:
* Historical Bytes (template), Extended Capabilities.
* Historical Bytes, Extended Capabilities.
*/
/* Historical Bytes (template) */
static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
/* Historical Bytes */
const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
10,
0x00,
0x31, 0x84, /* Full DF name, GET DATA, MF */
@@ -102,7 +102,12 @@ static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
0x80, 0x01, 0x80, /* Full DF name */
/* 1-byte */
/* Command chaining, No extended Lc and Le */
0x00, 0x90, 0x00 /* Status info (no life cycle management) */
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
0x05,
#else
0x00,
#endif
0x90, 0x00 /* Status info */
};
/* Extended Capabilities */
@@ -245,6 +250,28 @@ gpg_get_algo_attr (enum kind_of_key kk)
return algo_attr_p[1];
}
static void
gpg_reset_algo_attr (enum kind_of_key kk)
{
gpg_do_delete_prvkey (kk, CLEAN_PAGE_FULL);
if (kk == GPG_KEY_FOR_SIGNING)
{
gpg_reset_digital_signature_counter ();
gpg_do_write_simple (NR_DO_FP_SIG, NULL, 0);
gpg_do_write_simple (NR_DO_KGTIME_SIG, NULL, 0);
}
else if (kk == GPG_KEY_FOR_DECRYPTION)
{
gpg_do_write_simple (NR_DO_FP_DEC, NULL, 0);
gpg_do_write_simple (NR_DO_KGTIME_DEC, NULL, 0);
}
else
{
gpg_do_write_simple (NR_DO_FP_AUT, NULL, 0);
gpg_do_write_simple (NR_DO_KGTIME_AUT, NULL, 0);
}
}
static const uint8_t *
get_algo_attr_data_object (enum kind_of_key kk)
{
@@ -331,7 +358,7 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc)
else
{
hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2);
hw1 = NR_COUNTER_DS_LSB;
hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8);
flash_put_data_internal (p, hw0);
flash_put_data_internal (p+2, hw1);
return p+4;
@@ -485,23 +512,6 @@ copy_tag (uint16_t tag)
}
}
static int
do_hist_bytes (uint16_t tag, int with_tag)
{
/*
* Currently, we support no life cycle management. In case of Gnuk,
* user could flash the MCU with SWD/JTAG, instead. It is also
* possible for user to do firmware upgrade through USB.
*
* Thus, here, it just returns the template as is.
*
* In future (when Gnuk will be on the real smartcard),
* we can support life cycle management by implementing
* TERMINATE DF / ACTIVATE FILE and fix code around here.
*/
copy_do_1 (tag, historical_bytes, with_tag);
return 1;
}
#define SIZE_FP 20
#define SIZE_KGTIME 4
@@ -761,15 +771,15 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
return 0; /* Error. */
else if (algo == ALGO_RSA2K && *algo_attr_pp != NULL)
{
gpg_do_delete_prvkey (kk, CLEAN_PAGE_FULL);
gpg_reset_algo_attr (kk);
flash_enum_clear (algo_attr_pp);
if (*algo_attr_pp != NULL)
return 0;
}
else if ((algo != ALGO_RSA2K && *algo_attr_pp == NULL)
|| (*algo_attr_pp)[1] != algo)
else if ((algo != ALGO_RSA2K && *algo_attr_pp == NULL) ||
(*algo_attr_pp != NULL && (*algo_attr_pp)[1] != algo))
{
gpg_do_delete_prvkey (kk, CLEAN_PAGE_FULL);
gpg_reset_algo_attr (kk);
*algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo);
if (*algo_attr_pp == NULL)
return 0;
@@ -1042,6 +1052,28 @@ gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full)
}
}
void
gpg_do_terminate (void)
{
int i;
for (i = 0; i < 3; i++)
kd[i].pubkey = NULL;
for (i = 0; i < NR_DO__LAST__; i++)
do_ptr[i] = NULL;
num_prv_keys = 0;
data_objects_number_of_bytes = 0;
digital_signature_counter = 0;
pw1_lifetime_p = NULL;
pw_err_counter_p[PW_ERR_PW1] = NULL;
pw_err_counter_p[PW_ERR_RC] = NULL;
pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
}
static int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
int prvkey_len, const uint8_t *keystring_admin,
@@ -1459,7 +1491,6 @@ gpg_do_table[] = {
{ GPG_DO_NAME, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[12] },
{ GPG_DO_LANGUAGE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[13] },
/* Pseudo DO READ: calculated */
{ GPG_DO_HIST_BYTES, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_hist_bytes },
{ GPG_DO_FP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_fp_all },
{ GPG_DO_CAFP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_cafp_all },
{ GPG_DO_KGTIME_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_kgtime_all },
@@ -1476,6 +1507,7 @@ gpg_do_table[] = {
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_algorithm_attr },
/* Fixed data */
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
/* Compound data: Read access only */
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
@@ -1501,7 +1533,7 @@ gpg_do_table[] = {
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
*/
void
gpg_data_scan (const uint8_t *p_start)
gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
{
const uint8_t *p;
int i;
@@ -1514,10 +1546,15 @@ gpg_data_scan (const uint8_t *p_start)
pw_err_counter_p[PW_ERR_RC] = NULL;
pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
digital_signature_counter = 0;
/* When the card is terminated no data objects are valid. */
if (do_start == NULL)
return;
/* Traverse DO, counters, etc. in DATA pool */
p = p_start;
while (*p != NR_EMPTY)
p = do_start;
while (p < do_end && *p != NR_EMPTY)
{
uint8_t nr = *p++;
uint8_t second_byte = *p;
@@ -1529,7 +1566,9 @@ gpg_data_scan (const uint8_t *p_start)
if (nr < 0x80)
{
/* It's Data Object */
do_ptr[nr] = p;
if (nr < NR_DO__LAST__)
do_ptr[nr] = p;
p += second_byte + 1; /* second_byte has length */
if (((uint32_t)p & 1))

View File

@@ -1,7 +1,7 @@
/*
* openpgp.c -- OpenPGP card protocol support
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -31,7 +31,7 @@
#include "gnuk.h"
#include "sys.h"
#include "openpgp.h"
#include "status-code.h"
#include "sha256.h"
#include "random.h"
@@ -48,6 +48,7 @@ static struct eventflag *openpgp_comm;
#define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_PSO 0x2a
#define INS_RESET_RETRY_COUNTER 0x2c
#define INS_ACTIVATE_FILE 0x44
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47
#define INS_EXTERNAL_AUTHENTICATE 0x82
#define INS_GET_CHALLENGE 0x84
@@ -59,6 +60,7 @@ static struct eventflag *openpgp_comm;
#define INS_UPDATE_BINARY 0xd6
#define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb /* For key import */
#define INS_TERMINATE_DF 0xe6
static const uint8_t *challenge; /* Random bytes */
@@ -96,17 +98,24 @@ set_res_sw (uint8_t sw1, uint8_t sw2)
#define FILE_EF_UPDATE_KEY_2 7
#define FILE_EF_UPDATE_KEY_3 8
#define FILE_EF_CH_CERTIFICATE 9
#define FILE_CARD_TERMINATED 255
static uint8_t file_selection;
uint8_t file_selection;
static void
gpg_init (void)
{
const uint8_t *flash_data_start;
const uint8_t *flash_do_start;
const uint8_t *flash_do_end;
file_selection = FILE_NONE;
flash_data_start = flash_init ();
gpg_data_scan (flash_data_start);
flash_init (&flash_do_start, &flash_do_end);
if (flash_do_start == NULL)
file_selection = FILE_CARD_TERMINATED;
else
file_selection = FILE_NONE;
gpg_data_scan (flash_do_start, flash_do_end);
flash_init_keys ();
}
@@ -616,9 +625,6 @@ cmd_put_data (void)
DEBUG_INFO (" - PUT DATA\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD();
tag = ((P1 (apdu)<<8) | P2 (apdu));
len = apdu.cmd_apdu_data_len;
data = apdu.cmd_apdu_data;
@@ -751,19 +757,16 @@ cmd_select_file (void)
return;
}
file_selection = FILE_DF_OPENPGP;
if ((P2 (apdu) & 0x0c) == 0x0c) /* No FCI */
GPG_SUCCESS ();
else
if (file_selection == FILE_CARD_TERMINATED)
{
gpg_do_get_data (0x004f, 1); /* AID */
memmove (res_APDU+2, res_APDU, res_APDU_size);
res_APDU[0] = 0x6f;
res_APDU[1] = 0x12;
res_APDU[2] = 0x84; /* overwrite: DF name */
res_APDU_size += 2;
GPG_SUCCESS ();
GPG_APPLICATION_TERMINATED ();
return;
}
file_selection = FILE_DF_OPENPGP;
/* Behave just like original OpenPGP card. */
GPG_SUCCESS ();
}
else if (apdu.cmd_apdu_data_len == 2
&& apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02)
@@ -813,9 +816,6 @@ cmd_get_data (void)
DEBUG_INFO (" - Get Data\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD ();
gpg_do_get_data (tag, 0);
}
@@ -1317,6 +1317,69 @@ cmd_get_challenge (void)
}
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
static void
cmd_activate_file (void)
{
if (file_selection != FILE_CARD_TERMINATED)
{
GPG_NO_RECORD ();
return;
}
flash_activate ();
file_selection = FILE_DF_OPENPGP;
GPG_SUCCESS ();
}
static void
cmd_terminate_df (void)
{
const uint8_t *ks_pw3;
uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu);
if (file_selection != FILE_DF_OPENPGP)
{
GPG_NO_RECORD ();
return;
}
if (p1 != 0 || p2 != 0)
{
GPG_BAD_P1_P2();
return;
}
if (apdu.cmd_apdu_data_len != 0)
{
GPG_WRONG_LENGTH();
return;
}
ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
if (!ac_check_status (AC_ADMIN_AUTHORIZED)
&& !((ks_pw3 && gpg_pw_locked (PW_ERR_PW3))
|| (ks_pw3 == NULL && gpg_pw_locked (PW_ERR_PW1))))
{
/* Only allow the case admin authorized, or, admin pass is locked. */
GPG_SECURITY_FAILURE();
return;
}
ac_reset_admin ();
ac_reset_pso_cds ();
ac_reset_other ();
gpg_do_terminate ();
flash_terminate ();
file_selection = FILE_CARD_TERMINATED;
GPG_SUCCESS ();
}
#endif
struct command
{
uint8_t command;
@@ -1328,13 +1391,16 @@ const struct command cmds[] = {
{ INS_CHANGE_REFERENCE_DATA, cmd_change_password },
{ INS_PSO, cmd_pso },
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_ACTIVATE_FILE, cmd_activate_file },
#endif
{ 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_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */
{ INS_GET_DATA, cmd_get_data },
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
#if defined(CERTDO_SUPPORT)
@@ -1342,6 +1408,9 @@ const struct command cmds[] = {
#endif
{ INS_PUT_DATA, cmd_put_data },
{ INS_PUT_DATA_ODD, cmd_put_data },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_TERMINATE_DF, cmd_terminate_df},
#endif
};
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
@@ -1357,9 +1426,22 @@ process_command_apdu (void)
if (i < NUM_CMDS)
{
chopstx_setcancelstate (1);
cmds[i].cmd_handler ();
chopstx_setcancelstate (0);
if (file_selection == FILE_CARD_TERMINATED
&& cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
&& cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE)
GPG_APPLICATION_TERMINATED ();
else if (file_selection != FILE_DF_OPENPGP
&& cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
&& cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE
&& cmd != INS_WRITE_BINARY && cmd != INS_UPDATE_BINARY
&& cmd != INS_READ_BINARY)
GPG_NO_RECORD ();
else
{
chopstx_setcancelstate (1);
cmds[i].cmd_handler ();
chopstx_setcancelstate (0);
}
}
else
{
@@ -1369,23 +1451,10 @@ process_command_apdu (void)
}
}
static void * card_thread (chopstx_t thd, struct eventflag *ccid_comm);
void * __attribute__ ((naked))
void *
openpgp_card_thread (void *arg)
{
chopstx_t thd;
asm ("mov %0, sp" : "=r" (thd));
return card_thread (thd, (struct eventflag *)arg);
}
chopstx_t openpgp_card_thd;
static void * __attribute__ ((noinline))
card_thread (chopstx_t thd, struct eventflag *ccid_comm)
{
openpgp_card_thd = thd;
struct eventflag *ccid_comm = (struct eventflag *)arg;
openpgp_comm = ccid_comm + 1;

View File

@@ -28,7 +28,7 @@
#include "config.h"
#include "board.h"
#include "gnuk.h"
#include "stm32f103.h"
#include "mcu/stm32f103.h"
#ifdef DEBUG
#define DEBUG_CIR 1
@@ -51,10 +51,9 @@ cir_ext_enable (void)
EXTI->IMR |= EXTI_IMR;
}
static chopstx_t pin_thread;
static uint32_t wait_usec;
static uint8_t notification;
static chopstx_mutex_t cir_input_mtx;
static chopstx_cond_t cir_input_cnd;
static int input_avail;
uint8_t pin_input_buffer[MAX_PIN_CHARS];
uint8_t pin_input_len;
@@ -500,9 +499,18 @@ hex (int x)
return (x - 10) + 'a';
}
static int
check_input (void *arg)
{
(void)arg;
return input_avail;
}
static int
cir_getchar (uint32_t timeout)
{
chopstx_poll_cond_t poll_desc;
struct chx_poll_head *pd_array[1] = { (struct chx_poll_head *)&poll_desc };
uint16_t cir_addr;
#if defined(DEBUG_CIR)
uint16_t *p;
@@ -514,10 +522,15 @@ cir_getchar (uint32_t timeout)
cir_ll_init ();
notification = 0;
wait_usec = timeout;
chopstx_usec_wait_var (&wait_usec);
if (notification == 0)
poll_desc.type = CHOPSTX_POLL_COND;
poll_desc.ready = 0;
poll_desc.cond = &cir_input_cnd;
poll_desc.mutex = &cir_input_mtx;
poll_desc.check = check_input;
poll_desc.arg = NULL;
input_avail = 0;
if (chopstx_poll (&timeout, 1, pd_array) == 0)
return -1;
/* Sleep 200ms to avoid detecting chatter inputs. */
@@ -631,13 +644,10 @@ cir_getchar (uint32_t timeout)
int
pinpad_getline (int msg_code, uint32_t timeout)
{
extern chopstx_t openpgp_card_thd;
(void)msg_code;
DEBUG_INFO (">>>\r\n");
pin_thread = openpgp_card_thd;
pin_input_len = 0;
while (1)
{
@@ -663,7 +673,6 @@ pinpad_getline (int msg_code, uint32_t timeout)
}
cir_ext_disable ();
pin_thread = NULL;
return pin_input_len;
}
@@ -932,13 +941,12 @@ cir_timer_interrupt (void)
{
/*
* Notify the thread, when it's waiting the input.
* If else, throw away the input.
* If else, the input is thrown away.
*/
if (pin_thread)
{
notification = 1;
chopstx_wakeup_usec_wait (pin_thread);
}
chopstx_mutex_lock (&cir_input_mtx);
input_avail = 1;
chopstx_cond_signal (&cir_input_cnd);
chopstx_mutex_unlock (&cir_input_mtx);
}
#if defined(DEBUG_CIR)
@@ -956,9 +964,9 @@ cir_timer_interrupt (void)
}
extern uint8_t __process6_stack_base__, __process6_stack_size__;
const uint32_t __stackaddr_tim = (uint32_t)&__process6_stack_base__;
const size_t __stacksize_tim = (size_t)&__process6_stack_size__;
extern uint8_t __process6_stack_base__[], __process6_stack_size__[];
#define STACK_ADDR_TIM ((uint32_t)__process6_stack_base__)
#define STACK_SIZE_TIM ((uint32_t)__process6_stack_size__)
#define PRIO_TIM 4
static void *
@@ -1004,6 +1012,9 @@ ext_main (void *arg)
void
cir_init (void)
{
chopstx_mutex_init (&cir_input_mtx);
chopstx_cond_init (&cir_input_cnd);
/*
* We use XOR function for three signals: TIMx_CH1, TIMx_CH2, and TIMx_CH3.
*
@@ -1046,6 +1057,6 @@ cir_init (void)
/* Generate UEV to upload PSC and ARR */
TIMx->EGR = TIM_EGR_UG;
chopstx_create (PRIO_TIM, __stackaddr_tim, __stacksize_tim, tim_main, NULL);
chopstx_create (PRIO_EXT, __stackaddr_ext, __stacksize_ext, ext_main, NULL);
chopstx_create (PRIO_TIM, STACK_ADDR_TIM, STACK_SIZE_TIM, tim_main, NULL);
chopstx_create (PRIO_EXT, STACK_ADDR_EXT, STACK_SIZE_EXT, ext_main, NULL);
}

View File

@@ -1,4 +1,6 @@
#define GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85)
#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define GPG_WRONG_LENGTH() set_res_sw (0x67, 0x00)
#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82)
#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83)
#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85)

View File

@@ -1,700 +0,0 @@
#define PERIPH_BASE 0x40000000
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
struct RCC {
volatile uint32_t CR;
volatile uint32_t CFGR;
volatile uint32_t CIR;
volatile uint32_t APB2RSTR;
volatile uint32_t APB1RSTR;
volatile uint32_t AHBENR;
volatile uint32_t APB2ENR;
volatile uint32_t APB1ENR;
volatile uint32_t BDCR;
volatile uint32_t CSR;
};
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
static struct RCC *const RCC = ((struct RCC *const)RCC_BASE);
#define RCC_AHBENR_DMA1EN 0x00000001
#define RCC_AHBENR_CRCEN 0x00000040
#define RCC_APB2ENR_ADC1EN 0x00000200
#define RCC_APB2ENR_ADC2EN 0x00000400
#define RCC_APB2ENR_TIM1EN 0x00000800
#define RCC_APB1ENR_TIM2EN 0x00000001
#define RCC_APB1ENR_TIM3EN 0x00000002
#define RCC_APB1ENR_TIM4EN 0x00000004
#define RCC_APB2RSTR_ADC1RST 0x00000200
#define RCC_APB2RSTR_ADC2RST 0x00000400
#define RCC_APB2RSTR_TIM1RST 0x00000800
#define RCC_APB1RSTR_TIM2RST 0x00000001
#define RCC_APB1RSTR_TIM3RST 0x00000002
#define RCC_APB1RSTR_TIM4RST 0x00000004
#define CRC_CR_RESET 0x00000001
struct CRC {
volatile uint32_t DR;
volatile uint8_t IDR;
uint8_t RESERVED0;
uint16_t RESERVED1;
volatile uint32_t CR;
};
#define CRC_BASE (AHBPERIPH_BASE + 0x3000)
static struct CRC *const CRC = ((struct CRC *const)CRC_BASE);
struct ADC {
volatile uint32_t SR;
volatile uint32_t CR1;
volatile uint32_t CR2;
volatile uint32_t SMPR1;
volatile uint32_t SMPR2;
volatile uint32_t JOFR1;
volatile uint32_t JOFR2;
volatile uint32_t JOFR3;
volatile uint32_t JOFR4;
volatile uint32_t HTR;
volatile uint32_t LTR;
volatile uint32_t SQR1;
volatile uint32_t SQR2;
volatile uint32_t SQR3;
volatile uint32_t JSQR;
volatile uint32_t JDR1;
volatile uint32_t JDR2;
volatile uint32_t JDR3;
volatile uint32_t JDR4;
volatile uint32_t DR;
};
#define ADC1_BASE (APB2PERIPH_BASE + 0x2400)
#define ADC2_BASE (APB2PERIPH_BASE + 0x2800)
static struct ADC *const ADC1 = (struct ADC *const)ADC1_BASE;
static struct ADC *const ADC2 = (struct ADC *const)ADC2_BASE;
#define ADC_CR1_DUALMOD_0 0x00010000
#define ADC_CR1_DUALMOD_1 0x00020000
#define ADC_CR1_DUALMOD_2 0x00040000
#define ADC_CR1_DUALMOD_3 0x00080000
#define ADC_CR1_SCAN 0x00000100
#define ADC_CR2_ADON 0x00000001
#define ADC_CR2_CONT 0x00000002
#define ADC_CR2_CAL 0x00000004
#define ADC_CR2_RSTCAL 0x00000008
#define ADC_CR2_DMA 0x00000100
#define ADC_CR2_ALIGN 0x00000800
#define ADC_CR2_EXTSEL 0x000E0000
#define ADC_CR2_EXTSEL_0 0x00020000
#define ADC_CR2_EXTSEL_1 0x00040000
#define ADC_CR2_EXTSEL_2 0x00080000
#define ADC_CR2_EXTTRIG 0x00100000
#define ADC_CR2_SWSTART 0x00400000
#define ADC_CR2_TSVREFE 0x00800000
struct DMA_Channel {
volatile uint32_t CCR;
volatile uint32_t CNDTR;
volatile uint32_t CPAR;
volatile uint32_t CMAR;
};
struct DMA {
volatile uint32_t ISR;
volatile uint32_t IFCR;
};
#define STM32_DMA_CR_MINC DMA_CCR1_MINC
#define STM32_DMA_CR_MSIZE_WORD DMA_CCR1_MSIZE_1
#define STM32_DMA_CR_PSIZE_WORD DMA_CCR1_PSIZE_1
#define STM32_DMA_CR_TCIE DMA_CCR1_TCIE
#define STM32_DMA_CR_TEIE DMA_CCR1_TEIE
#define STM32_DMA_CR_HTIE DMA_CCR1_HTIE
#define STM32_DMA_ISR_TEIF DMA_ISR_TEIF1
#define STM32_DMA_ISR_HTIF DMA_ISR_HTIF1
#define STM32_DMA_ISR_TCIF DMA_ISR_TCIF1
#define STM32_DMA_ISR_MASK 0x0F
#define STM32_DMA_CCR_RESET_VALUE 0x00000000
#define STM32_DMA_CR_PL_MASK DMA_CCR1_PL
#define STM32_DMA_CR_PL(n) ((n) << 12)
#define DMA_CCR1_EN 0x00000001
#define DMA_CCR1_TCIE 0x00000002
#define DMA_CCR1_HTIE 0x00000004
#define DMA_CCR1_TEIE 0x00000008
#define DMA_CCR1_DIR 0x00000010
#define DMA_CCR1_CIRC 0x00000020
#define DMA_CCR1_PINC 0x00000040
#define DMA_CCR1_MINC 0x00000080
#define DMA_CCR1_PSIZE 0x00000300
#define DMA_CCR1_PSIZE_0 0x00000100
#define DMA_CCR1_PSIZE_1 0x00000200
#define DMA_CCR1_MSIZE 0x00000C00
#define DMA_CCR1_MSIZE_0 0x00000400
#define DMA_CCR1_MSIZE_1 0x00000800
#define DMA_CCR1_PL 0x00003000
#define DMA_CCR1_PL_0 0x00001000
#define DMA_CCR1_PL_1 0x00002000
#define DMA_CCR1_MEM2MEM 0x00004000
#define DMA_ISR_GIF1 0x00000001
#define DMA_ISR_TCIF1 0x00000002
#define DMA_ISR_HTIF1 0x00000004
#define DMA_ISR_TEIF1 0x00000008
#define DMA_ISR_GIF2 0x00000010
#define DMA_ISR_TCIF2 0x00000020
#define DMA_ISR_HTIF2 0x00000040
#define DMA_ISR_TEIF2 0x00000080
#define DMA_ISR_GIF3 0x00000100
#define DMA_ISR_TCIF3 0x00000200
#define DMA_ISR_HTIF3 0x00000400
#define DMA_ISR_TEIF3 0x00000800
#define DMA_ISR_GIF4 0x00001000
#define DMA_ISR_TCIF4 0x00002000
#define DMA_ISR_HTIF4 0x00004000
#define DMA_ISR_TEIF4 0x00008000
#define DMA_ISR_GIF5 0x00010000
#define DMA_ISR_TCIF5 0x00020000
#define DMA_ISR_HTIF5 0x00040000
#define DMA_ISR_TEIF5 0x00080000
#define DMA_ISR_GIF6 0x00100000
#define DMA_ISR_TCIF6 0x00200000
#define DMA_ISR_HTIF6 0x00400000
#define DMA_ISR_TEIF6 0x00800000
#define DMA_ISR_GIF7 0x01000000
#define DMA_ISR_TCIF7 0x02000000
#define DMA_ISR_HTIF7 0x04000000
#define DMA_ISR_TEIF7 0x08000000
#define DMA1_BASE (AHBPERIPH_BASE + 0x0000)
static struct DMA *const DMA1 = (struct DMA *const)DMA1_BASE;
#define DMA1_Channel1_BASE (AHBPERIPH_BASE + 0x0008)
static struct DMA_Channel *const DMA1_Channel1 =
(struct DMA_Channel *const)DMA1_Channel1_BASE;
/* System Control Block */
struct SCB
{
volatile uint32_t CPUID;
volatile uint32_t ICSR;
volatile uint32_t VTOR;
volatile uint32_t AIRCR;
volatile uint32_t SCR;
volatile uint32_t CCR;
volatile uint8_t SHP[12];
volatile uint32_t SHCSR;
volatile uint32_t CFSR;
volatile uint32_t HFSR;
volatile uint32_t DFSR;
volatile uint32_t MMFAR;
volatile uint32_t BFAR;
volatile uint32_t AFSR;
volatile uint32_t PFR[2];
volatile uint32_t DFR;
volatile uint32_t ADR;
volatile uint32_t MMFR[4];
volatile uint32_t ISAR[5];
uint32_t RESERVED0[5];
volatile uint32_t CPACR;
};
#define SCS_BASE 0xE000E000
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = (struct SCB *const)SCB_BASE;
/* Timer */
struct TIM
{
volatile uint16_t CR1; uint16_t RESERVED0;
volatile uint16_t CR2; uint16_t RESERVED1;
volatile uint16_t SMCR; uint16_t RESERVED2;
volatile uint16_t DIER; uint16_t RESERVED3;
volatile uint16_t SR; uint16_t RESERVED4;
volatile uint16_t EGR; uint16_t RESERVED5;
volatile uint16_t CCMR1; uint16_t RESERVED6;
volatile uint16_t CCMR2; uint16_t RESERVED7;
volatile uint16_t CCER; uint16_t RESERVED8;
volatile uint16_t CNT; uint16_t RESERVED9;
volatile uint16_t PSC; uint16_t RESERVED10;
volatile uint16_t ARR; uint16_t RESERVED11;
volatile uint16_t RCR; uint16_t RESERVED12;
volatile uint16_t CCR1; uint16_t RESERVED13;
volatile uint16_t CCR2; uint16_t RESERVED14;
volatile uint16_t CCR3; uint16_t RESERVED15;
volatile uint16_t CCR4; uint16_t RESERVED16;
volatile uint16_t BDTR; uint16_t RESERVED17;
volatile uint16_t DCR; uint16_t RESERVED18;
volatile uint16_t DMAR; uint16_t RESERVED19;
};
#define TIM2_BASE 0x40000000
#define TIM3_BASE 0x40000400
#define TIM4_BASE 0x40000800
static struct TIM *const TIM2 = (struct TIM *const)TIM2_BASE;
static struct TIM *const TIM3 = (struct TIM *const)TIM3_BASE;
static struct TIM *const TIM4 = (struct TIM *const)TIM4_BASE;
#define TIM_CR1_CEN 0x0001
#define TIM_CR1_UDIS 0x0002
#define TIM_CR1_URS 0x0004
#define TIM_CR1_OPM 0x0008
#define TIM_CR1_DIR 0x0010
#define TIM_CR1_CMS 0x0060
#define TIM_CR1_CMS_0 0x0020
#define TIM_CR1_CMS_1 0x0040
#define TIM_CR1_ARPE 0x0080
#define TIM_CR1_CKD 0x0300
#define TIM_CR1_CKD_0 0x0100
#define TIM_CR1_CKD_1 0x0200
#define TIM_CR2_CCPC 0x0001
#define TIM_CR2_CCUS 0x0004
#define TIM_CR2_CCDS 0x0008
#define TIM_CR2_MMS 0x0070
#define TIM_CR2_MMS_0 0x0010
#define TIM_CR2_MMS_1 0x0020
#define TIM_CR2_MMS_2 0x0040
#define TIM_CR2_TI1S 0x0080
#define TIM_CR2_OIS1 0x0100
#define TIM_CR2_OIS1N 0x0200
#define TIM_CR2_OIS2 0x0400
#define TIM_CR2_OIS2N 0x0800
#define TIM_CR2_OIS3 0x1000
#define TIM_CR2_OIS3N 0x2000
#define TIM_CR2_OIS4 0x4000
#define TIM_SMCR_SMS 0x0007
#define TIM_SMCR_SMS_0 0x0001
#define TIM_SMCR_SMS_1 0x0002
#define TIM_SMCR_SMS_2 0x0004
#define TIM_SMCR_TS 0x0070
#define TIM_SMCR_TS_0 0x0010
#define TIM_SMCR_TS_1 0x0020
#define TIM_SMCR_TS_2 0x0040
#define TIM_SMCR_MSM 0x0080
#define TIM_SMCR_ETF 0x0F00
#define TIM_SMCR_ETF_0 0x0100
#define TIM_SMCR_ETF_1 0x0200
#define TIM_SMCR_ETF_2 0x0400
#define TIM_SMCR_ETF_3 0x0800
#define TIM_SMCR_ETPS 0x3000
#define TIM_SMCR_ETPS_0 0x1000
#define TIM_SMCR_ETPS_1 0x2000
#define TIM_SMCR_ECE 0x4000
#define TIM_SMCR_ETP 0x8000
#define TIM_DIER_UIE 0x0001
#define TIM_DIER_CC1IE 0x0002
#define TIM_DIER_CC2IE 0x0004
#define TIM_DIER_CC3IE 0x0008
#define TIM_DIER_CC4IE 0x0010
#define TIM_DIER_COMIE 0x0020
#define TIM_DIER_TIE 0x0040
#define TIM_DIER_BIE 0x0080
#define TIM_DIER_UDE 0x0100
#define TIM_DIER_CC1DE 0x0200
#define TIM_DIER_CC2DE 0x0400
#define TIM_DIER_CC3DE 0x0800
#define TIM_DIER_CC4DE 0x1000
#define TIM_DIER_COMDE 0x2000
#define TIM_DIER_TDE 0x4000
#define TIM_SR_UIF 0x0001
#define TIM_SR_CC1IF 0x0002
#define TIM_SR_CC2IF 0x0004
#define TIM_SR_CC3IF 0x0008
#define TIM_SR_CC4IF 0x0010
#define TIM_SR_COMIF 0x0020
#define TIM_SR_TIF 0x0040
#define TIM_SR_BIF 0x0080
#define TIM_SR_CC1OF 0x0200
#define TIM_SR_CC2OF 0x0400
#define TIM_SR_CC3OF 0x0800
#define TIM_SR_CC4OF 0x1000
#define TIM_EGR_UG 0x01
#define TIM_EGR_CC1G 0x02
#define TIM_EGR_CC2G 0x04
#define TIM_EGR_CC3G 0x08
#define TIM_EGR_CC4G 0x10
#define TIM_EGR_COMG 0x20
#define TIM_EGR_TG 0x40
#define TIM_EGR_BG 0x80
#define TIM_CCMR1_CC1S 0x0003
#define TIM_CCMR1_CC1S_0 0x0001
#define TIM_CCMR1_CC1S_1 0x0002
#define TIM_CCMR1_OC1FE 0x0004
#define TIM_CCMR1_OC1PE 0x0008
#define TIM_CCMR1_OC1M 0x0070
#define TIM_CCMR1_OC1M_0 0x0010
#define TIM_CCMR1_OC1M_1 0x0020
#define TIM_CCMR1_OC1M_2 0x0040
#define TIM_CCMR1_OC1CE 0x0080
#define TIM_CCMR1_CC2S 0x0300
#define TIM_CCMR1_CC2S_0 0x0100
#define TIM_CCMR1_CC2S_1 0x0200
#define TIM_CCMR1_OC2FE 0x0400
#define TIM_CCMR1_OC2PE 0x0800
#define TIM_CCMR1_OC2M 0x7000
#define TIM_CCMR1_OC2M_0 0x1000
#define TIM_CCMR1_OC2M_1 0x2000
#define TIM_CCMR1_OC2M_2 0x4000
#define TIM_CCMR1_OC2CE 0x8000
#define TIM_CCMR1_IC1PSC 0x000C
#define TIM_CCMR1_IC1PSC_0 0x0004
#define TIM_CCMR1_IC1PSC_1 0x0008
#define TIM_CCMR1_IC1F 0x00F0
#define TIM_CCMR1_IC1F_0 0x0010
#define TIM_CCMR1_IC1F_1 0x0020
#define TIM_CCMR1_IC1F_2 0x0040
#define TIM_CCMR1_IC1F_3 0x0080
#define TIM_CCMR1_IC2PSC 0x0C00
#define TIM_CCMR1_IC2PSC_0 0x0400
#define TIM_CCMR1_IC2PSC_1 0x0800
#define TIM_CCMR1_IC2F 0xF000
#define TIM_CCMR1_IC2F_0 0x1000
#define TIM_CCMR1_IC2F_1 0x2000
#define TIM_CCMR1_IC2F_2 0x4000
#define TIM_CCMR1_IC2F_3 0x8000
#define TIM_CCMR2_CC3S 0x0003
#define TIM_CCMR2_CC3S_0 0x0001
#define TIM_CCMR2_CC3S_1 0x0002
#define TIM_CCMR2_OC3FE 0x0004
#define TIM_CCMR2_OC3PE 0x0008
#define TIM_CCMR2_OC3M 0x0070
#define TIM_CCMR2_OC3M_0 0x0010
#define TIM_CCMR2_OC3M_1 0x0020
#define TIM_CCMR2_OC3M_2 0x0040
#define TIM_CCMR2_OC3CE 0x0080
#define TIM_CCMR2_CC4S 0x0300
#define TIM_CCMR2_CC4S_0 0x0100
#define TIM_CCMR2_CC4S_1 0x0200
#define TIM_CCMR2_OC4FE 0x0400
#define TIM_CCMR2_OC4PE 0x0800
#define TIM_CCMR2_OC4M 0x7000
#define TIM_CCMR2_OC4M_0 0x1000
#define TIM_CCMR2_OC4M_1 0x2000
#define TIM_CCMR2_OC4M_2 0x4000
#define TIM_CCMR2_OC4CE 0x8000
#define TIM_CCMR2_IC3PSC 0x000C
#define TIM_CCMR2_IC3PSC_0 0x0004
#define TIM_CCMR2_IC3PSC_1 0x0008
#define TIM_CCMR2_IC3F 0x00F0
#define TIM_CCMR2_IC3F_0 0x0010
#define TIM_CCMR2_IC3F_1 0x0020
#define TIM_CCMR2_IC3F_2 0x0040
#define TIM_CCMR2_IC3F_3 0x0080
#define TIM_CCMR2_IC4PSC 0x0C00
#define TIM_CCMR2_IC4PSC_0 0x0400
#define TIM_CCMR2_IC4PSC_1 0x0800
#define TIM_CCMR2_IC4F 0xF000
#define TIM_CCMR2_IC4F_0 0x1000
#define TIM_CCMR2_IC4F_1 0x2000
#define TIM_CCMR2_IC4F_2 0x4000
#define TIM_CCMR2_IC4F_3 0x8000
#define TIM_CCER_CC1E 0x0001
#define TIM_CCER_CC1P 0x0002
#define TIM_CCER_CC1NE 0x0004
#define TIM_CCER_CC1NP 0x0008
#define TIM_CCER_CC2E 0x0010
#define TIM_CCER_CC2P 0x0020
#define TIM_CCER_CC2NE 0x0040
#define TIM_CCER_CC2NP 0x0080
#define TIM_CCER_CC3E 0x0100
#define TIM_CCER_CC3P 0x0200
#define TIM_CCER_CC3NE 0x0400
#define TIM_CCER_CC3NP 0x0800
#define TIM_CCER_CC4E 0x1000
#define TIM_CCER_CC4P 0x2000
#define TIM_CNT_CNT 0xFFFF
#define TIM_PSC_PSC 0xFFFF
#define TIM_ARR_ARR 0xFFFF
#define TIM_RCR_REP 0xFF
#define TIM_CCR1_CCR1 0xFFFF
#define TIM_CCR2_CCR2 0xFFFF
#define TIM_CCR3_CCR3 0xFFFF
#define TIM_CCR4_CCR4 0xFFFF
#define TIM_BDTR_DTG 0x00FF
#define TIM_BDTR_DTG_0 0x0001
#define TIM_BDTR_DTG_1 0x0002
#define TIM_BDTR_DTG_2 0x0004
#define TIM_BDTR_DTG_3 0x0008
#define TIM_BDTR_DTG_4 0x0010
#define TIM_BDTR_DTG_5 0x0020
#define TIM_BDTR_DTG_6 0x0040
#define TIM_BDTR_DTG_7 0x0080
#define TIM_BDTR_LOCK 0x0300
#define TIM_BDTR_LOCK_0 0x0100
#define TIM_BDTR_LOCK_1 0x0200
#define TIM_BDTR_OSSI 0x0400
#define TIM_BDTR_OSSR 0x0800
#define TIM_BDTR_BKE 0x1000
#define TIM_BDTR_BKP 0x2000
#define TIM_BDTR_AOE 0x4000
#define TIM_BDTR_MOE 0x8000
#define TIM_DCR_DBA 0x001F
#define TIM_DCR_DBA_0 0x0001
#define TIM_DCR_DBA_1 0x0002
#define TIM_DCR_DBA_2 0x0004
#define TIM_DCR_DBA_3 0x0008
#define TIM_DCR_DBA_4 0x0010
#define TIM_DCR_DBL 0x1F00
#define TIM_DCR_DBL_0 0x0100
#define TIM_DCR_DBL_1 0x0200
#define TIM_DCR_DBL_2 0x0400
#define TIM_DCR_DBL_3 0x0800
#define TIM_DCR_DBL_4 0x1000
#define TIM_DMAR_DMAB 0xFFFF
struct EXTI
{
volatile uint32_t IMR;
volatile uint32_t EMR;
volatile uint32_t RTSR;
volatile uint32_t FTSR;
volatile uint32_t SWIER;
volatile uint32_t PR;
};
#define EXTI_BASE 0x40010400
static struct EXTI *const EXTI = (struct EXTI *const)EXTI_BASE;
#define EXTI_IMR_MR0 0x00000001
#define EXTI_IMR_MR1 0x00000002
#define EXTI_IMR_MR2 0x00000004
#define EXTI_IMR_MR3 0x00000008
#define EXTI_IMR_MR4 0x00000010
#define EXTI_IMR_MR5 0x00000020
#define EXTI_IMR_MR6 0x00000040
#define EXTI_IMR_MR7 0x00000080
#define EXTI_IMR_MR8 0x00000100
#define EXTI_IMR_MR9 0x00000200
#define EXTI_IMR_MR10 0x00000400
#define EXTI_IMR_MR11 0x00000800
#define EXTI_IMR_MR12 0x00001000
#define EXTI_IMR_MR13 0x00002000
#define EXTI_IMR_MR14 0x00004000
#define EXTI_IMR_MR15 0x00008000
#define EXTI_IMR_MR16 0x00010000
#define EXTI_IMR_MR17 0x00020000
#define EXTI_IMR_MR18 0x00040000
#define EXTI_IMR_MR19 0x00080000
#define EXTI_EMR_MR0 0x00000001
#define EXTI_EMR_MR1 0x00000002
#define EXTI_EMR_MR2 0x00000004
#define EXTI_EMR_MR3 0x00000008
#define EXTI_EMR_MR4 0x00000010
#define EXTI_EMR_MR5 0x00000020
#define EXTI_EMR_MR6 0x00000040
#define EXTI_EMR_MR7 0x00000080
#define EXTI_EMR_MR8 0x00000100
#define EXTI_EMR_MR9 0x00000200
#define EXTI_EMR_MR10 0x00000400
#define EXTI_EMR_MR11 0x00000800
#define EXTI_EMR_MR12 0x00001000
#define EXTI_EMR_MR13 0x00002000
#define EXTI_EMR_MR14 0x00004000
#define EXTI_EMR_MR15 0x00008000
#define EXTI_EMR_MR16 0x00010000
#define EXTI_EMR_MR17 0x00020000
#define EXTI_EMR_MR18 0x00040000
#define EXTI_EMR_MR19 0x00080000
#define EXTI_RTSR_TR0 0x00000001
#define EXTI_RTSR_TR1 0x00000002
#define EXTI_RTSR_TR2 0x00000004
#define EXTI_RTSR_TR3 0x00000008
#define EXTI_RTSR_TR4 0x00000010
#define EXTI_RTSR_TR5 0x00000020
#define EXTI_RTSR_TR6 0x00000040
#define EXTI_RTSR_TR7 0x00000080
#define EXTI_RTSR_TR8 0x00000100
#define EXTI_RTSR_TR9 0x00000200
#define EXTI_RTSR_TR10 0x00000400
#define EXTI_RTSR_TR11 0x00000800
#define EXTI_RTSR_TR12 0x00001000
#define EXTI_RTSR_TR13 0x00002000
#define EXTI_RTSR_TR14 0x00004000
#define EXTI_RTSR_TR15 0x00008000
#define EXTI_RTSR_TR16 0x00010000
#define EXTI_RTSR_TR17 0x00020000
#define EXTI_RTSR_TR18 0x00040000
#define EXTI_RTSR_TR19 0x00080000
#define EXTI_FTSR_TR0 0x00000001
#define EXTI_FTSR_TR1 0x00000002
#define EXTI_FTSR_TR2 0x00000004
#define EXTI_FTSR_TR3 0x00000008
#define EXTI_FTSR_TR4 0x00000010
#define EXTI_FTSR_TR5 0x00000020
#define EXTI_FTSR_TR6 0x00000040
#define EXTI_FTSR_TR7 0x00000080
#define EXTI_FTSR_TR8 0x00000100
#define EXTI_FTSR_TR9 0x00000200
#define EXTI_FTSR_TR10 0x00000400
#define EXTI_FTSR_TR11 0x00000800
#define EXTI_FTSR_TR12 0x00001000
#define EXTI_FTSR_TR13 0x00002000
#define EXTI_FTSR_TR14 0x00004000
#define EXTI_FTSR_TR15 0x00008000
#define EXTI_FTSR_TR16 0x00010000
#define EXTI_FTSR_TR17 0x00020000
#define EXTI_FTSR_TR18 0x00040000
#define EXTI_FTSR_TR19 0x00080000
#define EXTI_SWIER_SWIER0 0x00000001
#define EXTI_SWIER_SWIER1 0x00000002
#define EXTI_SWIER_SWIER2 0x00000004
#define EXTI_SWIER_SWIER3 0x00000008
#define EXTI_SWIER_SWIER4 0x00000010
#define EXTI_SWIER_SWIER5 0x00000020
#define EXTI_SWIER_SWIER6 0x00000040
#define EXTI_SWIER_SWIER7 0x00000080
#define EXTI_SWIER_SWIER8 0x00000100
#define EXTI_SWIER_SWIER9 0x00000200
#define EXTI_SWIER_SWIER10 0x00000400
#define EXTI_SWIER_SWIER11 0x00000800
#define EXTI_SWIER_SWIER12 0x00001000
#define EXTI_SWIER_SWIER13 0x00002000
#define EXTI_SWIER_SWIER14 0x00004000
#define EXTI_SWIER_SWIER15 0x00008000
#define EXTI_SWIER_SWIER16 0x00010000
#define EXTI_SWIER_SWIER17 0x00020000
#define EXTI_SWIER_SWIER18 0x00040000
#define EXTI_SWIER_SWIER19 0x00080000
#define EXTI_PR_PR0 0x00000001
#define EXTI_PR_PR1 0x00000002
#define EXTI_PR_PR2 0x00000004
#define EXTI_PR_PR3 0x00000008
#define EXTI_PR_PR4 0x00000010
#define EXTI_PR_PR5 0x00000020
#define EXTI_PR_PR6 0x00000040
#define EXTI_PR_PR7 0x00000080
#define EXTI_PR_PR8 0x00000100
#define EXTI_PR_PR9 0x00000200
#define EXTI_PR_PR10 0x00000400
#define EXTI_PR_PR11 0x00000800
#define EXTI_PR_PR12 0x00001000
#define EXTI_PR_PR13 0x00002000
#define EXTI_PR_PR14 0x00004000
#define EXTI_PR_PR15 0x00008000
#define EXTI_PR_PR16 0x00010000
#define EXTI_PR_PR17 0x00020000
#define EXTI_PR_PR18 0x00040000
#define EXTI_PR_PR19 0x00080000
#define EXTI0_IRQ 6
#define EXTI1_IRQ 7
#define EXTI2_IRQ 8
#define EXTI9_5_IRQ 23
#define TIM2_IRQ 28
#define TIM3_IRQ 29
#define TIM4_IRQ 30
struct AFIO
{
volatile uint32_t EVCR;
volatile uint32_t MAPR;
volatile uint32_t EXTICR[4];
uint32_t RESERVED0;
volatile uint32_t MAPR2;
};
#define AFIO_BASE 0x40010000
static struct AFIO *const AFIO = (struct AFIO *const)AFIO_BASE;
#define AFIO_EXTICR1_EXTI0_PA 0x0000
#define AFIO_EXTICR1_EXTI0_PB 0x0001
#define AFIO_EXTICR1_EXTI0_PC 0x0002
#define AFIO_EXTICR1_EXTI0_PD 0x0003
#define AFIO_EXTICR1_EXTI1_PA 0x0000
#define AFIO_EXTICR1_EXTI1_PB 0x0010
#define AFIO_EXTICR1_EXTI1_PC 0x0020
#define AFIO_EXTICR1_EXTI1_PD 0x0030
#define AFIO_EXTICR1_EXTI2_PA 0x0000
#define AFIO_EXTICR1_EXTI2_PB 0x0100
#define AFIO_EXTICR1_EXTI2_PC 0x0200
#define AFIO_EXTICR1_EXTI2_PD 0x0300
#define AFIO_EXTICR1_EXTI3_PA 0x0000
#define AFIO_EXTICR1_EXTI3_PB 0x1000
#define AFIO_EXTICR1_EXTI3_PC 0x2000
#define AFIO_EXTICR1_EXTI3_PD 0x3000
#define AFIO_EXTICR2_EXTI4_PA 0x0000
#define AFIO_EXTICR2_EXTI4_PB 0x0001
#define AFIO_EXTICR2_EXTI4_PC 0x0002
#define AFIO_EXTICR2_EXTI4_PD 0x0003
#define AFIO_EXTICR2_EXTI5_PA 0x0000
#define AFIO_EXTICR2_EXTI5_PB 0x0010
#define AFIO_EXTICR2_EXTI5_PC 0x0020
#define AFIO_EXTICR2_EXTI5_PD 0x0030
#define AFIO_EXTICR2_EXTI6_PA 0x0000
#define AFIO_EXTICR2_EXTI6_PB 0x0100
#define AFIO_EXTICR2_EXTI6_PC 0x0200
#define AFIO_EXTICR2_EXTI6_PD 0x0300
#define AFIO_EXTICR2_EXTI7_PA 0x0000
#define AFIO_EXTICR2_EXTI7_PB 0x1000
#define AFIO_EXTICR2_EXTI7_PC 0x2000
#define AFIO_EXTICR2_EXTI7_PD 0x3000
#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
#define AFIO_MAPR_SWJ_CFG_DISABLE 0x04000000

394
src/sys.c
View File

@@ -1,394 +0,0 @@
/*
* sys.c - system routines for the initial page for STM32F103.
*
* Copyright (C) 2013, 2014, 2015, 2016 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty.
*
* When the flash ROM is protected, we cannot modify the initial page.
* We put some system routines (which is useful for any program) here.
*/
#include <stdint.h>
#include <stdlib.h>
#include "board.h"
#include "clk_gpio_init-stm32.c"
static void
usb_cable_config (int enable)
{
#if defined(GPIO_USB_SET_TO_ENABLE)
if (enable)
GPIO_USB->BSRR = (1 << GPIO_USB_SET_TO_ENABLE);
else
GPIO_USB->BRR = (1 << GPIO_USB_SET_TO_ENABLE);
#elif defined(GPIO_USB_CLEAR_TO_ENABLE)
if (enable)
GPIO_USB->BRR = (1 << GPIO_USB_CLEAR_TO_ENABLE);
else
GPIO_USB->BSRR = (1 << GPIO_USB_CLEAR_TO_ENABLE);
#else
(void)enable;
#endif
}
void
set_led (int on)
{
#if defined(GPIO_LED_CLEAR_TO_EMIT)
if (on)
GPIO_LED->BRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
else
GPIO_LED->BSRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
#else
if (on)
GPIO_LED->BSRR = (1 << GPIO_LED_SET_TO_EMIT);
else
GPIO_LED->BRR = (1 << GPIO_LED_SET_TO_EMIT);
#endif
}
static void wait (int count)
{
int i;
for (i = 0; i < count; i++)
asm volatile ("" : : "r" (i) : "memory");
}
static void
usb_lld_sys_shutdown (void)
{
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
usb_cable_config (0);
}
static void
usb_lld_sys_init (void)
{
if ((RCC->APB1ENR & RCC_APB1ENR_USBEN)
&& (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0)
/* Make sure the device is disconnected, even after core reset. */
{
usb_lld_sys_shutdown ();
/* Disconnect requires SE0 (>= 2.5uS). */
wait (300);
}
usb_cable_config (1);
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0;
}
#define FLASH_KEY1 0x45670123UL
#define FLASH_KEY2 0xCDEF89ABUL
enum flash_status
{
FLASH_BUSY = 1,
FLASH_ERROR_PG,
FLASH_ERROR_WRP,
FLASH_COMPLETE,
FLASH_TIMEOUT
};
static void __attribute__ ((used))
flash_unlock (void)
{
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
#define intr_disable() asm volatile ("cpsid i" : : : "memory")
#define intr_enable() asm volatile ("cpsie i" : : : "memory")
#define FLASH_SR_BSY 0x01
#define FLASH_SR_PGERR 0x04
#define FLASH_SR_WRPRTERR 0x10
#define FLASH_SR_EOP 0x20
#define FLASH_CR_PG 0x0001
#define FLASH_CR_PER 0x0002
#define FLASH_CR_MER 0x0004
#define FLASH_CR_OPTPG 0x0010
#define FLASH_CR_OPTER 0x0020
#define FLASH_CR_STRT 0x0040
#define FLASH_CR_LOCK 0x0080
#define FLASH_CR_OPTWRE 0x0200
#define FLASH_CR_ERRIE 0x0400
#define FLASH_CR_EOPIE 0x1000
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);
intr_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;
}
intr_enable ();
return status;
}
static int
flash_erase_page (uint32_t addr)
{
int status;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
intr_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;
}
intr_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;
}
#define FLASH_START_ADDR 0x08000000 /* Fixed for all STM32F1. */
#define FLASH_OFFSET 0x1000 /* First pages are not-writable. */
#define FLASH_START (FLASH_START_ADDR+FLASH_OFFSET)
#define CHIP_ID_REG ((uint32_t *)0xe0042000)
#define FLASH_SIZE_REG ((uint16_t *)0x1ffff7e0)
static int
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
{
int status;
uint32_t flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
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);
intr_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;
}
intr_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 = FLASH_START;
uint32_t end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
uint32_t page_size = 1024;
int r;
if (((*CHIP_ID_REG) & 0xfff) == 0x0414)
page_size = 2048;
while (addr < end)
{
r = flash_erase_page (addr);
if (r != 0)
break;
addr += page_size;
}
if (addr >= end)
(*entry) ();
for (;;);
}
struct SCB
{
volatile uint32_t CPUID;
volatile uint32_t ICSR;
volatile uint32_t VTOR;
volatile uint32_t AIRCR;
volatile uint32_t SCR;
volatile uint32_t CCR;
volatile uint8_t SHP[12];
volatile uint32_t SHCSR;
volatile uint32_t CFSR;
volatile uint32_t HFSR;
volatile uint32_t DFSR;
volatile uint32_t MMFAR;
volatile uint32_t BFAR;
volatile uint32_t AFSR;
volatile uint32_t PFR[2];
volatile uint32_t DFR;
volatile uint32_t ADR;
volatile uint32_t MMFR[4];
volatile uint32_t ISAR[5];
};
#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = ((struct SCB *const) SCB_BASE);
#define SYSRESETREQ 0x04
static void
nvic_system_reset (void)
{
SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ);
asm volatile ("dsb");
for (;;);
}
static void __attribute__ ((naked))
reset (void)
{
extern const unsigned long *FT0, *FT1, *FT2;
/*
* This code may not be at the start of flash ROM, because of DFU.
* So, we take the address from PC.
*/
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
"ldr r0, 1f\n\t" /* r0 = SCR */
"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\t"
".align 2\n"
"1: .word 0xe000ed00"
: /* no output */ : /* no input */ : "memory");
/* Never reach here. */
/* Artificial entry to refer FT0, FT1, and FT2. */
asm volatile (""
: : "r" (FT0), "r" (FT1), "r" (FT2));
}
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,
clock_init,
gpio_init,
NULL,
};
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
3*2+2, /* bLength */
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
/* sys version: "3.0" */
'3', 0, '.', 0, '0', 0,
};
const uint32_t __attribute__((section(".sys.board_id")))
sys_board_id = BOARD_ID;
const uint8_t __attribute__((section(".sys.board_name")))
sys_board_name[] = BOARD_NAME;

130
src/sys.h
View File

@@ -1,130 +0,0 @@
#define BOARD_ID_CQ_STARM 0xc5480875
#define BOARD_ID_FST_01_00 0x613870a9
#define BOARD_ID_FST_01 0x696886af
#define BOARD_ID_MAPLE_MINI 0x7a445272
#define BOARD_ID_OLIMEX_STM32_H103 0xf92bb594
#define BOARD_ID_STBEE_MINI 0x1f341961
#define BOARD_ID_STBEE 0x945c37e8
#define BOARD_ID_STM32_PRIMER2 0x21e5798d
#define BOARD_ID_STM8S_DISCOVERY 0x2f0976bb
#define BOARD_ID_ST_DONGLE 0x2cd4e471
#define BOARD_ID_ST_NUCLEO_F103 0x9b87c16d
#define BOARD_ID_NITROKEY_START 0xad1e7ebd
extern const uint8_t sys_version[8];
extern const uint32_t sys_board_id;
extern const uint8_t sys_board_name[];
typedef void (*handler)(void);
extern handler vector[16];
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]) ();
}
/*
* Users can override INLINE by 'attribute((used))' to have an
* implementation defined.
*/
#if !defined(INLINE)
#define INLINE __inline__
#endif
static INLINE void
clock_init (void)
{
(*vector[13]) ();
}
static INLINE void
gpio_init (void)
{
(*vector[14]) ();
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,9 +31,9 @@
#include "usb_lld.h"
#include "usb-msc.h"
extern uint8_t __process5_stack_base__, __process5_stack_size__;
const uint32_t __stackaddr_msc = (uint32_t)&__process5_stack_base__;
const size_t __stacksize_msc = (size_t)&__process5_stack_size__;
extern uint8_t __process5_stack_base__[], __process5_stack_size__[];
#define STACK_ADDR_MSC ((uint32_t)__process5_stack_base__)
#define STACK_SIZE_MSC ((uint32_t)__process5_stack_size__)
#define PRIO_MSC 3
static chopstx_mutex_t a_pinpad_mutex;
@@ -86,13 +86,12 @@ static void usb_start_transmit (const uint8_t *p, size_t n)
/* "Data Transmitted" callback */
void
EP6_IN_Callback (void)
EP6_IN_Callback (uint16_t len)
{
size_t n;
size_t n = len;
chopstx_mutex_lock (msc_mutex);
n = (size_t)usb_lld_tx_data_len (ENDP6);
ep6_in.txbuf += n;
ep6_in.txcnt += n;
ep6_in.txsize -= n;
@@ -132,14 +131,13 @@ static void usb_start_receive (uint8_t *p, size_t n)
/* "Data Received" call back */
void
EP6_OUT_Callback (void)
EP6_OUT_Callback (uint16_t len)
{
size_t n;
size_t n = len;
int err = 0;
chopstx_mutex_lock (msc_mutex);
n = (size_t)usb_lld_rx_data_len (ENDP6);
if (n > ep6_out.rxsize)
{ /* buffer overflow */
err = 1;
@@ -570,5 +568,5 @@ msc_main (void *arg)
void
msc_init (void)
{
chopstx_create (PRIO_MSC, __stackaddr_msc, __stacksize_msc, msc_main, NULL);
chopstx_create (PRIO_MSC, STACK_ADDR_MSC, STACK_SIZE_MSC, msc_main, NULL);
}

View File

@@ -18,8 +18,8 @@
#define SCSI_WRITE10 0x2A
#define SCSI_VERIFY10 0x2F
#define SCSI_READ_FORMAT_CAPACITIES 0x23
#define SCSI_SYNCHRONIZE_CACHE 0x35
#define SCSI_REPORT_LUN 0xA0
#define MSC_IDLE 0
#define MSC_DATA_OUT 1

View File

@@ -3,8 +3,8 @@
#ifndef __USB_CONF_H
#define __USB_CONF_H
#define ICC_NUM_INTERFACES 1
#define ICC_INTERFACE 0
#define CCID_NUM_INTERFACES 1
#define CCID_INTERFACE 0
#ifdef HID_CARD_CHANGE_SUPPORT
#define HID_NUM_INTERFACES 1
#define HID_INTERFACE 1
@@ -13,18 +13,18 @@
#endif
#ifdef ENABLE_VIRTUAL_COM_PORT
#define VCOM_NUM_INTERFACES 2
#define VCOM_INTERFACE_0 (ICC_NUM_INTERFACES + HID_NUM_INTERFACES)
#define VCOM_INTERFACE_1 (ICC_NUM_INTERFACES + HID_NUM_INTERFACES + 1)
#define VCOM_INTERFACE_0 (CCID_NUM_INTERFACES + HID_NUM_INTERFACES)
#define VCOM_INTERFACE_1 (CCID_NUM_INTERFACES + HID_NUM_INTERFACES + 1)
#else
#define VCOM_NUM_INTERFACES 0
#endif
#ifdef PINPAD_DND_SUPPORT
#define MSC_NUM_INTERFACES 1
#define MSC_INTERFACE (ICC_NUM_INTERFACES + HID_NUM_INTERFACES + VCOM_NUM_INTERFACES)
#define MSC_INTERFACE (CCID_NUM_INTERFACES + HID_NUM_INTERFACES + VCOM_NUM_INTERFACES)
#else
#define MSC_NUM_INTERFACES 0
#endif
#define NUM_INTERFACES (ICC_NUM_INTERFACES + HID_NUM_INTERFACES \
#define NUM_INTERFACES (CCID_NUM_INTERFACES + HID_NUM_INTERFACES \
+ VCOM_NUM_INTERFACES + MSC_NUM_INTERFACES)
#if defined(USB_SELF_POWERED)

View File

@@ -38,7 +38,6 @@
#include "usb_lld.h"
#include "usb_conf.h"
#include "gnuk.h"
#include "stm32f103.h"
#ifdef ENABLE_VIRTUAL_COM_PORT
#include "usb-cdc.h"
@@ -61,47 +60,25 @@ static struct line_coding line_coding = {
#define CDC_CTRL_DTR 0x0001
static int
vcom_port_data_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
vcom_port_data_setup (struct usb_dev *dev)
{
if (USB_SETUP_GET (req))
struct device_req *arg = &dev->dev_req;
if (USB_SETUP_GET (arg->type))
{
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
return usb_lld_reply_request (&line_coding, sizeof(line_coding), arg);
if (arg->request == USB_CDC_REQ_GET_LINE_CODING)
return usb_lld_ctrl_send (dev, &line_coding, sizeof (line_coding));
}
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)
{
uint8_t connected_saved = stdout.connected;
if ((arg->value & CDC_CTRL_DTR) != 0)
{
if (stdout.connected == 0)
/* It's Open call */
stdout.connected++;
}
else
{
if (stdout.connected)
/* Close call */
stdout.connected = 0;
}
chopstx_mutex_lock (&stdout.m_dev);
if (stdout.connected != connected_saved)
chopstx_cond_signal (&stdout.cond_dev);
chopstx_mutex_unlock (&stdout.m_dev);
return USB_SUCCESS;
}
if (arg->request == USB_CDC_REQ_SET_LINE_CODING
&& arg->len == sizeof (line_coding))
return usb_lld_ctrl_recv (dev, &line_coding, sizeof (line_coding));
else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
return usb_lld_ctrl_ack (dev);
}
return USB_UNSUPPORT;
return -1;
}
#endif
@@ -132,7 +109,7 @@ static uint16_t hid_report;
static void
gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
{
if (interface == ICC_INTERFACE)
if (interface == CCID_INTERFACE)
{
if (!stop)
{
@@ -195,11 +172,11 @@ gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
}
void
usb_cb_device_reset (void)
usb_device_reset (struct usb_dev *dev)
{
int i;
usb_lld_reset (USB_INITIAL_FEATURE);
usb_lld_reset (dev, USB_INITIAL_FEATURE);
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
@@ -210,7 +187,7 @@ usb_cb_device_reset (void)
gnuk_setup_endpoints_for_interface (i, 1);
bDeviceState = ATTACHED;
ccid_usb_reset ();
ccid_usb_reset (1);
}
#define USB_CCID_REQ_ABORT 0x01
@@ -231,172 +208,152 @@ static const uint8_t *const mem_info[] = { &_regnual_start, __heap_end__, };
#define USB_FSIJ_GNUK_EXEC 2
#define USB_FSIJ_GNUK_CARD_CHANGE 3
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)
static int
download_check_crc32 (struct usb_dev *dev, const uint32_t *end_p)
{
uint32_t crc32 = *end_p;
const uint32_t *p;
if (check_crc32 ((const uint32_t *)&_regnual_start, end_p))
return usb_lld_ctrl_ack (dev);
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;
return -1;
}
int
usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
usb_setup (struct usb_dev *dev)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
{
if (USB_SETUP_GET (req))
if (USB_SETUP_GET (arg->type))
{
if (req_no == USB_FSIJ_GNUK_MEMINFO)
return usb_lld_reply_request (mem_info, sizeof (mem_info), arg);
if (arg->request == USB_FSIJ_GNUK_MEMINFO)
return usb_lld_ctrl_send (dev, mem_info, sizeof (mem_info));
}
else /* SETUP_SET */
{
uint8_t *addr = (uint8_t *)(0x20000000 + arg->value * 0x100
+ arg->index);
uint8_t *addr = sram_address ((arg->value * 0x100) + arg->index);
if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
if (arg->request == USB_FSIJ_GNUK_DOWNLOAD)
{
if (*icc_state_p != ICC_STATE_EXITED)
return USB_UNSUPPORT;
if (*ccid_state_p != CCID_STATE_EXITED)
return -1;
if (addr < &_regnual_start || addr + arg->len > __heap_end__)
return USB_UNSUPPORT;
return -1;
if (arg->index + arg->len < 256)
memset (addr + arg->index + arg->len, 0,
256 - (arg->index + arg->len));
usb_lld_set_data_to_recv (addr, arg->len);
return USB_SUCCESS;
return usb_lld_ctrl_recv (dev, addr, arg->len);
}
else if (req_no == USB_FSIJ_GNUK_EXEC && arg->len == 0)
else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0)
{
if (*icc_state_p != ICC_STATE_EXITED)
return USB_UNSUPPORT;
if (*ccid_state_p != CCID_STATE_EXITED)
return -1;
if (((uint32_t)addr & 0x03))
return USB_UNSUPPORT;
if (((uintptr_t)addr & 0x03))
return -1;
return download_check_crc32 ((uint32_t *)addr);
return download_check_crc32 (dev, (uint32_t *)addr);
}
else if (req_no == USB_FSIJ_GNUK_CARD_CHANGE && arg->len == 0)
else if (arg->request == USB_FSIJ_GNUK_CARD_CHANGE && arg->len == 0)
{
if (arg->value != 0 && arg->value != 1 && arg->value != 2)
return USB_UNSUPPORT;
return -1;
ccid_card_change_signal (arg->value);
return USB_SUCCESS;
return usb_lld_ctrl_ack (dev);
}
}
}
else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
{
if (arg->index == ICC_INTERFACE)
if (arg->index == CCID_INTERFACE)
{
if (USB_SETUP_GET (req))
if (USB_SETUP_GET (arg->type))
{
if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
return usb_lld_reply_request (freq_table, sizeof (freq_table),
arg);
else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
return usb_lld_reply_request (data_rate_table,
sizeof (data_rate_table), arg);
if (arg->request == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
return usb_lld_ctrl_send (dev, freq_table, sizeof (freq_table));
else if (arg->request == USB_CCID_REQ_GET_DATA_RATES)
return usb_lld_ctrl_send (dev, data_rate_table,
sizeof (data_rate_table));
}
else
{
if (req_no == USB_CCID_REQ_ABORT)
if (arg->request == USB_CCID_REQ_ABORT)
/* wValue: bSeq, bSlot */
/* Abortion is not supported in Gnuk */
return USB_UNSUPPORT;
return -1;
}
}
#ifdef HID_CARD_CHANGE_SUPPORT
else if (arg->index == HID_INTERFACE)
{
switch (req_no)
switch (arg->request)
{
case USB_HID_REQ_GET_IDLE:
return usb_lld_reply_request (&hid_idle_rate, 1, arg);
return usb_lld_ctrl_send (dev, &hid_idle_rate, 1);
case USB_HID_REQ_SET_IDLE:
usb_lld_set_data_to_recv (&hid_idle_rate, 1);
return USB_SUCCESS;
return usb_lld_ctrl_recv (dev, &hid_idle_rate, 1);
case USB_HID_REQ_GET_REPORT:
/* Request of LED status and key press */
return usb_lld_reply_request (&hid_report, 2, arg);
return usb_lld_ctrl_send (dev, &hid_report, 2);
case USB_HID_REQ_SET_REPORT:
/* Received LED set request */
if (arg->len == 1)
usb_lld_set_data_to_recv (&hid_report, arg->len);
return USB_SUCCESS;
return usb_lld_ctrl_recv (dev, &hid_report, arg->len);
else
return usb_lld_ctrl_ack (dev);
case USB_HID_REQ_GET_PROTOCOL:
case USB_HID_REQ_SET_PROTOCOL:
/* This driver doesn't support boot protocol. */
return USB_UNSUPPORT;
return -1;
default:
return USB_UNSUPPORT;
return -1;
}
}
#endif
#ifdef ENABLE_VIRTUAL_COM_PORT
else if (arg->index == VCOM_INTERFACE_0)
return vcom_port_data_setup (req, req_no, arg);
return vcom_port_data_setup (dev);
#endif
#ifdef PINPAD_DND_SUPPORT
else if (arg->index == MSC_INTERFACE)
{
if (USB_SETUP_GET (req))
if (USB_SETUP_GET (arg->type))
{
if (req_no == MSC_GET_MAX_LUN_COMMAND)
return usb_lld_reply_request (lun_table, sizeof (lun_table),
arg);
if (arg->request == MSC_GET_MAX_LUN_COMMAND)
return usb_lld_ctrl_send (dev, lun_table, sizeof (lun_table));
}
else
if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
/* Should call resetting MSC thread, something like msc_reset() */
return USB_SUCCESS;
if (arg->request == MSC_MASS_STORAGE_RESET_COMMAND)
return usb_lld_ctrl_ack (dev);
}
#endif
}
return USB_UNSUPPORT;
return -1;
}
void
usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
usb_ctrl_write_finish (struct usb_dev *dev)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
(void)arg;
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
{
if (USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC)
if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC)
{
if (*icc_state_p != ICC_STATE_EXITED)
if (*ccid_state_p != CCID_STATE_EXITED)
return;
bDeviceState = UNCONNECTED;
@@ -404,88 +361,122 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
led_blink (LED_GNUK_EXEC); /* Notify the main. */
}
}
#ifdef HID_CARD_CHANGE_SUPPORT
#if defined(HID_CARD_CHANGE_SUPPORT) || defined (ENABLE_VIRTUAL_COM_PORT)
else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
{
if (arg->index == HID_INTERFACE && req_no == USB_HID_REQ_SET_REPORT)
# if defined(ENABLE_VIRTUAL_COM_PORT)
if (arg->index == VCOM_INTERFACE_0 && USB_SETUP_SET (arg->type)
&& arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
{
uint8_t connected_saved = stdout.connected;
if ((arg->value & CDC_CTRL_DTR) != 0)
{
if (stdout.connected == 0)
/* It's Open call */
stdout.connected++;
}
else
{
if (stdout.connected)
/* Close call */
stdout.connected = 0;
}
chopstx_mutex_lock (&stdout.m_dev);
if (stdout.connected != connected_saved)
chopstx_cond_signal (&stdout.cond_dev);
chopstx_mutex_unlock (&stdout.m_dev);
}
# endif
# if defined(HID_CARD_CHANGE_SUPPORT)
if (arg->index == HID_INTERFACE && arg->request == USB_HID_REQ_SET_REPORT)
{
if ((hid_report ^ hid_report_saved) & HID_LED_STATUS_CARDCHANGE)
ccid_card_change_signal (CARD_CHANGE_TOGGLE);
hid_report_saved = hid_report;
}
# endif
}
#endif
}
int usb_cb_handle_event (uint8_t event_type, uint16_t value)
int
usb_set_configuration (struct usb_dev *dev)
{
int i;
uint8_t current_conf;
switch (event_type)
current_conf = usb_lld_current_configuration (dev);
if (current_conf == 0)
{
case USB_EVENT_ADDRESS:
if (dev->dev_req.value != 1)
return -1;
usb_lld_set_configuration (dev, 1);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 0);
bDeviceState = CONFIGURED;
}
else if (current_conf != dev->dev_req.value)
{
if (dev->dev_req.value != 0)
return -1;
usb_lld_set_configuration (dev, 0);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 1);
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);
ccid_card_change_signal (CCID_CARD_INIT);
bDeviceState = CONFIGURED;
}
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;
ccid_usb_reset (1);
}
return USB_UNSUPPORT;
/* Do nothing when current_conf == value */
return usb_lld_ctrl_ack (dev);
}
int usb_cb_interface (uint8_t cmd, struct req_args *arg)
int
usb_set_interface (struct usb_dev *dev)
{
const uint8_t zero = 0;
uint16_t interface = arg->index;
uint16_t alt = arg->value;
uint16_t interface = dev->dev_req.index;
uint16_t alt = dev->dev_req.value;
if (interface >= NUM_INTERFACES)
return USB_UNSUPPORT;
return -1;
switch (cmd)
if (alt != 0)
return -1;
else
{
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:
return usb_lld_reply_request (&zero, 1, arg);
case USB_QUERY_INTERFACE:
default:
return USB_SUCCESS;
gnuk_setup_endpoints_for_interface (interface, 0);
ccid_usb_reset (0);
return usb_lld_ctrl_ack (dev);
}
}
int
usb_get_interface (struct usb_dev *dev)
{
const uint8_t zero = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
return usb_lld_ctrl_send (dev, &zero, 1);
}
int
usb_get_status_interface (struct usb_dev *dev)
{
const uint16_t status_info = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
return usb_lld_ctrl_send (dev, &status_info, 2);
}

View File

@@ -53,10 +53,10 @@ static const uint8_t hid_report_desc[] = {
};
#endif
#define USB_ICC_INTERFACE_CLASS 0x0B
#define USB_ICC_INTERFACE_SUBCLASS 0x00
#define USB_ICC_INTERFACE_BULK_PROTOCOL 0x00
#define USB_ICC_DATA_SIZE 64
#define USB_CCID_INTERFACE_CLASS 0x0B
#define USB_CCID_INTERFACE_SUBCLASS 0x00
#define USB_CCID_INTERFACE_BULK_PROTOCOL 0x00
#define USB_CCID_DATA_SIZE 64
/* USB Standard Device Descriptor */
static const uint8_t device_desc[] = {
@@ -74,7 +74,7 @@ static const uint8_t device_desc[] = {
0x01 /* bNumConfigurations */
};
#define ICC_TOTAL_LENGTH (9+9+54+7+7+7)
#define CCID_TOTAL_LENGTH (9+9+54+7+7+7)
#ifdef HID_CARD_CHANGE_SUPPORT
#define HID_TOTAL_LENGTH (9+9+7)
@@ -94,7 +94,7 @@ static const uint8_t device_desc[] = {
#define MSC_TOTAL_LENGTH 0
#endif
#define W_TOTAL_LENGTH (ICC_TOTAL_LENGTH + HID_TOTAL_LENGTH \
#define W_TOTAL_LENGTH (CCID_TOTAL_LENGTH + HID_TOTAL_LENGTH \
+ VCOM_TOTAL_LENGTH + MSC_TOTAL_LENGTH)
@@ -112,12 +112,12 @@ static const uint8_t config_desc[] = {
/* Interface Descriptor */
9, /* bLength: Interface Descriptor size */
INTERFACE_DESCRIPTOR, /* bDescriptorType: Interface */
ICC_INTERFACE, /* bInterfaceNumber: Index of this interface */
CCID_INTERFACE, /* bInterfaceNumber: Index of this interface */
0, /* Alternate setting for this interface */
3, /* bNumEndpoints: Bulk-IN, Bulk-OUT, Intr-IN */
USB_ICC_INTERFACE_CLASS,
USB_ICC_INTERFACE_SUBCLASS,
USB_ICC_INTERFACE_BULK_PROTOCOL,
USB_CCID_INTERFACE_CLASS,
USB_CCID_INTERFACE_SUBCLASS,
USB_CCID_INTERFACE_BULK_PROTOCOL,
0, /* string index for interface */
/* ICC Descriptor */
@@ -170,14 +170,14 @@ static const uint8_t config_desc[] = {
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
0x81, /* bEndpointAddress: (IN1) */
0x02, /* bmAttributes: Bulk */
USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */
USB_CCID_DATA_SIZE, 0x00, /* wMaxPacketSize: */
0x00, /* bInterval */
/*Endpoint OUT1 Descriptor*/
7, /* bLength: Endpoint Descriptor size */
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
0x01, /* bEndpointAddress: (OUT1) */
0x02, /* bmAttributes: Bulk */
USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */
USB_CCID_DATA_SIZE, 0x00, /* wMaxPacketSize: */
0x00, /* bInterval */
/*Endpoint IN2 Descriptor*/
7, /* bLength: Endpoint Descriptor size */
@@ -345,21 +345,25 @@ static const struct desc string_descriptors[] = {
#define USB_DT_REPORT 0x22
int
usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
struct req_args *arg)
usb_get_descriptor (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
uint8_t desc_type = (arg->value >> 8);
uint8_t desc_index = (arg->value & 0xff);
if (rcp == DEVICE_RECIPIENT)
{
if (desc_type == DEVICE_DESCRIPTOR)
return usb_lld_reply_request (device_desc, sizeof (device_desc), arg);
return usb_lld_ctrl_send (dev, device_desc, sizeof (device_desc));
else if (desc_type == CONFIG_DESCRIPTOR)
return usb_lld_reply_request (config_desc, sizeof (config_desc), arg);
return usb_lld_ctrl_send (dev, config_desc, sizeof (config_desc));
else if (desc_type == STRING_DESCRIPTOR)
{
if (desc_index < NUM_STRING_DESC)
return usb_lld_reply_request (string_descriptors[desc_index].desc,
string_descriptors[desc_index].size,
arg);
return usb_lld_ctrl_send (dev, string_descriptors[desc_index].desc,
string_descriptors[desc_index].size);
#ifdef USE_SYS3
else if (desc_index == NUM_STRING_DESC)
{
uint8_t usbbuf[64];
@@ -376,8 +380,9 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
}
usbbuf[0] = len = i*2 + 2;
usbbuf[1] = STRING_DESCRIPTOR;
return usb_lld_reply_request (usbbuf, len, arg);
return usb_lld_ctrl_send (dev, usbbuf, len);
}
#endif
}
}
#ifdef HID_CARD_CHANGE_SUPPORT
@@ -386,14 +391,13 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
if (arg->index == HID_INTERFACE)
{
if (desc_type == USB_DT_HID)
return usb_lld_reply_request (config_desc+ICC_TOTAL_LENGTH+9, 9,
arg);
return usb_lld_ctrl_send (dev, config_desc+CCID_TOTAL_LENGTH+9, 9);
else if (desc_type == USB_DT_REPORT)
return usb_lld_reply_request (hid_report_desc, HID_REPORT_DESC_SIZE,
arg);
return usb_lld_ctrl_send (dev, hid_report_desc,
HID_REPORT_DESC_SIZE);
}
}
#endif
return USB_UNSUPPORT;
return -1;
}

View File

@@ -1,118 +0,0 @@
#define STANDARD_ENDPOINT_DESC_SIZE 0x09
/* endpoints enumeration */
#define ENDP0 ((uint8_t)0)
#define ENDP1 ((uint8_t)1)
#define ENDP2 ((uint8_t)2)
#define ENDP3 ((uint8_t)3)
#define ENDP4 ((uint8_t)4)
#define ENDP5 ((uint8_t)5)
#define ENDP6 ((uint8_t)6)
#define ENDP7 ((uint8_t)7)
/* EP_TYPE[1:0] EndPoint TYPE */
#define EP_BULK (0x0000) /* EndPoint BULK */
#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */
#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */
enum RECIPIENT_TYPE
{
DEVICE_RECIPIENT = 0, /* Recipient device */
INTERFACE_RECIPIENT, /* Recipient interface */
ENDPOINT_RECIPIENT, /* Recipient endpoint */
OTHER_RECIPIENT
};
enum DESCRIPTOR_TYPE
{
DEVICE_DESCRIPTOR = 1,
CONFIG_DESCRIPTOR,
STRING_DESCRIPTOR,
INTERFACE_DESCRIPTOR,
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)
enum
{
USB_UNSUPPORT = 0,
USB_SUCCESS = 1,
};
struct req_args {
uint16_t value;
uint16_t index;
uint16_t len;
};
void usb_cb_device_reset (void);
int usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg);
int usb_cb_interface (uint8_t cmd, struct req_args *arg);
int usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
struct req_args *arg);
int usb_cb_handle_event (uint8_t event_type, uint16_t value);
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no,
struct req_args *arg);
void usb_cb_tx_done (uint8_t ep_num);
void usb_cb_rx_ready (uint8_t ep_num);
enum {
USB_EVENT_ADDRESS,
USB_EVENT_CONFIG,
USB_EVENT_SUSPEND,
USB_EVENT_WAKEUP,
USB_EVENT_STALL,
};
enum {
USB_SET_INTERFACE,
USB_GET_INTERFACE,
USB_QUERY_INTERFACE,
};
enum DEVICE_STATE
{
UNCONNECTED,
ATTACHED,
POWERED,
SUSPENDED,
ADDRESSED,
CONFIGURED
};
void usb_lld_init (uint8_t feature);
void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n);
void usb_lld_stall_tx (int ep_num);
void usb_lld_stall_rx (int ep_num);
int usb_lld_tx_data_len (int ep_num);
void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len);
void usb_lld_tx_enable (int ep_num, size_t len);
void usb_lld_write (uint8_t ep_num, const void *buf, size_t len);
int usb_lld_reply_request (const void *buf, size_t buflen,
struct req_args *arg);
void usb_lld_rx_enable (int ep_num);
int usb_lld_rx_data_len (int ep_num);
void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len);
void usb_lld_reset (uint8_t feature);
void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
int ep_rx_addr, int ep_tx_addr,
int ep_rx_memory_size);
void usb_lld_set_configuration (uint8_t config);
uint8_t usb_lld_current_configuration (void);
void usb_lld_set_data_to_recv (void *p, size_t len);
void usb_lld_prepare_shutdown (void);
void usb_lld_shutdown (void);
void usb_interrupt_handler (void);

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ Feature: command GET DATA
Scenario: data object historical bytes
When requesting historical bytes: 5f52
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00
Then data should match: \x00\x31\x84\x73\x80\x01\x80[\x00\x05]\x90\x00
Scenario: data object extended capabilities
When requesting extended capabilities: c0

View File

@@ -4,7 +4,7 @@ Feature: command GET DATA
Scenario: data object historical bytes
When requesting historical bytes: 5f52
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00
Then data should match: \x00\x31\x84\x73\x80\x01\x80[\x00\x05]\x90\x00
Scenario: data object extended capabilities
When requesting extended capabilities: c0

View File

@@ -4,7 +4,7 @@ Feature: command GET DATA
Scenario: data object historical bytes
When requesting historical bytes: 5f52
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00
Then data should match: \x00\x31\x84\x73\x80\x01\x80[\x00\x05]\x90\x00
Scenario: data object extended capabilities
When requesting extended capabilities: c0

View File

@@ -11,19 +11,19 @@ from array import array
@Before
def ini(sc):
if not ftc.token:
ftc.token = gnuk.get_gnuk_device()
ftc.token.cmd_select_openpgp()
if not glc.token:
glc.token = gnuk.get_gnuk_device()
glc.token.cmd_select_openpgp()
@Given("cmd_verify with (.*) and \"(.*)\"")
def cmd_verify(who_str,pass_str):
who = int(who_str)
scc.result = ftc.token.cmd_verify(who, pass_str)
scc.result = glc.token.cmd_verify(who, pass_str)
@Given("cmd_change_reference_data with (.*) and \"(.*)\"")
def cmd_change_reference_data(who_str,pass_str):
who = int(who_str)
scc.result = ftc.token.cmd_change_reference_data(who, pass_str)
scc.result = glc.token.cmd_change_reference_data(who, pass_str)
@Given("cmd_put_data with (.*) and (\".*\")")
def cmd_put_data(tag_str,content_str_repr):
@@ -31,12 +31,12 @@ def cmd_put_data(tag_str,content_str_repr):
tag = int(tag_str, 16)
tagh = tag >> 8
tagl = tag & 0xff
scc.result = ftc.token.cmd_put_data(tagh, tagl, content_str)
scc.result = glc.token.cmd_put_data(tagh, tagl, content_str)
@Given("cmd_reset_retry_counter with (.*) and \"(.*)\"")
def cmd_reset_retry_counter(how_str, data):
how = int(how_str)
scc.result = ftc.token.cmd_reset_retry_counter(how, data)
scc.result = glc.token.cmd_reset_retry_counter(how, 0x81, data)
@Given("a RSA key pair (.*)")
def set_rsa_key(keyno_str):
@@ -46,7 +46,7 @@ def set_rsa_key(keyno_str):
def import_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str)
t = rsa_keys.build_privkey_template(openpgp_keyno, scc.keyno)
scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t)
scc.result = glc.token.cmd_put_data_odd(0x3f, 0xff, t)
@Given("a fingerprint of OPENPGP.(.*) key")
def get_key_fpr(openpgp_keyno_str):
@@ -63,7 +63,7 @@ def cmd_put_data_with_result(tag_str):
tag = int(tag_str, 16)
tagh = tag >> 8
tagl = tag & 0xff
scc.result = ftc.token.cmd_put_data(tagh, tagl, scc.result)
scc.result = glc.token.cmd_put_data(tagh, tagl, scc.result)
@Given("a message (\".*\")")
def set_msg(content_str_repr):
@@ -73,7 +73,7 @@ def set_msg(content_str_repr):
@Given("a public key from token for OPENPGP.(.*)")
def get_public_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str)
scc.pubkey_info = ftc.token.cmd_get_public_key(openpgp_keyno)
scc.pubkey_info = glc.token.cmd_get_public_key(openpgp_keyno)
@Given("verify signature")
def verify_signature():
@@ -81,11 +81,11 @@ def verify_signature():
@Given("let a token compute digital signature")
def compute_signature():
scc.sig = int(hexlify(ftc.token.cmd_pso(0x9e, 0x9a, scc.digestinfo)),16)
scc.sig = int(hexlify(glc.token.cmd_pso(0x9e, 0x9a, scc.digestinfo)),16)
@Given("let a token authenticate")
def internal_authenticate():
scc.sig = int(hexlify(ftc.token.cmd_internal_authenticate(scc.digestinfo)),16)
scc.sig = int(hexlify(glc.token.cmd_internal_authenticate(scc.digestinfo)),16)
@Given("compute digital signature on host with RSA key pair (.*)")
def compute_signature_on_host(keyno_str):
@@ -107,29 +107,29 @@ def encrypt_on_host_public_key():
@Given("let a token decrypt encrypted data")
def decrypt():
scc.result = ftc.token.cmd_pso_longdata(0x80, 0x86, scc.ciphertext).tostring()
scc.result = glc.token.cmd_pso_longdata(0x80, 0x86, scc.ciphertext).tostring()
@Given("USB version string of the token")
def usb_version_string():
scc.result = ftc.token.get_string(3)
scc.result = glc.token.get_string(3)
@When("requesting (.+): ([0-9a-fA-F]+)")
def get_data(name, tag_str):
tag = int(tag_str, 16)
tagh = tag >> 8
tagl = tag & 0xff
scc.result = ftc.token.cmd_get_data(tagh, tagl)
scc.result = glc.token.cmd_get_data(tagh, tagl)
@When("removing a key OPENPGP.(.*)")
def remove_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str)
t = rsa_keys.build_privkey_template_for_remove(openpgp_keyno)
scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t)
scc.result = glc.token.cmd_put_data_odd(0x3f, 0xff, t)
@When("generating a key of OPENPGP.(.*)")
def generate_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str)
pubkey_info = ftc.token.cmd_genkey(openpgp_keyno)
pubkey_info = glc.token.cmd_genkey(openpgp_keyno)
scc.data = rsa_keys.calc_fpr(pubkey_info[0].tostring(), pubkey_info[1].tostring())
@When("put the first data to (.*)")
@@ -137,14 +137,14 @@ def cmd_put_data_first_with_result(tag_str):
tag = int(tag_str, 16)
tagh = tag >> 8
tagl = tag & 0xff
scc.result = ftc.token.cmd_put_data(tagh, tagl, scc.data[0])
scc.result = glc.token.cmd_put_data(tagh, tagl, scc.data[0])
@When("put the second data to (.*)")
def cmd_put_data_second_with_result(tag_str):
tag = int(tag_str, 16)
tagh = tag >> 8
tagl = tag & 0xff
result = ftc.token.cmd_put_data(tagh, tagl, scc.data[1])
result = glc.token.cmd_put_data(tagh, tagl, scc.data[1])
scc.result = (scc.result and result)
@Then("you should get: (.*)")

View File

@@ -60,7 +60,7 @@ def build_privkey_template(openpgp_keyno, keyno):
suffix = b'\x5f\x48' + b'\x82\x01\x04'
t = b'\x4d' + b'\x82\01\16' + exthdr + suffix + e_bytes + p_bytes + q_bytes
t = b'\x4d' + b'\x82\x01\x16' + exthdr + suffix + e_bytes + p_bytes + q_bytes
return t
def build_privkey_template_for_remove(openpgp_keyno):

13
tests/README Normal file
View File

@@ -0,0 +1,13 @@
Here is a test suite for OpenPGP card.
For now, only TPDU card reader is supported for OpenPGP card.
Gnuk Token is supported as well.
You need to install:
$ sudo apt-get install python3-pytest python3-usb
Please run test by typing:
$ py.test-3 -x

329
tests/card_reader.py Normal file
View File

@@ -0,0 +1,329 @@
"""
card_reader.py - a library for smartcard reader
Copyright (C) 2016 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import usb.core
from struct import pack
from usb.util import find_descriptor, claim_interface, get_string, \
endpoint_type, endpoint_direction, \
ENDPOINT_TYPE_BULK, ENDPOINT_OUT, ENDPOINT_IN
# USB class, subclass, protocol
CCID_CLASS = 0x0B
CCID_SUBCLASS = 0x00
CCID_PROTOCOL_0 = 0x00
def ccid_compose(msg_type, seq, slot=0, rsv=0, param=0, data=b""):
return pack('<BiBBBH', msg_type, len(data), slot, seq, rsv, param) + data
IFSC=254
def compute_edc(pcb, info):
edc = pcb
edc ^= len(info)
for i in range(len(info)):
edc ^= info[i]
return edc
def compose_i_block(ns, info, more):
pcb = 0x00
if ns:
pcb |= 0x40
if more:
pcb |= 0x20
edc = compute_edc(pcb, info)
return bytes([0, pcb, len(info)]) + info + bytes([edc])
def compose_r_block(nr, edc_error=0):
pcb = 0x80
if nr:
pcb |= 0x10
if edc_error:
pcb |= 0x01
return bytes([0, pcb, 0, pcb])
def is_r_block_no_error_or_other(blk):
return (((blk[1] & 0xC0) == 0x80 and (blk[1] & 0x2f) == 0x00)) or \
((blk[1] & 0xC0) != 0x80)
def is_s_block_time_ext(blk):
return (blk[1] == 0xC3)
def is_i_block_last(blk):
return ((blk[1] & 0x80) == 0 and (blk[1] & 0x20) == 0)
def is_i_block_more(blk):
return ((blk[1] & 0x80) == 0 and (blk[1] & 0x20) == 0x20)
def is_edc_error(blk):
# to be implemented
return 0
def i_block_content(blk):
return blk[3:-1]
class CardReader(object):
def __init__(self, dev):
"""
__init__(dev) -> None
Initialize the DEV of CCID.
device: usb.core.Device object.
"""
cfg = dev.get_active_configuration()
intf = find_descriptor(cfg, bInterfaceClass=CCID_CLASS,
bInterfaceSubClass=CCID_SUBCLASS,
bInterfaceProtocol=CCID_PROTOCOL_0)
if intf is None:
raise ValueError("Not a CCID device")
claim_interface(dev, intf)
for ep in intf:
if endpoint_type(ep.bmAttributes) == ENDPOINT_TYPE_BULK and \
endpoint_direction(ep.bEndpointAddress) == ENDPOINT_OUT:
self.__bulkout = ep.bEndpointAddress
if endpoint_type(ep.bmAttributes) == ENDPOINT_TYPE_BULK and \
endpoint_direction(ep.bEndpointAddress) == ENDPOINT_IN:
self.__bulkin = ep.bEndpointAddress
assert len(intf.extra_descriptors) == 54
assert intf.extra_descriptors[1] == 33
if (intf.extra_descriptors[42] & 0x02):
# Short APDU level exchange
self.__use_APDU = True
elif (intf.extra_descriptors[42] & 0x04):
# Short and extended APDU level exchange
self.__use_APDU = True
elif (intf.extra_descriptors[42] & 0x01):
# TPDU level exchange
self.__use_APDU = False
else:
raise ValueError("Unknown exchange level")
# Check other bits???
# intf.extra_descriptors[40]
# intf.extra_descriptors[41]
self.__dev = dev
self.__timeout = 10000
self.__seq = 0
def get_string(self, num):
return get_string(self.__dev, num)
def increment_seq(self):
self.__seq = (self.__seq + 1) & 0xff
def reset_device(self):
try:
self.__dev.reset()
except:
pass
def is_tpdu_reader(self):
return not self.__use_APDU
def ccid_get_result(self):
msg = self.__dev.read(self.__bulkin, 1024, self.__timeout)
if len(msg) < 10:
print(msg)
raise ValueError("ccid_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.tobytes())
def ccid_get_status(self):
msg = ccid_compose(0x65, self.__seq)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data = self.ccid_get_result()
# XXX: check chain, data
return status
def ccid_power_on(self):
msg = ccid_compose(0x62, self.__seq, rsv=1) # Vcc=5V
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data = self.ccid_get_result()
# XXX: check status, chain
self.atr = data
#
if self.__use_APDU == False:
# TPDU reader configuration
self.ns = 0
self.nr = 0
# Set PPS
pps = b"\xFF\x11\x18\xF6"
status, chain, ret_pps = self.ccid_send_data_block(pps)
# Set parameters
param = b"\x18\x10\xFF\x75\x00\xFE\x00"
# ^--- This shoud be adapted by ATR string, see update_param_by_atr
msg = ccid_compose(0x61, self.__seq, rsv=0x1, data=param)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, ret_param = self.ccid_get_result()
# Send an S-block of changing IFSD=254
sblk = b"\x00\xC1\x01\xFE\x3E"
status, chain, ret_sblk = self.ccid_send_data_block(sblk)
return self.atr
def ccid_power_off(self):
msg = ccid_compose(0x63, self.__seq)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data = self.ccid_get_result()
# XXX: check chain, data
return status
def ccid_send_data_block(self, data):
msg = ccid_compose(0x6f, self.__seq, data=data)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
return self.ccid_get_result()
def ccid_send_cmd(self, data):
status, chain, data_rcv = self.ccid_send_data_block(data)
if chain == 0:
while status == 0x80:
status, chain, data_rcv = self.ccid_get_result()
return data_rcv
elif chain == 1:
d = data_rcv
while True:
msg = ccid_compose(0x6f, self.__seq, param=0x10)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data_rcv = self.ccid_get_result()
# XXX: check status
d += data_rcv
if chain == 2:
break
elif chain == 3:
continue
else:
raise ValueError("ccid_send_cmd chain")
return d
else:
raise ValueError("ccid_send_cmd")
def send_tpdu(self, info=None, more=0, response_time_ext=0,
edc_error=0, no_error=0):
if info:
data = compose_i_block(self.ns, info, more)
elif response_time_ext:
# compose S-block
data = b"\x00\xE3\x00\xE3"
elif edc_error:
data = compose_r_block(self.nr, edc_error=1)
elif no_error:
data = compose_r_block(self.nr)
msg = ccid_compose(0x6f, self.__seq, data=data)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
def recv_tpdu(self):
status, chain, data = self.ccid_get_result()
return data
def send_cmd(self, cmd):
# Simple APDU case
if self.__use_APDU:
return self.ccid_send_cmd(cmd)
# TPDU case
while len(cmd) > 254:
blk = cmd[0:254]
cmd = cmd[254:]
while True:
self.send_tpdu(info=blk,more=1)
rblk = self.recv_tpdu()
if is_r_block_no_error_or_other(rblk):
break
self.ns = self.ns ^ 1
while True:
self.send_tpdu(info=cmd)
blk = self.recv_tpdu()
if is_r_block_no_error_or_other(blk):
break
self.ns = self.ns ^ 1
res = b""
while True:
if is_s_block_time_ext(blk):
self.send_tpdu(response_time_ext=1)
elif is_i_block_last(blk):
self.nr = self.nr ^ 1
if is_edc_error(blk):
self.send_tpdu(edc_error=1)
else:
res += i_block_content(blk)
break
elif is_i_block_more(blk):
self.nr = self.nr ^ 1
if is_edc_error(blk):
self.send_tpdu(edc_error=1)
else:
res += i_block_content(blk)
self.send_tpdu(no_error=1)
blk = self.recv_tpdu()
return res
class find_class(object):
def __init__(self, usb_class):
self.__class = usb_class
def __call__(self, device):
if device.bDeviceClass == self.__class:
return True
for cfg in device:
intf = find_descriptor(cfg, bInterfaceClass=self.__class)
if intf is not None:
return True
return False
def get_ccid_device():
ccid = None
dev_list = usb.core.find(find_all=True, custom_match=find_class(CCID_CLASS))
for dev in dev_list:
try:
ccid = CardReader(dev)
print("CCID device: Bus %03d Device %03d" % (dev.bus, dev.address))
break
except:
pass
if not ccid:
raise ValueError("No CCID device present")
status = ccid.ccid_get_status()
if status == 0:
# It's ON already
atr = ccid.ccid_power_on()
elif status == 1:
atr = ccid.ccid_power_on()
else:
raise ValueError("Unknown CCID status", status)
return ccid

18
tests/conftest.py Normal file
View File

@@ -0,0 +1,18 @@
import pytest
from card_reader import get_ccid_device
from openpgp_card import OpenPGP_Card
def pytest_addoption(parser):
parser.addoption("--reader", dest="reader", type=str, action="store",
default="gnuk", help="specify reader: gnuk or gemalto")
@pytest.fixture(scope="session")
def card():
print()
print("Test start!")
reader = get_ccid_device()
print("Reader:", reader.get_string(1), reader.get_string(2))
card = OpenPGP_Card(reader)
card.cmd_select_openpgp()
yield card
del card

338
tests/openpgp_card.py Normal file
View File

@@ -0,0 +1,338 @@
"""
openpgp_card.py - a library for OpenPGP card
Copyright (C) 2011, 2012, 2013, 2015, 2016
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 struct import pack
def iso7816_compose(ins, p1, p2, data, cls=0x00, le=None):
data_len = len(data)
if data_len == 0:
if not le:
return pack('>BBBB', cls, ins, p1, p2)
else:
return pack('>BBBBB', cls, ins, p1, p2, le)
else:
if not le:
if data_len <= 255:
return pack('>BBBBB', cls, ins, p1, p2, data_len) + data
else:
return pack('>BBBBBH', cls, ins, p1, p2, 0, data_len) \
+ data
else:
if data_len <= 255 and le < 256:
return pack('>BBBBB', cls, ins, p1, p2, data_len) \
+ data + pack('>B', le)
else:
return pack('>BBBBBH', cls, ins, p1, p2, 0, data_len) \
+ data + pack('>H', le)
class OpenPGP_Card(object):
def __init__(self, reader):
"""
__init__(reader) -> None
Initialize a OpenPGP card with a CardReader.
reader: CardReader object.
"""
self.__reader = reader
def cmd_get_response(self, expected_len):
result = b""
while True:
cmd_data = iso7816_compose(0xc0, 0x00, 0x00, b'') + pack('>B', expected_len)
response = self.__reader.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.__reader.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]))
return True
def cmd_read_binary(self, fileid):
cmd_data = iso7816_compose(0xb0, 0x80+fileid, 0x00, b'')
sw = self.__reader.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:
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:
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.__reader.send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError("cmd_write_binary 0")
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("cmd_write_binary 0", "%02x%02x" % (sw[0], sw[1]))
if cmd_data1:
sw = self.__reader.send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError("cmd_write_binary 1", sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("cmd_write_binary 1", "%02x%02x" % (sw[0], sw[1]))
count += 1
def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x00, b"\xD2\x76\x00\x01\x24\x01")
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
self.cmd_get_response(sw[1])
return True
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_get_data(self, tagh, tagl):
cmd_data = iso7816_compose(0xca, tagh, tagl, b"", le=254)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) < 2:
raise ValueError(sw)
if sw[0] == 0x61:
return self.cmd_get_response(sw[1])
elif sw[-2] == 0x90 and sw[-1] == 0x00:
return sw[0:-2]
if sw[0] == 0x6a and sw[1] == 0x88:
return None
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def cmd_change_reference_data(self, who, data):
cmd_data = iso7816_compose(0x24, 0x00, 0x80+who, data)
sw = self.__reader.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]))
return True
def cmd_put_data(self, tagh, tagl, content):
cmd_data = iso7816_compose(0xda, tagh, tagl, content)
sw = self.__reader.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]))
return True
def cmd_put_data_odd(self, tagh, tagl, content):
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0xdb, tagh, tagl, content)
sw = self.__reader.send_cmd(cmd_data)
else:
cmd_data0 = iso7816_compose(0xdb, tagh, tagl, content[:128], 0x10)
cmd_data1 = iso7816_compose(0xdb, tagh, tagl, content[128:])
sw = self.__reader.send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
sw = self.__reader.send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_reset_retry_counter(self, how, who, data):
cmd_data = iso7816_compose(0x2c, how, who, data)
sw = self.__reader.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]))
return True
def cmd_pso(self, p1, p2, data):
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x2a, p1, p2, data, le=256)
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
return self.cmd_get_response(sw[1])
elif sw[0] == 0x90 and sw[1] == 0x00:
return r
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
else:
if len(data) > 128:
cmd_data0 = iso7816_compose(0x2a, p1, p2, data[:128], 0x10)
cmd_data1 = iso7816_compose(0x2a, p1, p2, data[128:])
sw = self.__reader.send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
sw = self.__reader.send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError(sw)
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
else:
cmd_data = iso7816_compose(0x2a, p1, p2, data)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if sw[0] == 0x90 and sw[1] == 0x00:
return b""
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_internal_authenticate(self, data):
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x88, 0, 0, data, le=256)
else:
cmd_data = iso7816_compose(0x88, 0, 0, data)
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
return self.cmd_get_response(sw[1])
elif sw[0] == 0x90 and sw[1] == 0x00:
return r
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def cmd_genkey(self, keyno):
if keyno == 1:
data = b'\xb6\x00'
elif keyno == 2:
data = b'\xb8\x00'
else:
data = b'\xa4\x00'
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if sw[0] == 0x90 and sw[1] == 0x00:
return b""
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
pk = self.cmd_get_response(sw[1])
return (pk[9:9+256], pk[9+256+2:9+256+2+3])
def cmd_get_public_key(self, keyno):
if keyno == 1:
data = b'\xb6\x00'
elif keyno == 2:
data = b'\xb8\x00'
else:
data = b'\xa4\x00'
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x47, 0x81, 0, data, le=512)
r = self.__reader.send_cmd(cmd_data)
else:
cmd_data = iso7816_compose(0x47, 0x81, 0, data)
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
pk = self.cmd_get_response(sw[1])
elif sw[0] == 0x90 and sw[1] == 0x00:
pk = r
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return pk
def cmd_put_data_remove(self, tagh, tagl):
cmd_data = iso7816_compose(0xda, tagh, tagl, b"")
sw = self.__reader.send_cmd(cmd_data)
if sw[0] != 0x90 and sw[1] != 0x00:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def cmd_put_data_key_import_remove(self, keyno):
if keyno == 1:
keyspec = b"\xb6\x00" # SIG
elif keyno == 2:
keyspec = b"\xb8\x00" # DEC
else:
keyspec = b"\xa4\x00" # AUT
cmd_data = iso7816_compose(0xdb, 0x3f, 0xff, b"\x4d\x02" + keyspec)
sw = self.__reader.send_cmd(cmd_data)
if 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.__reader.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_external_authenticate(self, keyno, signed):
cmd_data = iso7816_compose(0x82, 0x00, keyno, signed[0:128], cls=0x10)
sw = self.__reader.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, keyno, signed[128:])
sw = self.__reader.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]))

4
tests/rsa-aut.key Normal file
View File

@@ -0,0 +1,4 @@
9cf7192b51a574d1ad3ccb08ba09b87f228573893eee355529ff243e90fd4b86f79a82097cc7922c0485bed1616b1656a9b0b19ef78ea8ec34c384019adc5d5bf4db2d2a0a2d9cf14277bdcb7056f48b81214e3f7f7742231e29673966f9b1106862112cc798dba8d4a138bb5abfc6d4c12d53a5d39b2f783da916da20852ee139bbafda61d429caf2a4f30847ce7e7ae32ab4061e27dd9e4d00d60910249db8d8559dd85f7ca59659ef400c8f6318700f4e97f0c6f4165de80641490433c88da8682befe68eb311f54af2b07d97ac74edb5399cf054764211694fbb8d1d333f3269f235abe025067f811ff83a2224826219b309ea3e6c968f42b3e52f245dc9
010001
b5ab7b159220b18e363258f61ebde08bae83d6ce2dbfe4adc143628c527887acde9de09bf9b49f438019004d71855f30c2d69b6c29bb9882ab641b3387409fe9199464a7faa4b5230c56d9e17cd9ed074bc00180ebed62bae3af28e6ff2ac2654ad968834c5d5c88f8d9d3cc5e167b10453b049d4e454a5761fb0ac717185907
dd2fffa9814296156a6926cd17b65564187e424dcadce9b032246ad7e46448bb0f9e0ff3c64f987424b1a40bc694e2e9ac4fb1930d163582d7acf20653a1c44b97846c1c5fd8a7b19bb225fb39c30e25410483deaf8c2538d222b748c4d8103b11cec04f666a5c0dbcbf5d5f625f158f65746c3fafe6418145f7cffa5fadeeaf

4
tests/rsa-dec.key Normal file
View File

@@ -0,0 +1,4 @@
d392714c29738aac6372f2c8654a08c25a1299fed7004bd512cd2452b503ebad6301130816ac525ba528dc155be6347a5c70407fb4fbdaed751dfc0a7cd5e3910272ff236c4ed1ce5de6620b191a172e5b247347b8cab73a43d79221708755c959a2f83f486439da30917384554331532aabc8326db48866f8c91198834a86ab94679f6175db737bdf399e3f0b737dcb1f4208279d3e1cc694e78686785e4f363a377dec912b7c2f757b1422d866fb9fa85c96b83adfd6a223989a9a02988bdee81ad17eff6385e7b38cec8611fdf367ba4ac8e90d5f48ac7715c5f47aea06a4a37cdaa3029ce59d29bc66853bf6758ef4a7da5a5953f5e557a5a22f67c368c3
010001
dae085952c5beee38f25f09bc37a4ca2434c31f78055469d0d5f0bf3337e3a70ba6c91734f195b742e211a5fe283befdf66820008e6ef2c8ca54a91922838fce07d9e33a331ce20dac36803e777d5ee2195ed28d6a4045e28623a6a60b0661e45f7c4f84ae2b1dfad0cf1ec30605158323382a819e730c09a33fad704dd67501
f774be43ea198aa2f089274e4fffd7d0092ee7b35a1d2f854cdb166f698caab72fdeb099e690e78438b2e043e452d4d2f19d7f44ba6b286642f0ce5204966ff98ecd9e3b448877324631365dc860797429b9414a21a7e166d504cace156588b9a145657eeb1afb43b8ff65d8d6d93cea2ba4ef8aab047885c4de64ffef0b49c3

4
tests/rsa-sig.key Normal file
View File

@@ -0,0 +1,4 @@
c6c877dfd3b441f8fb1b8dc504093a51c2efe4883fe0a6379205acc6e673709905e4d767ddf46143c535cc6d7f10b616f520d8346320ef69ff4a2c4f4a148edc65f7ad24ed7d4fe23bb862a0ae71f4f7904abac0397abf3213df91326b1a25554b3b18cf54584d8bf220169fc92b2aa511e8313983e72b4c9110b3a1aea087aebef95873865608e8faea9ef10e7f7f3a66ca8def2d499c3149c127491e0e4339fd6abe10bfc6c13e43d522004f1485767328eabe35d6ffa8df4c15f0fbcd4eb1c07cc6d85e275139ac69e2962273ae987236926dd6c1144fce3e7ae567fa58ea60620dfafc52f95299fea601739fce27ee71eea978d0074f21e7086f60ba8331
010001
cc365b5702714bf203e8c49b0b8afa8dad586e929cf5edca38ad07fa45efd5c2d89022d29f40283a57e50ca24c5f28c8e911a74faaf796f112e7e48195956f9a4df7668a5342523b27179cec958f363211ee11d0ec0e0e1b92ca007a61e8c9ac14e00229b9a7624850199e6667afa1a44db8f3c5de0a8eef0e6de050ac0ac633
f931a3c12f0e3a5276f712b7706590ba02e14a97ff9b8ce3152af0fc4d9cdc690ea9bc4c82cb16c7d23136cbdab58fbec69880a88bca85c4214df01045082cbe9f4192e3e39c79896533c37dad9eb9e73c2643b9c0a704a4f93d81573537963d6b6e5140a24c702d9f26e06a2095de906daa8824172a6b39f563b7153907050b

148
tests/rsa_keys.py Normal file
View File

@@ -0,0 +1,148 @@
from binascii import hexlify, unhexlify
from time import time
from struct import pack
from hashlib import sha1, sha256
import string
from os import urandom
def read_key_from_file(file):
f = open(file)
n_str = f.readline()[:-1]
e_str = f.readline()[:-1]
p_str = f.readline()[:-1]
q_str = f.readline()[:-1]
f.close()
e = int(e_str, 16)
p = int(p_str, 16)
q = int(q_str, 16)
n = int(n_str, 16)
if n != p * q:
raise ValueError("wrong key", p, q, n)
return (unhexlify(n_str), unhexlify(e_str), unhexlify(p_str), unhexlify(q_str), e, p, q, n)
def calc_fpr(n,e):
timestamp = int(time())
timestamp_data = pack('>I', timestamp)
m_len = 6 + 2 + 256 + 2 + 4
m = b'\x99' + pack('>H', m_len) + b'\x04' + timestamp_data + b'\x01' + \
pack('>H', 2048) + n + pack('>H', 17) + e
fpr = sha1(m).digest()
return (fpr, timestamp_data)
key = [ None, None, None ]
fpr = [ None, None, None ]
timestamp = [ None, None, None ]
key[0] = read_key_from_file('rsa-sig.key')
key[1] = read_key_from_file('rsa-dec.key')
key[2] = read_key_from_file('rsa-aut.key')
(fpr[0], timestamp[0]) = calc_fpr(key[0][0], key[0][1])
(fpr[1], timestamp[1]) = calc_fpr(key[1][0], key[1][1])
(fpr[2], timestamp[2]) = calc_fpr(key[2][0], key[2][1])
def build_privkey_template(openpgp_keyno, keyno):
n_bytes = key[keyno][0]
e_bytes = b'\x00' + key[keyno][1]
p_bytes = key[keyno][2]
q_bytes = key[keyno][3]
if openpgp_keyno == 1:
keyspec = b'\xb6'
elif openpgp_keyno == 2:
keyspec = b'\xb8'
else:
keyspec = b'\xa4'
key_template = b'\x91\x04'+ b'\x92\x81\x80' + b'\x93\x81\x80'
exthdr = keyspec + b'\x00' + b'\x7f\x48' + b'\x08' + key_template
suffix = b'\x5f\x48' + b'\x82\x01\x04'
t = b'\x4d' + b'\x82\x01\x16' + exthdr + suffix + e_bytes + p_bytes + q_bytes
return t
def build_privkey_template_for_remove(openpgp_keyno):
if openpgp_keyno == 1:
keyspec = b'\xb6'
elif openpgp_keyno == 2:
keyspec = b'\xb8'
else:
keyspec = b'\xa4'
return b'\x4d\02' + keyspec + b'\0x00'
def compute_digestinfo(msg):
digest = sha256(msg).digest()
prefix = b'\x30\31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
return prefix + digest
# egcd and modinv are from wikibooks
# https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
def pkcs1_pad_for_sign(digestinfo):
byte_repr = b'\x00' + b'\x01' + bytes.ljust(b'', 256 - 19 - 32 - 3, b'\xff') \
+ b'\x00' + digestinfo
return int(hexlify(byte_repr), 16)
def pkcs1_pad_for_crypt(msg):
padlen = 256 - 3 - len(msg)
byte_repr = b'\x00' + b'\x02' \
+ bytes.replace(urandom(padlen), b'\x00', b'\x01') + b'\x00' + msg
return int(hexlify(byte_repr), 16)
def compute_signature(keyno, digestinfo):
e = key[keyno][4]
p = key[keyno][5]
q = key[keyno][6]
n = key[keyno][7]
p1 = p - 1
q1 = q - 1
h = p1 * q1
d = modinv(e, h)
dp = d % p1
dq = d % q1
qp = modinv(q, p)
input = pkcs1_pad_for_sign(digestinfo)
t1 = pow(input, dp, p)
t2 = pow(input, dq, q)
t = ((t1 - t2) * qp) % p
sig = t2 + t * q
return sig
def integer_to_bytes_256(i):
return i.to_bytes(256, byteorder='big')
def encrypt(keyno, plaintext):
e = key[keyno][4]
n = key[keyno][7]
m = pkcs1_pad_for_crypt(plaintext)
return b'\x00' + integer_to_bytes_256(pow(m, e, n))
def encrypt_with_pubkey(pubkey_info, plaintext):
n = int(hexlify(pubkey_info[0]), 16)
e = int(hexlify(pubkey_info[1]), 16)
m = pkcs1_pad_for_crypt(plaintext)
return b'\x00' + integer_to_bytes_256(pow(m, e, n))
def verify_signature(pubkey_info, digestinfo, sig):
n = int(hexlify(pubkey_info[0]), 16)
e = int(hexlify(pubkey_info[1]), 16)
di_pkcs1 = pow(sig,e,n)
m = pkcs1_pad_for_sign(digestinfo)
return di_pkcs1 == m

184
tests/test_empty_card.py Normal file
View File

@@ -0,0 +1,184 @@
"""
test_empty_card.py - test empty card
Copyright (C) 2016 g10 Code GmbH
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 binascii import hexlify
from re import match, DOTALL
from struct import pack
from util import *
import pytest
EMPTY_60=bytes(60)
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
def test_login(card):
login = get_data_object(card, 0x5e)
assert check_null(login)
"""
def test_name(card):
name = get_data_object(card, 0x5b)
assert check_null(name)
def test_lang(card):
lang = get_data_object(card, 0x5f2d)
assert check_null(lang)
def test_sex(card):
sex = get_data_object(card, 0x5f35)
assert check_null(sex)
"""
def test_name_lang_sex(card):
name = b""
lang = b""
sex = b"9"
expected = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
+ b'\x5f\x35' + pack('B', len(sex)) + sex
name_lang_sex = get_data_object(card, 0x65)
assert name_lang_sex == b'' or name_lang_sex == expected
def test_app_data(card):
app_data = get_data_object(card, 0x6e)
hist_len = app_data[20]
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
app_data[18:18+2] == b"\x5f\x52"
def test_url(card):
url = get_data_object(card, 0x5f50)
assert check_null(url)
def test_ds_counter(card):
c = get_data_object(card, 0x7a)
assert c == b'\x93\x03\x00\x00\x00'
def test_pw1_status(card):
s = get_data_object(card, 0xc4)
assert match(b'\x00...\x03[\x00\x03]\x03', s, DOTALL)
def test_fingerprint_0(card):
fprlist = get_data_object(card, 0xC5)
assert fprlist == None or fprlist == EMPTY_60
def test_fingerprint_1(card):
fpr = get_data_object(card, 0xC7)
assert check_null(fpr)
def test_fingerprint_2(card):
fpr = get_data_object(card, 0xC8)
assert check_null(fpr)
def test_fingerprint_3(card):
fpr = get_data_object(card, 0xC9)
assert check_null(fpr)
def test_ca_fingerprint_0(card):
cafprlist = get_data_object(card, 0xC6)
assert cafprlist == None or cafprlist == EMPTY_60
def test_ca_fingerprint_1(card):
cafp = get_data_object(card, 0xCA)
assert check_null(cafp)
def test_ca_fingerprint_2(card):
cafp = get_data_object(card, 0xCB)
assert check_null(cafp)
def test_ca_fingerprint_3(card):
cafp = get_data_object(card, 0xCC)
assert check_null(cafp)
def test_timestamp_0(card):
t = get_data_object(card, 0xCD)
assert t == None or t == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
def test_timestamp_1(card):
t = get_data_object(card, 0xCE)
assert check_null(t)
def test_timestamp_2(card):
t = get_data_object(card, 0xCF)
assert check_null(t)
def test_timestamp_3(card):
t = get_data_object(card, 0xD0)
assert check_null(t)
def test_verify_pw1_1(card):
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
assert v
def test_verify_pw1_2(card):
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
assert v
def test_verify_pw3(card):
v = card.cmd_verify(3, FACTORY_PASSPHRASE_PW3)
assert v
def test_historical_bytes(card):
h = get_data_object(card, 0x5f52)
assert h == b'\x001\xc5s\xc0\x01@\x05\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x00\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00'
def test_extended_capabilities(card):
a = get_data_object(card, 0xc0)
assert a == None or match(b'[\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00', a)
def test_algorithm_attributes_1(card):
a = get_data_object(card, 0xc1)
assert a == None or a == b'\x01\x08\x00\x00\x20\x00'
def test_algorithm_attributes_2(card):
a = get_data_object(card, 0xc2)
assert a == None or a == b'\x01\x08\x00\x00\x20\x00'
def test_algorithm_attributes_3(card):
a = get_data_object(card, 0xc3)
assert a == None or a == b'\x01\x08\x00\x00\x20\x00'
def test_public_key_1(card):
with pytest.raises(Exception) as excinfo:
pk = card.cmd_get_public_key(1)
assert excinfo.value.args[0] == "6a88"
def test_public_key_2(card):
with pytest.raises(Exception) as excinfo:
pk = card.cmd_get_public_key(2)
assert excinfo.value.args[0] == "6a88"
def test_public_key_3(card):
with pytest.raises(Exception) as excinfo:
pk = card.cmd_get_public_key(3)
assert excinfo.value.args[0] == "6a88"
def test_AID(card):
a = get_data_object(card, 0x4f)
print()
print("OpenPGP card version: %d.%d" % (a[6], a[7]))
print("Card Manufacturer: ", hexlify(a[8:10]).decode("UTF-8"))
print("Card serial: ", hexlify(a[10:14]).decode("UTF-8"))
assert match(b'\xd2\x76\x00\x01\\$\x01........\x00\x00', a, DOTALL)

View File

@@ -0,0 +1,290 @@
"""
test_personalize_card.py - test personalizing card
Copyright (C) 2016 g10 Code GmbH
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 struct import pack
from re import match, DOTALL
from util import *
import rsa_keys
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
PW1_TEST0=b"another user pass phrase"
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
PW1_TEST2=b"new user pass phrase"
PW1_TEST3=b"next user pass phrase"
PW1_TEST4=b"another user pass phrase"
PW3_TEST0=b"admin pass phrase"
PW3_TEST1=b"another admin pass phrase"
RESETCODE_TEST=b"example reset code 000"
def test_setup_pw3_0(card):
r = card.cmd_change_reference_data(3, FACTORY_PASSPHRASE_PW3 + PW3_TEST0)
assert r
def test_verify_pw3_0(card):
v = card.cmd_verify(3, PW3_TEST0)
assert v
def test_login_put(card):
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
assert r
def test_name_put(card):
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
assert r
def test_lang_put(card):
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
assert r
def test_sex_put(card):
r = card.cmd_put_data(0x5f, 0x35, b"1")
assert r
def test_url_put(card):
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
assert r
def test_pw1_status_put(card):
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
assert r
def test_login(card):
login = get_data_object(card, 0x5e)
assert login == b"gpg_user"
def test_name_lang_sex(card):
name = b"GnuPG User"
lang = b"ja"
sex = b"1"
expected = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
+ b'\x5f\x35' + pack('B', len(sex)) + sex
name_lang_sex = get_data_object(card, 0x65)
assert name_lang_sex == expected
def test_url(card):
url = get_data_object(card, 0x5f50)
assert url == b"https://www.fsij.org/gnuk/"
def test_pw1_status(card):
s = get_data_object(card, 0xc4)
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
def test_rsa_import_key_1(card):
t = rsa_keys.build_privkey_template(1, 0)
r = card.cmd_put_data_odd(0x3f, 0xff, t)
assert r
def test_rsa_import_key_2(card):
t = rsa_keys.build_privkey_template(2, 1)
r = card.cmd_put_data_odd(0x3f, 0xff, t)
assert r
def test_rsa_import_key_3(card):
t = rsa_keys.build_privkey_template(3, 2)
r = card.cmd_put_data_odd(0x3f, 0xff, t)
assert r
def test_fingerprint_1_put(card):
fpr1 = rsa_keys.fpr[0]
r = card.cmd_put_data(0x00, 0xc7, fpr1)
assert r
def test_fingerprint_2_put(card):
fpr2 = rsa_keys.fpr[1]
r = card.cmd_put_data(0x00, 0xc8, fpr2)
assert r
def test_fingerprint_3_put(card):
fpr3 = rsa_keys.fpr[2]
r = card.cmd_put_data(0x00, 0xc9, fpr3)
assert r
def test_timestamp_1_put(card):
timestamp1 = rsa_keys.timestamp[0]
r = card.cmd_put_data(0x00, 0xce, timestamp1)
assert r
def test_timestamp_2_put(card):
timestamp2 = rsa_keys.timestamp[1]
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
assert r
def test_timestamp_3_put(card):
timestamp3 = rsa_keys.timestamp[2]
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
assert r
def test_ds_counter_0(card):
c = get_data_object(card, 0x7a)
assert c == b'\x93\x03\x00\x00\x00'
def test_pw1_status(card):
s = get_data_object(card, 0xc4)
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
def test_app_data(card):
app_data = get_data_object(card, 0x6e)
hist_len = app_data[20]
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
app_data[18:18+2] == b"\x5f\x52"
def test_public_key_1(card):
pk = card.cmd_get_public_key(1)
assert rsa_keys.key[0][0] == pk[9:9+256]
def test_public_key_2(card):
pk = card.cmd_get_public_key(2)
assert rsa_keys.key[1][0] == pk[9:9+256]
def test_public_key_3(card):
pk = card.cmd_get_public_key(3)
assert rsa_keys.key[2][0] == pk[9:9+256]
def test_setup_pw1_0(card):
r = card.cmd_change_reference_data(1, FACTORY_PASSPHRASE_PW1 + PW1_TEST0)
assert r
def test_verify_pw1_0(card):
v = card.cmd_verify(1, PW1_TEST0)
assert v
def test_verify_pw1_0_2(card):
v = card.cmd_verify(2, PW1_TEST0)
assert v
def test_setup_pw1_1(card):
r = card.cmd_change_reference_data(1, PW1_TEST0 + PW1_TEST1)
assert r
def test_verify_pw1_1(card):
v = card.cmd_verify(1, PW1_TEST1)
assert v
def test_verify_pw1_1_2(card):
v = card.cmd_verify(2, PW1_TEST1)
assert v
def test_setup_reset_code(card):
r = card.cmd_put_data(0x00, 0xd3, RESETCODE_TEST)
assert r
def test_reset_code(card):
r = card.cmd_reset_retry_counter(0, 0x81, RESETCODE_TEST + PW1_TEST2)
assert r
def test_verify_pw1_2(card):
v = card.cmd_verify(1, PW1_TEST2)
assert v
def test_verify_pw1_2_2(card):
v = card.cmd_verify(2, PW1_TEST2)
assert v
def test_setup_pw3_1(card):
r = card.cmd_change_reference_data(3, PW3_TEST0 + PW3_TEST1)
assert r
def test_verify_pw3_1(card):
v = card.cmd_verify(3, PW3_TEST1)
assert v
def test_reset_userpass_admin(card):
r = card.cmd_reset_retry_counter(2, 0x81, PW1_TEST3)
assert r
def test_verify_pw1_3(card):
v = card.cmd_verify(1, PW1_TEST3)
assert v
def test_verify_pw1_3_2(card):
v = card.cmd_verify(2, PW1_TEST3)
assert v
def test_setup_pw1_4(card):
r = card.cmd_change_reference_data(1, PW1_TEST3 + PW1_TEST4)
assert r
def test_verify_pw1_4(card):
v = card.cmd_verify(1, PW1_TEST4)
assert v
def test_verify_pw1_4_2(card):
v = card.cmd_verify(2, PW1_TEST4)
assert v
def test_setup_pw3_2(card):
r = card.cmd_change_reference_data(3, PW3_TEST1 + PW3_TEST0)
assert r
def test_verify_pw3_2(card):
v = card.cmd_verify(3, PW3_TEST0)
assert v
PLAIN_TEXT0=b"This is a test message."
PLAIN_TEXT1=b"RSA decryption is as easy as pie."
PLAIN_TEXT2=b"This is another test message.\nMultiple lines.\n"
def test_sign_0(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
sig = rsa_keys.compute_signature(0, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_sign_1(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
sig = rsa_keys.compute_signature(0, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_ds_counter_1(card):
c = get_data_object(card, 0x7a)
assert c == b'\x93\x03\x00\x00\x02'
def test_sign_auth_0(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
r = card.cmd_internal_authenticate(digestinfo)
sig = rsa_keys.compute_signature(2, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_sign_auth_1(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
r = card.cmd_internal_authenticate(digestinfo)
sig = rsa_keys.compute_signature(2, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_decrypt_0(card):
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
r = card.cmd_pso(0x80, 0x86, ciphertext)
assert r == PLAIN_TEXT0
def test_decrypt_1(card):
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
r = card.cmd_pso(0x80, 0x86, ciphertext)
assert r == PLAIN_TEXT1

View File

@@ -0,0 +1,91 @@
"""
test_personalize_reset_card.py - test resetting personalization of card
Copyright (C) 2016 g10 Code GmbH
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 struct import pack
from re import match, DOTALL
from util import *
import rsa_keys
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
PW1_TEST0=b"another user pass phrase"
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
PW1_TEST2=b"new user pass phrase"
PW1_TEST3=b"next user pass phrase"
PW1_TEST4=b"another user pass phrase"
PW3_TEST0=b"admin pass phrase"
PW3_TEST1=b"another admin pass phrase"
RESETCODE_TEST=b"example reset code 000"
def test_login_put(card):
r = card.cmd_put_data(0x00, 0x5e, b"")
assert r
def test_name_put(card):
r = card.cmd_put_data(0x00, 0x5b, b"")
assert r
def test_lang_put(card):
r = card.cmd_put_data(0x5f, 0x2d, b"")
assert r
def test_sex_put(card):
try:
# Gnuk
r = card.cmd_put_data(0x5f, 0x35, b"")
except ValueError:
# OpenPGP card which doesn't allow b""
r = card.cmd_put_data(0x5f, 0x35, b"9")
assert r
def test_url_put(card):
r = card.cmd_put_data(0x5f, 0x50, b"")
assert r
def test_pw1_status_put(card):
r = card.cmd_put_data(0x00, 0xc4, b"\x00")
assert r
def test_setup_pw3_0(card):
r = card.cmd_change_reference_data(3, PW3_TEST0 + FACTORY_PASSPHRASE_PW3)
assert r
def test_verify_pw3_0(card):
v = card.cmd_verify(3, FACTORY_PASSPHRASE_PW3)
assert v
def test_setup_pw1_0(card):
r = card.cmd_change_reference_data(1, PW1_TEST4 + FACTORY_PASSPHRASE_PW1)
assert r
def test_verify_pw1_0(card):
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
assert v
def test_verify_pw1_0_2(card):
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
assert v
def test_setup_reset_code(card):
r = card.cmd_put_data(0x00, 0xd3, b"")
assert r

View File

@@ -0,0 +1,44 @@
"""
test_remove_keys_card.py - test removing keys on card
Copyright (C) 2016 g10 Code GmbH
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/>.
"""
# Remove a key material on card by changing algorithm attributes of the key
KEY_ATTRIBUTES_RSA4K=b"\x01\x10\x00\x00\x20\x00"
KEY_ATTRIBUTES_RSA2K=b"\x01\x08\x00\x00\x20\x00"
def test_rsa_import_key_1(card):
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
assert r
def test_rsa_import_key_2(card):
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
assert r
def test_rsa_import_key_3(card):
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)
assert r

7
tests/util.py Normal file
View File

@@ -0,0 +1,7 @@
def get_data_object(card, tag):
tagh = tag >> 8
tagl = tag & 0xff
return card.cmd_get_data(tagh, tagl)
def check_null(data_object):
return data_object == None or len(data_object) == 0

View File

@@ -49,6 +49,7 @@ def main(fileid, is_update, data, passwd):
raise ValueError("No ICC present")
elif gnuk.icc_get_status() == 1:
gnuk.icc_power_on()
gnuk.cmd_select_openpgp()
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8'))
gnuk.cmd_write_binary(fileid, data, is_update)
gnuk.cmd_select_openpgp()

View File

@@ -46,6 +46,7 @@ def main(passwd):
raise ValueError("No ICC present")
elif gnuk.icc_get_status() == 1:
gnuk.icc_power_on()
gnuk.cmd_select_openpgp()
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8'))
gnuk.cmd_select_openpgp()
gnuk.cmd_put_data_remove(0x00, 0xc7) # FP_SIG

View File

@@ -1,7 +1,7 @@
"""
gnuk_token.py - a library for Gnuk Token
Copyright (C) 2011, 2012, 2013, 2015
Copyright (C) 2011, 2012, 2013, 2015, 2017
Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -26,6 +26,12 @@ import binascii
import usb, time
from array import array
# Possible Gnuk Token products
USB_PRODUCT_LIST=[
{ 'vendor' : 0x234b, 'product' : 0x0000 }, # FSIJ Gnuk Token
{ 'vendor' : 0x20a0, 'product' : 0x4211 }, # Nitrokey Start
]
# USB class, subclass, protocol
CCID_CLASS = 0x0B
CCID_SUBCLASS = 0x00
@@ -68,7 +74,6 @@ class gnuk_token(object):
raise ValueError("Wrong interface sub class")
self.__devhandle = device.open()
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(0)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting
@@ -290,13 +295,19 @@ class gnuk_token(object):
count += 1
def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, b"\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):
cmd_data = iso7816_compose(0xa4, 0x04, 0x00, b"\xD2\x76\x00\x01\x24\x01")
r = self.icc_send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
self.cmd_get_response(sw[1])
return True
elif sw[0] == 0x90 and sw[1] == 0x00:
return True
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_get_data(self, tagh, tagl):
cmd_data = iso7816_compose(0xca, tagh, tagl, b"")
@@ -342,8 +353,8 @@ class gnuk_token(object):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_reset_retry_counter(self, how, data):
cmd_data = iso7816_compose(0x2c, how, 0x00, data)
def cmd_reset_retry_counter(self, how, who, data):
cmd_data = iso7816_compose(0x2c, how, who, data)
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
@@ -473,7 +484,6 @@ class regnual(object):
raise ValueError("Wrong interface class")
self.__devhandle = dev.open()
self.__devhandle.claimInterface(intf)
self.__devhandle.setAltInterface(0)
def mem_info(self):
mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0,
@@ -582,19 +592,18 @@ def gnuk_devices():
alt.interfaceProtocol == CCID_PROTOCOL_0:
yield dev, config, alt
USB_VENDOR_FSIJ=0x234b
USB_PRODUCT_GNUK=0x0000
def gnuk_devices_by_vidpid():
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
for cand in USB_PRODUCT_LIST:
if dev.idVendor != cand['vendor']:
continue
if dev.idProduct != cand['product']:
continue
yield dev
break
def get_gnuk_device():
icc = None

View File

@@ -3,7 +3,7 @@
"""
hub_ctrl.py - a tool to control port power/led of USB hub
Copyright (C) 2006, 2011 Free Software Initiative of Japan
Copyright (C) 2006, 2011, 2016 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -23,6 +23,7 @@ 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 __future__ import print_function
import usb
USB_RT_HUB = (usb.TYPE_CLASS | usb.RECIP_DEVICE)
@@ -43,7 +44,7 @@ def find_hubs(listing, verbose, busnum=None, devnum=None, hub=None):
hubs = []
busses = usb.busses()
if not busses:
raise ValueError, "can't access USB"
raise ValueError("can't access USB")
for bus in busses:
devices = bus.devices
@@ -79,17 +80,17 @@ def find_hubs(listing, verbose, busnum=None, devnum=None, hub=None):
continue
if printout_enable:
print "Hub #%d at %s:%03d" % (number_of_hubs_with_feature,
bus.dirname, dev.devnum)
print("Hub #%d at %s:%03d" % (number_of_hubs_with_feature,
bus.dirname, dev.devnum))
if (desc[3] & 0x03) == 0:
print " INFO: ganged power switching."
print(" INFO: ganged power switching.")
elif (desc[3] & 0x03) == 1:
print " INFO: individual power switching."
print(" INFO: individual power switching.")
elif (desc[3] & 0x03) == 2 or (desc[3] & 0x03) == 3:
print " WARN: no power switching."
print(" WARN: no power switching.")
if (desc[3] & 0x80) == 0:
print " WARN: Port indicators are NOT supported."
print(" WARN: Port indicators are NOT supported.")
hubs.append({ 'busnum' : bus.dirname, 'devnum' : dev.devnum,
'indicator_support' : (desc[3] & 0x80) == 0x80,
@@ -99,7 +100,7 @@ def find_hubs(listing, verbose, busnum=None, devnum=None, hub=None):
return hubs
def hub_port_status(handle, num_ports):
print " Hub Port Status:"
print(" Hub Port Status:")
for i in range(num_ports):
port = i + 1
status = handle.controlMsg(requestType = USB_RT_PORT | usb.ENDPOINT_IN,
@@ -108,31 +109,31 @@ def hub_port_status(handle, num_ports):
index = port, buffer = 4,
timeout = 1000)
print " Port %d: %02x%02x.%02x%02x" % (port, status[3], status[2],
status[1], status[0]),
print(" Port %d: %02x%02x.%02x%02x" % (port, status[3], status[2],
status[1], status[0]),)
if status[1] & 0x10:
print " indicator",
print(" indicator", end='')
if status[1] & 0x08:
print " test" ,
print(" test" , end='')
if status[1] & 0x04:
print " highspeed",
print(" highspeed", end='')
if status[1] & 0x02:
print " lowspeed",
print(" lowspeed", end='')
if status[1] & 0x01:
print " power",
print(" power", end='')
if status[0] & 0x10:
print " RESET",
print(" RESET", end='')
if status[0] & 0x08:
print " oc",
print(" oc", end='')
if status[0] & 0x04:
print " suspend",
print(" suspend", end='')
if status[0] & 0x02:
print " enable",
print(" enable", end='')
if status[0] & 0x01:
print " connect",
print(" connect", end='')
print
print()
import sys
@@ -142,9 +143,9 @@ COMMAND_SET_POWER = 2
HUB_LED_GREEN = 2
def usage(progname):
print >> sys.stderr, """Usage: %s [{-h HUBNUM | -b BUSNUM -d DEVNUM}]
print("""Usage: %s [{-h HUBNUM | -b BUSNUM -d DEVNUM}]
[-P PORT] [{-p [VALUE]|-l [VALUE]}]
""" % progname
""" % progname, file=sys.stderr)
def exit_with_usage(progname):
usage(progname)
@@ -219,7 +220,7 @@ if __name__ == '__main__':
hubs = find_hubs(listing, verbose, busnum, devnum, hub)
if len(hubs) == 0:
print >> sys.stderr, "No hubs found."
print("No hubs found.", file=sys.stderr)
exit(1)
if listing:
exit(0)
@@ -246,11 +247,11 @@ if __name__ == '__main__':
feature = USB_PORT_FEAT_INDICATOR
index = (value << 8) | port
if verbose:
print "Send control message (REQUEST=%d, FEATURE=%d, INDEX=%d) " % (request, feature, index)
print("Send control message (REQUEST=%d, FEATURE=%d, INDEX=%d) " % (request, feature, index))
uh.controlMsg(requestType = USB_RT_PORT, request = request, value = feature,
index = index, buffer = None, timeout = 1000)
if verbose:
hub_port_status(uh,nports)
hub_port_status(uh,nports)
del uh

View File

@@ -146,15 +146,7 @@ class stlinkv2(object):
if intf.interfaceClass != 0xff: # Vendor specific
raise ValueError("Wrong interface class.", intf.interfaceClass)
self.__devhandle = dev.open()
# ST-Link/V2-1 has other interfaces
# Some other processes or kernel would use it
# So, write access to configuration causes error
try:
self.__devhandle.setConfiguration(conf.value)
except:
pass
self.__devhandle.claimInterface(intf.interfaceNumber)
# self.__devhandle.setAltInterface(0) # This was not good for libusb-win32 with wrong arg intf, new correct value 0 would be OK
def shutdown(self):
self.__devhandle.releaseInterface()

View File

@@ -44,6 +44,7 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
rsa_raw_pubkey = rsa.get_raw_pubkey(rsa_key)
gnuk = get_gnuk_device()
gnuk.cmd_select_openpgp()
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8'))
gnuk.cmd_write_binary(1+keyno, rsa_raw_pubkey, False)
@@ -68,8 +69,9 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
gnuk = None
#
reg = None
print("Waiting for device to appear:")
while reg == None:
print("Wait %d seconds..." % wait_e)
print(" Wait %d seconds..." % wait_e)
time.sleep(wait_e)
for dev in gnuk_devices_by_vidpid():
try:
@@ -83,9 +85,13 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
print("%08x:%08x" % mem_info)
print("Downloading the program")
reg.download(mem_info[0], data_upgrade)
print("Protecting device")
reg.protect()
print("Finish flashing")
reg.finish()
print("Resetting device")
reg.reset_device()
print("Update procedure finished")
return 0
from getpass import getpass
@@ -118,6 +124,9 @@ if __name__ == '__main__':
passwd = getpass("Admin password: ")
filename_regnual = sys.argv[1]
filename_upgrade = sys.argv[2]
if not filename_regnual.endswith('bin') or not filename_upgrade.endswith('bin'):
print("Both input files must be in binary format (*.bin)!")
exit(1)
f = open(filename_regnual,"rb")
data_regnual = f.read()
f.close()

View File

@@ -3,7 +3,7 @@
"""
usb_strings.py - a tool to dump USB string
Copyright (C) 2012, 2015 Free Software Initiative of Japan
Copyright (C) 2012, 2015, 2017 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -22,28 +22,14 @@ 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 gnuk_token import *
import usb, sys
USB_VENDOR_FSIJ=0x234b
USB_PRODUCT_GNUK=0x0000
def gnuk_devices_by_vidpid():
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
field = ['', 'Vendor', 'Product', 'Serial', 'Revision', 'Config', 'Sys', 'Board']
def main(n):
for dev in gnuk_devices_by_vidpid():
handle = dev.open()
print("Device: %s" % dev.filename)
try:
for i in range(1,n):
s = handle.getString(i, 512)