Compare commits
72 Commits
release/1.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32779b6f96 | ||
|
|
55c1015faa | ||
|
|
0932465f0b | ||
|
|
4417799a51 | ||
|
|
b424cecf1e | ||
|
|
7ef417ae36 | ||
|
|
d4469c24ec | ||
|
|
e4333c6580 | ||
|
|
d2261d53e3 | ||
|
|
27bd37781a | ||
|
|
bed43d4049 | ||
|
|
f7d857b527 | ||
|
|
350528e1f4 | ||
|
|
4de605ed63 | ||
|
|
ffa9bf1f94 | ||
|
|
34d0b34144 | ||
|
|
5795dc9877 | ||
|
|
c8b17a8759 | ||
|
|
38d70e277b | ||
|
|
b00bab8dbf | ||
|
|
3c91dce8b7 | ||
|
|
f1773c146b | ||
|
|
979992c046 | ||
|
|
50700e3887 | ||
|
|
b0ee8b4452 | ||
|
|
a73f8cf4fd | ||
|
|
c1cc75f5b0 | ||
|
|
47150b5c98 | ||
|
|
f46880d2a8 | ||
|
|
23bbc9c755 | ||
|
|
2b784cb3b9 | ||
|
|
452c15c908 | ||
|
|
dc568422b1 | ||
|
|
5edcf32bb7 | ||
|
|
2647797348 | ||
|
|
9697694e45 | ||
|
|
f5cbc71a54 | ||
|
|
5099bfee88 | ||
|
|
691e16c605 | ||
|
|
eabcec107e | ||
|
|
73c698c67e | ||
|
|
d035c53b9c | ||
|
|
a96a3eefe6 | ||
|
|
fd08a853fd | ||
|
|
f882acc1b4 | ||
|
|
907d8c7a8e | ||
|
|
d636bf314c | ||
|
|
0212328a6a | ||
|
|
eb90074e11 | ||
|
|
38d164360c | ||
|
|
ff190a8053 | ||
|
|
f86f97cdbe | ||
|
|
1e004bec78 | ||
|
|
d68bee21e5 | ||
|
|
2903e88986 | ||
|
|
25fed157e1 | ||
|
|
d5c5571423 | ||
|
|
51d4b754e6 | ||
|
|
48905155c5 | ||
|
|
772071d1ba | ||
|
|
1fa45e3273 | ||
|
|
1a5eb0ec3b | ||
|
|
106b042e75 | ||
|
|
eebd40d946 | ||
|
|
5e37c7722a | ||
|
|
b1a582e87c | ||
|
|
3f1ee534fe | ||
|
|
522ec3299e | ||
|
|
34e2099b23 | ||
|
|
baf09ecac9 | ||
|
|
db23a1d051 | ||
|
|
3f8c4d1f17 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -12,3 +12,5 @@ regnual/regnual.bin
|
||||
regnual/regnual.hex
|
||||
regnual/regnual.elf
|
||||
doc/_build
|
||||
tests/.cache
|
||||
tests/__pycache__
|
||||
|
||||
354
ChangeLog
354
ChangeLog
@@ -1,3 +1,357 @@
|
||||
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.
|
||||
* src/usb-ccid.c (ccid_thread): Fix timeout.
|
||||
(icc_handle_timeout, icc_send_status): Tweak.
|
||||
|
||||
2016-05-19 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb_ctrl.c (usb_cb_ctrl_write_finish): Set bDeviceState.
|
||||
|
||||
* src/usb-ccid.c: Rename from usb-icc.c.
|
||||
(ccid_thread): Handle reGNUal upgrade.
|
||||
|
||||
* src/Makefile.in (CSRC): Follow the change.
|
||||
|
||||
* chopstx: Update to 0.11.
|
||||
|
||||
2016-05-18 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/gnuk.ld.in: Tweak thread size.
|
||||
* src/main.c (main): Use chopstx_setpriority.
|
||||
* src/usb-icc.c (ccid_init): Use new eventflag API.
|
||||
|
||||
* regnual/regnual.c (nvic_enable_intr): New.
|
||||
(main): Call nvic_enable_intr.
|
||||
|
||||
* chopstx: Update.
|
||||
|
||||
2016-05-16 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* regnual/regnual.c (usb_cb_rx_ready, usb_cb_tx_done)
|
||||
(usb_cb_device_reset): Follow the change of USB API.
|
||||
|
||||
* chopstx: Update.
|
||||
* src/sys.c: Update from Chopstx.
|
||||
|
||||
2016-05-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/neug.c (rng): Call chopstx_claim_irq before adc_start.
|
||||
Remove call of chopstx_release_irq.
|
||||
|
||||
2016-05-12 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx: Update.
|
||||
* src/sys.c: Update from Chopstx.
|
||||
* src/usb_lld.h: Likewise.
|
||||
* src/usb_stm32f103.c: Likewise.
|
||||
|
||||
* src/usb_ctrl.c (usb_intr): Follow the change of USB API.
|
||||
(usb_cb_rx_ready, usb_cb_tx_done): Likewise.
|
||||
|
||||
* src/adc.h: Remove unused declarations.
|
||||
|
||||
2016-03-08 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_token.py (gnuk_token.__init__, regnual.__init__):
|
||||
Don't call setConfiguration method.
|
||||
|
||||
* src/usb_lld.h (usb_cb_ctrl_write_finish): Change the API of
|
||||
callback, which possibly needs INDEX, VALUE, and LEN parameters.
|
||||
(usb_lld_set_data_to_recv): Fix the type of P.
|
||||
(USB_DEVICE_DESCRIPTOR_TYPE, USB_CONFIGURATION_DESCRIPTOR_TYPE)
|
||||
(USB_STRING_DESCRIPTOR_TYPE, USB_INTERFACE_DESCRIPTOR_TYPE)
|
||||
(USB_ENDPOINT_DESCRIPTOR_TYPE): Remove, as we have the enumeration
|
||||
values for same things.
|
||||
|
||||
* src/usb_stm32f103.c (handle_in0): Follow the change.
|
||||
* src/usb_ctrl.c (usb_cb_ctrl_write_finish): Likewise.
|
||||
|
||||
* src/usb_desc.c (usb_cb_get_descriptor): Use HID_INTERFACE.
|
||||
(device_desc, config_desc, string_descriptors)
|
||||
(usb_cb_get_descriptor): Use the enumeration types.
|
||||
* src/configure: Use the enumeration types.
|
||||
|
||||
* regnual/regnual.c: Follow the change of usb_lld.h.
|
||||
|
||||
2016-02-09 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_verify): Support VERIFY reset, which is
|
||||
described in the specification V2.2 and V3.1.
|
||||
|
||||
* polarssl/library/bignum.c (mpi_exp_mod): Fix to our local
|
||||
change. Thanks to Aidan Thornton for the failure test case.
|
||||
|
||||
Fix of mpi_div_mpi from upstream.
|
||||
* polarssl/library/bignum.c (int_clz, int_div_int): New.
|
||||
(mpi_div_mpi): Use int_div_int.
|
||||
|
||||
2016-02-09 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (s2k): Include the unique ID of MCU into the
|
||||
computation of S2K function.
|
||||
|
||||
2016-02-08 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/modp256r1.c (modp256r1_add, modp256r1_sub): Keep the result
|
||||
less than P256R1.
|
||||
(modp256r1_reduce): Fix wrong calculation.
|
||||
* src/modp256k1.c (modp256k1_add, modp256k1_sub): Likewise.
|
||||
Thanks to Aidan Thornton.
|
||||
|
||||
2016-02-05 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/configure: Add submodule check suggested by Elliott
|
||||
Mitchell.
|
||||
|
||||
2015-11-30 perillamint <perillamint@gentoo.moe>
|
||||
|
||||
* src/openpgp.c (card_thread): Fix offset of bConfirmPIN.
|
||||
|
||||
2015-09-18 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.1.9.
|
||||
|
||||
58
NEWS
58
NEWS
@@ -1,5 +1,63 @@
|
||||
Gnuk NEWS - User visible changes
|
||||
|
||||
* 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
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 0.11.
|
||||
|
||||
** Support authentication status reset by VERIFY command.
|
||||
This feature is described in the OpenPGPcard specification V2.2 and
|
||||
V3.1, which allow user to reset authentication status.
|
||||
|
||||
** S2K algorithm tweak to defeat "copycat" service of MCU.
|
||||
Even if the existence of some services copying MCU, your private key
|
||||
will not be controled by others, in some cases.
|
||||
|
||||
** Bug fix for secp256k1 and NIST P-256.
|
||||
Bugs in basic computation were fixed.
|
||||
|
||||
** Bug fix for bignum routines.
|
||||
Bignum routine update from upstream (failure doesn't occur for our RSA
|
||||
computation, though). Another fix for mpi_exp_mod.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.1.9
|
||||
|
||||
Released 2015-09-18, by NIIBE Yutaka
|
||||
|
||||
155
README
155
README
@@ -1,28 +1,27 @@
|
||||
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
|
||||
|
||||
Version 1.1.9
|
||||
2015-09-18
|
||||
Version 1.2.3
|
||||
2017-02-02
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
Warning
|
||||
=======
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
This is another experimental release of Gnuk, version 1.1.9, which has
|
||||
This is the release of Gnuk, version 1.2.3, 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 ECDSA (with NIST P256 and secp256k1), EdDSA, and ECDH
|
||||
(with NIST P256, secp256k1, and Curve25519), but this ECC feature is
|
||||
pretty much experimental, and it requires modern GnuPG with
|
||||
development version of libgcrypt.
|
||||
that the instruction of importing keys won't cause any confusion.
|
||||
|
||||
It also supports RSA-4096 experimentally, but users should know that
|
||||
it takes more than 8 second to sign/decrypt.
|
||||
It has supports of EdDSA, ECDSA (with NIST P256 and secp256k1), and
|
||||
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.
|
||||
|
||||
You will not able to keep using Curve25519 keys, as the key format is
|
||||
subject to change.
|
||||
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,
|
||||
because the device doesn't have enough memory.
|
||||
|
||||
|
||||
What's Gnuk?
|
||||
@@ -48,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
|
||||
@@ -63,11 +62,12 @@ A0: Good points of Gnuk are:
|
||||
|
||||
Q1: What kind of key algorithm is supported?
|
||||
A1: Gnuk version 1.0 only supports RSA-2048.
|
||||
Development version of Gnuk (1.1.x) supports 256-bit ECDSA and EdDSA,
|
||||
as well as RSA 4096-bit. 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.
|
||||
It takes more than 8 secondd for RSA-4096.
|
||||
|
||||
Q3: What's your recommendation for target board?
|
||||
A3: Orthodox choice is Olimex STM32-H103.
|
||||
@@ -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.x 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.
|
||||
|
||||
@@ -139,22 +139,14 @@ Ac: That's because gnome-keyring-daemon interferes GnuPG. Please
|
||||
Qd: Do you know a good SWD debugger to connect FST-01 or something?
|
||||
Ad: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
|
||||
writer program. STM32 Nucleo F103 comes with the valiant of
|
||||
ST-Link/V2.
|
||||
ST-Link/V2. However, the firmware of ST-Link/V2 is proprietary.
|
||||
Now, I develop BBG-SWD, SWD debugger by BeagleBone Green.
|
||||
|
||||
|
||||
Release notes
|
||||
=============
|
||||
Tested features
|
||||
===============
|
||||
|
||||
This is ninth experimental release in version 1.1 series of Gnuk.
|
||||
|
||||
While it is daily use by its developer, some newly introduced features
|
||||
(including ECDSA/EdDSA/ECDH, key generation and firmware upgrade)
|
||||
should be considered experimental. ECDSA/EdDSA/ECDH is really
|
||||
experimental. Further, ECDH on Curve25519 is much experimental. You
|
||||
won't be able to keep using the key, since the key format of GnuPG is
|
||||
not defined and it's subject to change.
|
||||
|
||||
Tested features are:
|
||||
Gnuk is tested by test suite. Please see the test directory.
|
||||
|
||||
* Personalization of the card
|
||||
* Changing Login name, URL, Name, Sex, Language, etc.
|
||||
@@ -171,10 +163,10 @@ Tested features are:
|
||||
* Modify with pin pad
|
||||
* Card holder certificate (read)
|
||||
* Removal of keys
|
||||
* Key generation on device side
|
||||
* Key generation on device side for RSA-2048
|
||||
* Overriding key import
|
||||
|
||||
Original features of Gnuk, tested lightly:
|
||||
Original features of Gnuk, tested manually lightly:
|
||||
|
||||
* OpenPGP card serial number setup
|
||||
* Card holder certificate (write by UPDATE BINARY)
|
||||
@@ -182,12 +174,12 @@ Original features of Gnuk, tested lightly:
|
||||
|
||||
It is known not-working well:
|
||||
|
||||
* It is known that the combination of libccid 1.4.1 (or newer)
|
||||
with libusb 1.0.8 (or older) has a minor problem. It is
|
||||
rare but it is possible for USB communication to be failed,
|
||||
because of a bug in libusb implementation. Use libusbx
|
||||
1.0.9 or newer, or don't use PC/SC, but use internal CCID
|
||||
driver of GnuPG.
|
||||
* It is known that the specific combination of libccid 1.4.1
|
||||
(or newer) with libusb 1.0.8 (or older) had a minor problem.
|
||||
It is rare but it is possible for USB communication to be
|
||||
failed, because of a bug in libusb implementation. Use
|
||||
libusbx 1.0.9 or newer, or don't use PC/SC, but use internal
|
||||
CCID driver of GnuPG.
|
||||
|
||||
|
||||
Targets
|
||||
@@ -256,7 +248,7 @@ External source code
|
||||
|
||||
Gnuk is distributed with external source code.
|
||||
|
||||
* chopstx/ -- Chopstx 0.10
|
||||
* chopstx/ -- Chopstx 1.3
|
||||
|
||||
We use Chopstx as the kernel for Gnuk.
|
||||
|
||||
@@ -369,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.25-5+5+b1
|
||||
gcc-arm-none-eabi 15:4.9.3+svn227297-1
|
||||
gdb-arm-none-eabi 7.7.1+dfsg-5+8
|
||||
libnewlib-arm-none-eabi 2.2.0+git20150830.5a3d536-1
|
||||
binutils-arm-none-eabi 2.27-9+9
|
||||
gcc-arm-none-eabi 15:5.4.1+svn241155-1
|
||||
gdb-arm-none-eabi 7.11.1-2+9+b1
|
||||
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.
|
||||
@@ -403,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
|
||||
@@ -422,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"
|
||||
|
||||
|
||||
|
||||
@@ -443,27 +432,33 @@ 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.
|
||||
|
||||
|
||||
How to configure
|
||||
================
|
||||
(Optional) Configure serial number and X.509 certificate
|
||||
========================================================
|
||||
|
||||
You need python and pyscard (python-pyscard package in Debian) or
|
||||
PyUSB 0.4.3 (python-usb package in Debian).
|
||||
This is completely optional.
|
||||
|
||||
For this procedure, you need python and pyscard (python-pyscard
|
||||
package in Debian) or PyUSB 0.4.3 (python-usb package in Debian).
|
||||
|
||||
(1) [pyscard] Stop scdaemon
|
||||
[PyUSB] Stop the pcsc daemon.
|
||||
@@ -557,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:
|
||||
|
||||
@@ -588,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
|
||||
@@ -605,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:
|
||||
|
||||
@@ -616,7 +615,7 @@ Your Contributions
|
||||
==================
|
||||
|
||||
FSIJ welcomes your contributions. Please assign your copyright
|
||||
to FSIJ (if possible).
|
||||
to FSIJ (if possible), as I do.
|
||||
|
||||
|
||||
Foot note
|
||||
|
||||
4
THANKS
4
THANKS
@@ -14,10 +14,12 @@ Andre Zepezauer andre.zepezauer@student.uni-halle.de
|
||||
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
|
||||
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
|
||||
@@ -27,9 +29,11 @@ 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
|
||||
Szczepan Zalega szczepan@nitrokey.com
|
||||
Vasily Evseenko
|
||||
Werner Koch wk@gnupg.org
|
||||
Yuji Imai ug@xcast.jp
|
||||
|
||||
2
chopstx
2
chopstx
Submodule chopstx updated: a30a069ed8...89eb54929e
@@ -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']
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
487
doc/generating-key.rst
Normal 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
|
||||
$
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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. ::
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
==========
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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::
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -223,6 +223,24 @@ size_t mpi_lsb( const mpi *X )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Count leading zero bits in a given integer
|
||||
*/
|
||||
static size_t int_clz( const t_uint x )
|
||||
{
|
||||
size_t j;
|
||||
t_uint mask = (t_uint) 1 << (biL - 1);
|
||||
|
||||
for( j = 0; j < biL; j++ )
|
||||
{
|
||||
if( x & mask ) break;
|
||||
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of most significant bits
|
||||
*/
|
||||
@@ -1102,6 +1120,100 @@ int mpi_mul_int( mpi *X, const mpi *A, t_sint b )
|
||||
return( mpi_mul_mpi( X, A, &_B ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Unsigned integer divide - 64bit dividend and 32bit divisor
|
||||
*/
|
||||
static t_uint int_div_int(t_uint u1, t_uint u0, t_uint d, t_uint *r)
|
||||
{
|
||||
#if defined(POLARSSL_HAVE_UDBL)
|
||||
t_udbl dividend, quotient;
|
||||
#else
|
||||
const t_uint radix = (t_uint) 1 << biH;
|
||||
const t_uint uint_halfword_mask = ( (t_uint) 1 << biH ) - 1;
|
||||
t_uint d0, d1, q0, q1, rAX, r0, quotient;
|
||||
t_uint u0_msw, u0_lsw;
|
||||
size_t s;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check for overflow
|
||||
*/
|
||||
if(( 0 == d ) || ( u1 >= d ))
|
||||
{
|
||||
if (r != NULL) *r = (~0);
|
||||
|
||||
return (~0);
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_HAVE_UDBL)
|
||||
dividend = (t_udbl) u1 << biL;
|
||||
dividend |= (t_udbl) u0;
|
||||
quotient = dividend / d;
|
||||
if( quotient > ( (t_udbl) 1 << biL ) - 1 )
|
||||
quotient = ( (t_udbl) 1 << biL ) - 1;
|
||||
|
||||
if( r != NULL )
|
||||
*r = (t_uint)( dividend - (quotient * d ) );
|
||||
|
||||
return (t_uint) quotient;
|
||||
#else
|
||||
|
||||
/*
|
||||
* Algorithm D, Section 4.3.1 - The Art of Computer Programming
|
||||
* Vol. 2 - Seminumerical Algorithms, Knuth
|
||||
*/
|
||||
|
||||
/*
|
||||
* Normalize the divisor, d, and dividend, u0, u1
|
||||
*/
|
||||
s = int_clz( d );
|
||||
d = d << s;
|
||||
|
||||
u1 = u1 << s;
|
||||
u1 |= ( u0 >> ( biL - s ) ) & ( -(t_sint)s >> ( biL - 1 ) );
|
||||
u0 = u0 << s;
|
||||
|
||||
d1 = d >> biH;
|
||||
d0 = d & uint_halfword_mask;
|
||||
|
||||
u0_msw = u0 >> biH;
|
||||
u0_lsw = u0 & uint_halfword_mask;
|
||||
|
||||
/*
|
||||
* Find the first quotient and remainder
|
||||
*/
|
||||
q1 = u1 / d1;
|
||||
r0 = u1 - d1 * q1;
|
||||
|
||||
while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
|
||||
{
|
||||
q1 -= 1;
|
||||
r0 += d1;
|
||||
|
||||
if ( r0 >= radix ) break;
|
||||
}
|
||||
|
||||
rAX = (u1 * radix) + (u0_msw - q1 * d);
|
||||
q0 = rAX / d1;
|
||||
r0 = rAX - q0 * d1;
|
||||
|
||||
while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
|
||||
{
|
||||
q0 -= 1;
|
||||
r0 += d1;
|
||||
|
||||
if ( r0 >= radix ) break;
|
||||
}
|
||||
|
||||
if (r != NULL)
|
||||
*r = (rAX * radix + u0_lsw - q0 * d) >> s;
|
||||
|
||||
quotient = q1 * radix + q0;
|
||||
|
||||
return quotient;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Division by mpi: A = Q * B + R (HAC 14.20)
|
||||
*/
|
||||
@@ -1159,57 +1271,7 @@ int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B )
|
||||
Z.p[i - t - 1] = ~0;
|
||||
else
|
||||
{
|
||||
#if defined(POLARSSL_HAVE_UDBL)
|
||||
t_udbl r;
|
||||
|
||||
r = (t_udbl) X.p[i] << biL;
|
||||
r |= (t_udbl) X.p[i - 1];
|
||||
r /= Y.p[t];
|
||||
if( r > ((t_udbl) 1 << biL) - 1)
|
||||
r = ((t_udbl) 1 << biL) - 1;
|
||||
|
||||
Z.p[i - t - 1] = (t_uint) r;
|
||||
#else
|
||||
/*
|
||||
* __udiv_qrnnd_c, from gmp/longlong.h
|
||||
*/
|
||||
t_uint q0, q1, r0, r1;
|
||||
t_uint d0, d1, d, m;
|
||||
|
||||
d = Y.p[t];
|
||||
d0 = ( d << biH ) >> biH;
|
||||
d1 = ( d >> biH );
|
||||
|
||||
q1 = X.p[i] / d1;
|
||||
r1 = X.p[i] - d1 * q1;
|
||||
r1 <<= biH;
|
||||
r1 |= ( X.p[i - 1] >> biH );
|
||||
|
||||
m = q1 * d0;
|
||||
if( r1 < m )
|
||||
{
|
||||
q1--, r1 += d;
|
||||
while( r1 >= d && r1 < m )
|
||||
q1--, r1 += d;
|
||||
}
|
||||
r1 -= m;
|
||||
|
||||
q0 = r1 / d1;
|
||||
r0 = r1 - d1 * q0;
|
||||
r0 <<= biH;
|
||||
r0 |= ( X.p[i - 1] << biH ) >> biH;
|
||||
|
||||
m = q0 * d0;
|
||||
if( r0 < m )
|
||||
{
|
||||
q0--, r0 += d;
|
||||
while( r0 >= d && r0 < m )
|
||||
q0--, r0 += d;
|
||||
}
|
||||
r0 -= m;
|
||||
|
||||
Z.p[i - t - 1] = ( q1 << biH ) | q0;
|
||||
#endif
|
||||
Z.p[i - t - 1] = int_div_int( X.p[i], X.p[i-1], Y.p[t], NULL);
|
||||
}
|
||||
|
||||
Z.p[i - t - 1]++;
|
||||
@@ -1584,6 +1646,7 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
|
||||
memset (d, 0, 2 * N->n * ciL); /* Set D zero. */
|
||||
mpi_sub_hlp( N->n, N->p, d + N->n);
|
||||
MPI_CHK( mpi_mod_mpi( &RR, &T, N ) );
|
||||
MPI_CHK( mpi_grow( &RR, N->n ) );
|
||||
|
||||
if( _RR != NULL )
|
||||
memcpy( _RR, &RR, sizeof( mpi ) );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
PROJECT = regnual
|
||||
|
||||
OBJS = regnual.o usb_stm32f103.o sys.o
|
||||
OBJS = regnual.o usb-stm32f103.o reset.o
|
||||
LDSCRIPT= regnual.ld
|
||||
|
||||
###################################
|
||||
@@ -23,7 +23,7 @@ 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 +32,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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* regnual.c -- Firmware installation for STM32F103 Flash ROM
|
||||
*
|
||||
* Copyright (C) 2012, 2013, 2015
|
||||
* Copyright (C) 2012, 2013, 2015, 2016
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -51,7 +51,7 @@ static uint32_t flash_end;
|
||||
/* USB Standard Device Descriptor */
|
||||
static const uint8_t regnual_device_desc[] = {
|
||||
18, /* bLength */
|
||||
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
DEVICE_DESCRIPTOR, /* bDescriptorType */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0xFF, /* bDeviceClass: VENDOR */
|
||||
0x00, /* bDeviceSubClass */
|
||||
@@ -64,24 +64,26 @@ static const uint8_t regnual_device_desc[] = {
|
||||
0x01 /* bNumConfigurations */
|
||||
};
|
||||
|
||||
#if defined(USB_SELF_POWERED)
|
||||
#define REGNUAL_FEATURE_INIT 0xC0 /* self powered */
|
||||
#else
|
||||
#define REGNUAL_FEATURE_INIT 0x80 /* bus powered */
|
||||
#endif
|
||||
|
||||
static const uint8_t regnual_config_desc[] = {
|
||||
9,
|
||||
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
|
||||
18, 0, /* wTotalLength: no of returned bytes */
|
||||
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
|
||||
18, 0, /* wTotalLength: no of returned bytes */
|
||||
1, /* bNumInterfaces: single vendor interface */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: None */
|
||||
#if defined(USB_SELF_POWERED)
|
||||
0xC0, /* bmAttributes: self powered */
|
||||
#else
|
||||
0x80, /* bmAttributes: bus powered */
|
||||
#endif
|
||||
50, /* MaxPower 100 mA */
|
||||
REGNUAL_FEATURE_INIT, /* bmAttributes: bus powered */
|
||||
50, /* MaxPower 100 mA */
|
||||
|
||||
/* Interface Descriptor */
|
||||
9,
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
0, /* bInterfaceNumber: Index of this interface */
|
||||
INTERFACE_DESCRIPTOR, /* bDescriptorType: Interface */
|
||||
0, /* bInterfaceNumber: Index of this interface */
|
||||
0, /* Alternate setting for this interface */
|
||||
0, /* bNumEndpoints: None */
|
||||
0xFF,
|
||||
@@ -92,7 +94,7 @@ static const uint8_t regnual_config_desc[] = {
|
||||
|
||||
static const uint8_t regnual_string_lang_id[] = {
|
||||
4, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE,
|
||||
STRING_DESCRIPTOR,
|
||||
0x09, 0x04 /* LangID = 0x0409: US-English */
|
||||
};
|
||||
|
||||
@@ -100,23 +102,17 @@ static const uint8_t regnual_string_lang_id[] = {
|
||||
|
||||
static const uint8_t regnual_string_serial[] = {
|
||||
8*2+2,
|
||||
USB_STRING_DESCRIPTOR_TYPE,
|
||||
STRING_DESCRIPTOR,
|
||||
/* FSIJ-0.0 */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
|
||||
'0', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
usb_cb_device_reset (void)
|
||||
static void
|
||||
usb_device_reset (struct usb_dev *dev)
|
||||
{
|
||||
/* Set DEVICE as not configured */
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (regnual_config_desc[7]);
|
||||
|
||||
usb_lld_reset ();
|
||||
usb_lld_reset (dev, REGNUAL_FEATURE_INIT);
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
|
||||
@@ -173,94 +169,101 @@ static uint32_t calc_crc32 (void)
|
||||
}
|
||||
|
||||
|
||||
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value)
|
||||
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 && 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 + value * 0x100);
|
||||
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 && value == 0)
|
||||
else if (arg->request == USB_REGNUAL_PROTECT && arg->value == 0)
|
||||
result = flash_protect ();
|
||||
else if (req_no == USB_REGNUAL_FINISH && 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 control_info *detail)
|
||||
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), detail);
|
||||
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), detail);
|
||||
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 (detail->value != 0 || detail->index + detail->len > 256)
|
||||
return USB_UNSUPPORT;
|
||||
if (arg->value != 0 || arg->index + arg->len > 256)
|
||||
return -1;
|
||||
|
||||
if (detail->index + detail->len < 256)
|
||||
memset ((uint8_t *)mem + detail->index + detail->len, 0xff,
|
||||
256 - (detail->index + detail->len));
|
||||
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 + detail->index, detail->len);
|
||||
return USB_SUCCESS;
|
||||
return usb_lld_ctrl_recv (dev, mem + arg->index, arg->len);
|
||||
}
|
||||
else if (req_no == USB_REGNUAL_FLASH && detail->len == 0
|
||||
&& detail->index == 0)
|
||||
else if (arg->request == USB_REGNUAL_FLASH && arg->len == 0
|
||||
&& arg->index == 0)
|
||||
{
|
||||
uint32_t dst_addr = (0x08000000 + detail->value * 0x100);
|
||||
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 && detail->len == 0
|
||||
&& detail->value == 0 && detail->index == 0)
|
||||
return USB_SUCCESS;
|
||||
else if (req_no == USB_REGNUAL_FINISH && detail->len == 0
|
||||
&& detail->value == 0 && detail->index == 0)
|
||||
return USB_SUCCESS;
|
||||
else if (arg->request == USB_REGNUAL_PROTECT && arg->len == 0
|
||||
&& arg->value == 0 && arg->index == 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_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 control_info *detail)
|
||||
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), detail);
|
||||
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), detail);
|
||||
return usb_lld_ctrl_send (dev, regnual_config_desc,
|
||||
sizeof (regnual_config_desc));
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
const uint8_t *str;
|
||||
@@ -285,35 +288,38 @@ 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, detail);
|
||||
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;
|
||||
}
|
||||
|
||||
int usb_cb_interface (uint8_t cmd, struct control_info *detail)
|
||||
{
|
||||
(void)cmd; (void)detail;
|
||||
return USB_UNSUPPORT;
|
||||
/* Do nothing when current_conf == value */
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -327,6 +333,31 @@ static void wait (int count)
|
||||
|
||||
#define WAIT 2400000
|
||||
|
||||
/* NVIC: Nested Vectored Interrupt Controller. */
|
||||
struct NVIC {
|
||||
volatile uint32_t ISER[8];
|
||||
uint32_t unused1[24];
|
||||
volatile uint32_t ICER[8];
|
||||
uint32_t unused2[24];
|
||||
volatile uint32_t ISPR[8];
|
||||
uint32_t unused3[24];
|
||||
volatile uint32_t ICPR[8];
|
||||
uint32_t unused4[24];
|
||||
volatile uint32_t IABR[8];
|
||||
uint32_t unused5[56];
|
||||
volatile uint32_t IPR[60];
|
||||
};
|
||||
static struct NVIC *const NVIC = (struct NVIC *const)0xE000E100;
|
||||
#define NVIC_ISER(n) (NVIC->ISER[n >> 5])
|
||||
|
||||
static void nvic_enable_intr (uint8_t irq_num)
|
||||
{
|
||||
NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
#define USB_LP_CAN1_RX0_IRQn 20
|
||||
static struct usb_dev dev;
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -335,7 +366,14 @@ main (int argc, char *argv[])
|
||||
set_led (0);
|
||||
|
||||
flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
|
||||
usb_lld_init (regnual_config_desc[7]);
|
||||
|
||||
/*
|
||||
* 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 (&dev, REGNUAL_FEATURE_INIT);
|
||||
nvic_enable_intr (USB_LP_CAN1_RX0_IRQn);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -345,3 +383,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,14 @@ CHOPSTX = ../chopstx
|
||||
# Define linker script file here
|
||||
LDSCRIPT= gnuk.ld
|
||||
|
||||
CSRC = main.c usb_stm32f103.c adc_stm32f103.c \
|
||||
usb_desc.c usb_ctrl.c \
|
||||
CSRC = main.c usb_desc.c usb_ctrl.c \
|
||||
call-rsa.c \
|
||||
usb-icc.c openpgp.c ac.c openpgp-do.c flash.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 =
|
||||
|
||||
@@ -46,6 +45,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
|
||||
@@ -55,7 +59,7 @@ OBJCOPY = $(CROSS)objcopy
|
||||
MCU = cortex-m3
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
# DEFS: Add
|
||||
DEFS = @HAVE_SYS_H@
|
||||
DEFS = @USE_SYS3@
|
||||
OPT = -O3 -Os -g
|
||||
LIBS =
|
||||
|
||||
|
||||
16
src/adc.h
16
src/adc.h
@@ -1,16 +0,0 @@
|
||||
extern chopstx_mutex_t adc_mtx;
|
||||
extern chopstx_cond_t adc_cond;
|
||||
extern int adc_waiting;
|
||||
extern int adc_data_available;
|
||||
|
||||
void adc_init (void);
|
||||
void adc_start (void);
|
||||
void adc_stop (void);
|
||||
|
||||
#define ADC_SAMPLE_MODE 0
|
||||
#define ADC_CRC32_MODE 1
|
||||
|
||||
extern uint32_t adc_buf[64];
|
||||
|
||||
void adc_start_conversion (int offset, int count);
|
||||
int adc_wait_completion (chopstx_intr_t *intr);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
@CERTDO_DEFINE@
|
||||
@HID_CARD_CHANGE_DEFINE@
|
||||
@SERIALNO_STR_LEN_DEFINE@
|
||||
@LIFE_CYCLE_MANAGEMENT_DEFINE@
|
||||
|
||||
78
src/configure
vendored
78
src/configure
vendored
@@ -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
|
||||
# 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.
|
||||
@@ -23,6 +23,15 @@ nl=$'\n'
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#
|
||||
# Submodule check
|
||||
#
|
||||
if ! test -f ../chopstx/rules.mk; then
|
||||
echo "Submodule 'chopstx' not found" >&2
|
||||
echo "You might need: git submodule update --init" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Default settings
|
||||
help=no
|
||||
vidpid=none
|
||||
@@ -34,9 +43,10 @@ sys1_compat=yes
|
||||
pinpad=no
|
||||
certdo=no
|
||||
hid_card_change=no
|
||||
factory_reset=no
|
||||
|
||||
# Revision number
|
||||
if test -d ../.git; then
|
||||
if test -e ../.git; then
|
||||
REVISION=`git describe --dirty="-modified"`
|
||||
else
|
||||
REVISION=`cat ../VERSION`
|
||||
@@ -78,6 +88,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)
|
||||
@@ -102,15 +116,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
|
||||
@@ -121,13 +137,15 @@ 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
|
||||
fi
|
||||
|
||||
if test "$vidpid" = "none"; then
|
||||
echo "Please specify Vendor ID and Product ID by --vidpid option."
|
||||
echo "Please specify Vendor ID and Product ID by --vidpid option." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -180,8 +198,9 @@ fi
|
||||
|
||||
# --with-dfu option
|
||||
if test "$with_dfu" = "yes"; then
|
||||
if test "$target" = "FST_01" -o "$target" = "FST_01_00"; then
|
||||
echo "FST-01 doesn't have DFU loader, you should not use --with-dfu."
|
||||
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"
|
||||
@@ -237,6 +256,15 @@ 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%^[^/]*/%%'`-"
|
||||
|
||||
@@ -247,7 +275,7 @@ if test "$sys1_compat" = "yes"; then
|
||||
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo"
|
||||
else
|
||||
if test "$with_dfu" = "yes"; then
|
||||
echo "Common binary can't support DFU loader, don't use --with-dfu."
|
||||
echo "Common binary can't support DFU loader, don't use --with-dfu." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Override settings for common binary. Safer side.
|
||||
@@ -267,23 +295,23 @@ output_vendor_product_serial_strings () {
|
||||
|
||||
echo "static const uint8_t ${prefix}string_vendor[] = {"
|
||||
echo " ${#VENDOR}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
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 '};'
|
||||
echo
|
||||
echo "static const uint8_t ${prefix}string_product[] = {"
|
||||
echo " ${#PRODUCT}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
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 '};'
|
||||
|
||||
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 " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
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 " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
|
||||
@@ -293,14 +321,14 @@ output_vendor_product_serial_strings () {
|
||||
echo '#ifdef USB_STRINGS_FOR_GNUK'
|
||||
echo "static const uint8_t ${prefix}revision_detail[] = {"
|
||||
echo " ${#REVISION}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
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 '};'
|
||||
echo
|
||||
echo "static const uint8_t ${prefix}config_options[] = {"
|
||||
echo " ${#CONFIG}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
|
||||
echo " /* configure options: \"$CONFIG\" */"
|
||||
echo $CONFIG | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
|
||||
echo '};'
|
||||
@@ -317,23 +345,24 @@ if !(IFS=" "
|
||||
fi
|
||||
done; exit 1) < ../GNUK_USB_DEVICE_ID
|
||||
then
|
||||
echo "Please specify valid Vendor ID and Product ID."
|
||||
echo "Check ../GNUK_USB_DEVICE_ID."
|
||||
echo "Please specify valid Vendor ID and Product ID." >&2
|
||||
echo "Check ../GNUK_USB_DEVICE_ID." >&2
|
||||
exit 1
|
||||
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%" \
|
||||
sed -e "s%@USE_SYS3@%$use_sys3%" \
|
||||
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
|
||||
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
|
||||
-e "s%@HEXOUTPUT_MAKE_OPTION@%$HEXOUTPUT_MAKE_OPTION%" \
|
||||
@@ -363,6 +392,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
45
src/flash.c
45
src/flash.c
@@ -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
|
||||
* 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 */
|
||||
@@ -114,22 +114,51 @@ 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. */
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
flash_activate (void)
|
||||
{
|
||||
flash_program_halfword ((uint32_t)&_data_pool, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
flash_init_keys (void)
|
||||
{
|
||||
@@ -209,8 +238,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;
|
||||
}
|
||||
|
||||
|
||||
48
src/gnuk.h
48
src/gnuk.h
@@ -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_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);
|
||||
@@ -137,6 +140,8 @@ 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_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
|
||||
@@ -421,11 +427,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_USB_RESET 64
|
||||
#define LED_GNUK_EXEC 128
|
||||
#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)
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
*/
|
||||
__main_stack_size__ = 0x0080; /* Exception handlers */
|
||||
__process0_stack_size__ = 0x0100; /* main */
|
||||
__process1_stack_size__ = 0x0120; /* ccid */
|
||||
__process2_stack_size__ = 0x01a0; /* rng */
|
||||
__process1_stack_size__ = 0x01a0; /* ccid */
|
||||
__process2_stack_size__ = 0x0180; /* rng */
|
||||
__process3_stack_size__ = 0x1640; /* gpg */
|
||||
__process4_stack_size__ = 0x0120; /* intr: usb */
|
||||
__process4_stack_size__ = 0; /* --- */
|
||||
__process5_stack_size__ = @MSC_SIZE@; /* msc */
|
||||
__process6_stack_size__ = @TIM_SIZE@; /* intr: timer */
|
||||
__process7_stack_size__ = @EXT_SIZE@; /* intr: ext */
|
||||
@@ -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)
|
||||
|
||||
220
src/main.c
220
src/main.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* main.c - main routine of Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -35,87 +35,12 @@
|
||||
#include "usb_lld.h"
|
||||
#include "usb-cdc.h"
|
||||
#include "random.h"
|
||||
#include "stm32f103.h"
|
||||
#include "mcu/stm32f103.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
struct stdout stdout;
|
||||
|
||||
static void
|
||||
stdout_init (void)
|
||||
{
|
||||
chopstx_mutex_init (&stdout.m);
|
||||
chopstx_mutex_init (&stdout.m_dev);
|
||||
chopstx_cond_init (&stdout.cond_dev);
|
||||
stdout.connected = 0;
|
||||
}
|
||||
|
||||
void
|
||||
_write (const char *s, int len)
|
||||
{
|
||||
int packet_len;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
chopstx_mutex_lock (&stdout.m);
|
||||
|
||||
chopstx_mutex_lock (&stdout.m_dev);
|
||||
if (!stdout.connected)
|
||||
chopstx_cond_wait (&stdout.cond_dev, &stdout.m_dev);
|
||||
chopstx_mutex_unlock (&stdout.m_dev);
|
||||
|
||||
do
|
||||
{
|
||||
packet_len =
|
||||
(len < VIRTUAL_COM_PORT_DATA_SIZE) ? len : VIRTUAL_COM_PORT_DATA_SIZE;
|
||||
|
||||
chopstx_mutex_lock (&stdout.m_dev);
|
||||
usb_lld_write (ENDP3, s, packet_len);
|
||||
chopstx_cond_wait (&stdout.cond_dev, &stdout.m_dev);
|
||||
chopstx_mutex_unlock (&stdout.m_dev);
|
||||
|
||||
s += packet_len;
|
||||
len -= packet_len;
|
||||
}
|
||||
/* Send a Zero-Length-Packet if the last packet is full size. */
|
||||
while (len != 0 || packet_len == VIRTUAL_COM_PORT_DATA_SIZE);
|
||||
|
||||
chopstx_mutex_unlock (&stdout.m);
|
||||
}
|
||||
|
||||
void
|
||||
EP3_IN_Callback (void)
|
||||
{
|
||||
chopstx_mutex_lock (&stdout.m_dev);
|
||||
chopstx_cond_signal (&stdout.cond_dev);
|
||||
chopstx_mutex_unlock (&stdout.m_dev);
|
||||
}
|
||||
|
||||
void
|
||||
EP5_OUT_Callback (void)
|
||||
{
|
||||
chopstx_mutex_lock (&stdout.m_dev);
|
||||
usb_lld_rx_enable (ENDP5);
|
||||
chopstx_mutex_unlock (&stdout.m_dev);
|
||||
}
|
||||
#else
|
||||
void
|
||||
_write (const char *s, int size)
|
||||
{
|
||||
(void)s;
|
||||
(void)size;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void *USBthread (void *arg);
|
||||
|
||||
/*
|
||||
* main thread does 1-bit LED display output
|
||||
*/
|
||||
#define MAIN_TIMEOUT_INTERVAL (5000*1000)
|
||||
|
||||
#define LED_TIMEOUT_INTERVAL (75*1000)
|
||||
#define LED_TIMEOUT_ZERO (25*1000)
|
||||
#define LED_TIMEOUT_ONE (100*1000)
|
||||
@@ -195,65 +120,50 @@ static void display_fatal_code (void)
|
||||
|
||||
static uint8_t led_inverted;
|
||||
|
||||
static eventmask_t emit_led (int on_time, int off_time)
|
||||
static void emit_led (int on_time, int off_time)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
set_led (!led_inverted);
|
||||
m = eventflag_wait_timeout (&led_event, on_time);
|
||||
chopstx_usec_wait (on_time);
|
||||
set_led (led_inverted);
|
||||
if (m) return m;
|
||||
if ((m = eventflag_wait_timeout (&led_event, off_time)))
|
||||
return m;
|
||||
return 0;
|
||||
chopstx_usec_wait (off_time);
|
||||
}
|
||||
|
||||
static eventmask_t display_status_code (void)
|
||||
static void display_status_code (void)
|
||||
{
|
||||
eventmask_t m;
|
||||
enum icc_state icc_state = *icc_state_p;
|
||||
enum ccid_state ccid_state = *ccid_state_p;
|
||||
|
||||
if (icc_state == ICC_STATE_START)
|
||||
return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
|
||||
if (ccid_state == CCID_STATE_START)
|
||||
emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
|
||||
else
|
||||
/* OpenPGP card thread running */
|
||||
/* OpenPGP card thread is running */
|
||||
{
|
||||
if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_INTERVAL);
|
||||
emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_INTERVAL);
|
||||
emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_INTERVAL);
|
||||
|
||||
if (icc_state == ICC_STATE_WAIT)
|
||||
{
|
||||
if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP * 2)))
|
||||
return m;
|
||||
}
|
||||
if (ccid_state == CCID_STATE_WAIT)
|
||||
chopstx_usec_wait (LED_TIMEOUT_STOP * 2);
|
||||
else
|
||||
{
|
||||
if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
|
||||
if ((m = emit_led (icc_state == ICC_STATE_RECEIVE?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_STOP)))
|
||||
return m;
|
||||
chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
|
||||
emit_led (ccid_state == CCID_STATE_RECEIVE?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -274,20 +184,14 @@ calculate_regnual_entry_address (const uint8_t *addr)
|
||||
return v;
|
||||
}
|
||||
|
||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||
extern uint8_t __process4_stack_base__, __process4_stack_size__;
|
||||
|
||||
const uint32_t __stackaddr_ccid = (uint32_t)&__process1_stack_base__;
|
||||
const size_t __stacksize_ccid = (size_t)&__process1_stack_size__;
|
||||
|
||||
const uint32_t __stackaddr_usb = (uint32_t)&__process4_stack_base__;
|
||||
const size_t __stacksize_usb = (size_t)&__process4_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_USB 4
|
||||
#define PRIO_MAIN 5
|
||||
|
||||
extern void *usb_intr (void *arg);
|
||||
extern void *ccid_thread (void *arg);
|
||||
|
||||
static void gnuk_malloc_init (void);
|
||||
|
||||
@@ -296,16 +200,11 @@ extern uint32_t bDeviceState;
|
||||
|
||||
/*
|
||||
* Entry point.
|
||||
*
|
||||
* NOTE: the main function is already a thread in the system on entry.
|
||||
* See the hwinit1_common function.
|
||||
*/
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
unsigned int count = 0;
|
||||
uint32_t entry;
|
||||
chopstx_t usb_thd;
|
||||
chopstx_t ccid_thd;
|
||||
|
||||
(void)argc;
|
||||
@@ -318,7 +217,7 @@ main (int argc, char *argv[])
|
||||
|
||||
adc_init ();
|
||||
|
||||
eventflag_init (&led_event, chopstx_main);
|
||||
eventflag_init (&led_event);
|
||||
|
||||
random_init ();
|
||||
|
||||
@@ -326,8 +225,8 @@ main (int argc, char *argv[])
|
||||
stdout_init ();
|
||||
#endif
|
||||
|
||||
ccid_thd = chopstx_create (PRIO_CCID, __stackaddr_ccid, __stacksize_ccid,
|
||||
USBthread, NULL);
|
||||
ccid_thd = chopstx_create (PRIO_CCID, STACK_ADDR_CCID, STACK_SIZE_CCID,
|
||||
ccid_thread, NULL);
|
||||
|
||||
#ifdef PINPAD_CIR_SUPPORT
|
||||
cir_init ();
|
||||
@@ -336,10 +235,7 @@ main (int argc, char *argv[])
|
||||
msc_init ();
|
||||
#endif
|
||||
|
||||
usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
|
||||
usb_intr, NULL);
|
||||
|
||||
chopstx_main_init (PRIO_MAIN);
|
||||
chopstx_setpriority (PRIO_MAIN);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -353,56 +249,31 @@ main (int argc, char *argv[])
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
m = eventflag_wait_timeout (&led_event, MAIN_TIMEOUT_INTERVAL);
|
||||
got_it:
|
||||
count++;
|
||||
m = eventflag_wait (&led_event);
|
||||
switch (m)
|
||||
{
|
||||
case LED_ONESHOT:
|
||||
if ((m = emit_led (100*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
emit_led (100*1000, LED_TIMEOUT_STOP);
|
||||
break;
|
||||
case LED_TWOSHOTS:
|
||||
if ((m = emit_led (50*1000, 50*1000))) goto got_it;
|
||||
if ((m = emit_led (50*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
emit_led (50*1000, 50*1000);
|
||||
emit_led (50*1000, LED_TIMEOUT_STOP);
|
||||
break;
|
||||
case LED_SHOW_STATUS:
|
||||
if ((count & 0x07) != 0) continue; /* Display once for eight times */
|
||||
if ((m = display_status_code ())) goto got_it;
|
||||
break;
|
||||
case LED_START_COMMAND:
|
||||
set_led (1);
|
||||
led_inverted = 1;
|
||||
break;
|
||||
case LED_FINISH_COMMAND:
|
||||
m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP);
|
||||
led_inverted = 0;
|
||||
set_led (0);
|
||||
if (m)
|
||||
goto got_it;
|
||||
display_status_code ();
|
||||
break;
|
||||
case LED_FATAL:
|
||||
display_fatal_code ();
|
||||
break;
|
||||
case LED_USB_RESET:
|
||||
ccid_usb_reset ();
|
||||
case LED_SYNC:
|
||||
set_led (led_inverted);
|
||||
break;
|
||||
case LED_GNUK_EXEC:
|
||||
goto exec;
|
||||
default:
|
||||
if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
|
||||
goto got_it;
|
||||
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MORE
|
||||
if (stdout.connected && (count % 10) == 0)
|
||||
{
|
||||
DEBUG_SHORT (count / 10);
|
||||
_write ("\r\nThis is Gnuk on STM32F103.\r\n"
|
||||
"Testing USB driver.\n\n"
|
||||
"Hello world\r\n\r\n", 30+21+15);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
exec:
|
||||
@@ -414,9 +285,6 @@ main (int argc, char *argv[])
|
||||
/* Finish application. */
|
||||
chopstx_join (ccid_thd, NULL);
|
||||
|
||||
chopstx_cancel (usb_thd);
|
||||
chopstx_join (usb_thd, NULL);
|
||||
|
||||
/* Set vector */
|
||||
SCB->VTOR = (uint32_t)&_regnual_start;
|
||||
entry = calculate_regnual_entry_address (&_regnual_start);
|
||||
@@ -458,6 +326,8 @@ main (int argc, char *argv[])
|
||||
void
|
||||
fatal (uint8_t code)
|
||||
{
|
||||
extern void _write (const char *s, int len);
|
||||
|
||||
fatal_code = code;
|
||||
eventflag_signal (&led_event, LED_FATAL);
|
||||
_write ("fatal\r\n", 7);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* modp256k1.c -- modulo arithmetic for p256k1
|
||||
*
|
||||
* Copyright (C) 2014 Free Software Initiative of Japan
|
||||
* Copyright (C) 2014, 2016 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -55,12 +55,12 @@ const bn256 p256k1 = { {0xfffffc2f, 0xfffffffe, 0xffffffff, 0xffffffff,
|
||||
/*
|
||||
* Implementation Note.
|
||||
*
|
||||
* It's not always modulo p256k1. The representation is redundant
|
||||
* during computation. For example, when we add the prime - 1 and 1,
|
||||
* it won't overflow to 2^256, and the result is represented within
|
||||
* 256-bit.
|
||||
* It's always modulo p256k1.
|
||||
*
|
||||
* Once, I tried redundant representation which caused wrong
|
||||
* calculation. Implementation could be correct with redundant
|
||||
* representation, but it found that it's more expensive.
|
||||
*
|
||||
* It is guaranteed that modp256k1_reduce reduces to modulo p256k1.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -69,14 +69,16 @@ const bn256 p256k1 = { {0xfffffc2f, 0xfffffffe, 0xffffffff, 0xffffffff,
|
||||
void
|
||||
modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
{
|
||||
uint32_t carry;
|
||||
uint32_t cond;
|
||||
bn256 tmp[1];
|
||||
|
||||
carry = bn256_add (X, A, B);
|
||||
if (carry)
|
||||
bn256_sub (X, X, P256K1);
|
||||
cond = (bn256_add (X, A, B) == 0);
|
||||
cond &= bn256_sub (tmp, X, P256K1);
|
||||
if (cond)
|
||||
/* No-carry AND borrow */
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
else
|
||||
bn256_sub (tmp, X, P256K1);
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,10 +91,11 @@ modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
bn256 tmp[1];
|
||||
|
||||
borrow = bn256_sub (X, A, B);
|
||||
bn256_add (tmp, X, P256K1);
|
||||
if (borrow)
|
||||
bn256_add (X, X, P256K1);
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
else
|
||||
bn256_add (tmp, X, P256K1);
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* modp256r1.c -- modulo arithmetic for p256r1
|
||||
*
|
||||
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
|
||||
* Copyright (C) 2011, 2013, 2014, 2016
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -49,12 +50,12 @@ const bn256 p256r1 = { {0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
/*
|
||||
* Implementation Note.
|
||||
*
|
||||
* It's not always modulo p256r1. The representation is redundant
|
||||
* during computation. For example, when we add the prime - 1 and 1,
|
||||
* it won't overflow to 2^256, and the result is represented within
|
||||
* 256-bit.
|
||||
* It's always modulo p256r1.
|
||||
*
|
||||
* Once, I tried redundant representation which caused wrong
|
||||
* calculation. Implementation could be correct with redundant
|
||||
* representation, but it found that it's more expensive.
|
||||
*
|
||||
* It is guaranteed that modp256r1_reduce reduces to modulo p256r1.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -63,14 +64,16 @@ const bn256 p256r1 = { {0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
void
|
||||
modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
{
|
||||
uint32_t carry;
|
||||
uint32_t cond;
|
||||
bn256 tmp[1];
|
||||
|
||||
carry = bn256_add (X, A, B);
|
||||
if (carry)
|
||||
bn256_sub (X, X, P256R1);
|
||||
cond = (bn256_add (X, A, B) == 0);
|
||||
cond &= bn256_sub (tmp, X, P256R1);
|
||||
if (cond)
|
||||
/* No-carry AND borrow */
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
else
|
||||
bn256_sub (tmp, X, P256R1);
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,10 +86,11 @@ modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
bn256 tmp[1];
|
||||
|
||||
borrow = bn256_sub (X, A, B);
|
||||
bn256_add (tmp, X, P256R1);
|
||||
if (borrow)
|
||||
bn256_add (X, X, P256R1);
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
else
|
||||
bn256_add (tmp, X, P256R1);
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +99,7 @@ modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
void
|
||||
modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
{
|
||||
bn256 tmp[1];
|
||||
bn256 tmp[1], tmp0[1];
|
||||
uint32_t borrow;
|
||||
|
||||
#define S1 X
|
||||
@@ -116,6 +120,11 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S1->word[2] = A->word[2];
|
||||
S1->word[1] = A->word[1];
|
||||
S1->word[0] = A->word[0];
|
||||
borrow = bn256_sub (tmp0, S1, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S1, tmp0, sizeof (bn256));
|
||||
/* X = S1 */
|
||||
|
||||
S2->word[7] = A->word[15];
|
||||
@@ -155,6 +164,11 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S5->word[2] = A->word[11];
|
||||
S5->word[1] = A->word[10];
|
||||
S5->word[0] = A->word[9];
|
||||
borrow = bn256_sub (tmp0, S5, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S5, tmp0, sizeof (bn256));
|
||||
/* X += S5 */
|
||||
modp256r1_add (X, X, S5);
|
||||
|
||||
@@ -164,6 +178,11 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S6->word[2] = A->word[13];
|
||||
S6->word[1] = A->word[12];
|
||||
S6->word[0] = A->word[11];
|
||||
borrow = bn256_sub (tmp0, S6, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S6, tmp0, sizeof (bn256));
|
||||
/* X -= S6 */
|
||||
modp256r1_sub (X, X, S6);
|
||||
|
||||
@@ -174,6 +193,11 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S7->word[2] = A->word[14];
|
||||
S7->word[1] = A->word[13];
|
||||
S7->word[0] = A->word[12];
|
||||
borrow = bn256_sub (tmp0, S7, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S7, tmp0, sizeof (bn256));
|
||||
/* X -= S7 */
|
||||
modp256r1_sub (X, X, S7);
|
||||
|
||||
|
||||
24
src/neug.c
24
src/neug.c
@@ -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;
|
||||
@@ -583,7 +577,6 @@ rng (void *arg)
|
||||
|
||||
/* Enable ADCs */
|
||||
adc_start ();
|
||||
chopstx_claim_irq (&adc_intr, INTR_REQ_DMA1_Channel1);
|
||||
|
||||
ep_init (mode);
|
||||
while (!rng_should_terminate)
|
||||
@@ -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)
|
||||
@@ -641,16 +634,15 @@ rng (void *arg)
|
||||
}
|
||||
|
||||
adc_stop ();
|
||||
chopstx_release_irq (&adc_intr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -676,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
* 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"
|
||||
@@ -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 */
|
||||
@@ -485,23 +490,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
|
||||
@@ -763,6 +751,22 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
|
||||
{
|
||||
gpg_do_delete_prvkey (kk, CLEAN_PAGE_FULL);
|
||||
flash_enum_clear (algo_attr_pp);
|
||||
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);
|
||||
}
|
||||
if (*algo_attr_pp != NULL)
|
||||
return 0;
|
||||
}
|
||||
@@ -770,6 +774,22 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
|
||||
|| (*algo_attr_pp)[1] != algo)
|
||||
{
|
||||
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);
|
||||
}
|
||||
*algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo);
|
||||
if (*algo_attr_pp == NULL)
|
||||
return 0;
|
||||
@@ -1042,6 +1062,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 +1501,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 +1517,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 },
|
||||
@@ -1517,7 +1559,7 @@ gpg_data_scan (const uint8_t *p_start)
|
||||
|
||||
/* Traverse DO, counters, etc. in DATA pool */
|
||||
p = p_start;
|
||||
while (*p != NR_EMPTY)
|
||||
while (p && *p != NR_EMPTY)
|
||||
{
|
||||
uint8_t nr = *p++;
|
||||
uint8_t second_byte = *p;
|
||||
|
||||
193
src/openpgp.c
193
src/openpgp.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* openpgp.c -- OpenPGP card protocol support
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016
|
||||
* 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,16 +98,23 @@ 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_OPENPGP 254
|
||||
#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;
|
||||
|
||||
file_selection = FILE_NONE;
|
||||
flash_data_start = flash_init ();
|
||||
|
||||
if (flash_data_start == NULL)
|
||||
file_selection = FILE_CARD_TERMINATED;
|
||||
else
|
||||
file_selection = FILE_NONE;
|
||||
|
||||
gpg_data_scan (flash_data_start);
|
||||
flash_init_keys ();
|
||||
}
|
||||
@@ -138,6 +147,7 @@ static void
|
||||
cmd_verify (void)
|
||||
{
|
||||
int len;
|
||||
uint8_t p1 = P1 (apdu);
|
||||
uint8_t p2 = P2 (apdu);
|
||||
int r;
|
||||
const uint8_t *pw;
|
||||
@@ -149,22 +159,36 @@ cmd_verify (void)
|
||||
pw = apdu.cmd_apdu_data;
|
||||
|
||||
if (len == 0)
|
||||
{ /* This is to examine status. */
|
||||
if (p2 == 0x81)
|
||||
r = ac_check_status (AC_PSO_CDS_AUTHORIZED);
|
||||
else if (p2 == 0x82)
|
||||
r = ac_check_status (AC_OTHER_AUTHORIZED);
|
||||
else
|
||||
r = ac_check_status (AC_ADMIN_AUTHORIZED);
|
||||
{
|
||||
if (p1 == 0)
|
||||
{ /* This is to examine status. */
|
||||
if (p2 == 0x81)
|
||||
r = ac_check_status (AC_PSO_CDS_AUTHORIZED);
|
||||
else if (p2 == 0x82)
|
||||
r = ac_check_status (AC_OTHER_AUTHORIZED);
|
||||
else
|
||||
r = ac_check_status (AC_ADMIN_AUTHORIZED);
|
||||
|
||||
if (r)
|
||||
GPG_SUCCESS (); /* If authentication done already, return success. */
|
||||
else
|
||||
{ /* If not, return retry counter, encoded. */
|
||||
r = gpg_pw_get_retry_counter (p2);
|
||||
set_res_sw (0x63, 0xc0 | (r&0x0f));
|
||||
if (r)
|
||||
GPG_SUCCESS (); /* If authentication done already, return success. */
|
||||
else
|
||||
{ /* If not, return retry counter, encoded. */
|
||||
r = gpg_pw_get_retry_counter (p2);
|
||||
set_res_sw (0x63, 0xc0 | (r&0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
else if (p1 == 0xff)
|
||||
{ /* Reset the status. */
|
||||
if (p2 == 0x81)
|
||||
ac_reset_pso_cds ();
|
||||
else if (p2 == 0x82)
|
||||
ac_reset_other ();
|
||||
else
|
||||
ac_reset_admin ();
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
else
|
||||
GPG_BAD_P1_P2 ();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -437,9 +461,12 @@ s2k (const unsigned char *salt, size_t slen,
|
||||
{
|
||||
sha256_context ctx;
|
||||
size_t count = S2KCOUNT;
|
||||
const uint8_t *unique = unique_device_id ();
|
||||
|
||||
sha256_start (&ctx);
|
||||
|
||||
sha256_update (&ctx, unique, 12);
|
||||
|
||||
while (count > slen + ilen)
|
||||
{
|
||||
if (slen)
|
||||
@@ -598,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;
|
||||
@@ -733,19 +757,17 @@ 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 ();
|
||||
file_selection = FILE_CARD_TERMINATED_OPENPGP;
|
||||
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)
|
||||
@@ -795,9 +817,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);
|
||||
}
|
||||
|
||||
@@ -1299,6 +1318,64 @@ cmd_get_challenge (void)
|
||||
}
|
||||
|
||||
|
||||
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
|
||||
static void
|
||||
cmd_activate_file (void)
|
||||
{
|
||||
if (file_selection != FILE_CARD_TERMINATED_OPENPGP)
|
||||
{
|
||||
GPG_NO_RECORD();
|
||||
return;
|
||||
}
|
||||
|
||||
flash_activate ();
|
||||
file_selection = FILE_DF_OPENPGP;
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_terminate_df (void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
if (!ac_check_status (AC_ADMIN_AUTHORIZED) && !gpg_pw_locked (PW_ERR_PW3))
|
||||
{
|
||||
/* 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;
|
||||
@@ -1310,13 +1387,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)
|
||||
@@ -1324,6 +1404,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)))
|
||||
|
||||
@@ -1339,9 +1422,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
|
||||
{
|
||||
@@ -1351,23 +1447,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;
|
||||
|
||||
@@ -1407,7 +1490,7 @@ card_thread (chopstx_t thd, struct eventflag *ccid_comm)
|
||||
else if (m == EV_MODIFY_CMD_AVAILABLE)
|
||||
{
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
uint8_t bConfirmPIN = apdu.cmd_apdu_data[5];
|
||||
uint8_t bConfirmPIN = apdu.cmd_apdu_data[0];
|
||||
uint8_t *p = apdu.cmd_apdu_data;
|
||||
|
||||
if (INS (apdu) != INS_CHANGE_REFERENCE_DATA
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
700
src/stm32f103.h
700
src/stm32f103.h
@@ -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
|
||||
434
src/sys.c
434
src/sys.c
@@ -1,434 +0,0 @@
|
||||
/*
|
||||
* sys.c - system routines for the initial page for STM32F103.
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015 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.c"
|
||||
|
||||
#define CORTEX_PRIORITY_BITS 4
|
||||
#define CORTEX_PRIORITY_MASK(n) ((n) << (8 - CORTEX_PRIORITY_BITS))
|
||||
#define USB_LP_CAN1_RX0_IRQn 20
|
||||
#define STM32_USB_IRQ_PRIORITY 11
|
||||
|
||||
struct NVIC {
|
||||
uint32_t ISER[8];
|
||||
uint32_t unused1[24];
|
||||
uint32_t ICER[8];
|
||||
uint32_t unused2[24];
|
||||
uint32_t ISPR[8];
|
||||
uint32_t unused3[24];
|
||||
uint32_t ICPR[8];
|
||||
uint32_t unused4[24];
|
||||
uint32_t IABR[8];
|
||||
uint32_t unused5[56];
|
||||
uint32_t IPR[60];
|
||||
};
|
||||
|
||||
static struct NVIC *const NVICBase = ((struct NVIC *const)0xE000E100);
|
||||
#define NVIC_ISER(n) (NVICBase->ISER[n >> 5])
|
||||
#define NVIC_ICPR(n) (NVICBase->ICPR[n >> 5])
|
||||
#define NVIC_IPR(n) (NVICBase->IPR[n >> 2])
|
||||
|
||||
static void
|
||||
nvic_enable_vector (uint32_t n, uint32_t prio)
|
||||
{
|
||||
unsigned int sh = (n & 3) << 3;
|
||||
|
||||
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh)) | (prio << sh);
|
||||
NVIC_ICPR (n) = 1 << (n & 0x1F);
|
||||
NVIC_ISER (n) = 1 << (n & 0x1F);
|
||||
}
|
||||
|
||||
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;
|
||||
nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
|
||||
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
|
||||
/*
|
||||
* Note that we also have other IRQ(s):
|
||||
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
|
||||
* USBWakeUp_IRQn (suspend/resume)
|
||||
*/
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
}
|
||||
|
||||
#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: "2.1" */
|
||||
'2', 0, '.', 0, '1', 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
130
src/sys.h
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
350
src/usb_ctrl.c
350
src/usb_ctrl.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "usb_lld.h"
|
||||
#include "usb_conf.h"
|
||||
#include "gnuk.h"
|
||||
#include "stm32f103.h"
|
||||
#include "mcu/stm32f103.h"
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#include "usb-cdc.h"
|
||||
@@ -61,47 +61,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 control_info *detail)
|
||||
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), detail);
|
||||
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 ((detail->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 +110,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,17 +173,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;
|
||||
|
||||
/* Set DEVICE as not configured */
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (USB_INITIAL_FEATURE);
|
||||
|
||||
usb_lld_reset ();
|
||||
usb_lld_reset (dev, USB_INITIAL_FEATURE);
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
|
||||
@@ -216,7 +188,7 @@ usb_cb_device_reset (void)
|
||||
gnuk_setup_endpoints_for_interface (i, 1);
|
||||
|
||||
bDeviceState = ATTACHED;
|
||||
led_blink (LED_USB_RESET); /* Notify the main. */
|
||||
ccid_usb_reset (1);
|
||||
}
|
||||
|
||||
#define USB_CCID_REQ_ABORT 0x01
|
||||
@@ -246,7 +218,7 @@ static uint32_t rbit (uint32_t v)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@@ -258,261 +230,271 @@ static int download_check_crc32 (const uint32_t *end_p)
|
||||
CRC->DR = rbit (*p);
|
||||
|
||||
if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
|
||||
return USB_SUCCESS;
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
usb_cb_setup (uint8_t req, uint8_t req_no, struct control_info *detail)
|
||||
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), detail);
|
||||
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 + detail->value * 0x100 + detail->index);
|
||||
uint8_t *addr = (uint8_t *)(0x20000000 + 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 + detail->len > __heap_end__)
|
||||
return USB_UNSUPPORT;
|
||||
if (addr < &_regnual_start || addr + arg->len > __heap_end__)
|
||||
return -1;
|
||||
|
||||
if (detail->index + detail->len < 256)
|
||||
memset (addr + detail->index + detail->len, 0, 256 - (detail->index + detail->len));
|
||||
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, detail->len);
|
||||
return USB_SUCCESS;
|
||||
return usb_lld_ctrl_recv (dev, addr, arg->len);
|
||||
}
|
||||
else if (req_no == USB_FSIJ_GNUK_EXEC && detail->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;
|
||||
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 && detail->len == 0)
|
||||
else if (arg->request == USB_FSIJ_GNUK_CARD_CHANGE && arg->len == 0)
|
||||
{
|
||||
if (detail->value != 0 && detail->value != 1 && detail->value != 2)
|
||||
return USB_UNSUPPORT;
|
||||
if (arg->value != 0 && arg->value != 1 && arg->value != 2)
|
||||
return -1;
|
||||
|
||||
ccid_card_change_signal (detail->value);
|
||||
return USB_SUCCESS;
|
||||
ccid_card_change_signal (arg->value);
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
||||
{
|
||||
if (detail->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),
|
||||
detail);
|
||||
else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
|
||||
return usb_lld_reply_request (data_rate_table,
|
||||
sizeof (data_rate_table), detail);
|
||||
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 (index == HID_INTERFACE)
|
||||
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, detail);
|
||||
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, detail);
|
||||
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, detail);
|
||||
return usb_lld_ctrl_send (dev, &hid_report, 2);
|
||||
|
||||
case USB_HID_REQ_SET_REPORT:
|
||||
/* Received LED set request */
|
||||
if (detail->len == 1)
|
||||
usb_lld_set_data_to_recv (&hid_report, detail->len);
|
||||
return USB_SUCCESS;
|
||||
if (arg->len == 1)
|
||||
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 (index == VCOM_INTERFACE_0)
|
||||
return vcom_port_data_setup (req, req_no, detail);
|
||||
else if (arg->index == VCOM_INTERFACE_0)
|
||||
return vcom_port_data_setup (dev);
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (index == MSC_INTERFACE)
|
||||
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),
|
||||
detail);
|
||||
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, uint16_t value)
|
||||
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))
|
||||
{
|
||||
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;
|
||||
|
||||
(void)value; (void)index;
|
||||
bDeviceState = UNCONNECTED;
|
||||
usb_lld_prepare_shutdown (); /* No further USB communication */
|
||||
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 (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 control_info *detail)
|
||||
|
||||
int
|
||||
usb_set_interface (struct usb_dev *dev)
|
||||
{
|
||||
const uint8_t zero = 0;
|
||||
uint16_t interface = detail->index;
|
||||
uint16_t alt = detail->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, detail);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define INTR_REQ_USB 20
|
||||
|
||||
void *
|
||||
usb_intr (void *arg)
|
||||
int
|
||||
usb_get_interface (struct usb_dev *dev)
|
||||
{
|
||||
chopstx_intr_t interrupt;
|
||||
const uint8_t zero = 0;
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
|
||||
(void)arg;
|
||||
usb_lld_init (USB_INITIAL_FEATURE);
|
||||
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
|
||||
usb_interrupt_handler ();
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
chopstx_intr_wait (&interrupt);
|
||||
|
||||
/* Process interrupt. */
|
||||
usb_interrupt_handler ();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -53,15 +53,15 @@ 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[] = {
|
||||
18, /* bLength */
|
||||
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
DEVICE_DESCRIPTOR, /* bDescriptorType */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0x00, /* bDeviceClass: 0 means deferred to interface */
|
||||
0x00, /* bDeviceSubClass */
|
||||
@@ -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,16 +94,16 @@ 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)
|
||||
|
||||
|
||||
/* Configuation Descriptor */
|
||||
static const uint8_t config_desc[] = {
|
||||
9, /* bLength: Configuation Descriptor size */
|
||||
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
|
||||
W_TOTAL_LENGTH, 0x00, /* wTotalLength:no of returned bytes */
|
||||
NUM_INTERFACES, /* bNumInterfaces: */
|
||||
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
|
||||
W_TOTAL_LENGTH, 0x00, /* wTotalLength:no of returned bytes */
|
||||
NUM_INTERFACES, /* bNumInterfaces: */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||
USB_INITIAL_FEATURE, /* bmAttributes*/
|
||||
@@ -111,13 +111,13 @@ static const uint8_t config_desc[] = {
|
||||
|
||||
/* Interface Descriptor */
|
||||
9, /* bLength: Interface Descriptor size */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
ICC_INTERFACE, /* bInterfaceNumber: Index of this interface */
|
||||
INTERFACE_DESCRIPTOR, /* bDescriptorType: 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 */
|
||||
@@ -167,21 +167,21 @@ static const uint8_t config_desc[] = {
|
||||
1, /* bMaxCCIDBusySlots: 1 */
|
||||
/*Endpoint IN1 Descriptor*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
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 */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
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 */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
0x82, /* bEndpointAddress: (IN2) */
|
||||
0x03, /* bmAttributes: Interrupt */
|
||||
0x04, 0x00, /* wMaxPacketSize: 4 */
|
||||
@@ -190,7 +190,7 @@ static const uint8_t config_desc[] = {
|
||||
#ifdef HID_CARD_CHANGE_SUPPORT
|
||||
/* Interface Descriptor */
|
||||
9, /* bLength: Interface Descriptor size */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
INTERFACE_DESCRIPTOR, /* bDescriptorType: Interface */
|
||||
HID_INTERFACE, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints: One endpoint used */
|
||||
@@ -209,7 +209,7 @@ static const uint8_t config_desc[] = {
|
||||
|
||||
/*Endpoint IN7 Descriptor*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
0x87, /* bEndpointAddress: (IN7) */
|
||||
0x03, /* bmAttributes: Interrupt */
|
||||
0x02, 0x00, /* wMaxPacketSize: 2 */
|
||||
@@ -219,7 +219,7 @@ static const uint8_t config_desc[] = {
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
/* Interface Descriptor */
|
||||
9, /* bLength: Interface Descriptor size */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
INTERFACE_DESCRIPTOR, /* bDescriptorType: Interface */
|
||||
VCOM_INTERFACE_0, /* bInterfaceNumber: Index of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints: One endpoints used */
|
||||
@@ -251,7 +251,7 @@ static const uint8_t config_desc[] = {
|
||||
VCOM_INTERFACE_1, /* bSlaveInterface0: Data Class Interface */
|
||||
/*Endpoint 4 Descriptor*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
0x84, /* bEndpointAddress: (IN4) */
|
||||
0x03, /* bmAttributes: Interrupt */
|
||||
VIRTUAL_COM_PORT_INT_SIZE, 0x00, /* wMaxPacketSize: */
|
||||
@@ -259,7 +259,7 @@ static const uint8_t config_desc[] = {
|
||||
|
||||
/*Data class interface descriptor*/
|
||||
9, /* bLength: Endpoint Descriptor size */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
|
||||
INTERFACE_DESCRIPTOR, /* bDescriptorType: */
|
||||
VCOM_INTERFACE_1, /* bInterfaceNumber: Index of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x02, /* bNumEndpoints: Two endpoints used */
|
||||
@@ -269,14 +269,14 @@ static const uint8_t config_desc[] = {
|
||||
0x00, /* iInterface: */
|
||||
/*Endpoint 5 Descriptor*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
0x05, /* bEndpointAddress: (OUT5) */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
/*Endpoint 3 Descriptor*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
0x83, /* bEndpointAddress: (IN3) */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
||||
@@ -285,7 +285,7 @@ static const uint8_t config_desc[] = {
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
/* Interface Descriptor.*/
|
||||
9, /* bLength: Interface Descriptor size */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
INTERFACE_DESCRIPTOR, /* bDescriptorType: Interface */
|
||||
MSC_INTERFACE, /* bInterfaceNumber. */
|
||||
0x00, /* bAlternateSetting. */
|
||||
0x02, /* bNumEndpoints. */
|
||||
@@ -298,14 +298,14 @@ static const uint8_t config_desc[] = {
|
||||
0x00, /* iInterface. */
|
||||
/* Endpoint Descriptor.*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
0x86, /* bEndpointAddress: (IN6) */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval (ignored for bulk). */
|
||||
/* Endpoint Descriptor.*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
0x06, /* bEndpointAddress: (OUT6) */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
@@ -317,7 +317,7 @@ static const uint8_t config_desc[] = {
|
||||
/* USB String Descriptors */
|
||||
static const uint8_t gnuk_string_lang_id[] = {
|
||||
4, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE,
|
||||
STRING_DESCRIPTOR,
|
||||
0x09, 0x04 /* LangID = 0x0409: US-English */
|
||||
};
|
||||
|
||||
@@ -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 control_info *detail)
|
||||
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), detail);
|
||||
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), detail);
|
||||
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,
|
||||
detail);
|
||||
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];
|
||||
@@ -375,25 +379,25 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
|
||||
usbbuf[i*2+3] = 0;
|
||||
}
|
||||
usbbuf[0] = len = i*2 + 2;
|
||||
usbbuf[1] = USB_STRING_DESCRIPTOR_TYPE;
|
||||
return usb_lld_reply_request (usbbuf, len, detail);
|
||||
usbbuf[1] = STRING_DESCRIPTOR;
|
||||
return usb_lld_ctrl_send (dev, usbbuf, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HID_CARD_CHANGE_SUPPORT
|
||||
else if (rcp == INTERFACE_RECIPIENT)
|
||||
{
|
||||
if (detail->index == 1)
|
||||
if (arg->index == HID_INTERFACE)
|
||||
{
|
||||
if (desc_type == USB_DT_HID)
|
||||
return usb_lld_reply_request (config_desc+ICC_TOTAL_LENGTH+9, 9,
|
||||
detail);
|
||||
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,
|
||||
detail);
|
||||
return usb_lld_ctrl_send (dev, hid_report_desc,
|
||||
HID_REPORT_DESC_SIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
122
src/usb_lld.h
122
src/usb_lld.h
@@ -1,122 +0,0 @@
|
||||
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
|
||||
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
|
||||
#define USB_STRING_DESCRIPTOR_TYPE 0x03
|
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
|
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
|
||||
|
||||
#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, /* 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 control_info {
|
||||
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 control_info *detail);
|
||||
int usb_cb_interface (uint8_t cmd, struct control_info *detail);
|
||||
int usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
|
||||
struct control_info *detail);
|
||||
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, uint16_t value);
|
||||
|
||||
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 control_info *ctrl);
|
||||
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 (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_set_configuration (uint8_t config);
|
||||
uint8_t usb_lld_current_configuration (void);
|
||||
void usb_lld_set_feature (uint8_t feature);
|
||||
void usb_lld_set_data_to_recv (const void *p, size_t len);
|
||||
|
||||
void usb_lld_prepare_shutdown (void);
|
||||
void usb_lld_shutdown (void);
|
||||
|
||||
void usb_interrupt_handler (void);
|
||||
1168
src/usb_stm32f103.c
1168
src/usb_stm32f103.c
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: (.*)")
|
||||
|
||||
@@ -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
13
tests/README
Normal 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
329
tests/card_reader.py
Normal 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
18
tests/conftest.py
Normal 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
338
tests/openpgp_card.py
Normal 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
4
tests/rsa-aut.key
Normal file
@@ -0,0 +1,4 @@
|
||||
9cf7192b51a574d1ad3ccb08ba09b87f228573893eee355529ff243e90fd4b86f79a82097cc7922c0485bed1616b1656a9b0b19ef78ea8ec34c384019adc5d5bf4db2d2a0a2d9cf14277bdcb7056f48b81214e3f7f7742231e29673966f9b1106862112cc798dba8d4a138bb5abfc6d4c12d53a5d39b2f783da916da20852ee139bbafda61d429caf2a4f30847ce7e7ae32ab4061e27dd9e4d00d60910249db8d8559dd85f7ca59659ef400c8f6318700f4e97f0c6f4165de80641490433c88da8682befe68eb311f54af2b07d97ac74edb5399cf054764211694fbb8d1d333f3269f235abe025067f811ff83a2224826219b309ea3e6c968f42b3e52f245dc9
|
||||
010001
|
||||
b5ab7b159220b18e363258f61ebde08bae83d6ce2dbfe4adc143628c527887acde9de09bf9b49f438019004d71855f30c2d69b6c29bb9882ab641b3387409fe9199464a7faa4b5230c56d9e17cd9ed074bc00180ebed62bae3af28e6ff2ac2654ad968834c5d5c88f8d9d3cc5e167b10453b049d4e454a5761fb0ac717185907
|
||||
dd2fffa9814296156a6926cd17b65564187e424dcadce9b032246ad7e46448bb0f9e0ff3c64f987424b1a40bc694e2e9ac4fb1930d163582d7acf20653a1c44b97846c1c5fd8a7b19bb225fb39c30e25410483deaf8c2538d222b748c4d8103b11cec04f666a5c0dbcbf5d5f625f158f65746c3fafe6418145f7cffa5fadeeaf
|
||||
4
tests/rsa-dec.key
Normal file
4
tests/rsa-dec.key
Normal file
@@ -0,0 +1,4 @@
|
||||
d392714c29738aac6372f2c8654a08c25a1299fed7004bd512cd2452b503ebad6301130816ac525ba528dc155be6347a5c70407fb4fbdaed751dfc0a7cd5e3910272ff236c4ed1ce5de6620b191a172e5b247347b8cab73a43d79221708755c959a2f83f486439da30917384554331532aabc8326db48866f8c91198834a86ab94679f6175db737bdf399e3f0b737dcb1f4208279d3e1cc694e78686785e4f363a377dec912b7c2f757b1422d866fb9fa85c96b83adfd6a223989a9a02988bdee81ad17eff6385e7b38cec8611fdf367ba4ac8e90d5f48ac7715c5f47aea06a4a37cdaa3029ce59d29bc66853bf6758ef4a7da5a5953f5e557a5a22f67c368c3
|
||||
010001
|
||||
dae085952c5beee38f25f09bc37a4ca2434c31f78055469d0d5f0bf3337e3a70ba6c91734f195b742e211a5fe283befdf66820008e6ef2c8ca54a91922838fce07d9e33a331ce20dac36803e777d5ee2195ed28d6a4045e28623a6a60b0661e45f7c4f84ae2b1dfad0cf1ec30605158323382a819e730c09a33fad704dd67501
|
||||
f774be43ea198aa2f089274e4fffd7d0092ee7b35a1d2f854cdb166f698caab72fdeb099e690e78438b2e043e452d4d2f19d7f44ba6b286642f0ce5204966ff98ecd9e3b448877324631365dc860797429b9414a21a7e166d504cace156588b9a145657eeb1afb43b8ff65d8d6d93cea2ba4ef8aab047885c4de64ffef0b49c3
|
||||
4
tests/rsa-sig.key
Normal file
4
tests/rsa-sig.key
Normal file
@@ -0,0 +1,4 @@
|
||||
c6c877dfd3b441f8fb1b8dc504093a51c2efe4883fe0a6379205acc6e673709905e4d767ddf46143c535cc6d7f10b616f520d8346320ef69ff4a2c4f4a148edc65f7ad24ed7d4fe23bb862a0ae71f4f7904abac0397abf3213df91326b1a25554b3b18cf54584d8bf220169fc92b2aa511e8313983e72b4c9110b3a1aea087aebef95873865608e8faea9ef10e7f7f3a66ca8def2d499c3149c127491e0e4339fd6abe10bfc6c13e43d522004f1485767328eabe35d6ffa8df4c15f0fbcd4eb1c07cc6d85e275139ac69e2962273ae987236926dd6c1144fce3e7ae567fa58ea60620dfafc52f95299fea601739fce27ee71eea978d0074f21e7086f60ba8331
|
||||
010001
|
||||
cc365b5702714bf203e8c49b0b8afa8dad586e929cf5edca38ad07fa45efd5c2d89022d29f40283a57e50ca24c5f28c8e911a74faaf796f112e7e48195956f9a4df7668a5342523b27179cec958f363211ee11d0ec0e0e1b92ca007a61e8c9ac14e00229b9a7624850199e6667afa1a44db8f3c5de0a8eef0e6de050ac0ac633
|
||||
f931a3c12f0e3a5276f712b7706590ba02e14a97ff9b8ce3152af0fc4d9cdc690ea9bc4c82cb16c7d23136cbdab58fbec69880a88bca85c4214df01045082cbe9f4192e3e39c79896533c37dad9eb9e73c2643b9c0a704a4f93d81573537963d6b6e5140a24c702d9f26e06a2095de906daa8824172a6b39f563b7153907050b
|
||||
148
tests/rsa_keys.py
Normal file
148
tests/rsa_keys.py
Normal 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
184
tests/test_empty_card.py
Normal 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)
|
||||
290
tests/test_personalize_card.py
Normal file
290
tests/test_personalize_card.py
Normal 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
|
||||
91
tests/test_personalize_reset_card.py
Normal file
91
tests/test_personalize_reset_card.py
Normal 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
|
||||
44
tests/test_remove_keys_card.py
Normal file
44
tests/test_remove_keys_card.py
Normal 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
7
tests/util.py
Normal 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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -67,9 +73,7 @@ class gnuk_token(object):
|
||||
if interface.interfaceSubClass != CCID_SUBCLASS:
|
||||
raise ValueError("Wrong interface sub class")
|
||||
self.__devhandle = device.open()
|
||||
self.__devhandle.setConfiguration(configuration.value)
|
||||
self.__devhandle.claimInterface(interface)
|
||||
self.__devhandle.setAltInterface(0)
|
||||
|
||||
self.__intf = interface.interfaceNumber
|
||||
self.__alt = interface.alternateSetting
|
||||
@@ -291,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"")
|
||||
@@ -343,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,12 +483,7 @@ class regnual(object):
|
||||
if intf.interfaceClass != 0xff:
|
||||
raise ValueError("Wrong interface class")
|
||||
self.__devhandle = dev.open()
|
||||
try:
|
||||
self.__devhandle.setConfiguration(conf)
|
||||
except:
|
||||
pass
|
||||
self.__devhandle.claimInterface(intf)
|
||||
self.__devhandle.setAltInterface(0)
|
||||
|
||||
def mem_info(self):
|
||||
mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0,
|
||||
@@ -587,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user