Compare commits
167 Commits
release/0.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93867d0c8b | ||
|
|
a1a112d213 | ||
|
|
e679b4da7a | ||
|
|
095f854fa8 | ||
|
|
f9292f1157 | ||
|
|
b619db59d2 | ||
|
|
8870d58b69 | ||
|
|
4abcddef93 | ||
|
|
ca46cc465c | ||
|
|
3cf5ed482f | ||
|
|
87d95d0864 | ||
|
|
428adc7ac6 | ||
|
|
cc185eabb5 | ||
|
|
80e3cda267 | ||
|
|
ee867794e7 | ||
|
|
a4f7386b8a | ||
|
|
7d4d6cff5e | ||
|
|
b09460f0ae | ||
|
|
4298809ffb | ||
|
|
b297cf22b6 | ||
|
|
f84f52156c | ||
|
|
1564a4fbe6 | ||
|
|
16610ca5c7 | ||
|
|
352f81a61f | ||
|
|
7c82839fba | ||
|
|
10c685be16 | ||
|
|
ed61ed980d | ||
|
|
7ff0baf5df | ||
|
|
46259ce63d | ||
|
|
0aca10f307 | ||
|
|
5f2a8b835c | ||
|
|
5213d9ab82 | ||
|
|
c12f331217 | ||
|
|
62b4369d2c | ||
|
|
9dde59867d | ||
|
|
eae955b15e | ||
|
|
7e8dd12654 | ||
|
|
8c91d2ef2e | ||
|
|
6b6913c676 | ||
|
|
3ad9373163 | ||
|
|
220d5c0307 | ||
|
|
de7f9f6417 | ||
|
|
a302585602 | ||
|
|
ea2191105f | ||
|
|
32094099dd | ||
|
|
9b71d70b73 | ||
|
|
77d06fb301 | ||
|
|
78b642507b | ||
|
|
90a11859dc | ||
|
|
ad9a901e1b | ||
|
|
500b12b60d | ||
|
|
4bfe087583 | ||
|
|
22d0cb689a | ||
|
|
fe6337f988 | ||
|
|
1a2560531d | ||
|
|
40e234b799 | ||
|
|
deccb981ad | ||
|
|
12bd1161a4 | ||
|
|
d72a0b7893 | ||
|
|
ee5b6a2a82 | ||
|
|
f9b43a67ee | ||
|
|
70846e8b81 | ||
|
|
f6df7701f9 | ||
|
|
b9772265cf | ||
|
|
254c521c6f | ||
|
|
d7c6b95ba1 | ||
|
|
2e7d93a556 | ||
|
|
db2d897c3f | ||
|
|
23a9fe3bdc | ||
|
|
e8f773d2f6 | ||
|
|
6b5fc04c0d | ||
|
|
39bee2ee01 | ||
|
|
f39380d3aa | ||
|
|
0d36a58804 | ||
|
|
eb0e913eee | ||
|
|
7575dda42a | ||
|
|
61ec9b7ed7 | ||
|
|
b49390de7a | ||
|
|
71eaffc0ee | ||
|
|
5e9a35c881 | ||
|
|
df5b7f31a3 | ||
|
|
add6fa8b67 | ||
|
|
c488bed215 | ||
|
|
63979416f6 | ||
|
|
92be182e8a | ||
|
|
9ffa68355d | ||
|
|
814f6b6329 | ||
|
|
1927f8a1ec | ||
|
|
d3fb62b437 | ||
|
|
5d3e6c2b29 | ||
|
|
8be278be17 | ||
|
|
6de9c11329 | ||
|
|
63df97a2e0 | ||
|
|
144dd88a07 | ||
|
|
e80c8f1e8e | ||
|
|
99d7e8d396 | ||
|
|
f38f33dade | ||
|
|
cbed6b49c7 | ||
|
|
51435e7dba | ||
|
|
29b68186bf | ||
|
|
a5fddc691d | ||
|
|
965dace0a4 | ||
|
|
ee4f3806c2 | ||
|
|
9ad6c6461d | ||
|
|
a796e9f145 | ||
|
|
f88e7af3ce | ||
|
|
fe31219d94 | ||
|
|
6f97e8a7c4 | ||
|
|
e78206e1cd | ||
|
|
ffba0e0158 | ||
|
|
324b648de8 | ||
|
|
9ef97836c9 | ||
|
|
628c03634b | ||
|
|
315bef4639 | ||
|
|
610573256e | ||
|
|
976e123413 | ||
|
|
6f4c868336 | ||
|
|
33c3980e46 | ||
|
|
6d8580f67a | ||
|
|
506761d823 | ||
|
|
09f22b114c | ||
|
|
9f0b8ff4c3 | ||
|
|
2764bbb5a9 | ||
|
|
3202b7d45c | ||
|
|
19e677ae74 | ||
|
|
9cc6de9e65 | ||
|
|
0988474d87 | ||
|
|
d564e4a3c1 | ||
|
|
839b0156a9 | ||
|
|
92d500d4b5 | ||
|
|
1944a78443 | ||
|
|
e11d81376c | ||
|
|
3c7a5bff61 | ||
|
|
a41476ab32 | ||
|
|
1118cd030a | ||
|
|
e6e11ddcb0 | ||
|
|
5c5074c5c7 | ||
|
|
d3f092a736 | ||
|
|
70efd3a1cd | ||
|
|
fd9f46bcc7 | ||
|
|
6f203bc4ea | ||
|
|
c25d98bc58 | ||
|
|
4290a2cc10 | ||
|
|
b3c15ce93c | ||
|
|
cb8ee10292 | ||
|
|
3df59ca6f9 | ||
|
|
6a4d7fa108 | ||
|
|
de51fc2fd4 | ||
|
|
c61a63dbb6 | ||
|
|
e0282629e3 | ||
|
|
fe58e86c6c | ||
|
|
abd64bc495 | ||
|
|
2d5246e7fa | ||
|
|
94a65f0d99 | ||
|
|
2e5973e7cc | ||
|
|
a5d77ec5af | ||
|
|
a2855c9442 | ||
|
|
670e9058f1 | ||
|
|
81f8f94dd4 | ||
|
|
956e89d10a | ||
|
|
ec0297050a | ||
|
|
258552e544 | ||
|
|
17fd82ffa1 | ||
|
|
3fa01ef7a9 | ||
|
|
ee743ca042 | ||
|
|
39a3cb8b09 | ||
|
|
2db7875da7 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,9 +11,7 @@ src/gnuk.elf
|
||||
src/gnuk.hex
|
||||
src/gnuk.map
|
||||
src/*.inc
|
||||
regnual/sys.h
|
||||
regnual/regnual.bin
|
||||
regnual/regnual.hex
|
||||
regnual/regnual.elf
|
||||
regnual/usb_lld.c
|
||||
regnual/usb_lld.h
|
||||
doc/_build
|
||||
|
||||
644
ChangeLog
644
ChangeLog
@@ -1,3 +1,647 @@
|
||||
2013-03-15 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 1.0.4.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
* regnual/regnual.ld (.bss): Put at RAM1. This makes reGNUal can
|
||||
be loaded on the lower address.
|
||||
|
||||
* regnual/sys.c (entry): Don't change SP. Put alignment.
|
||||
|
||||
* regnual/regnual.c (usb_cb_get_descriptor): Fix adding break.
|
||||
|
||||
2013-03-14 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 1.0.3.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.start): Call write_debug_reg to run
|
||||
the core again.
|
||||
|
||||
2013-03-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* ChibiOS_2.0.8/os/ports/GCC/ARMCMx/cmsis/core_cm3.c (__STREXB)
|
||||
(__STREXH, __STREXW): Specify R2 to avoid %0 and %2 will be same
|
||||
register. This is for newer GNU binutils (>= 2.22).
|
||||
|
||||
2013-03-12 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.exit_from_debug_swd)
|
||||
(stlinkv2.exit_from_debug_swim): New.
|
||||
(stlinkv2.start): Call exit_from_debug_swd or
|
||||
exit_from_debug_swim.
|
||||
|
||||
2013-03-09 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/main.c (calculate_regnual_entry_address): New.
|
||||
(main): Use calculate_regnual_entry_address for entry point.
|
||||
|
||||
2013-03-08 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Relocatable reGNUal.
|
||||
|
||||
* regnual/regnual.ld (MEMORY): 0x1400 was the value of Gnuk 1.0.1.
|
||||
Keep this value.
|
||||
(.text): Include .text.entry next to the .vectors.
|
||||
(.got): New.
|
||||
|
||||
* regnual/sys.c (entry): Now, it's at .text.entry section.
|
||||
Do relocations.
|
||||
Don't use absolute values which causes relocations, but
|
||||
access at GOT.
|
||||
|
||||
* regnual/Makefile (CFLAGS): Add -fpie.
|
||||
|
||||
2013-03-07 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb_stm32f103.c (handle_setup0): Fix selecting handler.
|
||||
|
||||
Follow the USB stack change.
|
||||
|
||||
* regnual/regnual.c (usb_cb_device_reset): Rename from
|
||||
regnual_device_reset.
|
||||
(mem): Change type to uint32_t.
|
||||
(mem_info): Removed.
|
||||
(fetch): Avoid pointer punning.
|
||||
(usb_cb_ctrl_write_finish): Rename from regnual_ctrl_write_finish.
|
||||
(usb_cb_setup): Rename from regnual_setup.
|
||||
(usb_cb_get_descriptor): Rename from regnual_get_descriptor.
|
||||
(usb_cb_handle_event): Rename regnual_usb_event.
|
||||
(usb_cb_interface): Rename regnual_interface.
|
||||
(Device_Method): Remove.
|
||||
(usb_cb_get_descriptor): Not use struct Descriptor.
|
||||
|
||||
2013-03-06 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
USB stack implementation improvement.
|
||||
|
||||
* src/usb_lld.c (Device_Method, method_p): Remove.
|
||||
(usb_interrupt_handler): Call usb_cb_device_reset.
|
||||
(std_get_descriptor): Call usb_cb_get_descriptor.
|
||||
(std_set_configuration): Call usb_cb_handle_event.
|
||||
(std_get_status, std_get_interface, std_set_interface): Call
|
||||
usb_cb_interface.
|
||||
(handle_setup0): Call usb_cb_setup.
|
||||
(handle_in0): Call usb_cb_handle_event and
|
||||
usb_cb_ctrl_write_finish.
|
||||
(request_handler): Remove.
|
||||
(handle_setup0): Call std_* directly, not indirectly by
|
||||
request_handler.
|
||||
(ep_intr_handler_IN, ep_intr_handler_OUT): Remove.
|
||||
(usb_handle_transfer): Call EP*_Callback directly, not indirectly
|
||||
by ep_intr_handler_IN, ep_intr_handler_OUT.
|
||||
|
||||
* src/usb_lld.h (struct usb_device_method, Device_Method): Remove.
|
||||
(usb_cb_device_reset, usb_cb_ctrl_write_finish)
|
||||
(usb_cb_setup, usb_cb_get_descriptor, usb_cb_handle_event)
|
||||
(usb_cb_interface): Define callbacks.
|
||||
(usb_initial_feature): New.
|
||||
(struct Descriptor): Move to ...
|
||||
* src/usb_desc.c: ... here.
|
||||
(usb_initial_feature): New.
|
||||
(usb_cb_get_descriptor): Rename from gnuk_get_descriptor and move
|
||||
from usb_ctrl.c.
|
||||
|
||||
* src/usb_ctrl.c (usb_cb_device_reset): Rename from
|
||||
gnuk_device_reset.
|
||||
(usb_cb_setup): Rename from gnuk_setup.
|
||||
(usb_cb_ctrl_write_finish): Rename from gnuk_ctrl_write_finish.
|
||||
(usb_cb_event): Rename from gnuk_usb_event.
|
||||
(usb_cb_interface): Rename from gnuk_interface.
|
||||
(Device_Method): Remove.
|
||||
|
||||
* src/main.c (main): Use usb_initial_feature.
|
||||
|
||||
2013-02-27 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb-icc.c (set_sw1sw2): Arguments are C and CHUNK_LEN.
|
||||
Fix reporting remaining bytes.
|
||||
(icc_send_data_block_gr): Follow the arguments change of
|
||||
set_sw1sw2.
|
||||
|
||||
2013-02-25 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/configure: Correct typo in help text.
|
||||
|
||||
* src/gnuk.h (struct key_data_internal): Use uint32_t.
|
||||
* src/openpgp-do.c (do_openpgpcard_aid): Fix calculation of VID.
|
||||
(compute_key_data_checksum): Don't use type-punning pointer.
|
||||
(gpg_do_write_prvkey): Use coercing to char *.
|
||||
|
||||
2013-02-22 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (GPG_DO_DISCRETIONARY, cmp_discretionary): New.
|
||||
(cmp_app_data): Change to factor out GPG_DO_DISCRETIONARY.
|
||||
(gpg_do_table): Add GPG_DO_DISCRETIONARY.
|
||||
|
||||
2013-02-15 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 1.0.2.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
2013-02-14 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/002_get_data_static.feature: Value of extended
|
||||
capabilities changed.
|
||||
* test/features/402_get_data_static.feature: Ditto.
|
||||
* test/features/802_get_data_static.feature: Ditto.
|
||||
|
||||
* src/openpgp.c (cmd_write_binary): Move erasing page of update
|
||||
keys to...
|
||||
(modify_binary): ...here.
|
||||
|
||||
* src/flash.c (flash_write_binary): Handle removal of update keys.
|
||||
|
||||
2013-02-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_get_challenge): Handle Le field.
|
||||
|
||||
* src/openpgp-do.c (extended_capabilities): Fix for GET CHALLENGE.
|
||||
|
||||
* src/gnuk.h (CHALLENGE_LEN): Moved here (was: openpgp.c).
|
||||
|
||||
* tool/gnuk_token.py (iso7816_compose): Add Le field.
|
||||
|
||||
2013-01-30 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_external_authenticate): Fix off-by-one error.
|
||||
|
||||
* tool/gnuk_token.py (gnuk_token.cmd_external_authenticate): Add
|
||||
KEYNO to the arguments.
|
||||
|
||||
* tool/upgrade_by_passwd.py (main): Explicitly say it's KEYNO.
|
||||
|
||||
2013-01-28 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (gpg_pw_get_retry_counter): New.
|
||||
* src/openpgp.c (cmd_verify): Implement VERIFY with empty data.
|
||||
|
||||
2013-01-22 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/pinpadtest.py (Card.cmd_vega_alpha_disable_empty_verify):
|
||||
New.
|
||||
(main): call cmd_vega_alpha_disable_empty_verify if it's
|
||||
COVADIS_VEGA_ALPHA.
|
||||
|
||||
2013-01-21 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/pageant_proxy_to_gpg.py: New.
|
||||
* tool/sexp.py: New.
|
||||
|
||||
2013-01-20 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gpg_agent.py: New.
|
||||
|
||||
2013-01-11 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/pinpadtest.py: Add fixed length input.
|
||||
|
||||
2012-12-25 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/rsa.py: New.
|
||||
|
||||
* tool/rsa_example.key: New. Example RSA key information.
|
||||
|
||||
* tool/upgrade_by_passwd.py: New.
|
||||
|
||||
2012-12-19 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/Makefile.in (USE_OPT): -O3 and -Os (was: -O2).
|
||||
|
||||
* tool/gnuk_token.py (gnuk_token.stop_gnuk, gnuk_token.mem_info)
|
||||
(gnuk_token.download, gnuk_token.execute)
|
||||
(gnuk_token.cmd_get_challenge)
|
||||
(gnuk_token.cmd_external_authenticate): New.
|
||||
(gnuk_devices_by_vidpid): New.
|
||||
(regnual): New.
|
||||
|
||||
2012-12-18 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/gnuk.py: Remove.
|
||||
|
||||
* test/features/steps.py: Use tool/gnuk_token.py.
|
||||
|
||||
* tool/gnuk_put_binary_libusb.py: Use gnuk_token.py.
|
||||
(main): Follow the API change.
|
||||
|
||||
* tool/gnuk_token.py (list_to_string): New.
|
||||
(gnuk_token.get_string, gnuk_token.increment_seq)
|
||||
(gnuk_token.reset_device, gnuk_token.release_gnuk): New.
|
||||
(gnuk_token.icc_power_on): Set self.atr and it's now string.
|
||||
(gnuk_token.icc_send_cmd): Handle time extension.
|
||||
(gnuk_token.cmd_get_response): Return string (was: list).
|
||||
(gnuk_token.cmd_get_data): Return "" when success.
|
||||
(gnuk_token.cmd_change_reference_data, gnuk_token.cmd_put_data)
|
||||
(gnuk_token.cmd_put_data_odd)
|
||||
(gnuk_token.cmd_reset_retry_counter, gnuk_token.cmd_pso)
|
||||
(gnuk_token.cmd_pso_longdata)
|
||||
(gnuk_token.cmd_internal_authenticate, gnuk_token.cmd_genkey)
|
||||
(gnuk_token.cmd_get_public_key): New.
|
||||
(compare): New.
|
||||
(get_gnuk_device): New.
|
||||
|
||||
2012-12-14 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Check password length
|
||||
for admin less mode.
|
||||
|
||||
2012-12-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (gpg_do_put_data): Add GPG_SUCCESS for
|
||||
completeness (it worked because of lower layer goodness).
|
||||
|
||||
2012-12-12 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_token.py: Add module imports.
|
||||
|
||||
* tool/gnuk_remove_keys.py (main): Fix data object number
|
||||
for KGTIME_SIG, KGTIME_DEC and KGTIME_AUT.
|
||||
|
||||
* tool/gnuk_remove_keys_libusb.py (main): Likewise.
|
||||
|
||||
2012-12-05 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_remove_keys_libusb.py: New.
|
||||
* tool/gnuk_token.py: New.
|
||||
|
||||
2012-11-07 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb-icc.c (icc_send_data_block_internal): New.
|
||||
(icc_send_data_block_time_extension): New.
|
||||
(icc_handle_timeout): Use icc_send_data_block_time_extension.
|
||||
(icc_send_data_block): Only one argument.
|
||||
(USBthread): Follow the change.
|
||||
|
||||
2012-11-01 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_upgrade.py (main): New option '-k' to specify keygrip
|
||||
for non-smartcard key.
|
||||
(gpg_sign): Support non-smartcard key.
|
||||
|
||||
2012-10-31 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/get_raw_public_key.py: New.
|
||||
|
||||
2012-10-26 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* GNUK_USB_DEVICE_ID (Product_STRING): It's considered better not
|
||||
to include vendor name. Change the name to "Gnuk Token" (was:
|
||||
FSIJ USB Token).
|
||||
|
||||
2012-10-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* boards/STBEE_MINI/board.c [!DFU_SUPPORT] (hwinit1): Don't run
|
||||
when "user switch" is pushed. This is for JTAG/SWD debugger.
|
||||
|
||||
2012-09-25 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/stlinkv2.py (main): Print out option bytes value.
|
||||
Call reset_sys before blank_check.
|
||||
|
||||
2012-09-18 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.option_bytes_erase)
|
||||
(stlinkv2.flash_erase_all, stlinkv2.flash_erase_page): : Fix
|
||||
OperationFailure (was OperationError).
|
||||
(main): Call option_bytes_erase if it's not 0xff.
|
||||
|
||||
2012-09-12 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/sha256.c: Include <stdint.h>.
|
||||
|
||||
* src/sha256.h (SHA256_DIGEST_SIZE, SHA256_BLOCK_SIZE): Move
|
||||
from sha256.c.
|
||||
|
||||
2012-08-29 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/hub_ctrl.py (__main__): Fix to busnum (was: bunum).
|
||||
Thanks to Henry Hu.
|
||||
|
||||
2012-08-03 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 1.0.1.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
* src/main.c (ID_OFFSET): Fix.
|
||||
|
||||
2012-08-02 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/gnuk.py (gnuk_token.get_string): New.
|
||||
* test/features/991_version_string.feature: New.
|
||||
|
||||
2012-07-21 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 1.0.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
Documentation by Sphinx.
|
||||
* doc/Makefile: New.
|
||||
* doc/note: Old notes are moved here.
|
||||
|
||||
2012-07-20 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/002_get_data_static.feature: Support CERTDO enabled
|
||||
Gnuk for the test of extended capabilities.
|
||||
* test/features/802_get_data_static.feature: Ditto.
|
||||
* test/features/402_get_data_static.feature: Ditto.
|
||||
|
||||
2012-07-10 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/*: Add test cases for PW1/PW3 of factory settings.
|
||||
|
||||
* test/features/202_keygen.feature: Add PSO signature test after
|
||||
keygen.
|
||||
* test/features/602_keygen.feature: Ditto.
|
||||
|
||||
Bug fix.
|
||||
* src/openpgp-do.c (gpg_do_write_prvkey): Don't call ac_reset_*
|
||||
here.
|
||||
(proc_key_import): But call ac_reset_* here.
|
||||
(gpg_do_keygen): Load private key for signing.
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.usb_disconnect): New.
|
||||
|
||||
2012-07-09 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_pso): For decryption, return error sooner for
|
||||
invalid data.
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.setup_gpio): Fix GPIOB_CRL.
|
||||
|
||||
* test/rsa_keys.py (integer_to_bytes_256): Rename from
|
||||
integer_to_bytes and it should be exactly 256-byte long.
|
||||
|
||||
2012-07-06 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.21.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
* boards/FST_01/board.h (VAL_GPIOACRL): Change for SPI flash.
|
||||
* tool/stlinkv2.py (stlinkv2.setup_gpio): Likewise.
|
||||
(stlinkv2.spi_flash_init, stlinkv2.spi_flash_select)
|
||||
(stlinkv2.spi_flash_sendbyte, stlinkv2.spi_flash_read_id): New.
|
||||
(main): Add SPI flash ROM id check.
|
||||
|
||||
2012-07-05 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/call-rsa.c (rsa_sign, rsa_decrypt): Don't need to setup N.
|
||||
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_check_pubkey)
|
||||
(rsa_check_privkey): Ifdef-out.
|
||||
|
||||
More tests.
|
||||
* test/*: Add tests for admin-less mode.
|
||||
* test/features/990_reset_passphrase.feature: This is now for
|
||||
admin-less mode.
|
||||
* test/features/970_key_removal.feature: Ditto.
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Call ac_reset_admin when
|
||||
admin-less mode.
|
||||
(cmd_reset_user_password): Likewise.
|
||||
|
||||
* src/ac.c (ac_reset_admin, ac_fini): Clear ADMIN_AUTHORIZED.
|
||||
|
||||
Bug fix.
|
||||
* src/ac.c (verify_admin): Call s2k with ADMIN_AUTHORIZED.
|
||||
|
||||
2012-07-04 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Bug fixes.
|
||||
* src/ac.c (verify_admin_0): Compare PW_LEN and BUF_LEN.
|
||||
|
||||
* src/openpgp-do.c (gpg_do_chks_prvkey): Set do_ptr to NULL before
|
||||
calling flash_do_write (which might cause GC).
|
||||
(gpg_do_put_data, gpg_do_write_simple): Likewise.
|
||||
|
||||
* src/openpgp.c (cmd_reset_user_password): Write to
|
||||
DO_KEYSTRING_PW1.
|
||||
|
||||
2012-07-03 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/040_passphrase_change.feature: New.
|
||||
* test/features/203_passphrase_change.feature: New.
|
||||
* test/features/210_compute_signature.feature: Rename (was:
|
||||
203_compute_signature.feature)
|
||||
* test/features/211_decryption.feature: Rename (was:
|
||||
204_decryption.feature)
|
||||
|
||||
2012-07-02 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.__init__): Don't call setAltInterface.
|
||||
|
||||
2012-06-30 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (s2k): New.
|
||||
(resetcode_s2k): Remove.
|
||||
(cmd_reset_user_password, cmd_change_password): Use s2k (was:
|
||||
sha256 directly or resetcode_s2k).
|
||||
* src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey):
|
||||
Likewise.
|
||||
* src/ac.c (verify_user_0, verify_admin): Likewise.
|
||||
|
||||
2012-06-29 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* regnual/Makefile: Don't copy usb_lld.c.
|
||||
|
||||
2012-06-28 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/204_decryption.feature: New.
|
||||
* test/features/203_compute_signature.feature: New.
|
||||
* test/features/202_keygen.feature: New.
|
||||
* test/features/201_setup_passphrase.feature: New.
|
||||
* test/features/200_key_removal.feature: New.
|
||||
|
||||
* test/rsa_keys.py (verify_signature): New.
|
||||
(encrypt_with_pubkey): New.
|
||||
|
||||
* test/gnuk.py (gnuk_token): New method: increment_seq.
|
||||
(gnuk_token.icc_send_cmd): Handle timeout.
|
||||
(gnuk_token.cmd_genkey): New.
|
||||
(gnuk_token.cmd_get_public_key): New.
|
||||
|
||||
2012-06-27 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/101_decryption.feature: New.
|
||||
* test/features/100_compute_signature.feature: New.
|
||||
|
||||
* src/openpgp-do.c (gpg_do_chks_prvkey): Call flash_do_release before
|
||||
flash_do_write.
|
||||
(gpg_do_write_prvkey): Bug fix when GC occurs.
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Support resetting to
|
||||
factory setting of PW3.
|
||||
|
||||
* src/openpgp-do.c (gpg_do_write_prvkey): Don't reset signagure
|
||||
counter here.
|
||||
(proc_key_import): But reset here.
|
||||
Call ac_reset_* when key is imported.
|
||||
|
||||
2012-06-26 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test: New.
|
||||
|
||||
2012-06-25 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/usb_strings.py: New.
|
||||
|
||||
2012-06-22 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.blank_check): Add blank check of
|
||||
Flash ROM.
|
||||
|
||||
2012-06-21 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/asm-thumb/blank_check.S: New.
|
||||
|
||||
2012-06-20 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
ST-Link/V2 flash ROM writer.
|
||||
* tool/stlinkv2.py: New.
|
||||
* tool/asm-thumb/opt_bytes_write.S: New.
|
||||
* tool/asm-thumb/flash_write.S: New.
|
||||
|
||||
2012-06-19 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.20.
|
||||
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
2012-06-18 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
LED display output change.
|
||||
* src/main.c (MAIN_TIMEOUT_INTERVAL): New.
|
||||
(LED_TIMEOUT_INTERVAL, etc.): New values.
|
||||
(main_mode, display_interaction): Remove.
|
||||
(led_inverted, emit_led): New.
|
||||
(display_status_code): Use emit_led.
|
||||
(led_blink): Use LED_* for SPEC.
|
||||
(main, fatal): New LED display output.
|
||||
* src/gnuk.h (LED_ONESHOT, LED_TWOSHOTS, LED_SHOW_STATUS)
|
||||
(LED_START_COMMAND, LED_FINISH_COMMAND, LED_FATAL): New semantics.
|
||||
(main_thread): Remove.
|
||||
* src/openpgp-do.c (gpg_do_keygen): Don't touch LED here.
|
||||
* src/openpgp.c (get_pinpad_input): Call led_blink.
|
||||
(cmd_pso, cmd_internal_authenticate): Don't touch LED here.
|
||||
(GPGthread): Call led_blink.
|
||||
* src/pin-cir.c (pinpad_getline): Change arg of led_blink.
|
||||
* src/pin-dnd.c (pinpad_getline): Ditto.
|
||||
* src/usb-icc.c (icc_handle_timeout): Ditto.
|
||||
(icc_send_status): Call led_blink.
|
||||
* src/usb_ctrl.c (gnuk_usb_event): Don't touch LED here.
|
||||
|
||||
2012-06-16 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Use SHA256 format for "external authenticate".
|
||||
* tool/gnuk_upgrade.py (gpg_sign): SHA256 sign by "SCD PKAUTH".
|
||||
(main): Not specify keygrip, but always use key for authentication.
|
||||
* src/call-rsa.c (rsa_verify): It is SHA256 format (was: SHA1).
|
||||
* src/openpgp.c (cmd_get_challenge): Don't add chip-id prefix.
|
||||
(cmd_external_authenticate): Likewise.
|
||||
|
||||
2012-06-15 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/random.c (random_bytes_free): Clear out random bytes.
|
||||
|
||||
More protection improvements.
|
||||
* src/random.c (RANDOM_BYTES_LENGTH): It's 32 now (was: 16).
|
||||
* src/gnuk.h (struct key_data_internal): Remove check, random,
|
||||
magic. Add checksum.
|
||||
(struct prvkey_data): Remove crm_encrypted. Add iv and
|
||||
checksum_encrypted.
|
||||
* src/openpgp-do.c (encrypt, decrypt): Add IV argument.
|
||||
(encrypt_dek, decrypt_dek): New. It's in ECB mode.
|
||||
(compute_key_data_checksum): New.
|
||||
(gpg_do_load_prvkey): Handle initial vector and checksum.
|
||||
Use decrypt_dek to decrypt DEK. Clear DEK after use.
|
||||
(calc_check32):Remove.
|
||||
(gpg_do_write_prvkey): Use encrypt_dek to encrypt DEK.
|
||||
(gpg_do_chks_prvkey): Likewise.
|
||||
|
||||
* polarssl-0.14.0/include/polarssl/aes.h (aes_crypt_cbc)
|
||||
* polarssl-0.14.0/library/aes.c (aes_crypt_cbc): ifdef-out.
|
||||
|
||||
* src/configure (--enable-pinpad): Deprecate DND.
|
||||
|
||||
2012-06-14 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Protection improvement.
|
||||
* src/openpgp.c (resetcode_s2k): New.
|
||||
(cmd_reset_user_password): Use resetcode_s2k.
|
||||
* src/openpgp-do.c (proc_resetting_code): Likewise.
|
||||
|
||||
* src/sha256.c (sha256_finish): Clear out CTX at the end.
|
||||
|
||||
* src/call-rsa.c (rsa_sign, rsa_decrypt, rsa_verify): Use
|
||||
mpi_lset (was: mpi_read_string).
|
||||
* polarssl-0.14.0/library/bignum.c (mpi_get_digit)
|
||||
(mpi_read_string): ifdef-out.
|
||||
|
||||
KDF is now SHA-256 (was: SHA1).
|
||||
* src/sha256.c: New file. Based on the implementation by Dr Brian
|
||||
Gladman.
|
||||
* src/openpgp.c (cmd_change_password, cmd_reset_user_password):
|
||||
Use sha256.
|
||||
* src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey): Likewise.
|
||||
* src/ac.c (verify_user_0, calc_md, verify_admin): Likewise.
|
||||
* src/crypt.mk (CRYPTSRC): Add sha256.c, removing sha1.c.
|
||||
* src/gnuk.h (KEYSTRING_MD_SIZE): It's 32 for SHA-256.
|
||||
|
||||
2012-06-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Bug fixes.
|
||||
* src/main.c (display_interaction): Assign to main_mode.
|
||||
* src/openpgp.c (cmd_change_password): Bug fix for admin less mode
|
||||
to admin full mode. Variable who_old should be admin_authorized.
|
||||
|
||||
Key generation is configure option.
|
||||
* src/configure (keygen): Add --enable-keygen option.
|
||||
* src/Makefile.in (UDEFS): Add definition of KEYGEN_SUPPORT.
|
||||
* src/call-rsa.c [KEYGEN_SUPPORT] (rsa_genkey): Conditionalize.
|
||||
* src/random.c [KEYGEN_SUPPORT] (random_byte): Ditto.
|
||||
* src/openpgp.c [KEYGEN_SUPPORT] (cmd_pgp_gakp): Ditto.
|
||||
* src/openpgp-do.c [KEYGEN_SUPPORT] (gpg_do_keygen): Ditto.
|
||||
* polarssl-0.14.0/include/polarssl/config.h: Ditto.
|
||||
* polarssl-0.14.0/library/bignum.c [POLARSSL_GENPRIME]
|
||||
(mpi_inv_mod): Unconditionalize.
|
||||
|
||||
2012-06-08 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* polarssl-0.14.0/library/bignum.c (mpi_cmp_mpi): Bug fix.
|
||||
Though it doesn't matter for Gnuk usage.
|
||||
|
||||
Emit LED light while computation (or asking user input).
|
||||
* src/usb-icc.c (icc_handle_timeout): Call led_blink.
|
||||
* src/openpgp.c (cmd_pso, cmd_internal_authenticate): Call
|
||||
LED_WAIT_MODE, LED_STATUS_MODE to show "it's under computation".
|
||||
* src/openpgp-do.c (gpg_do_keygen): Ditto.
|
||||
* src/gnuk.h (LED_WAIT_MODE): Rename (was: LED_INPUT_MODE).
|
||||
* src/main.c (display_interaction): Change the behavior of LED,
|
||||
now, it's mostly ON (was: mostly OFF).
|
||||
|
||||
2012-06-07 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_internal_authenticate): Add check for input
|
||||
length.
|
||||
|
||||
Implement key generation.
|
||||
* src/openpgp.c (cmd_pgp_gakp): Call gpg_do_keygen.
|
||||
* src/openpgp-do.c (proc_key_import): Call with modulus = NULL.
|
||||
(gpg_do_keygen): New function.
|
||||
(gpg_reset_digital_signature_counter): New function.
|
||||
(gpg_do_write_prvkey): New argument MODULUS. Call
|
||||
gpg_reset_digital_signature_counter.
|
||||
* src/call-rsa.c (rsa_genkey): New function.
|
||||
* src/random.c (random_byte): New function.
|
||||
|
||||
PolarSSL modification.
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_gen_key): Don't set D, DP,
|
||||
DQ, and QP. It's only for key generation.
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_gen_key, rsa_pkcs1_encrypt):
|
||||
Change f_rng function return type.
|
||||
* polarssl-0.14.0/include/polarssl/rsa.h: Likewise.
|
||||
* polarssl-0.14.0/library/bignum.c (mpi_is_prime, mpi_gen_prime):
|
||||
Change f_rng function return type.
|
||||
* polarssl-0.14.0/include/polarssl/bignum.h: Likewise.
|
||||
|
||||
2012-06-06 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.19.
|
||||
|
||||
@@ -731,7 +731,7 @@ uint32_t __LDREXW(uint32_t *addr)
|
||||
*/
|
||||
uint32_t __STREXB(uint8_t value, uint8_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
register uint32_t result asm ("r2");
|
||||
|
||||
__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
@@ -748,7 +748,7 @@ uint32_t __STREXB(uint8_t value, uint8_t *addr)
|
||||
*/
|
||||
uint32_t __STREXH(uint16_t value, uint16_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
register uint32_t result asm ("r2");
|
||||
|
||||
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
@@ -765,7 +765,7 @@ uint32_t __STREXH(uint16_t value, uint16_t *addr)
|
||||
*/
|
||||
uint32_t __STREXW(uint32_t value, uint32_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
register uint32_t result asm ("r2");
|
||||
|
||||
__ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# VID:PID bcdDev Product_STRING Vender_STRING
|
||||
234b:0000 0200 FSIJ USB Token Free Software Initiative of Japan
|
||||
234b:0000 0200 Gnuk Token Free Software Initiative of Japan
|
||||
##########<TAB> ##<TAB> ##########<TAB> #################
|
||||
|
||||
140
NEWS
140
NEWS
@@ -1,5 +1,145 @@
|
||||
Gnuk NEWS - User visible changes
|
||||
|
||||
* Major changes in Gnuk 1.0.4
|
||||
|
||||
Released 2013-03-15, by NIIBE Yutaka
|
||||
|
||||
** Relocatable reGNUal, really
|
||||
In 1.0.3, reGNUal was not fully relocatable. It worked loaded on higher
|
||||
address, but didn't work for lower address. This was fixed.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.0.3
|
||||
|
||||
Released 2013-03-14, by NIIBE Yutaka
|
||||
|
||||
** Relocatable reGNUal
|
||||
The upgrade helper, reGNUal, is now relocatable (other than the first
|
||||
vector table). It runs well when loaded at different address. This
|
||||
makes the upgrade procedure more stable.
|
||||
|
||||
** Compilation by newer GNU Toolchain
|
||||
Now, Gnuk can be compiled with newer GNU Toolchain, specifically GCC
|
||||
4.7.x and GNU Binutils 2.22. Old versions of Gnuk had problem for
|
||||
ChibiOS_2.0.8/os/ports/GCC/ARMCMx/cmsis/core_cm3.c, which was fixed.
|
||||
|
||||
** Data object 0x0073
|
||||
Data object 0x0073 is now available.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.0.2
|
||||
|
||||
Released 2013-02-15, by NIIBE Yutaka
|
||||
|
||||
** Product string is now "Gnuk Token" (was: "FSIJ USB Token")
|
||||
Since the USB ID Repository suggests not including vendor name
|
||||
in product string, we changed the product string.
|
||||
|
||||
** New tool (experimental): test/upgrade_by_passwd.py
|
||||
This is the tool to install new firmware to Gnuk Token, provided
|
||||
that it's just shipped from factory (and nothing changed). It
|
||||
authenticate as admin by factory setting, register a public key
|
||||
for firmware upgrade, and then, does firmware upgrade.
|
||||
|
||||
** tool/gnuk_upgrade.py supports '-k' option
|
||||
It now supports RSA key on the host PC (not the one on the Token).
|
||||
|
||||
** New tool: tool/get_raw_public_key.py
|
||||
This is a script to dump raw data of RSA public key, which is useful
|
||||
to register to Gnuk Token as a firmware upgrade key.
|
||||
|
||||
** New tool: tool/gnuk_remove_keys_libusb.py
|
||||
This tool is libusb version of gnuk_remove_keys.py. Besides, a bug in
|
||||
gnuk_remove_keys.py was fixed.
|
||||
|
||||
** CCID protocol fix
|
||||
When time extension is requested by Gnuk Token to host PC, argument
|
||||
field was 0, which was wrong (but it works for most PC/SC
|
||||
implementations and GnuPG internal driver). Now it's 1, which means
|
||||
1*BWT.
|
||||
|
||||
** OpenPGP card protocol enhancement
|
||||
Now, VERIFY command accepts empty data and returns remaining trial
|
||||
counts, or 0x9000 (OK) when it's already authenticated. This is
|
||||
useful for application to synchronize card's authentication status.
|
||||
|
||||
** Extended Capabilities
|
||||
Since Gnuk supports GET CHALLENGE command, the flag for GET CHALLENGE
|
||||
in extended capabilities are now on.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.0.1
|
||||
|
||||
Released 2012-08-03, by NIIBE Yutaka
|
||||
|
||||
** USB SerialNumber String
|
||||
In 1.0, it has a bug for USB SerialNumber String. It has been fixed
|
||||
in 1.0.1.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.0
|
||||
|
||||
Released 2012-07-21, by NIIBE Yutaka
|
||||
|
||||
This is bug fixes only release.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.21
|
||||
|
||||
Released 2012-07-06, by NIIBE Yutaka
|
||||
|
||||
** Test suite
|
||||
A functinality test suite is added under test/ directory.
|
||||
|
||||
** New tool: stlinkv2.py
|
||||
This tool is SWD flash ROM writer with ST-Link/V2.
|
||||
|
||||
** New tool: usb_strings.py
|
||||
This tool is to dump USB strings, which include revision detail and config
|
||||
options.
|
||||
|
||||
** Protection improvement (even when internal data is disclosed)
|
||||
Even if PW1 and PW3 is same, content of encrypted DEK is different
|
||||
now.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.20
|
||||
|
||||
Released 2012-06-19, by NIIBE Yutaka
|
||||
|
||||
** Key generation feature added
|
||||
Finally, key generation is supported. Note that it may be very slow.
|
||||
It may take a few minutes (or more) to generate two or three keys,
|
||||
when you are unlucky.
|
||||
|
||||
** DnD pinentry support is deprecated
|
||||
Once, DnD pinentry was considered a great feature, but it found that
|
||||
it is difficult to remember moves of folders.
|
||||
|
||||
** gnuk_upgrade.py assumes using another token for authentication
|
||||
Use of another token for authentication is assumed now. This is
|
||||
incompatible change. Note that when you upgrade a token of version
|
||||
0.19 to 0.20 (or later), you need gnuk_upgrade.py of version 0.19.
|
||||
|
||||
** KDF (Key Derivation Function) is now SHA-256
|
||||
Keystring is now computed by SHA-256 (it was SHA1 before).
|
||||
|
||||
** Protection improvements (even when internal data is disclosed)
|
||||
Three improvements. (1) Even if PW1 and Reset-code is same, content
|
||||
of encrypted DEK is different now. (2) DEK is now encrypted and
|
||||
decrypted by keystring in ECB mode (it was just a kind of xor by
|
||||
single block CFB mode). (3) Key data plus checksum are encrypted in
|
||||
CFB mode with initial vector (it will be able to switch OCB mode
|
||||
easily).
|
||||
|
||||
** LED display output change
|
||||
LED display output by Gnuk is now more reactive. It shows status code
|
||||
when it gets GET_STATUS message of CCID. When you communicate Gnuk by
|
||||
internal CCID driver of GnuPG (instead of PC/SC), and enable
|
||||
'debug-disable-ticker' option in .gnupg/scdaemon.conf, it is more
|
||||
silent now.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.19
|
||||
|
||||
Released 2012-06-06, by NIIBE Yutaka
|
||||
|
||||
177
README
177
README
@@ -1,26 +1,26 @@
|
||||
Gnuk - software for GnuPG USB Token
|
||||
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
|
||||
|
||||
Version 0.19
|
||||
2012-06-06
|
||||
Version 1.0.4
|
||||
2013-03-15
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
What's Gnuk?
|
||||
============
|
||||
|
||||
Gnuk is software implementation of a USB token for GNU Privacy Guard.
|
||||
Gnuk supports OpenPGP card protocol version 2, and it runs on
|
||||
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.
|
||||
|
||||
I wish that Gnuk will be a developer's soother who uses GnuPG. I have
|
||||
been nervous of storing secret key(s) on usual secondary storage.
|
||||
There is a solution with OpenPGP card, but it is not the choice for me
|
||||
to bring a card reader all the time. With Gnuk, this issue will be
|
||||
solved by a USB token which is small enough.
|
||||
There is a solution with OpenPGP card, but it is not the choice for
|
||||
me, as card reader is not common device. With Gnuk, this issue will
|
||||
be solved by a USB token.
|
||||
|
||||
Please look at the graphics of "gnuk.svg" for the software name. My
|
||||
son used to be with his NUK(R), always, everywhere. I am with a USB
|
||||
Token by "Gnuk", always, everywhere.
|
||||
son used to be with his NUK(R), always, everywhere. Now, I am with a
|
||||
USB Cryptographic Token by "Gnuk", always, everywhere.
|
||||
|
||||
|
||||
FAQ
|
||||
@@ -30,23 +30,19 @@ Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
|
||||
card 2.0, GPF Crypto Stick, etc.) ?
|
||||
http://www.g10code.de/p-card.html
|
||||
http://www.privacyfoundation.de/crypto_stick/
|
||||
A0: IMRHO, not quite, since there is no ready-to-use out-of-box Gnuk
|
||||
product yet. (It is welcome for me that some vendor will
|
||||
manufacture Gnuk USB Token. Even I can help design of hardware,
|
||||
if needed.)
|
||||
Good points for Gnuk are:
|
||||
A0: Good points of Gnuk are:
|
||||
* If you have skill of electronics and like DIY, you can build
|
||||
Gnuk Token cheaper (see Q8-A8).
|
||||
* You can study Gnuk to modify and to enhance. For example, you
|
||||
can implement your own authentication method with some sensor
|
||||
such as acceleration sensor.
|
||||
such as an acceleration sensor.
|
||||
* It is "of Free Software"; Gnuk is distributed under GPLv3+,
|
||||
"by Free Software"; Gnuk development requires only Free Software
|
||||
(GNU Toolchain, Python, etc.),
|
||||
"for Free Software"; Gnuk supports GnuPG.
|
||||
|
||||
Q1: What kind of key algorithm is supported?
|
||||
A1: Gnuk only supports 2048-bit RSA.
|
||||
A1: Gnuk version 1 only supports 2048-bit RSA.
|
||||
|
||||
Q2: How long does it take for digital signing?
|
||||
A2: It takes a second and a half or so.
|
||||
@@ -55,24 +51,25 @@ Q3: What's your recommendation for target board?
|
||||
A3: Orthodox choice is Olimex STM32-H103.
|
||||
If you have skill of electronics and like DIY, STM32 part of STM8S
|
||||
Discovery Kit might be the best choice.
|
||||
Currently FST-01 (Flying Stone Tiny 01) is under development,
|
||||
it will be the best choice, hopefully.
|
||||
FST-01 (Flying Stone Tiny 01) will be soon available for sale,
|
||||
and it will be the best choice, hopefully.
|
||||
|
||||
Q4: What's version of GnuPG are you using?
|
||||
A4: In Debian GNU/Linux system, I use gnupg 1.4.11-3 and gnupg-agent
|
||||
2.0.14-2 (in sid). With older versions, you can only sign with SHA1.
|
||||
2.0.18-2. With older versions, you can only sign with SHA1.
|
||||
See: http://www.fsij.org/gnuk/gnupg2-fixes-needed
|
||||
|
||||
Q5: What's version of pcscd and libccid are you using?
|
||||
A5: In Debian GNU/Linux system, I use pcscd 1.5.5-4 and libccid 1.3.11-2,
|
||||
which is in squeeze. Note that you need to edit /etc/libccid_Info.plist
|
||||
when using libccid (< 1.4.1).
|
||||
Note that pcscd and libccid are optional, you can use Gnuk without them.
|
||||
|
||||
Q6: What kinds of hardware is required for development?
|
||||
A6: You need a target board plus a JTAG debugger. If you just want to
|
||||
test Gnuk for target boards with DfuSe, JTAG debugger is not
|
||||
the requirement. Note that for real use, you need JTAG debugger
|
||||
to enable flash ROM protection.
|
||||
A6: You need a target board plus a JTAG/SWD debugger. If you just
|
||||
want to test Gnuk for target boards with DfuSe, JTAG debugger is
|
||||
not the requirement. Note that for real use, you need JTAG/SWD
|
||||
debugger to enable flash ROM protection.
|
||||
|
||||
Q7: How much does it cost?
|
||||
A7: Olimex STM32-H103 plus ARM-USB-TINY-H cost 70 Euro or so.
|
||||
@@ -83,13 +80,18 @@ A8: STM8S Discovery Kit costs 750 JPY (< $10 USD) only. You can build
|
||||
http://www.fsij.org/gnuk/jtag_dongle_ftdi2232
|
||||
|
||||
Q9: I got an error like "gpg: selecting openpgp failed: ec=6.108", what's up?
|
||||
|
||||
A9: GnuPG's SCDaemon has problems for handling insertion/removal of
|
||||
card/reader (problems are fixed in trunk). When your newly
|
||||
inserted token is not found by GnuPG, try killing scdaemon and let
|
||||
it to be invoked again. I do:
|
||||
$ killall -9 scdaemon
|
||||
card/reader (problems are fixed in trunk, and backported to 2.0
|
||||
branch, it will be 2.0.20). When your newly inserted token is not
|
||||
found by GnuPG, try killing scdaemon and let it to be invoked
|
||||
again. I do:
|
||||
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
and confirm scdaemon doesn't exist, then,
|
||||
$ gpg-connect-agent learn /bye
|
||||
|
||||
$ gpg-connect-agent learn /bye
|
||||
|
||||
Qa: With GNOME 2, I can't use Gnuk Token for SSH. How can we use it for SSH?
|
||||
Aa: You need to deactivate seahorse-agent and gnome-keyring, but use
|
||||
@@ -106,16 +108,23 @@ Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
|
||||
"GPG Password Agent" and "SSH Key Agent".
|
||||
|
||||
Qc: Do you know a good SWD debugger to connect FST-01 or something?
|
||||
Ac: STLink v2 is cheap one. See http://code.google.com/p/arm-utilities/
|
||||
for a control program.
|
||||
|
||||
Ac: ST-Link/V2 is cheap one and works, although it's not very good
|
||||
(for example, we have not yet been able to use OpenOCD to write
|
||||
option bytes of STM32F103). We have a tool/stlinkv2.py as a flash
|
||||
ROM writer program. Note that some "Discovery Kit" from ST has
|
||||
the feature of ST-Link/V2, but it is not as stable as the real
|
||||
one.
|
||||
|
||||
|
||||
Release notes
|
||||
=============
|
||||
|
||||
This is twentieth release of Gnuk. In this release, firmware upgrade
|
||||
feature is added. While it is daily use, some features (including
|
||||
firmware upgrade) are still considered experimental.
|
||||
This is a fourth minor release in version 1.0 series of Gnuk.
|
||||
|
||||
While it is daily use for a year and a half, some newly introduced
|
||||
features (including key generation and firmware upgrade) should be
|
||||
considered experimental.
|
||||
|
||||
Tested features are:
|
||||
|
||||
@@ -132,9 +141,17 @@ Tested features are:
|
||||
* Changing value of password status bytes (0x00C4): forcesig
|
||||
* Verify with pin pad
|
||||
* Modify with pin pad
|
||||
* Card holder certificate
|
||||
* Removal of keys (Overriding key import is not supported,
|
||||
* Card holder certificate (read)
|
||||
* Removal of keys
|
||||
(Overriding key import is not supported,
|
||||
but you can remove all keys to import again).
|
||||
* Key generation on device side
|
||||
|
||||
Original features of Gnuk, tested lightly:
|
||||
|
||||
* OpenPGP card serial number setup
|
||||
* Card holder certificate (write by UPDATE BINARY)
|
||||
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
|
||||
|
||||
It is known not-working well:
|
||||
|
||||
@@ -142,9 +159,11 @@ It is known not-working well:
|
||||
work well. Please make sure to disable DEBUG option if it
|
||||
doesn't work well.
|
||||
|
||||
Not supported feature(s):
|
||||
|
||||
* Key generation on device side
|
||||
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.
|
||||
|
||||
|
||||
Targets
|
||||
@@ -160,7 +179,7 @@ disable read from flash. For real use, please consider killing DfuSe
|
||||
and enabling read protection using JTAG debugger.
|
||||
|
||||
I think that it could run on Olimex STM32-P103, or other boards with
|
||||
STM32F103. Besides, we are porting it to STM32 Primer 2.
|
||||
STM32F103. Besides, we did an experiment with STM32 Primer 2.
|
||||
|
||||
For PIN-pad support, I connect a consumer IR receive module to STBee
|
||||
Mini and STM8S Discovery Kit, and use controller for TV. PIN
|
||||
@@ -174,13 +193,6 @@ Another PIN-pad support is connecting rotary encoder, push switch and
|
||||
7-segment LED display. Both of PIN verification and PIN modification
|
||||
are supported for this circuit extension.
|
||||
|
||||
Also, there is "DnDpinentry" support. This is using usual file
|
||||
manager for pinentry. User does "drag and drop" folders and it will
|
||||
be pin entry. This feature doesn't require any additional hardware.
|
||||
See doc/settings-for-DnDpinentry for your desktop configuration.
|
||||
However, this will be removed in future version, as it found it's
|
||||
not that useful.
|
||||
|
||||
Note that you need pinpad support for GnuPG to use PIN-pad enabled
|
||||
Gnuk. The pinpad support for GnuPG is currently in the master branch
|
||||
of GnuPG git repository at git.gnupg.org, and it's under evaluation.
|
||||
@@ -192,6 +204,11 @@ Souce code
|
||||
|
||||
Gnuk source code is under src/ directory.
|
||||
|
||||
Note that SHA-2 hash function implementation, src/sha256.c, is based
|
||||
on the original implementation by Dr. Brian Gladman. See:
|
||||
|
||||
http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
@@ -200,7 +217,7 @@ It is distributed under GNU General Public Licence version 3 or later
|
||||
(GPLv3+). Please see src/COPYING.
|
||||
|
||||
Please note that it is distributed with external source code too.
|
||||
Please read relevant licenses for external source code, too.
|
||||
Please read relevant licenses for external source code as well.
|
||||
|
||||
The author(s) of Gnuk expect users of Gnuk will be able to access the
|
||||
source code of Gnuk, so that users can study the code and can modify
|
||||
@@ -224,12 +241,18 @@ Gnuk is distributed with external source code.
|
||||
* polarssl-0.14.0/ -- PolarSSL 0.14.0
|
||||
|
||||
Taken from http://polarssl.org/
|
||||
We use PolarSSL for RSA computation, AES encryption/decryption
|
||||
and SHA-1 computation.
|
||||
We use PolarSSL for RSA computation, AES encryption/decryption.
|
||||
|
||||
The file include/polarssl/bn_mul.h is heavily modified for ARM
|
||||
Cortex-M3.
|
||||
|
||||
The files include/polarssl/rsa.h, library/rsa.c,
|
||||
include/polarssl/bignum.h, and library/bignum.c are modified so that
|
||||
f_rng function returns unsigned char.
|
||||
|
||||
The file library/rsa.c is modified so that it only computes things
|
||||
needed for Gnuk.
|
||||
|
||||
The file library/aes.c is modified so that some constants can
|
||||
go to .sys section.
|
||||
|
||||
@@ -243,9 +266,8 @@ please contact Niibe, so that it is listed to the file in the official
|
||||
release of the source code.
|
||||
|
||||
When you are modifing Gnuk and installing the binary to device, you
|
||||
should replace "FSIJ" in the string gnukStringSerial (usb_desc.c) to
|
||||
yours, so that the device will say it's modified version by device
|
||||
serial number.
|
||||
should replace the vendor string to yours, so that users can see it's
|
||||
not by original vendor, and it is modified version.
|
||||
|
||||
FSIJ allows you to use USB device ID of FSIJ (234b:0000) for devices
|
||||
with Gnuk under one of following conditions:
|
||||
@@ -276,15 +298,16 @@ respect users' freedom for computing. Please ask FSIJ for the
|
||||
license.
|
||||
|
||||
Otherwise, companies which want to distribute Gnuk devices, please use
|
||||
your own USB vendor ID and product ID. Note that please replace
|
||||
"FSIJ" in the string gnukStringSerial (usb_desc.c) to yours, when you
|
||||
modify Gnuk.
|
||||
your own USB vendor ID and product ID. Please replace vendor string
|
||||
and possibly product string to yours, when you modify Gnuk.
|
||||
|
||||
|
||||
Host Requirements
|
||||
=================
|
||||
|
||||
For GNU/Linux, libccid version >= 1.3.11 is recommended.
|
||||
For GNU/Linux, PC/SC service is an option, you can use GnuPG's
|
||||
internal CCID driver instead. If you chose using PC/SC service,
|
||||
libccid version >= 1.3.11 is recommended for GNU/Linux.
|
||||
|
||||
I think that it should not be requirment but the kernel version of my use is:
|
||||
Linux version 2.6.32-5-686 (Debian 2.6.32-18) (ben@decadent.org.uk) (gcc version 4.3.5 (Debian 4.3.5-2) ) #1 SMP Sat Jul 24 02:27:10 UTC 2010
|
||||
@@ -300,7 +323,7 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
||||
|
||||
See http://github.com/esden/summon-arm-toolchain/ (which includes fix
|
||||
of binutils-2.21.1) for preparation of GNU Toolchain for
|
||||
'arm-none-eabi' target.
|
||||
'arm-none-eabi' target. This is for GCC 4.5.
|
||||
|
||||
# Note that we need to link correct C library (for string functions).
|
||||
# For this purpose, Makefile.in contains following line:
|
||||
@@ -316,6 +339,12 @@ of binutils-2.21.1) for preparation of GNU Toolchain for
|
||||
# -mno-thumb-interwork option. This means that you should not
|
||||
# link C library which contains ARM (not Thumb) code.
|
||||
|
||||
Recently, there is "gcc-arm-embedded" project. See:
|
||||
|
||||
https://launchpad.net/gcc-arm-embedded/
|
||||
|
||||
It is based on GCC 4.6 or 4.7.
|
||||
|
||||
|
||||
Change directory to `src':
|
||||
|
||||
@@ -463,7 +492,7 @@ PyUSB (python-usb package in Debian).
|
||||
If scdaemon is running, please kill it, or you will get "Smartcard
|
||||
Exception" by "Sharing violation".
|
||||
|
||||
$ killall -9 scdaemon
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
In case of PyUSB tool, you need to stop pcscd.
|
||||
|
||||
@@ -542,11 +571,15 @@ This entry has been added into libccid 1.4.1 already ([r5425]).
|
||||
Testing Gnuk
|
||||
------------
|
||||
|
||||
Try following to see Gnuk runs:
|
||||
Type following command to see Gnuk runs:
|
||||
|
||||
$ gpg --card-status
|
||||
|
||||
|
||||
Besides, there is a functinality test under test/ directory. See
|
||||
test/README.
|
||||
|
||||
|
||||
Personalize the Token and import keys
|
||||
-------------------------------------
|
||||
|
||||
@@ -559,18 +592,21 @@ command is:
|
||||
Note that the factory setting of user password is "123456" and admin
|
||||
password is "12345678" as the specification.
|
||||
|
||||
No, Gnuk doesn't support key generation. You need to create your
|
||||
keys on your computer, and import them to Gnuk Token. After you create
|
||||
your keys (they must be 2048-bit RSA), you can import them.
|
||||
It is recommended to create your keys on your computer, and import
|
||||
them to Gnuk Token. After you create your keys (they must be 2048-bit
|
||||
RSA), you can import them.
|
||||
|
||||
For detail, please see doc/DEMO and doc/DEMO-2.
|
||||
Gnuk supports key generation, but this feature is young and should be
|
||||
considered experimental.
|
||||
|
||||
For detail, please see doc/note/DEMO and doc/note/DEMO-2.
|
||||
|
||||
Note that it make sense to preserve your keys on your computer so that
|
||||
you can import the keys (again) to (possibly another) Gnuk Token. In
|
||||
this case, you can use GnuPG's option to specify the home directory by
|
||||
--homedir.
|
||||
|
||||
After creating keys by:
|
||||
After creating keys on your computer by:
|
||||
|
||||
$ gpg --gen-key
|
||||
...
|
||||
@@ -625,13 +661,14 @@ linux/Documentation/usb/usbmon.txt
|
||||
Firmware update
|
||||
===============
|
||||
|
||||
See doc/firmware-update.
|
||||
See doc/note/firmware-update. Note that this is an experimental
|
||||
feature.
|
||||
|
||||
|
||||
Read-only Git Repository
|
||||
========================
|
||||
Git Repositories
|
||||
================
|
||||
|
||||
You can browse at http://www.gniibe.org/gitweb?p=gnuk.git;a=summary
|
||||
You can browse at: http://www.gniibe.org/gitweb?p=gnuk.git;a=summary
|
||||
|
||||
You can get it by:
|
||||
|
||||
@@ -642,6 +679,8 @@ or
|
||||
$ git clone http://www.gniibe.org/git/gnuk.git/
|
||||
|
||||
|
||||
Copy is available at: http://gitorious.org/gnuk
|
||||
|
||||
|
||||
Information on the Web
|
||||
======================
|
||||
|
||||
5
THANKS
5
THANKS
@@ -1,3 +1,5 @@
|
||||
-*- coding: utf-8 -*-
|
||||
|
||||
We would like to express our gratitudes to Werner Koch for GnuPG, and
|
||||
Giovanni Di Sirio for ChibiOS/RT.
|
||||
|
||||
@@ -11,7 +13,10 @@ Hironobu SUZUKI hironobu@h2np.net
|
||||
Jan Suhr jan@suhr.info
|
||||
Kaz Kojima kkojima@rr.iij4u.or.jp
|
||||
Ludovic Rousseau ludovic.rousseau@free.fr
|
||||
Luis Felipe R. Murillo luisfelipe@ucla.edu
|
||||
MATSUU Takuto matsuu@gentoo.org
|
||||
NAGAMI Takeshi nagami-takeshi@aist.go.jp
|
||||
Nguyễn Hồng Quân quannguyen@mbm.vn
|
||||
Paul Bakker polarssl_maintainer@polarssl.org
|
||||
Shane Coughlan scoughlan@openinventionnetwork.com
|
||||
Werner Koch wk@gnupg.org
|
||||
|
||||
@@ -97,12 +97,15 @@
|
||||
* PA0 - input with pull-up (TIM2_CH1)
|
||||
* PA1 - input with pull-down (TIM2_CH2)
|
||||
* PA2 - input with pull-up (TIM2_CH3)
|
||||
* PA4 - Push pull output (SPI1_NSS)
|
||||
* PA5 - Alternate Push pull output (SPI1_SCK)
|
||||
* PA6 - Alternate Push pull output (SPI1_MISO)
|
||||
* PA7 - Alternate Push pull output (SPI1_MOSI)
|
||||
* PA10 - Push pull output (USB 1:ON 0:OFF)
|
||||
* PA11 - input with pull-up (USBDM)
|
||||
* PA12 - input with pull-up (USBDP)
|
||||
* Everything input with pull-up except:
|
||||
* PA10 - Push pull output (USB 1:ON 0:OFF)
|
||||
*/
|
||||
#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */
|
||||
#define VAL_GPIOACRL 0xBBB38888 /* PA7...PA0 */
|
||||
#define VAL_GPIOACRH 0x88888388 /* PA15...PA8 */
|
||||
#define VAL_GPIOAODR 0xFFFFFFFD
|
||||
|
||||
|
||||
@@ -9,6 +9,15 @@ hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
|
||||
#if !defined(DFU_SUPPORT)
|
||||
if (palReadPad (IOPORT3, GPIOC_BUTTON) == 0)
|
||||
/*
|
||||
* Since LEDs are connected to JTMS/SWDIO and JTDI pin,
|
||||
* we can't use LED to let know users in this state.
|
||||
*/
|
||||
for (;;); /* Wait for JTAG debugger connection */
|
||||
#endif
|
||||
|
||||
#if defined(PINPAD_SUPPORT) && !defined(DFU_SUPPORT)
|
||||
palWritePort(IOPORT2, 0x7fff); /* Only clear GPIOB_7SEG_DP */
|
||||
while (palReadPad (IOPORT2, GPIOB_BUTTON) != 0)
|
||||
|
||||
153
doc/Makefile
Normal file
153
doc/Makefile
Normal file
@@ -0,0 +1,153 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER = a4
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GnukDocumentation.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GnukDocumentation.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/GnukDocumentation"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GnukDocumentation"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
3
doc/__update_web
Normal file
3
doc/__update_web
Normal file
@@ -0,0 +1,3 @@
|
||||
cd _build
|
||||
rsync -rntpv html/ atom.fsij.org:/home/fsij/gnuk-doc-html/
|
||||
rsync -rtpv html/ atom.fsij.org:/home/fsij/gnuk-doc-html/
|
||||
246
doc/conf.py
Normal file
246
doc/conf.py
Normal file
@@ -0,0 +1,246 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Gnuk Documentation documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Jul 4 15:29:05 2012.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# 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']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Gnuk Documentation'
|
||||
copyright = u'2012, NIIBE Yutaka'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'GnukDocumentationdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'GnukDocumentation.tex', u'Gnuk Documentation Documentation',
|
||||
u'NIIBE Yutaka', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'gnukdocumentation', u'Gnuk Documentation Documentation',
|
||||
[u'NIIBE Yutaka'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'GnukDocumentation', u'Gnuk Documentation Documentation',
|
||||
u'NIIBE Yutaka', 'GnukDocumentation', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'http://docs.python.org/': None}
|
||||
71
doc/development.rst
Normal file
71
doc/development.rst
Normal file
@@ -0,0 +1,71 @@
|
||||
Development Environment
|
||||
=======================
|
||||
|
||||
|
||||
Hardware
|
||||
--------
|
||||
|
||||
For development, it is highly recommended to have JTAG/SWD debugger.
|
||||
|
||||
For boards with DFU (Device Firmware Upgrade) feature (such as DfuSe),
|
||||
it is possible to develop with that. But it should be considered
|
||||
*experimental* environment, and it should not be used for usual
|
||||
purpose. That's because it is basically impossible for DfuSe
|
||||
implementations to disable reading-out from flash ROM. It means
|
||||
that your secret will be readily extracted by DfuSe.
|
||||
|
||||
For JTAG debugger, Olimex JTAG-Tiny is good and supported well. For
|
||||
SWD debugger, ST-Link/V2 would be good, and it is supported by
|
||||
tool/stlinkv2.py.
|
||||
|
||||
|
||||
OpenOCD
|
||||
-------
|
||||
|
||||
For JTAG/SWD debugger, we can use OpenOCD.
|
||||
|
||||
Note that ST-Link/V2 is *not* supported by OpenOCD 0.5.0. It is
|
||||
supported by version 0.6 or later.
|
||||
|
||||
|
||||
GNU Toolchain
|
||||
-------------
|
||||
|
||||
You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
||||
|
||||
There is "gcc-arm-embedded" project. See:
|
||||
https://launchpad.net/gcc-arm-embedded/
|
||||
|
||||
It is based on GCC 4.6. You'd need "-O3 -Os" instead of "-O2" and it
|
||||
will be slightly better.
|
||||
|
||||
Note that we need to link correct C library (for string functions).
|
||||
For this purpose, our src/Makefile.in contains following line:
|
||||
|
||||
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
|
||||
|
||||
This should not be needed (as -mcpu=cortex-m3 means
|
||||
-mfix-cortex-m3-ldrd), but it was needed for the configuration of
|
||||
patch-gcc-config-arm-t-arm-elf.diff in summon-arm-toolchain in practice.
|
||||
|
||||
|
||||
Building Gnuk
|
||||
-------------
|
||||
|
||||
Change directory to ``src``:
|
||||
|
||||
$ cd gnuk-VERSION/src
|
||||
|
||||
Then, run ``configure``:
|
||||
|
||||
$ ./configure --vidpid=<VID:PID>
|
||||
|
||||
Here, you need to specify USB vendor ID and product ID. For FSIJ's,
|
||||
it's: --vidpid=234b:0000 . Please read the section 'USB vendor ID and
|
||||
product ID' in README.
|
||||
|
||||
Type:
|
||||
|
||||
$ make
|
||||
|
||||
Then, we will have "gnuk.elf".
|
||||
311
doc/generating-2048-RSA-key.rst
Normal file
311
doc/generating-2048-RSA-key.rst
Normal file
@@ -0,0 +1,311 @@
|
||||
============================
|
||||
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 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 password 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 28C0CD7C 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, use of paperkey. 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
|
||||
38
doc/gnome3-gpg-settings.rst
Normal file
38
doc/gnome3-gpg-settings.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
==========================
|
||||
GnuPG settings for GNOME 3
|
||||
==========================
|
||||
|
||||
In the article `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
|
||||
=========================
|
||||
|
||||
It seems that it is more integrated into the desktop.
|
||||
It is difficult to kill it. It would be possible to kill it simply,
|
||||
but then, I can't use, say, wi-fi access (which needs to access "secrets")
|
||||
any more.
|
||||
|
||||
We can't use GNOME configuration tool to disable interference by
|
||||
GNOME keyrings any more. It seems that desktop should not have
|
||||
customization these days.
|
||||
|
||||
|
||||
GNOME-SESSION-PROPERTIES
|
||||
========================
|
||||
|
||||
After struggling some hours, I figured out 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".
|
||||
|
||||
|
||||
Now, I use gpg-agent for GnuPG Agent and SSH agent with Gnuk Token.
|
||||
183
doc/gnuk-keytocard-noremoval.rst
Normal file
183
doc/gnuk-keytocard-noremoval.rst
Normal file
@@ -0,0 +1,183 @@
|
||||
=============================================
|
||||
Key import from PC to Gnuk Token (no removal)
|
||||
=============================================
|
||||
|
||||
This document describes how I put my **keys on PC** to the Token
|
||||
without removing keys from PC.
|
||||
|
||||
The difference is just not-to-save changes after key imports.
|
||||
|
||||
After personalization, I put my keys into the Token.
|
||||
|
||||
Here is the log.
|
||||
|
||||
I invoke GnuPG with my key (4ca7babe) and with ``--homedir`` option
|
||||
to specify the directory which contains my secret keys. ::
|
||||
|
||||
$ gpg --homedir=/home/gniibe/tmp/gnuk-testing-dir --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
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
|
||||
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,
|
||||
and type ``1`` to say it's signature key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Really move the primary key? (y/N) y
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00'
|
||||
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,
|
||||
although they can be same.
|
||||
|
||||
I enter these passwords. ::
|
||||
|
||||
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 the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-GNUK>
|
||||
|
||||
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.
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
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>
|
||||
|
||||
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>
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
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>
|
||||
|
||||
The sub key is now on the Token and GnuPG says its card-no for it.
|
||||
|
||||
Lastly, I quit GnuPG. Note that I **don't** save changes. ::
|
||||
|
||||
gpg> quit
|
||||
Save changes? (y/N) n
|
||||
Quit without saving? (y/N) y
|
||||
$
|
||||
|
||||
All keys are imported to Gnuk Token now.
|
||||
193
doc/gnuk-keytocard.rst
Normal file
193
doc/gnuk-keytocard.rst
Normal file
@@ -0,0 +1,193 @@
|
||||
================================
|
||||
Key import from PC to Gnuk Token
|
||||
================================
|
||||
|
||||
This document describes how I put my **keys on PC** to the Token,
|
||||
and remove keys from PC.
|
||||
|
||||
Note that there is **no ways** to export keys from the Token,
|
||||
so please be careful.
|
||||
|
||||
|
||||
If you want to import same keys to multiple Tokens,
|
||||
please copy ``.gnupg`` directory beforehand.
|
||||
|
||||
In my case, I do something like following: ::
|
||||
|
||||
$ cp -a .gnupg tmp/gnuk-testing-dir
|
||||
|
||||
See `another document`_ to import keys to the Token from copied directory.
|
||||
|
||||
.. _another document: gnuk-keytocard-noremoval
|
||||
|
||||
After personalization, I put my keys into the Token.
|
||||
|
||||
Here is the log.
|
||||
|
||||
I invoke GnuPG with my key (4ca7babe). ::
|
||||
|
||||
$ gpg --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
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
|
||||
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,
|
||||
and type ``1`` to say it's signature key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Really move the primary key? (y/N) y
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00'
|
||||
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,
|
||||
although they can be same.
|
||||
|
||||
I enter these passwords. ::
|
||||
|
||||
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 the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-GNUK>
|
||||
|
||||
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.
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
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>
|
||||
|
||||
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>
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
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>
|
||||
|
||||
The sub key is now on the Token and GnuPG says its card-no for it.
|
||||
|
||||
Lastly, I save changes of **keys on PC** and quit GnuPG. ::
|
||||
|
||||
gpg> save
|
||||
$
|
||||
|
||||
All secret keys are imported to Gnuk Token now.
|
||||
On PC, only references (card-no) to the Token remain.
|
||||
153
doc/gnuk-personalization.rst
Normal file
153
doc/gnuk-personalization.rst
Normal file
@@ -0,0 +1,153 @@
|
||||
=============================
|
||||
Personalization of Gnuk Token
|
||||
=============================
|
||||
|
||||
|
||||
Personalize your Gnuk Token
|
||||
===========================
|
||||
|
||||
Invoke GnuPG with the option ``--card-edit``. ::
|
||||
|
||||
$ gpg --card-edit
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-34006E06) 00 00'
|
||||
Application ID ...: D276000124010200F517000000010000
|
||||
Version ..........: 2.0
|
||||
Manufacturer .....: FSIJ
|
||||
Serial number ....: 00000001
|
||||
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
|
||||
Max. PIN lengths .: 127 127 127
|
||||
PIN retry counter : 3 3 3
|
||||
Signature counter : 0
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
General key info..: [none]
|
||||
|
||||
It shows the status of the card (as same as the output of ``gpg --card-status``). It shows token's name and its USB serial string (0.12-34006E06) from PC/SC-lite.
|
||||
|
||||
Then, GnuPG enters its own command interaction mode. The prompt is ``gpg/card>``.
|
||||
|
||||
In the OpenPGPcard specification, there are two passwords: one is
|
||||
user-password and another is admin-password. In the specification,
|
||||
user-password is refered as PW1, and admin-password is refered as PW3.
|
||||
|
||||
Note that people sometimes use different words than "password" to
|
||||
refer same thing, in GnuPG and its applications. For example, the
|
||||
output explained above includes the word "PIN" (Personal
|
||||
Identification Number), and the helper program for input is named
|
||||
"pinentry". Note that it is OK (and recommended) to include
|
||||
characters other than digits for the case of OpenPGPcard.
|
||||
|
||||
Besides, some people sometimes prefer the word "passphrase" to
|
||||
"password", as it can encourage to have longer string, but it means
|
||||
same thing and it just refer user-password or admin-password.
|
||||
|
||||
Firstly, I change PIN of card user from factory setting (of "123456").
|
||||
Note that, by only changing user's PIN, it enables "admin less mode" of Gnuk.
|
||||
"Admin less mode" means that admin password will become same one of user's.
|
||||
That is, PW1 = PW3.
|
||||
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
|
||||
|
||||
Please enter the PIN
|
||||
Enter PIN: 123456
|
||||
|
||||
New PIN
|
||||
Enter New PIN: <PASSWORD-OF-GNUK>
|
||||
|
||||
New PIN
|
||||
Repeat this PIN: <PASSWORD-OF-GNUK>
|
||||
PIN changed.
|
||||
|
||||
The "admin less mode" is Gnuk only feature, not defined in the
|
||||
OpenPGPcard specification. By using "admin less mode", it will be
|
||||
only a sigle password for user to memorize, and it will be easier if a token
|
||||
is used by an individual.
|
||||
|
||||
(If you want normal way ("admin full mode" in Gnuk's term),
|
||||
that is, user-password *and* admin-password independently,
|
||||
please change admin-password at first.
|
||||
Then, the token works as same as OpenPGPcard specification
|
||||
with regards to PW1 and PW3.)
|
||||
|
||||
Secondly, enabling admin command, I put name of mine.
|
||||
Note that I input user's PIN (which I set above) here,
|
||||
because it is "admin less mode". ::
|
||||
|
||||
gpg/card> admin
|
||||
Admin commands are allowed
|
||||
|
||||
gpg/card> name
|
||||
Cardholder's surname: Niibe
|
||||
Cardholder's given name: Yutaka
|
||||
gpg: 3 Admin PIN attempts remaining before card is permanently locked
|
||||
|
||||
Please enter the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-OF-GNUK>
|
||||
|
||||
Thirdly, I put some other informations, such as language, sex,
|
||||
login, and URL. URL specifies the place where I put my public keys. ::
|
||||
|
||||
gpg/card> lang
|
||||
Language preferences: ja
|
||||
|
||||
gpg/card> sex
|
||||
Sex ((M)ale, (F)emale or space): m
|
||||
|
||||
gpg/card> url
|
||||
URL to retrieve public key: http://www.gniibe.org/gniibe.asc
|
||||
|
||||
gpg/card> login
|
||||
Login data (account name): gniibe
|
||||
|
||||
Since I don't force PIN input everytime,
|
||||
toggle it to non-force-pin-for-signature. ::
|
||||
|
||||
gpg/card> forcesig
|
||||
|
||||
Lastly, I setup reset code. This is optional. ::
|
||||
|
||||
gpg/card> passwd
|
||||
gpg: OpenPGP card no. D276000124010200F517000000010000 detected
|
||||
|
||||
1 - change PIN
|
||||
2 - unblock PIN
|
||||
3 - change Admin PIN
|
||||
4 - set the Reset Code
|
||||
Q - quit
|
||||
|
||||
Your selection? 4
|
||||
gpg: 3 Admin PIN attempts remaining before card is permanently locked
|
||||
|
||||
Please enter the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-OF-GNUK>
|
||||
|
||||
New Reset Code
|
||||
Enter New PIN: <RESETCODE-OF-GNUK>
|
||||
|
||||
New Reset Code
|
||||
Repeat this PIN: <RESETCODE-OF-GNUK>
|
||||
Reset Code set.
|
||||
|
||||
1 - change PIN
|
||||
2 - unblock PIN
|
||||
3 - change Admin PIN
|
||||
4 - set the Reset Code
|
||||
Q - quit
|
||||
|
||||
Your selection? q
|
||||
|
||||
Then, I quit. ::
|
||||
|
||||
gpg/card> quit
|
||||
|
||||
That's all.
|
||||
43
doc/gnuk-token-initial-configuration.rst
Normal file
43
doc/gnuk-token-initial-configuration.rst
Normal file
@@ -0,0 +1,43 @@
|
||||
===================================
|
||||
Initial Configuration of Gnuk Token
|
||||
===================================
|
||||
|
||||
This is optional. You don't need to setup the serial number of Gnuk Token,
|
||||
as it comes with its default serial number based on MCU's chip ID.
|
||||
|
||||
You can setup the serial number of Gnuk Token only once.
|
||||
|
||||
|
||||
Conditions
|
||||
==========
|
||||
|
||||
I assume you are using GNU/Linux.
|
||||
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
Make sure there is no ``scdaemon`` for configuring Gnuk Token. You can kill ``scdaemon`` by: ::
|
||||
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
|
||||
Serial Number (optional)
|
||||
========================
|
||||
|
||||
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
|
||||
Configuration: 1
|
||||
Interface: 0
|
||||
d2 76 00 01 24 01 02 00 f5 17 00 00 00 01 00 00
|
||||
|
||||
|
||||
The example above is the case of libusb version.
|
||||
|
||||
Use the tool ``../tool/gnuk_put_binary.py`` instead , for PC/SC Lite.
|
||||
You need PyScard for this.
|
||||
43
doc/gpg-settings.rst
Normal file
43
doc/gpg-settings.rst
Normal file
@@ -0,0 +1,43 @@
|
||||
.. -*- coding: utf-8 -*-
|
||||
|
||||
==============
|
||||
GnuPG settings
|
||||
==============
|
||||
|
||||
Here is my GnuPG settings.
|
||||
|
||||
.gnupg/gpg.conf
|
||||
===============
|
||||
|
||||
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 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
|
||||
|
||||
default-key 0x4ca7babe
|
||||
|
||||
|
||||
Let gpg-agent manage SSH key
|
||||
============================
|
||||
|
||||
I deactivate seahose-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. ::
|
||||
|
||||
enable-ssh-support
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
* `Creating a new GPG key`_
|
||||
* `Use OpenPGP Keys for OpenSSH, how to use gpg with ssh`_
|
||||
|
||||
.. _Creating a new GPG key: http://keyring.debian.org/creating-key.html
|
||||
.. _Use OpenPGP Keys for OpenSSH, how to use gpg with ssh: http://www.programmierecke.net/howto/gpg-ssh.html
|
||||
BIN
doc/images/gnuk-sticker.png
Normal file
BIN
doc/images/gnuk-sticker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
37
doc/index.rst
Normal file
37
doc/index.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
.. Gnuk Documentation documentation master file, created by
|
||||
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 NIIBE Yutaka
|
||||
Copyright (C) 2012 Free Software Initiative of Japan
|
||||
This document is licensed under a CC-BY-SA 3.0 Unported License
|
||||
|
||||
Gnuk Documentation
|
||||
==================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro.rst
|
||||
development.rst
|
||||
stop-scdaemon.rst
|
||||
udev-rules.rst
|
||||
gnuk-token-initial-configuration.rst
|
||||
gnuk-personalization.rst
|
||||
generating-2048-RSA-key.rst
|
||||
gnuk-keytocard.rst
|
||||
gnuk-keytocard-noremoval.rst
|
||||
using-gnuk-token-with-another-computer.rst
|
||||
gpg-settings.rst
|
||||
gnome3-gpg-settings.rst
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
69
doc/intro.rst
Normal file
69
doc/intro.rst
Normal file
@@ -0,0 +1,69 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
|
||||
What's Gnuk?
|
||||
------------
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Cryptographic token and feature of Gnuk
|
||||
---------------------------------------
|
||||
|
||||
Cryptographic token is a store of private keys and it computes cryptographic
|
||||
functions on the device.
|
||||
|
||||
The idea is to separate important secrets to independent device,
|
||||
from where nobody can extract them.
|
||||
|
||||
|
||||
Development Environment
|
||||
-----------------------
|
||||
|
||||
See :doc:`development` for development environment for Gnuk.
|
||||
Gnuk is developed on the environment where there are only Free Software.
|
||||
|
||||
|
||||
Target boards for running Gnuk
|
||||
------------------------------
|
||||
|
||||
Hardware requirement for Gnuk is the micro controller STM32F103.
|
||||
In version 1.0, Gnuk supports following boards.
|
||||
|
||||
* FST-01 (Flying Stone Tiny ZERO-ONE)
|
||||
|
||||
* Olimex STM32-H103
|
||||
|
||||
* CQ STARM
|
||||
|
||||
* STBee
|
||||
|
||||
* STBee Mini
|
||||
|
||||
* STM32 part of STM8S Discovery Kit
|
||||
|
||||
|
||||
Host prerequisites for using Gnuk Token
|
||||
---------------------------------------
|
||||
|
||||
* GNU Privacy Guard (GnuPG)
|
||||
|
||||
* libusb
|
||||
|
||||
* [Optional] PC/SC lite (pcscd, libccid)
|
||||
|
||||
* SSH: openssh
|
||||
|
||||
* Web: scute, firefox
|
||||
|
||||
|
||||
Usages
|
||||
------
|
||||
|
||||
* Sign with GnuPG
|
||||
* Decrypt with GnuPG
|
||||
* Use with OpenSSH
|
||||
* Use with Firefox for X.509 client certificate authentication
|
||||
@@ -1,4 +1,4 @@
|
||||
* Random Number Generator
|
||||
* [DONE] Random Number Generator
|
||||
|
||||
RNG is needed for Data Encryption Key to encrypt private key (P and Q).
|
||||
It is important to collect enough entropy. Perhaps, it would
|
||||
@@ -77,7 +77,8 @@ KEYPTR
|
||||
<---encrypted----><--- plain ---->
|
||||
|
||||
key_addr 4-byte
|
||||
additional_data_encrypted 16-byte
|
||||
initial_vector (random) 16-byte
|
||||
checksum_encrypted 16-byte
|
||||
dek_encrypted_by_keystring_pw1 16-byte
|
||||
dek_encrypted_by_keystring_rc 16-byte
|
||||
dek_encrypted_by_keystring_pw3 16-byte
|
||||
@@ -85,6 +86,4 @@ dek_encrypted_by_keystring_pw3 16-byte
|
||||
... decrypted to
|
||||
|
||||
[ P ][ Q ]
|
||||
check 4-byte
|
||||
random 4-byte
|
||||
magic[] 8-byte
|
||||
checksum 16-byte
|
||||
@@ -8,7 +8,6 @@ Note that updating firmware, all data objects and keys will be
|
||||
removed. There is _no way_ to preserve those data.
|
||||
|
||||
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
@@ -39,14 +38,12 @@ We can examine key information of gpg-agent by "KEYINFO" command.
|
||||
Here is my example::
|
||||
|
||||
$ gpg-connect-agent "KEYINFO --list" /bye
|
||||
S KEYINFO 4970A0D537CA2EF7CE6A106E47AD89B0EFB684C8 D - - - - -
|
||||
S KEYINFO 65F67E742101C7FE6D5B33FCEFCF4F65EAF0688C T D276000124010200F517000000010000 OPENPGP.2 - - -
|
||||
S KEYINFO 5D6C89682D07CCFC034AF508420BF2276D8018ED T D276000124010200F517000000010000 OPENPGP.3 - - -
|
||||
S KEYINFO 7D180C0C2A991B25204110A92F5F92A5A509845B D - - - - -
|
||||
S KEYINFO 101DE7B639FE29F4636BDEECF442A9273AFA6565 T D276000124010200F517000000010000 OPENPGP.1 - - -
|
||||
S KEYINFO 5D6C89682D07CCFC034AF508420BF2276D8018ED T D276000124010200F517000000010000 OPENPGP.3 - - -
|
||||
OK
|
||||
|
||||
I have two local keys (in my PC) and three keys in my token.
|
||||
I have three keys in my token.
|
||||
|
||||
With the script below, I extract public key of the keygrip
|
||||
5D6C89682D07CCFC034AF508420BF2276D8018ED into the file: 5D6C8968.bin::
|
||||
@@ -64,7 +61,7 @@ Here is the script, get_public_key.py::
|
||||
result = check_output(["gpg-connect-agent", "READKEY %s" % keygrip, "/bye"])
|
||||
key = ""
|
||||
while True:
|
||||
i = result.find('%')
|
||||
i = result.find('%')
|
||||
if i < 0:
|
||||
key += result
|
||||
break
|
||||
@@ -96,9 +93,9 @@ Then, we can put the data of public key into token by::
|
||||
Invoking firmware update
|
||||
========================
|
||||
|
||||
We specify the keygrip to authenticate, reGNUal binary, and Gnuk binary.
|
||||
We specify reGNUal binary and Gnuk binary.
|
||||
|
||||
$ ../tool/gnuk_upgrade.py 5D6C89682D07CCFC034AF508420BF2276D8018ED ../regnual/regnual.bin gnuk.bin
|
||||
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk.bin
|
||||
|
||||
|
||||
Two or more tokens
|
||||
@@ -107,9 +104,9 @@ Two or more tokens
|
||||
Currently, GnuPG doesn't support multiple devices connected to the
|
||||
host.
|
||||
|
||||
In order to update the firmware of a token TARGET, we use GnuPG to
|
||||
authenticate with public key. If it is on another token AUTH, it is
|
||||
somewhat complicated.
|
||||
In order to update the firmware of a TARGET token, we use GnuPG to
|
||||
authenticate with public key. It is assumed that you have another
|
||||
AUTH token for this. This situation is somewhat complicated.
|
||||
|
||||
What I do is:
|
||||
(1) Don't run PC/SC daemon::
|
||||
@@ -120,9 +117,14 @@ What I do is:
|
||||
|
||||
$ killall -9 scdaemon
|
||||
|
||||
(3) Connect the token of AUTH, and use it::
|
||||
(3) Insert the AUTH token to USB, and use it::
|
||||
|
||||
$ gpg --card-status
|
||||
|
||||
(4) Connect TARGET, and invoke gnuk_update.py
|
||||
(4) Insert the TARGET token to USB (after scdaemon communicates AUTH
|
||||
token), and invoke gnuk_upgrade.py.
|
||||
In this situation, gnuk_upgrade.py tries to connect one of tokens,
|
||||
but a connection to the AUTH token will fail because scdaemon is
|
||||
connecting to that device, and will be expected to connect to the
|
||||
TARGET token succesufully, instead.
|
||||
--
|
||||
37
doc/stop-scdaemon.rst
Normal file
37
doc/stop-scdaemon.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
===========================
|
||||
Stopping/Resetting SCDAEMON
|
||||
===========================
|
||||
|
||||
There is a daemon named ``scdaemon`` behind gpg-agent, which handles
|
||||
communication to smartcard/token.
|
||||
|
||||
Ideally, we don't need to care about ``scdaemon``, and it should
|
||||
handle everything automatically. But, there are some cases (because
|
||||
of bugs), where we need to talk to the daemon directly, in practice.
|
||||
|
||||
|
||||
How to communicate SCDAEMON
|
||||
===========================
|
||||
|
||||
We have a utility to communicate with a running gpg-agent, that's
|
||||
gpg-connect-agent. We can use it to communicate with scdaemon,
|
||||
as it supports sub-command "SCD", exactly for this purpose.
|
||||
|
||||
|
||||
Stopping SCDAEMON
|
||||
=================
|
||||
|
||||
To stop SCDAEMON and let it exit, type::
|
||||
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
Then, you can confirm that there is no SCDAEMON any more by ``ps``
|
||||
command.
|
||||
|
||||
|
||||
Let GPG-AGENT/SCDAEMON learn
|
||||
============================
|
||||
|
||||
To let gpg-agent/scdaemon learn, type::
|
||||
|
||||
$ gpg-connect-agent learn /bye
|
||||
51
doc/udev-rules.rst
Normal file
51
doc/udev-rules.rst
Normal file
@@ -0,0 +1,51 @@
|
||||
===============================================
|
||||
Device Configuration for Gnuk Token with libusb
|
||||
===============================================
|
||||
|
||||
In order to use Gnuk Token with libusb, configuration of device is
|
||||
needed for permissions. Note that this is not needed for the case of
|
||||
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.
|
||||
We add lines for Gnuk Token to give a desktop user the permission to
|
||||
use the device. We specify USB ID of Gnuk Token (by FSIJ)::
|
||||
|
||||
--- /lib/udev/rules.d/60-gnupg.rules.orig 2012-06-24 21:51:26.000000000 +0900
|
||||
+++ /lib/udev/rules.d/60-gnupg.rules 2012-07-13 17:18:55.149587687 +0900
|
||||
@@ -10,4 +10,7 @@
|
||||
ATTR{idVendor}=="04e6", ATTR{idProduct}=="5115", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
|
||||
+# Gnuk
|
||||
+ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
+
|
||||
LABEL="gnupg_rules_end"
|
||||
|
||||
When we install "gnupg2" package only (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::
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
||||
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
|
||||
Usually, udev daemon automatically handles for the changes of configuration
|
||||
files. If not, please let the daemon reload rules::
|
||||
|
||||
# udevadm control --reload-rules
|
||||
|
||||
|
||||
|
||||
|
||||
udev rules for ST-Link/V2
|
||||
=========================
|
||||
|
||||
We need to have a udev rule for ST-Link/V2. It's like::
|
||||
|
||||
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", GROUP="tape", MODE="664", SYMLINK+="stlink"
|
||||
|
||||
I have this in the file /etc/udev/rules.d/10-stlink.rules.
|
||||
178
doc/using-gnuk-token-with-another-computer.rst
Normal file
178
doc/using-gnuk-token-with-another-computer.rst
Normal file
@@ -0,0 +1,178 @@
|
||||
======================================
|
||||
Using Gnuk Token with another computer
|
||||
======================================
|
||||
|
||||
This document describes how you can use Gnuk Token
|
||||
on another PC (which is not the one you generate your keys).
|
||||
|
||||
Note that the Token only brings your secret keys,
|
||||
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``.
|
||||
|
||||
To do that, invoke GnuPG with ``--card-edit`` option. ::
|
||||
|
||||
$ gpg --card-edit
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-37006A06) 00 00'
|
||||
Application ID ...: D276000124010200F517000000010000
|
||||
Version ..........: 2.0
|
||||
Manufacturer .....: FSIJ
|
||||
Serial number ....: 00000001
|
||||
Name of cardholder: Yutaka Niibe
|
||||
Language prefs ...: ja
|
||||
Sex ..............: male
|
||||
URL of public key : http://www.gniibe.org/gniibe.asc
|
||||
Login data .......: gniibe
|
||||
Signature PIN ....: not forced
|
||||
Key attributes ...: 2048R 2048R 2048R
|
||||
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..: [none]
|
||||
|
||||
gpg/card>
|
||||
|
||||
It says, there is no key info related to this token on your PC (``[none]``).
|
||||
|
||||
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: Total number processed: 1
|
||||
gpg: imported: 1 (RSA: 1)
|
||||
|
||||
gpg/card>
|
||||
|
||||
Good. The public key is now in ``.gnupg``. We can examine by ``gpg --list-keys``.
|
||||
|
||||
However, the secret key reference (to the token) is not in ``.gnupg`` yet.
|
||||
|
||||
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
|
||||
Version ..........: 2.0
|
||||
Manufacturer .....: FSIJ
|
||||
Serial number ....: 00000001
|
||||
Name of cardholder: Yutaka Niibe
|
||||
Language prefs ...: ja
|
||||
Sex ..............: male
|
||||
URL of public key : http://www.gniibe.org/gniibe.asc
|
||||
Login data .......: gniibe
|
||||
Signature PIN ....: not forced
|
||||
Key attributes ...: 2048R 2048R 2048R
|
||||
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
|
||||
|
||||
gpg/card>
|
||||
|
||||
OK, now I can use the Token on this computer.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
To do that I do: ::
|
||||
|
||||
$ gpg --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: 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
|
||||
[ 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. ::
|
||||
|
||||
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
|
||||
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
|
||||
|
||||
Please decide how far you trust this user to correctly verify other users' keys
|
||||
(by looking at passports, checking fingerprints from different sources, etc.)
|
||||
|
||||
1 = I don't know or won't say
|
||||
2 = I do NOT trust
|
||||
3 = I trust marginally
|
||||
4 = I trust fully
|
||||
5 = I trust ultimately
|
||||
m = back to the main menu
|
||||
|
||||
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
|
||||
[ 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.
|
||||
|
||||
$
|
||||
|
||||
Next time 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.
|
||||
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>
|
||||
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
|
||||
|
||||
gpg> quit
|
||||
$
|
||||
@@ -83,6 +83,7 @@ int aes_crypt_ecb( aes_context *ctx,
|
||||
const unsigned char input[16],
|
||||
unsigned char output[16] );
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* \brief AES-CBC buffer encryption/decryption
|
||||
* Length should be a multiple of the block
|
||||
@@ -103,6 +104,7 @@ int aes_crypt_cbc( aes_context *ctx,
|
||||
unsigned char iv[16],
|
||||
const unsigned char *input,
|
||||
unsigned char *output );
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief AES-CFB128 buffer encryption/decryption.
|
||||
|
||||
@@ -501,7 +501,7 @@ int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
|
||||
* 1 if memory allocation failed,
|
||||
* POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
|
||||
*/
|
||||
int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
|
||||
int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng );
|
||||
|
||||
/**
|
||||
* \brief Prime number generation
|
||||
@@ -517,7 +517,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
|
||||
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
|
||||
*/
|
||||
int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
|
||||
int (*f_rng)(void *), void *p_rng );
|
||||
unsigned char (*f_rng)(void *), void *p_rng );
|
||||
|
||||
/**
|
||||
* \brief Checkup routine
|
||||
|
||||
@@ -86,10 +86,12 @@
|
||||
*/
|
||||
#define POLARSSL_VERSION_C
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
/*
|
||||
* Enable the prime-number generation code.
|
||||
*/
|
||||
#define POLARSSL_GENPRIME
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Uncomment this macro to store the AES tables in ROM.
|
||||
|
||||
@@ -183,7 +183,7 @@ void rsa_init( rsa_context *ctx,
|
||||
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||
*/
|
||||
int rsa_gen_key( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int nbits, int exponent );
|
||||
|
||||
@@ -258,7 +258,7 @@ int rsa_private( rsa_context *ctx,
|
||||
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||
*/
|
||||
int rsa_pkcs1_encrypt( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int mode, int ilen,
|
||||
const unsigned char *input,
|
||||
|
||||
@@ -753,6 +753,7 @@ int aes_crypt_ecb( aes_context *ctx,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* AES-CBC buffer encryption/decryption
|
||||
*/
|
||||
@@ -816,6 +817,7 @@ int aes_crypt_cbc( aes_context *ctx,
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AES-CFB128 buffer encryption/decryption
|
||||
|
||||
@@ -225,6 +225,7 @@ int mpi_size( const mpi *X )
|
||||
return( ( mpi_msb( X ) + 7 ) >> 3 );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Convert an ASCII character to digit value
|
||||
*/
|
||||
@@ -310,7 +311,6 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Helper to write the digits high-order first
|
||||
*/
|
||||
@@ -649,7 +649,7 @@ int mpi_cmp_mpi( const mpi *X, const mpi *Y )
|
||||
return( 0 );
|
||||
|
||||
if( i > j ) return( X->s );
|
||||
if( j > i ) return( -X->s );
|
||||
if( j > i ) return( -Y->s );
|
||||
|
||||
if( X->s > 0 && Y->s < 0 ) return( 1 );
|
||||
if( Y->s > 0 && X->s < 0 ) return( -1 );
|
||||
@@ -1570,8 +1570,6 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_GENPRIME)
|
||||
|
||||
/*
|
||||
* Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
|
||||
*/
|
||||
@@ -1665,6 +1663,8 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_GENPRIME)
|
||||
|
||||
static const int small_prime[] =
|
||||
{
|
||||
3, 5, 7, 11, 13, 17, 19, 23,
|
||||
@@ -1693,7 +1693,7 @@ static const int small_prime[] =
|
||||
/*
|
||||
* Miller-Rabin primality test (HAC 4.24)
|
||||
*/
|
||||
int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
|
||||
int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng )
|
||||
{
|
||||
int ret, i, j, n, s, xs;
|
||||
mpi W, R, T, A, RR;
|
||||
@@ -1755,7 +1755,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
|
||||
|
||||
p = (unsigned char *) A.p;
|
||||
for( j = 0; j < A.n * ciL; j++ )
|
||||
*p++ = (unsigned char) f_rng( p_rng );
|
||||
*p++ = f_rng( p_rng );
|
||||
|
||||
j = mpi_msb( &A ) - mpi_msb( &W );
|
||||
MPI_CHK( mpi_shift_r( &A, j + 1 ) );
|
||||
@@ -1809,7 +1809,7 @@ cleanup:
|
||||
* Prime number generation
|
||||
*/
|
||||
int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
|
||||
int (*f_rng)(void *), void *p_rng )
|
||||
unsigned char (*f_rng)(void *), void *p_rng )
|
||||
{
|
||||
int ret, k, n;
|
||||
unsigned char *p;
|
||||
@@ -1827,7 +1827,7 @@ int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
|
||||
|
||||
p = (unsigned char *) X->p;
|
||||
for( k = 0; k < X->n * ciL; k++ )
|
||||
*p++ = (unsigned char) f_rng( p_rng );
|
||||
*p++ = f_rng( p_rng );
|
||||
|
||||
k = mpi_msb( X );
|
||||
if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );
|
||||
|
||||
@@ -58,7 +58,7 @@ void rsa_init( rsa_context *ctx,
|
||||
* Generate an RSA keypair
|
||||
*/
|
||||
int rsa_gen_key( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int nbits, int exponent )
|
||||
{
|
||||
@@ -101,6 +101,7 @@ int rsa_gen_key( rsa_context *ctx,
|
||||
}
|
||||
while( mpi_cmp_int( &G, 1 ) != 0 );
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* D = E^-1 mod ((P-1)*(Q-1))
|
||||
* DP = D mod (P - 1)
|
||||
@@ -111,6 +112,7 @@ int rsa_gen_key( rsa_context *ctx,
|
||||
MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
|
||||
MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
|
||||
MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
|
||||
#endif
|
||||
|
||||
ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
|
||||
|
||||
@@ -129,6 +131,7 @@ cleanup:
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Check a public RSA key
|
||||
*/
|
||||
@@ -197,6 +200,7 @@ cleanup:
|
||||
mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL );
|
||||
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED | ret );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do an RSA public key operation
|
||||
@@ -295,7 +299,7 @@ cleanup:
|
||||
* Add the message padding, then do an RSA operation
|
||||
*/
|
||||
int rsa_pkcs1_encrypt( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int mode, int ilen,
|
||||
const unsigned char *input,
|
||||
@@ -323,7 +327,7 @@ int rsa_pkcs1_encrypt( rsa_context *ctx,
|
||||
int rng_dl = 100;
|
||||
|
||||
do {
|
||||
*p = (unsigned char) f_rng( p_rng );
|
||||
*p = f_rng( p_rng );
|
||||
} while( *p == 0 && --rng_dl );
|
||||
|
||||
// Check if RNG failed to generate data
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
PROJECT = regnual
|
||||
|
||||
SRCS = regnual.c usb_lld.c sys.c
|
||||
OBJS = regnual.o usb_lld.o sys.o
|
||||
LDSCRIPT= regnual.ld
|
||||
|
||||
@@ -23,7 +22,8 @@ MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
|
||||
DEFS = -DFREE_STANDING
|
||||
|
||||
CFLAGS = -O2 -g
|
||||
CFLAGS += $(CWARN) -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
|
||||
CFLAGS += -Wa,-alms=$(notdir $(<:.c=.lst)) -fpie
|
||||
CFLAGS += $(CWARN) -I . -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
|
||||
|
||||
LDFLAGS = -T$(LDSCRIPT) -nostartfiles $(MCFLAGS) $(TOPT)
|
||||
|
||||
@@ -38,8 +38,8 @@ regnual.hex: regnual.elf
|
||||
$(OBJCOPY) -Obinary regnual.elf regnual.bin
|
||||
$(OBJCOPY) -Oihex regnual.elf regnual.hex
|
||||
|
||||
usb_lld.c: ../src/usb_lld.c
|
||||
cp -p ../src/usb_lld.c .
|
||||
usb_lld.o: ../src/usb_lld.c
|
||||
$(CC) $(CFLAGS) -c -o usb_lld.o ../src/usb_lld.c
|
||||
|
||||
regnual.elf: $(OBJS) $(LDSCRIPT)
|
||||
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS)
|
||||
@@ -48,4 +48,3 @@ clean:
|
||||
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin
|
||||
|
||||
distclean: clean
|
||||
-rm -f usb_lld.c
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* regnual.c -- Firmware installation for STM32F103 Flash ROM
|
||||
*
|
||||
* Copyright (C) 2012 Free Software Initiative of Japan
|
||||
* Copyright (C) 2012, 2013 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -99,33 +99,15 @@ static const uint8_t regnual_string_serial[] = {
|
||||
'0', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
const struct Descriptor device_desc = {
|
||||
regnual_device_desc,
|
||||
sizeof (regnual_device_desc)
|
||||
};
|
||||
|
||||
const struct Descriptor config_desc = {
|
||||
regnual_config_desc,
|
||||
sizeof (regnual_config_desc)
|
||||
};
|
||||
|
||||
const struct Descriptor string_descs[] = {
|
||||
{regnual_string_lang_id, sizeof (regnual_string_lang_id)},
|
||||
{gnukStringVendor, sizeof (gnukStringVendor)},
|
||||
{gnukStringProduct, sizeof (gnukStringProduct)},
|
||||
{regnual_string_serial, sizeof (regnual_string_serial)},
|
||||
};
|
||||
|
||||
#define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
|
||||
|
||||
static void
|
||||
regnual_device_reset (void)
|
||||
void
|
||||
usb_cb_device_reset (void)
|
||||
{
|
||||
/* Set DEVICE as not configured */
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (config_desc.Descriptor[7]);
|
||||
usb_lld_set_feature (regnual_config_desc[7]);
|
||||
|
||||
usb_lld_reset ();
|
||||
|
||||
@@ -141,11 +123,9 @@ regnual_device_reset (void)
|
||||
#define USB_REGNUAL_PROTECT 4
|
||||
#define USB_REGNUAL_FINISH 5
|
||||
|
||||
static uint8_t mem[256];
|
||||
static uint32_t mem[256/4];
|
||||
static uint32_t result;
|
||||
|
||||
static const uint8_t *const mem_info[] = { &_flash_start, &_flash_end, };
|
||||
|
||||
|
||||
static uint32_t rbit (uint32_t v)
|
||||
{
|
||||
@@ -159,7 +139,7 @@ static uint32_t fetch (int i)
|
||||
{
|
||||
uint32_t v;
|
||||
|
||||
v = *(uint32_t *)(&mem[i*4]);
|
||||
v = mem[i];
|
||||
return rbit (v);
|
||||
}
|
||||
|
||||
@@ -186,9 +166,8 @@ static uint32_t calc_crc32 (void)
|
||||
}
|
||||
|
||||
|
||||
static void regnual_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index,
|
||||
uint16_t len)
|
||||
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
|
||||
uint16_t index, uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
@@ -200,7 +179,7 @@ static void regnual_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
{
|
||||
uint32_t dst_addr = (0x08000000 + value * 0x100);
|
||||
|
||||
result = flash_write (dst_addr, mem, 256);
|
||||
result = flash_write (dst_addr, (const uint8_t *)mem, 256);
|
||||
}
|
||||
else if (req_no == USB_REGNUAL_PROTECT && len == 0
|
||||
&& value == 0 && index == 0)
|
||||
@@ -211,9 +190,9 @@ static void regnual_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
regnual_setup (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len)
|
||||
int
|
||||
usb_cb_setup (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
@@ -223,6 +202,10 @@ regnual_setup (uint8_t req, uint8_t req_no,
|
||||
{
|
||||
if (req_no == USB_REGNUAL_MEMINFO)
|
||||
{
|
||||
static const uint8_t *mem_info[2];
|
||||
|
||||
mem_info[0] = &_flash_start;
|
||||
mem_info[1] = &_flash_end;
|
||||
usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
@@ -240,7 +223,8 @@ regnual_setup (uint8_t req, uint8_t req_no,
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (index + len < 256)
|
||||
memset (mem + index + len, 0xff, 256 - (index + len));
|
||||
memset ((uint8_t *)mem + index + len, 0xff,
|
||||
256 - (index + len));
|
||||
|
||||
usb_lld_set_data_to_recv (mem + index, len);
|
||||
return USB_SUCCESS;
|
||||
@@ -264,38 +248,58 @@ regnual_setup (uint8_t req, uint8_t req_no,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int
|
||||
regnual_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
int
|
||||
usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
{
|
||||
(void)index;
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (device_desc.Descriptor,
|
||||
device_desc.Descriptor_Size);
|
||||
usb_lld_set_data_to_send (regnual_device_desc,
|
||||
sizeof (regnual_device_desc));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (config_desc.Descriptor,
|
||||
config_desc.Descriptor_Size);
|
||||
usb_lld_set_data_to_send (regnual_config_desc,
|
||||
sizeof (regnual_config_desc));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
uint8_t desc_index = value & 0xff;
|
||||
const uint8_t *str;
|
||||
int size;
|
||||
|
||||
if (desc_index < NUM_STRING_DESC)
|
||||
switch (desc_index)
|
||||
{
|
||||
usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
|
||||
string_descs[desc_index].Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
case 0:
|
||||
str = regnual_string_lang_id;
|
||||
size = sizeof (regnual_string_lang_id);
|
||||
break;
|
||||
case 1:
|
||||
str = gnukStringVendor;
|
||||
size = sizeof (gnukStringVendor);
|
||||
break;
|
||||
case 2:
|
||||
str = gnukStringProduct;
|
||||
size = sizeof (gnukStringProduct);
|
||||
break;
|
||||
case 3:
|
||||
str = regnual_string_serial;
|
||||
size = sizeof (regnual_string_serial);
|
||||
break;
|
||||
default:
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
usb_lld_set_data_to_send (str, size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int regnual_usb_event (uint8_t event_type, uint16_t value)
|
||||
int usb_cb_handle_event (uint8_t event_type, uint16_t value)
|
||||
{
|
||||
(void)value;
|
||||
|
||||
@@ -311,20 +315,12 @@ static int regnual_usb_event (uint8_t event_type, uint16_t value)
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int regnual_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
{
|
||||
(void)cmd; (void)interface; (void)alt;
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
const struct usb_device_method Device_Method = {
|
||||
regnual_device_reset,
|
||||
regnual_ctrl_write_finish,
|
||||
regnual_setup,
|
||||
regnual_get_descriptor,
|
||||
regnual_usb_event,
|
||||
regnual_interface,
|
||||
};
|
||||
|
||||
static void wait (int count)
|
||||
{
|
||||
|
||||
@@ -23,22 +23,11 @@ SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
.bss :
|
||||
{
|
||||
_bss_start = .;
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_bss_end = .;
|
||||
} > ram0
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
_text = .;
|
||||
KEEP(*(.vectors))
|
||||
*(.text.entry)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
@@ -48,6 +37,12 @@ SECTIONS
|
||||
*(.gcc*)
|
||||
} > ram1
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
*(.got.*)
|
||||
} > ram1
|
||||
|
||||
.ctors :
|
||||
{
|
||||
PROVIDE(_ctors_start_ = .);
|
||||
@@ -90,6 +85,18 @@ SECTIONS
|
||||
_edata = .;
|
||||
} > ram1
|
||||
|
||||
.bss :
|
||||
{
|
||||
_bss_start = .;
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_bss_end = .;
|
||||
} > ram1
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
@@ -9,17 +9,38 @@ static void none (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Note: it is not reset */
|
||||
static __attribute__ ((naked))
|
||||
/*
|
||||
* Note: the address of this routine 'entry' will be in the vectors as
|
||||
* RESET, but this will be called from application. It's not RESET
|
||||
* state, then.
|
||||
*
|
||||
* This routine doesn't change PSP and MSP. Application should
|
||||
* prepare those stack pointers.
|
||||
*/
|
||||
static __attribute__ ((naked,section(".text.entry")))
|
||||
void entry (void)
|
||||
{
|
||||
asm volatile ("ldr r0, =__ram_end__\n\t"
|
||||
"ldr r1, =__main_stack_size__\n\t"
|
||||
"sub r0, r0, r1\n\t"
|
||||
"mov sp, r0\n\t"
|
||||
asm volatile ("mov r0, pc\n\t"
|
||||
"bic r0, r0, #255\n\t" /* R0 := vector_table address */
|
||||
"mov r1, #0x90\n\t" /* R1 := numbers of entries * 4 */
|
||||
"ldr r3, .L01\n" /* R3 := -0x20001400 fixed addr */
|
||||
"0:\n\t"
|
||||
"ldr r2, [r0, r1]\n\t"
|
||||
"add r2, r0\n\t" /* Relocate: R0 - 0x20001400 */
|
||||
"add r2, r3\n\t"
|
||||
"str r2, [r0, r1]\n\t"
|
||||
"subs r1, r1, #4\n\t"
|
||||
"bne 0b\n\t"
|
||||
/* Relocation done. */
|
||||
"ldr r3, .L00\n"
|
||||
".LPIC00:\n\t"
|
||||
"add r3, pc\n\t" /* R3 := @_GLOBAL_OFFSET_TABLE_ */
|
||||
/* Clear BSS. */
|
||||
"mov r0, #0\n\t"
|
||||
"ldr r1, =_bss_start\n\t"
|
||||
"ldr r2, =_bss_end\n"
|
||||
"ldr r4, .L00+4\n\t"
|
||||
"ldr r1, [r3, r4]\n\t"
|
||||
"ldr r4, .L00+8\n\t"
|
||||
"ldr r2, [r3, r4]\n"
|
||||
"0:\n\t"
|
||||
"str r0, [r1], #4\n\t"
|
||||
"cmp r2, r1\n\t"
|
||||
@@ -29,7 +50,14 @@ void entry (void)
|
||||
"mov r1, r0\n\t"
|
||||
"bl main\n"
|
||||
"1:\n\t"
|
||||
"b 1b\n"
|
||||
"b 1b\n\t"
|
||||
".align 2\n"
|
||||
".L01:\n\t"
|
||||
".word -0x20001400\n"
|
||||
".L00:\n\t"
|
||||
".word _GLOBAL_OFFSET_TABLE_-(.LPIC00+4)\n\t"
|
||||
".word _bss_start(GOT)\n\t"
|
||||
".word _bss_end(GOT)"
|
||||
: /* no output */ : /* no input */ : "memory");
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ BOARD_DIR=@BOARD_DIR@
|
||||
|
||||
# Compiler options here.
|
||||
ifeq ($(USE_OPT),)
|
||||
USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
|
||||
USE_OPT = -O3 -Os -ggdb -fomit-frame-pointer -falign-functions=16
|
||||
endif
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
@@ -175,7 +175,7 @@ DLIBS =
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
UDEFS =
|
||||
UDEFS = @KEYGEN_SUPPORT@
|
||||
|
||||
# Define ASM defines here
|
||||
UADEFS =
|
||||
|
||||
31
src/ac.c
31
src/ac.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ac.c -- Check access condition
|
||||
*
|
||||
* Copyright (C) 2010 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -24,9 +24,7 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/sha1.h"
|
||||
#include "sha256.h"
|
||||
|
||||
uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */
|
||||
|
||||
@@ -89,7 +87,7 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
}
|
||||
|
||||
success_one_step:
|
||||
sha1 (pw, pw_len, keystring);
|
||||
s2k (BY_USER, pw, pw_len, keystring);
|
||||
if (access == AC_PSO_CDS_AUTHORIZED)
|
||||
{
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
@@ -161,28 +159,27 @@ static void
|
||||
calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
|
||||
uint8_t md[KEYSTRING_MD_SIZE])
|
||||
{
|
||||
sha1_context sha1_ctx;
|
||||
sha256_context sha256_ctx;
|
||||
|
||||
sha1_starts (&sha1_ctx);
|
||||
sha256_start (&sha256_ctx);
|
||||
|
||||
while (count > pw_len + 8)
|
||||
{
|
||||
sha1_update (&sha1_ctx, salt, 8);
|
||||
sha1_update (&sha1_ctx, pw, pw_len);
|
||||
sha256_update (&sha256_ctx, salt, 8);
|
||||
sha256_update (&sha256_ctx, pw, pw_len);
|
||||
count -= pw_len + 8;
|
||||
}
|
||||
|
||||
if (count <= 8)
|
||||
sha1_update (&sha1_ctx, salt, count);
|
||||
sha256_update (&sha256_ctx, salt, count);
|
||||
else
|
||||
{
|
||||
sha1_update (&sha1_ctx, salt, 8);
|
||||
sha256_update (&sha256_ctx, salt, 8);
|
||||
count -= 8;
|
||||
sha1_update (&sha1_ctx, pw, count);
|
||||
sha256_update (&sha256_ctx, pw, count);
|
||||
}
|
||||
|
||||
sha1_finish (&sha1_ctx, md);
|
||||
memset (&sha1_ctx, 0, sizeof (sha1_ctx));
|
||||
sha256_finish (&sha256_ctx, md);
|
||||
}
|
||||
|
||||
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
|
||||
@@ -205,7 +202,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
|
||||
return 0;
|
||||
|
||||
pw_len = pw3_keystring[0];
|
||||
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len)
|
||||
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len > buf_len)
|
||||
goto failure;
|
||||
|
||||
salt = &pw3_keystring[1];
|
||||
@@ -283,7 +280,7 @@ verify_admin (const uint8_t *pw, int pw_len)
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
sha1 (pw, pw_len, keystring_md_pw3);
|
||||
s2k (admin_authorized, pw, pw_len, keystring_md_pw3);
|
||||
auth_status |= AC_ADMIN_AUTHORIZED;
|
||||
return 1;
|
||||
}
|
||||
@@ -293,6 +290,7 @@ ac_reset_admin (void)
|
||||
{
|
||||
memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE);
|
||||
auth_status &= ~AC_ADMIN_AUTHORIZED;
|
||||
admin_authorized = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -303,4 +301,5 @@ ac_fini (void)
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
|
||||
auth_status = AC_NONE_AUTHORIZED;
|
||||
admin_authorized = 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -47,10 +47,12 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
|
||||
rsa_ctx.len = KEY_CONTENT_LEN;
|
||||
mpi_read_string (&rsa_ctx.E, 16, "10001");
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2], rsa_ctx.len / 2);
|
||||
#if 0 /* Using CRT, we don't use N */
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
#endif
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
mpi_mul_mpi (&H, &P1, &Q1);
|
||||
@@ -61,17 +63,6 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
mpi_free (&P1, &Q1, &H, NULL);
|
||||
|
||||
DEBUG_INFO ("RSA sign...");
|
||||
#if 0
|
||||
if ((r = rsa_check_privkey (&rsa_ctx)) == 0)
|
||||
DEBUG_INFO ("ok...");
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("failed.\r\n");
|
||||
DEBUG_SHORT (r);
|
||||
rsa_free (&rsa_ctx);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = rsa_pkcs1_sign (&rsa_ctx, RSA_PRIVATE, SIG_RSA_RAW,
|
||||
msg_len, raw_message, temp);
|
||||
@@ -138,11 +129,13 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
rsa_ctx.len = msg_len;
|
||||
DEBUG_WORD (msg_len);
|
||||
|
||||
mpi_read_string (&rsa_ctx.E, 16, "10001");
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.P, &kd->data[0], KEY_CONTENT_LEN / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2],
|
||||
KEY_CONTENT_LEN / 2);
|
||||
#if 0 /* Using CRT, we don't use N */
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
#endif
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
mpi_mul_mpi (&H, &P1, &Q1);
|
||||
@@ -153,18 +146,6 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
mpi_free (&P1, &Q1, &H, NULL);
|
||||
|
||||
DEBUG_INFO ("RSA decrypt ...");
|
||||
#if 0
|
||||
/* This consume some memory */
|
||||
if ((r = rsa_check_privkey (&rsa_ctx)) == 0)
|
||||
DEBUG_INFO ("ok...");
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("failed.\r\n");
|
||||
DEBUG_SHORT (r);
|
||||
rsa_free (&rsa_ctx);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = rsa_pkcs1_decrypt (&rsa_ctx, RSA_PRIVATE, &output_len,
|
||||
input, output, MAX_RES_APDU_DATA_SIZE);
|
||||
@@ -191,12 +172,12 @@ rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
|
||||
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
rsa_ctx.len = KEY_CONTENT_LEN;
|
||||
mpi_read_string (&rsa_ctx.E, 16, "10001");
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.N, pubkey, KEY_CONTENT_LEN);
|
||||
|
||||
DEBUG_INFO ("RSA verify...");
|
||||
|
||||
r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA1, 20, hash, sig);
|
||||
r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA256, 32, hash, sig);
|
||||
|
||||
rsa_free (&rsa_ctx);
|
||||
if (r < 0)
|
||||
@@ -211,3 +192,37 @@ rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define RSA_EXPONENT 0x10001
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
const uint8_t *
|
||||
rsa_genkey (void)
|
||||
{
|
||||
int r;
|
||||
uint8_t index = 0;
|
||||
uint8_t *p_q_modulus = (uint8_t *)malloc (KEY_CONTENT_LEN*2);
|
||||
uint8_t *p = p_q_modulus;
|
||||
uint8_t *q = p_q_modulus + KEY_CONTENT_LEN/2;
|
||||
uint8_t *modulus = p_q_modulus + KEY_CONTENT_LEN;
|
||||
|
||||
if (p_q_modulus == NULL)
|
||||
return NULL;
|
||||
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
r = rsa_gen_key (&rsa_ctx, random_byte, &index,
|
||||
KEY_CONTENT_LEN * 8, RSA_EXPONENT);
|
||||
if (r < 0)
|
||||
{
|
||||
free (p_q_modulus);
|
||||
rsa_free (&rsa_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mpi_write_binary (&rsa_ctx.P, p, KEY_CONTENT_LEN/2);
|
||||
mpi_write_binary (&rsa_ctx.Q, q, KEY_CONTENT_LEN/2);
|
||||
mpi_write_binary (&rsa_ctx.N, modulus, KEY_CONTENT_LEN);
|
||||
rsa_free (&rsa_ctx);
|
||||
return p_q_modulus;
|
||||
}
|
||||
#endif
|
||||
|
||||
32
src/configure
vendored
32
src/configure
vendored
@@ -28,6 +28,7 @@ with_dfu=default
|
||||
debug=no
|
||||
pinpad=no
|
||||
certdo=no
|
||||
keygen=no
|
||||
|
||||
# Process each option
|
||||
for option; do
|
||||
@@ -49,8 +50,6 @@ for option; do
|
||||
debug=yes ;;
|
||||
--disable-debug)
|
||||
debug=no ;;
|
||||
--enable-pinpad)
|
||||
pinpad=yes ;;
|
||||
--enable-pinpad=*)
|
||||
pinpad=$optarg ;;
|
||||
--disable-pinpad)
|
||||
@@ -59,6 +58,10 @@ for option; do
|
||||
certdo=yes ;;
|
||||
--disable-certdo)
|
||||
certdo=no ;;
|
||||
--enable-keygen)
|
||||
keygen=yes ;;
|
||||
--disable-keygen)
|
||||
keygen=no ;;
|
||||
--with-dfu)
|
||||
with_dfu=yes ;;
|
||||
--without-dfu)
|
||||
@@ -81,7 +84,7 @@ Configuration:
|
||||
-h, --help display this help and exit [no]
|
||||
--vidpid=VID:PID specify vendor/product ID [<NONE>]
|
||||
--target=TARGET specify target [OLIMEX_STM32_H103]
|
||||
supported targes are:
|
||||
supported targets are:
|
||||
OLIMEX_STM32_H103
|
||||
STM32_PRIMER2
|
||||
CQ_STARM
|
||||
@@ -90,9 +93,10 @@ Configuration:
|
||||
STBEE
|
||||
FST_01
|
||||
--enable-debug debug with virtual COM port [no]
|
||||
--enable-pinpad={dnd,cir,dial}
|
||||
--enable-pinpad={cir,dial}
|
||||
PIN entry support [no]
|
||||
--enable-certdo support CERT.3 data object [no]
|
||||
--enable-keygen support key generation [no]
|
||||
--with-dfu build image for DFU [<target specific>]
|
||||
EOF
|
||||
exit 0
|
||||
@@ -169,12 +173,6 @@ if test "$pinpad" = "no"; then
|
||||
PINPAD_DEFINE="#undef PINPAD_SUPPORT"
|
||||
PINPAD_MORE_DEFINE=""
|
||||
echo "PIN pad option disabled"
|
||||
elif test "$pinpad" = "yes"; then
|
||||
pinpad=dnd
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=dnd"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
PINPAD_MORE_DEFINE="#define PINPAD_DND_SUPPORT 1"
|
||||
echo "PIN pad option enabled (dnd)"
|
||||
else
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
@@ -188,11 +186,20 @@ if test "$certdo" = "yes"; then
|
||||
echo "CERT.3 Data Object is supported"
|
||||
else
|
||||
CERTDO_DEFINE="#undef CERTDO_SUPPORT"
|
||||
echo "CERT.3 Data Object is not supported"
|
||||
echo "CERT.3 Data Object is NOT supported"
|
||||
fi
|
||||
|
||||
# --enable-keygen option
|
||||
if test "$keygen" = "yes"; then
|
||||
KEYGEN_SUPPORT="-DKEYGEN_SUPPORT"
|
||||
echo "Key generation on device is supported"
|
||||
else
|
||||
KEYGEN_SUPPORT=""
|
||||
echo "Key generation on device is NOT supported"
|
||||
fi
|
||||
|
||||
REVISION=`git describe --dirty="-modified"`
|
||||
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo"
|
||||
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:keygen=$keygen"
|
||||
|
||||
if !(IFS=" "
|
||||
while read VIDPID VERSION PRODUCT VENDOR; do
|
||||
@@ -242,6 +249,7 @@ fi
|
||||
sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \
|
||||
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
|
||||
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
|
||||
-e "s%@KEYGEN_SUPPORT@%$KEYGEN_SUPPORT%" \
|
||||
< Makefile.in > Makefile
|
||||
if test "$certdo" = "yes"; then
|
||||
sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CRYPTDIR = ../polarssl-0.14.0
|
||||
CRYPTSRCDIR = $(CRYPTDIR)/library
|
||||
CRYPTINCDIR = $(CRYPTDIR)/include
|
||||
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/sha1.c \
|
||||
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c \
|
||||
$(CRYPTSRCDIR)/aes.c \
|
||||
call-rsa.c
|
||||
sha256.c call-rsa.c
|
||||
|
||||
19
src/flash.c
19
src/flash.c
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012, 2013
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -46,7 +47,7 @@
|
||||
* .data
|
||||
* _bss_start
|
||||
* .bss
|
||||
* _end
|
||||
* _end
|
||||
* <alignment to page>
|
||||
* ch_certificate_startp
|
||||
* <2048 bytes>
|
||||
@@ -55,9 +56,11 @@
|
||||
* _keystore_pool
|
||||
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3)
|
||||
*/
|
||||
#define KEY_SIZE 512 /* P, Q and N */
|
||||
|
||||
#define FLASH_DATA_POOL_HEADER_SIZE 2
|
||||
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
|
||||
#define FLASH_KEYSTORE_SIZE (512*3)
|
||||
#define FLASH_KEYSTORE_SIZE (KEY_SIZE*3)
|
||||
|
||||
static const uint8_t *data_pool;
|
||||
extern uint8_t _keystore_pool;
|
||||
@@ -96,7 +99,7 @@ flash_init (void)
|
||||
/* Seek empty keystore */
|
||||
p = &_keystore_pool;
|
||||
while (*p != 0xff || *(p+1) != 0xff)
|
||||
p += 512;
|
||||
p += KEY_SIZE;
|
||||
|
||||
keystore = p;
|
||||
|
||||
@@ -279,7 +282,7 @@ flash_key_alloc (void)
|
||||
if ((k - &_keystore_pool) >= FLASH_KEYSTORE_SIZE)
|
||||
return NULL;
|
||||
|
||||
keystore += 512;
|
||||
keystore += KEY_SIZE;
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -514,6 +517,12 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
|
||||
{
|
||||
maxsize = KEY_CONTENT_LEN;
|
||||
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
|
||||
if (len == 0 && offset == 0)
|
||||
{ /* This means removal of update key. */
|
||||
if (flash_program_halfword ((uint32_t)p, 0) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
else if (file_id == FILEID_CH_CERTIFICATE)
|
||||
|
||||
55
src/gnuk.h
55
src/gnuk.h
@@ -94,6 +94,7 @@ extern volatile uint8_t auth_status;
|
||||
#define PW_ERR_PW1 0
|
||||
#define PW_ERR_RC 1
|
||||
#define PW_ERR_PW3 2
|
||||
extern int gpg_pw_get_retry_counter (int who);
|
||||
extern int gpg_pw_locked (uint8_t which);
|
||||
extern void gpg_pw_reset_err_counter (uint8_t which);
|
||||
extern void gpg_pw_increment_err_counter (uint8_t which);
|
||||
@@ -115,11 +116,14 @@ extern void ac_fini (void);
|
||||
extern void set_res_sw (uint8_t sw1, uint8_t sw2);
|
||||
extern uint16_t data_objects_number_of_bytes;
|
||||
|
||||
#define CHALLENGE_LEN 32
|
||||
|
||||
extern void gpg_data_scan (const uint8_t *p);
|
||||
extern void gpg_data_copy (const uint8_t *p);
|
||||
extern void gpg_do_get_data (uint16_t tag, int with_tag);
|
||||
extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
|
||||
extern void gpg_do_public_key (uint8_t kk_byte);
|
||||
extern void gpg_do_keygen (uint8_t kk_byte);
|
||||
|
||||
extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
|
||||
|
||||
@@ -134,6 +138,8 @@ extern const uint8_t *flash_init (void);
|
||||
extern void flash_do_release (const uint8_t *);
|
||||
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
|
||||
extern uint8_t *flash_key_alloc (void);
|
||||
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
|
||||
const uint8_t *modulus);
|
||||
extern void flash_keystore_release (void);
|
||||
extern void flash_set_data_pool_last (const uint8_t *p);
|
||||
extern void flash_clear_halfword (uint32_t addr);
|
||||
@@ -155,9 +161,9 @@ extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t le
|
||||
extern uint8_t ch_certificate_start;
|
||||
extern uint8_t random_bits_start;
|
||||
|
||||
#define KEY_MAGIC_LEN 8
|
||||
#define KEY_CONTENT_LEN 256 /* p and q */
|
||||
#define GNUK_MAGIC "Gnuk KEY"
|
||||
#define INITIAL_VECTOR_SIZE 16
|
||||
#define DATA_ENCRYPTION_KEY_SIZE 16
|
||||
|
||||
/* encrypted data content */
|
||||
struct key_data {
|
||||
@@ -165,23 +171,22 @@ struct key_data {
|
||||
};
|
||||
|
||||
struct key_data_internal {
|
||||
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
|
||||
uint32_t check;
|
||||
uint32_t random;
|
||||
char magic[KEY_MAGIC_LEN];
|
||||
uint32_t data[KEY_CONTENT_LEN/4]; /* p and q */
|
||||
uint32_t checksum[DATA_ENCRYPTION_KEY_SIZE/4];
|
||||
};
|
||||
|
||||
#define ADDITIONAL_DATA_SIZE 16
|
||||
#define DATA_ENCRYPTION_KEY_SIZE 16
|
||||
struct prvkey_data {
|
||||
const uint8_t *key_addr;
|
||||
/*
|
||||
* CRM: [C]heck, [R]andom, and [M]agic in struct key_data_internal
|
||||
*
|
||||
* IV: Initial Vector
|
||||
*/
|
||||
uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE];
|
||||
uint8_t iv[INITIAL_VECTOR_SIZE];
|
||||
/*
|
||||
* DEK: Data Encryption Key
|
||||
* Checksum
|
||||
*/
|
||||
uint8_t checksum_encrypted[DATA_ENCRYPTION_KEY_SIZE];
|
||||
/*
|
||||
* DEK (Data Encryption Key) encrypted
|
||||
*/
|
||||
uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */
|
||||
uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */
|
||||
@@ -192,12 +197,14 @@ struct prvkey_data {
|
||||
#define BY_RESETCODE 2
|
||||
#define BY_ADMIN 3
|
||||
|
||||
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus);
|
||||
extern void s2k (int who, const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32]);
|
||||
|
||||
|
||||
#define KEYSTRING_PASSLEN_SIZE 1
|
||||
#define KEYSTRING_SALT_SIZE 8 /* optional */
|
||||
#define KEYSTRING_ITER_SIZE 1 /* optional */
|
||||
#define KEYSTRING_MD_SIZE 20
|
||||
#define KEYSTRING_MD_SIZE 32
|
||||
#define KEYSTRING_SIZE_PW1 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
|
||||
#define KEYSTRING_SIZE_RC (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
|
||||
#define KEYSTRING_SIZE_PW3 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_SALT_SIZE \
|
||||
@@ -234,6 +241,7 @@ extern void modulus_free (const uint8_t *);
|
||||
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
|
||||
extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
|
||||
const uint8_t *signature);
|
||||
extern const uint8_t *rsa_genkey (void);
|
||||
|
||||
extern const uint8_t *gpg_do_read_simple (uint8_t);
|
||||
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);
|
||||
@@ -301,7 +309,7 @@ extern uint8_t admin_authorized;
|
||||
/*
|
||||
* Representation of Boolean object:
|
||||
* 0: No record in flash memory
|
||||
* 1: 0xc?00
|
||||
* 1: 0xf000
|
||||
*/
|
||||
#define NR_BOOL_PW1_LIFETIME 0xf0
|
||||
/*
|
||||
@@ -310,7 +318,7 @@ extern uint8_t admin_authorized;
|
||||
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
||||
/*
|
||||
* Representation of 123-counters:
|
||||
* 0: No record in flash memory
|
||||
* 0: No record in flash memory
|
||||
* 1: 0xfe?? 0xffff
|
||||
* 2: 0xfe?? 0xc3c3
|
||||
* 3: 0xfe?? 0x0000
|
||||
@@ -327,6 +335,8 @@ extern const uint8_t *random_bytes_get (void);
|
||||
extern void random_bytes_free (const uint8_t *);
|
||||
/* 4-byte salt */
|
||||
extern uint32_t get_salt (void);
|
||||
/* iterator returning a byta at a time */
|
||||
extern uint8_t random_byte (void *arg);
|
||||
|
||||
extern uint32_t hardclock (void);
|
||||
|
||||
@@ -359,13 +369,12 @@ extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *da
|
||||
|
||||
extern const uint8_t gnukStringSerial[];
|
||||
|
||||
#define LED_ONESHOT_SHORT ((eventmask_t)1)
|
||||
#define LED_ONESHOT_LONG ((eventmask_t)2)
|
||||
#define LED_TWOSHOT ((eventmask_t)4)
|
||||
#define LED_STATUS_MODE ((eventmask_t)8)
|
||||
#define LED_INPUT_MODE ((eventmask_t)16)
|
||||
#define LED_FATAL_MODE ((eventmask_t)32)
|
||||
extern Thread *main_thread;
|
||||
#define LED_ONESHOT ((eventmask_t)1)
|
||||
#define LED_TWOSHOTS ((eventmask_t)2)
|
||||
#define LED_SHOW_STATUS ((eventmask_t)4)
|
||||
#define LED_START_COMMAND ((eventmask_t)8)
|
||||
#define LED_FINISH_COMMAND ((eventmask_t)16)
|
||||
#define LED_FATAL ((eventmask_t)32)
|
||||
extern void led_blink (int spec);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
|
||||
307
src/main.c
307
src/main.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* main.c - main routine of Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012, 2013 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -170,13 +170,16 @@ extern msg_t USBthread (void *arg);
|
||||
/*
|
||||
* main thread does 1-bit LED display output
|
||||
*/
|
||||
#define LED_TIMEOUT_INTERVAL MS2ST(100)
|
||||
#define LED_TIMEOUT_ZERO MS2ST(50)
|
||||
#define LED_TIMEOUT_ONE MS2ST(200)
|
||||
#define LED_TIMEOUT_STOP MS2ST(500)
|
||||
#define MAIN_TIMEOUT_INTERVAL MS2ST(5000)
|
||||
|
||||
#define LED_TIMEOUT_INTERVAL MS2ST(75)
|
||||
#define LED_TIMEOUT_ZERO MS2ST(25)
|
||||
#define LED_TIMEOUT_ONE MS2ST(100)
|
||||
#define LED_TIMEOUT_STOP MS2ST(200)
|
||||
|
||||
|
||||
#define ID_OFFSET 22
|
||||
/* It has two-byte prefix and content is "FSIJ-1.0.1-" (2 + 11*2). */
|
||||
#define ID_OFFSET 24
|
||||
static void
|
||||
device_initialize_once (void)
|
||||
{
|
||||
@@ -194,7 +197,7 @@ device_initialize_once (void)
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
uint8_t b = u[i];
|
||||
uint8_t nibble;
|
||||
uint8_t nibble;
|
||||
|
||||
nibble = (b >> 4);
|
||||
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
||||
@@ -208,95 +211,64 @@ device_initialize_once (void)
|
||||
|
||||
static volatile uint8_t fatal_code;
|
||||
|
||||
Thread *main_thread;
|
||||
|
||||
#define GNUK_INIT 0
|
||||
#define GNUK_RUNNING 1
|
||||
#define GNUK_INPUT_WAIT 2
|
||||
#define GNUK_FATAL 255
|
||||
/*
|
||||
* 0 for initializing
|
||||
* 1 for normal mode
|
||||
* 2 for input waiting
|
||||
* 255 for fatal
|
||||
*/
|
||||
static uint8_t main_mode;
|
||||
|
||||
static void display_interaction (void)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
while (1)
|
||||
{
|
||||
m = chEvtWaitOne (ALL_EVENTS);
|
||||
set_led (1);
|
||||
switch (m)
|
||||
{
|
||||
case LED_ONESHOT_SHORT:
|
||||
chThdSleep (MS2ST (100));
|
||||
break;
|
||||
case LED_ONESHOT_LONG:
|
||||
chThdSleep (MS2ST (400));
|
||||
break;
|
||||
case LED_TWOSHOT:
|
||||
chThdSleep (MS2ST (50));
|
||||
set_led (0);
|
||||
chThdSleep (MS2ST (50));
|
||||
set_led (1);
|
||||
chThdSleep (MS2ST (50));
|
||||
break;
|
||||
case LED_STATUS_MODE:
|
||||
chThdSleep (MS2ST (400));
|
||||
set_led (0);
|
||||
return;
|
||||
case LED_FATAL_MODE:
|
||||
main_mode = GNUK_FATAL;
|
||||
set_led (0);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
set_led (0);
|
||||
}
|
||||
}
|
||||
static Thread *main_thread;
|
||||
|
||||
static void display_fatal_code (void)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (1);
|
||||
if (fatal_code & 1)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if (fatal_code & 2)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
while (1)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (1);
|
||||
if (fatal_code & 1)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if (fatal_code & 2)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL*10);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_status_code (void)
|
||||
static uint8_t led_inverted;
|
||||
|
||||
static eventmask_t emit_led (int on_time, int off_time)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
set_led (!led_inverted);
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, on_time);
|
||||
set_led (led_inverted);
|
||||
if (m) return m;
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, off_time)))
|
||||
return m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static eventmask_t display_status_code (void)
|
||||
{
|
||||
enum icc_state icc_state;
|
||||
eventmask_t m;
|
||||
|
||||
if (icc_state_p == NULL)
|
||||
icc_state = ICC_STATE_START;
|
||||
@@ -304,70 +276,64 @@ static void display_status_code (void)
|
||||
icc_state = *icc_state_p;
|
||||
|
||||
if (icc_state == ICC_STATE_START)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 3);
|
||||
}
|
||||
return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
|
||||
else
|
||||
/* GPGthread running */
|
||||
{
|
||||
set_led (1);
|
||||
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
if ((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;
|
||||
|
||||
if (icc_state == ICC_STATE_WAIT)
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 2);
|
||||
}
|
||||
else if (icc_state == ICC_STATE_RECEIVE)
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP * 2)))
|
||||
return m;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, 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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
led_blink (int spec)
|
||||
{
|
||||
if (spec == 0)
|
||||
chEvtSignal (main_thread, LED_ONESHOT_SHORT);
|
||||
else if (spec == 1)
|
||||
chEvtSignal (main_thread, LED_ONESHOT_LONG);
|
||||
else
|
||||
chEvtSignal (main_thread, LED_TWOSHOT);
|
||||
chEvtSignal (main_thread, spec);
|
||||
}
|
||||
|
||||
/*
|
||||
* In Gnuk 1.0.[12], reGNUal was not relocatable.
|
||||
* Now, it's relocatable, but we need to calculate its entry address
|
||||
* based on it's pre-defined address.
|
||||
*/
|
||||
#define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
|
||||
static uint32_t
|
||||
calculate_regnual_entry_address (const uint8_t *addr)
|
||||
{
|
||||
const uint8_t *p = addr + 4;
|
||||
uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
|
||||
|
||||
v -= REGNUAL_START_ADDRESS_COMPATIBLE;
|
||||
v += (uint32_t)addr;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
@@ -380,7 +346,8 @@ led_blink (int spec)
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int count = 0;
|
||||
unsigned int count = 0;
|
||||
uint32_t entry;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
@@ -389,7 +356,7 @@ main (int argc, char *argv[])
|
||||
|
||||
flash_unlock ();
|
||||
device_initialize_once ();
|
||||
usb_lld_init (Config_Descriptor.Descriptor[7]);
|
||||
usb_lld_init (usb_initial_feature);
|
||||
random_init ();
|
||||
|
||||
while (1)
|
||||
@@ -417,6 +384,7 @@ main (int argc, char *argv[])
|
||||
msc_init ();
|
||||
#endif
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
@@ -424,45 +392,41 @@ main (int argc, char *argv[])
|
||||
if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED)
|
||||
break;
|
||||
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, MAIN_TIMEOUT_INTERVAL);
|
||||
got_it:
|
||||
count++;
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL);
|
||||
switch (m)
|
||||
{
|
||||
case LED_STATUS_MODE:
|
||||
main_mode = GNUK_RUNNING;
|
||||
case LED_ONESHOT:
|
||||
if ((m = emit_led (MS2ST (100), MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
break;
|
||||
case LED_FATAL_MODE:
|
||||
main_mode = GNUK_FATAL;
|
||||
case LED_TWOSHOTS:
|
||||
if ((m = emit_led (MS2ST (50), MS2ST (50)))) goto got_it;
|
||||
if ((m = emit_led (MS2ST (50), MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
break;
|
||||
case LED_INPUT_MODE:
|
||||
main_mode = GNUK_INPUT_WAIT;
|
||||
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);
|
||||
chThdSleep (MS2ST (400));
|
||||
led_inverted = 1;
|
||||
break;
|
||||
case LED_FINISH_COMMAND:
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP);
|
||||
led_inverted = 0;
|
||||
set_led (0);
|
||||
if (m)
|
||||
goto got_it;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (main_mode)
|
||||
{
|
||||
case GNUK_FATAL:
|
||||
case LED_FATAL:
|
||||
display_fatal_code ();
|
||||
break;
|
||||
case GNUK_INIT:
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 3);
|
||||
break;
|
||||
case GNUK_INPUT_WAIT:
|
||||
display_interaction ();
|
||||
break;
|
||||
case GNUK_RUNNING:
|
||||
default:
|
||||
display_status_code ();
|
||||
if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
|
||||
goto got_it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MORE
|
||||
if (bDeviceState == CONFIGURED && (count % 10) == 0)
|
||||
@@ -483,6 +447,7 @@ main (int argc, char *argv[])
|
||||
port_disable ();
|
||||
/* Set vector */
|
||||
SCB->VTOR = (uint32_t)&_regnual_start;
|
||||
entry = calculate_regnual_entry_address (&_regnual_start);
|
||||
#ifdef DFU_SUPPORT
|
||||
#define FLASH_SYS_START_ADDR 0x08000000
|
||||
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
|
||||
@@ -500,13 +465,13 @@ main (int argc, char *argv[])
|
||||
/* copy system service routines */
|
||||
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
|
||||
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
(*func) (*((void (**)(void))(&_regnual_start+4)));
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
(*func) ((void (*)(void))entry);
|
||||
for (;;);
|
||||
}
|
||||
#else
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
flash_erase_all_and_exec ((void (*)(void))entry);
|
||||
#endif
|
||||
|
||||
/* Never reached */
|
||||
@@ -517,7 +482,7 @@ void
|
||||
fatal (uint8_t code)
|
||||
{
|
||||
fatal_code = code;
|
||||
chEvtSignal (main_thread, LED_FATAL_MODE);
|
||||
chEvtSignal (main_thread, LED_FATAL);
|
||||
_write ("fatal\r\n", 7);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
@@ -32,15 +32,15 @@ static Thread *rng_thread;
|
||||
|
||||
/* Total number of channels to be sampled by a single ADC operation.*/
|
||||
#define ADC_GRP1_NUM_CHANNELS 2
|
||||
|
||||
|
||||
/* Depth of the conversion buffer, channels are sampled one time each.*/
|
||||
#define ADC_GRP1_BUF_DEPTH 4
|
||||
|
||||
|
||||
/*
|
||||
* ADC samples buffer.
|
||||
*/
|
||||
static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
|
||||
|
||||
|
||||
static void adccb (adcsample_t *buffer, size_t n);
|
||||
|
||||
/*
|
||||
|
||||
373
src/openpgp-do.c
373
src/openpgp-do.c
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012, 2013
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -31,7 +32,6 @@
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/aes.h"
|
||||
#include "polarssl/sha1.h"
|
||||
|
||||
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
|
||||
static const uint8_t *pw_err_counter_p[3];
|
||||
@@ -42,6 +42,17 @@ gpg_pw_get_err_counter (uint8_t which)
|
||||
return flash_cnt123_get_value (pw_err_counter_p[which]);
|
||||
}
|
||||
|
||||
int
|
||||
gpg_pw_get_retry_counter (int who)
|
||||
{
|
||||
if (who == 0x81 || who == 0x82)
|
||||
return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW1);
|
||||
else if (who == 0x83)
|
||||
return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW3);
|
||||
else
|
||||
return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_RC);
|
||||
}
|
||||
|
||||
int
|
||||
gpg_pw_locked (uint8_t which)
|
||||
{
|
||||
@@ -89,16 +100,16 @@ static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
|
||||
/* Extended Capabilities */
|
||||
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
|
||||
10,
|
||||
0x30, /*
|
||||
0x70, /*
|
||||
* No SM,
|
||||
* No get challenge,
|
||||
* GET CHALLENGE supported,
|
||||
* Key import supported,
|
||||
* PW status byte can be put,
|
||||
* No private_use_DO,
|
||||
* No algo change allowed
|
||||
*/
|
||||
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
|
||||
0x00, 0x00, /* Max get challenge (0: Get challenge not supported) */
|
||||
0x00, CHALLENGE_LEN, /* Max size of GET CHALLENGE */
|
||||
#ifdef CERTDO_SUPPORT
|
||||
0x08, 0x00, /* max. length of cardholder certificate (2KiB) */
|
||||
#else
|
||||
@@ -163,6 +174,17 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gpg_reset_digital_signature_counter (void)
|
||||
{
|
||||
if (digital_signature_counter != 0)
|
||||
{
|
||||
flash_put_data (NR_COUNTER_DS);
|
||||
flash_put_data (NR_COUNTER_DS_LSB);
|
||||
digital_signature_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gpg_increment_digital_signature_counter (void)
|
||||
{
|
||||
@@ -219,7 +241,7 @@ static const struct do_table_entry *get_do_entry (uint16_t tag);
|
||||
#define GPG_DO_LOGIN_DATA 0x005e
|
||||
#define GPG_DO_CH_DATA 0x0065
|
||||
#define GPG_DO_APP_DATA 0x006e
|
||||
/* XXX: 0x0073 ??? */
|
||||
#define GPG_DO_DISCRETIONARY 0x0073
|
||||
#define GPG_DO_SS_TEMP 0x007a
|
||||
#define GPG_DO_DS_COUNT 0x0093
|
||||
#define GPG_DO_EXTCAP 0x00c0
|
||||
@@ -425,7 +447,7 @@ const uint8_t openpgpcard_aid[] = {
|
||||
static int
|
||||
do_openpgpcard_aid (uint16_t tag, int with_tag)
|
||||
{
|
||||
uint16_t vid = *((const volatile uint16_t *)&openpgpcard_aid[8]);
|
||||
uint16_t vid = (openpgpcard_aid[8] << 8) | openpgpcard_aid[9];
|
||||
|
||||
if (with_tag)
|
||||
{
|
||||
@@ -532,7 +554,7 @@ proc_resetting_code (const uint8_t *data, int len)
|
||||
|
||||
newpw_len = len;
|
||||
newpw = data;
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (BY_RESETCODE, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
|
||||
if (r <= -2)
|
||||
@@ -561,40 +583,58 @@ proc_resetting_code (const uint8_t *data, int len)
|
||||
}
|
||||
|
||||
static void
|
||||
encrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
aes_context aes;
|
||||
uint8_t iv[16];
|
||||
uint8_t iv0[INITIAL_VECTOR_SIZE];
|
||||
int iv_offset;
|
||||
|
||||
DEBUG_INFO ("ENC\r\n");
|
||||
DEBUG_BINARY (data, len);
|
||||
|
||||
aes_setkey_enc (&aes, key_str, 128);
|
||||
memset (iv, 0, 16);
|
||||
aes_setkey_enc (&aes, key, 128);
|
||||
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
|
||||
iv_offset = 0;
|
||||
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data);
|
||||
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv0, data, data);
|
||||
}
|
||||
|
||||
/* Signing, Decryption, and Authentication */
|
||||
struct key_data kd[3];
|
||||
|
||||
static void
|
||||
decrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
decrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
aes_context aes;
|
||||
uint8_t iv[16];
|
||||
uint8_t iv0[INITIAL_VECTOR_SIZE];
|
||||
int iv_offset;
|
||||
|
||||
aes_setkey_enc (&aes, key_str, 128);
|
||||
memset (iv, 0, 16);
|
||||
aes_setkey_enc (&aes, key, 128); /* This is setkey_enc, because of CFB. */
|
||||
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
|
||||
iv_offset = 0;
|
||||
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv, data, data);
|
||||
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv0, data, data);
|
||||
|
||||
DEBUG_INFO ("DEC\r\n");
|
||||
DEBUG_BINARY (data, len);
|
||||
}
|
||||
|
||||
static void
|
||||
encrypt_dek (const uint8_t *key_string, uint8_t *dek)
|
||||
{
|
||||
aes_context aes;
|
||||
|
||||
aes_setkey_enc (&aes, key_string, 128);
|
||||
aes_crypt_ecb (&aes, AES_ENCRYPT, dek, dek);
|
||||
}
|
||||
|
||||
static void
|
||||
decrypt_dek (const uint8_t *key_string, uint8_t *dek)
|
||||
{
|
||||
aes_context aes;
|
||||
|
||||
aes_setkey_dec (&aes, key_string, 128);
|
||||
aes_crypt_ecb (&aes, AES_DECRYPT, dek, dek);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
get_do_ptr_nr_for_kk (enum kind_of_key kk)
|
||||
{
|
||||
@@ -616,6 +656,25 @@ gpg_do_clear_prvkey (enum kind_of_key kk)
|
||||
memset ((void *)&kd[kk], 0, sizeof (struct key_data));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
compute_key_data_checksum (struct key_data_internal *kdi, int check_or_calc)
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t d[4] = { 0, 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < KEY_CONTENT_LEN / sizeof (uint32_t); i++)
|
||||
d[i&3] ^= kdi->data[i];
|
||||
|
||||
if (check_or_calc == 0) /* store */
|
||||
{
|
||||
memcpy (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
else /* check */
|
||||
return memcmp (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 on success,
|
||||
* 0 if none,
|
||||
@@ -626,8 +685,9 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
|
||||
{
|
||||
uint8_t nr = get_do_ptr_nr_for_kk (kk);
|
||||
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
|
||||
uint8_t *key_addr;
|
||||
const uint8_t *key_addr;
|
||||
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
|
||||
const uint8_t *iv;
|
||||
struct key_data_internal kdi;
|
||||
|
||||
DEBUG_INFO ("Loading private key: ");
|
||||
@@ -636,60 +696,47 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
|
||||
if (do_data == NULL)
|
||||
return 0;
|
||||
|
||||
key_addr = *(uint8_t **)&(do_data)[1];
|
||||
key_addr = *(const uint8_t **)&(do_data)[1]; /* Possible unaligned access */
|
||||
memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
|
||||
memcpy (((uint8_t *)&kdi.check), do_data+5, ADDITIONAL_DATA_SIZE);
|
||||
iv = do_data+5;
|
||||
memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (dek, do_data+5+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt_dek (keystring, dek);
|
||||
|
||||
decrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
if (memcmp (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
|
||||
decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
memset (dek, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
if (!compute_key_data_checksum (&kdi, 1))
|
||||
{
|
||||
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
|
||||
return -1;
|
||||
}
|
||||
/* more sanity check??? */
|
||||
|
||||
memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
|
||||
DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
calc_check32 (const uint8_t *p, int len)
|
||||
{
|
||||
uint32_t check = 0;
|
||||
uint32_t *data = (uint32_t *)p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len/4; i++)
|
||||
check += data[i];
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
static int8_t num_prv_keys;
|
||||
|
||||
static int
|
||||
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
const uint8_t *keystring_admin)
|
||||
const uint8_t *keystring_admin, const uint8_t *modulus)
|
||||
{
|
||||
uint8_t nr = get_do_ptr_nr_for_kk (kk);
|
||||
const uint8_t *p;
|
||||
int r;
|
||||
const uint8_t *modulus;
|
||||
struct prvkey_data *pd;
|
||||
uint8_t *key_addr;
|
||||
const uint8_t *dek;
|
||||
const uint8_t *dek, *iv;
|
||||
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
|
||||
const uint8_t *ks_pw1;
|
||||
const uint8_t *ks_rc;
|
||||
struct key_data_internal kdi;
|
||||
|
||||
#if 0
|
||||
assert (key_len == KEY_CONTENT_LEN);
|
||||
#endif
|
||||
int modulus_allocated_here = 0;
|
||||
uint8_t ks_pw1_len = 0;
|
||||
uint8_t ks_rc_len = 0;
|
||||
|
||||
DEBUG_INFO ("Key import\r\n");
|
||||
DEBUG_SHORT (key_len);
|
||||
@@ -698,15 +745,23 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
/* No replace support, you need to remove it first. */
|
||||
return -1;
|
||||
|
||||
if (key_len != KEY_CONTENT_LEN)
|
||||
return -1;
|
||||
|
||||
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
|
||||
if (pd == NULL)
|
||||
return -1;
|
||||
|
||||
modulus = modulus_calc (key_data, key_len);
|
||||
if (modulus == NULL)
|
||||
{
|
||||
free (pd);
|
||||
return -1;
|
||||
modulus = modulus_calc (key_data, key_len);
|
||||
if (modulus == NULL)
|
||||
{
|
||||
free (pd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
modulus_allocated_here = 1;
|
||||
}
|
||||
|
||||
DEBUG_INFO ("Getting keystore address...\r\n");
|
||||
@@ -714,7 +769,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
if (key_addr == NULL)
|
||||
{
|
||||
free (pd);
|
||||
modulus_free (modulus);
|
||||
if (modulus_allocated_here)
|
||||
modulus_free (modulus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -722,21 +778,21 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
DEBUG_WORD ((uint32_t)key_addr);
|
||||
|
||||
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
|
||||
kdi.check = calc_check32 (key_data, KEY_CONTENT_LEN);
|
||||
kdi.random = get_salt ();
|
||||
memcpy (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
|
||||
compute_key_data_checksum (&kdi, 0);
|
||||
|
||||
dek = random_bytes_get (); /* 16-byte random bytes */
|
||||
dek = random_bytes_get (); /* 32-byte random bytes */
|
||||
iv = dek + DATA_ENCRYPTION_KEY_SIZE;
|
||||
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
|
||||
|
||||
encrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
|
||||
r = flash_key_write (key_addr, kdi.data, modulus);
|
||||
modulus_free (modulus);
|
||||
r = flash_key_write (key_addr, (const uint8_t *)kdi.data, modulus);
|
||||
if (modulus_allocated_here)
|
||||
modulus_free (modulus);
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
@@ -746,32 +802,33 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
}
|
||||
|
||||
pd->key_addr = key_addr;
|
||||
memcpy (pd->crm_encrypted, (uint8_t *)&kdi.check, ADDITIONAL_DATA_SIZE);
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
ac_reset_pso_cds ();
|
||||
else
|
||||
ac_reset_other ();
|
||||
memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE);
|
||||
memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
if (ks_pw1)
|
||||
encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
|
||||
{
|
||||
ks_pw1_len = ks_pw1[0];
|
||||
encrypt_dek (ks_pw1+1, pd->dek_encrypted_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t ks123_pw1[KEYSTRING_SIZE_PW1];
|
||||
uint8_t ks[KEYSTRING_MD_SIZE];
|
||||
|
||||
ks123_pw1[0] = strlen (OPENPGP_CARD_INITIAL_PW1);
|
||||
sha1 ((uint8_t *)OPENPGP_CARD_INITIAL_PW1,
|
||||
strlen (OPENPGP_CARD_INITIAL_PW1), ks123_pw1+1);
|
||||
encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
|
||||
s2k (BY_USER, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1,
|
||||
strlen (OPENPGP_CARD_INITIAL_PW1), ks);
|
||||
encrypt_dek (ks, pd->dek_encrypted_1);
|
||||
}
|
||||
|
||||
if (ks_rc)
|
||||
encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
|
||||
{
|
||||
ks_rc_len = ks_rc[0];
|
||||
encrypt_dek (ks_rc+1, pd->dek_encrypted_2);
|
||||
}
|
||||
else
|
||||
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
if (keystring_admin)
|
||||
encrypt (keystring_admin, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
|
||||
encrypt_dek (keystring_admin, pd->dek_encrypted_3);
|
||||
else
|
||||
memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
@@ -786,17 +843,11 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
if (++num_prv_keys == NUM_ALL_PRV_KEYS) /* All keys are registered. */
|
||||
{
|
||||
/* Remove contents of keystrings from DO, but length */
|
||||
if (ks_pw1)
|
||||
{
|
||||
uint8_t ks_pw1_len = ks_pw1[0];
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
|
||||
}
|
||||
if (ks_pw1_len)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
|
||||
|
||||
if (ks_rc)
|
||||
{
|
||||
uint8_t ks_rc_len = ks_rc[0];
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
|
||||
}
|
||||
if (ks_rc_len)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -821,19 +872,21 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
|
||||
if (pd == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy (pd, &(do_data)[1], sizeof (struct prvkey_data));
|
||||
dek_p = ((uint8_t *)pd) + 4 + ADDITIONAL_DATA_SIZE
|
||||
+ DATA_ENCRYPTION_KEY_SIZE * (who_old - 1);
|
||||
memcpy (pd, &do_data[1], sizeof (struct prvkey_data));
|
||||
flash_do_release (do_data);
|
||||
|
||||
dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE
|
||||
+ DATA_ENCRYPTION_KEY_SIZE * who_old;
|
||||
memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt (old_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
encrypt (new_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt_dek (old_ks, dek);
|
||||
encrypt_dek (new_ks, dek);
|
||||
dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old);
|
||||
memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
do_ptr[nr - NR_DO__FIRST__] = NULL;
|
||||
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
|
||||
do_ptr[nr - NR_DO__FIRST__] = p;
|
||||
|
||||
flash_do_release (do_data);
|
||||
free (pd);
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
@@ -877,11 +930,19 @@ proc_key_import (const uint8_t *data, int len)
|
||||
p += 1;
|
||||
|
||||
if (*p == 0xb6)
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
else if (*p == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
{
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
ac_reset_pso_cds ();
|
||||
gpg_reset_digital_signature_counter ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*p == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
ac_reset_other ();
|
||||
}
|
||||
|
||||
if (len <= 22)
|
||||
{ /* Deletion of the key */
|
||||
@@ -901,6 +962,11 @@ proc_key_import (const uint8_t *data, int len)
|
||||
/* Delete PW1 and RC if any */
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
|
||||
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -908,7 +974,7 @@ proc_key_import (const uint8_t *data, int len)
|
||||
|
||||
/* It should starts with 00 01 00 01 (E) */
|
||||
/* Skip E, 4-byte */
|
||||
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin);
|
||||
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
else
|
||||
@@ -923,10 +989,14 @@ static const uint16_t cmp_ch_data[] = {
|
||||
};
|
||||
|
||||
static const uint16_t cmp_app_data[] = {
|
||||
10,
|
||||
3,
|
||||
GPG_DO_AID,
|
||||
GPG_DO_HIST_BYTES,
|
||||
/* XXX Discretionary data objects 0x0073 ??? */
|
||||
GPG_DO_DISCRETIONARY,
|
||||
};
|
||||
|
||||
static const uint16_t cmp_discretionary[] = {
|
||||
8,
|
||||
GPG_DO_EXTCAP,
|
||||
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
|
||||
GPG_DO_PW_STATUS,
|
||||
@@ -972,6 +1042,7 @@ gpg_do_table[] = {
|
||||
/* Compound data: Read access only */
|
||||
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
|
||||
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
|
||||
{ GPG_DO_DISCRETIONARY, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_discretionary },
|
||||
{ GPG_DO_SS_TEMP, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ss_temp },
|
||||
/* Simple data: write access only */
|
||||
{ GPG_DO_RESETTING_CODE, DO_PROC_WRITE, AC_NEVER, AC_ADMIN_AUTHORIZED,
|
||||
@@ -989,7 +1060,7 @@ gpg_do_table[] = {
|
||||
/ sizeof (struct do_table_entry))
|
||||
|
||||
/*
|
||||
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
|
||||
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
|
||||
*/
|
||||
void
|
||||
gpg_data_scan (const uint8_t *p_start)
|
||||
@@ -1039,18 +1110,18 @@ gpg_data_scan (const uint8_t *p_start)
|
||||
}
|
||||
else
|
||||
switch (nr)
|
||||
{
|
||||
case NR_BOOL_PW1_LIFETIME:
|
||||
pw1_lifetime_p = p - 1;
|
||||
p++;
|
||||
continue;
|
||||
case NR_COUNTER_123:
|
||||
p++;
|
||||
if (second_byte <= PW_ERR_PW3)
|
||||
pw_err_counter_p[second_byte] = p;
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
{
|
||||
case NR_BOOL_PW1_LIFETIME:
|
||||
pw1_lifetime_p = p - 1;
|
||||
p++;
|
||||
continue;
|
||||
case NR_COUNTER_123:
|
||||
p++;
|
||||
if (second_byte <= PW_ERR_PW3)
|
||||
pw_err_counter_p[second_byte] = p;
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1237,8 +1308,8 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
|
||||
}
|
||||
case DO_PROC_READWRITE:
|
||||
{
|
||||
int (*rw_func)(uint16_t, int, uint8_t *, int, int)
|
||||
= (int (*)(uint16_t, int, uint8_t *, int, int))do_p->obj;
|
||||
int (*rw_func)(uint16_t, int, const uint8_t *, int, int)
|
||||
= (int (*)(uint16_t, int, const uint8_t *, int, int))do_p->obj;
|
||||
|
||||
return rw_func (do_p->tag, with_tag, NULL, 0, 0);
|
||||
}
|
||||
@@ -1327,8 +1398,11 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
|
||||
flash_do_release (*do_data_p);
|
||||
|
||||
if (len == 0)
|
||||
/* make DO empty */
|
||||
*do_data_p = NULL;
|
||||
{
|
||||
/* make DO empty */
|
||||
*do_data_p = NULL;
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
else if (len > 255)
|
||||
GPG_MEMORY_FAILURE ();
|
||||
else
|
||||
@@ -1339,6 +1413,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
|
||||
GPG_MEMORY_FAILURE ();
|
||||
else
|
||||
{
|
||||
*do_data_p = NULL;
|
||||
*do_data_p = flash_do_write (nr, data, len);
|
||||
if (*do_data_p)
|
||||
GPG_SUCCESS ();
|
||||
@@ -1453,6 +1528,7 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
*do_data_p = NULL;
|
||||
*do_data_p = flash_do_write (nr, data, size);
|
||||
if (*do_data_p == NULL)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
@@ -1460,3 +1536,78 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
|
||||
else
|
||||
*do_data_p = NULL;
|
||||
}
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
void
|
||||
gpg_do_keygen (uint8_t kk_byte)
|
||||
{
|
||||
enum kind_of_key kk;
|
||||
const uint8_t *keystring_admin;
|
||||
const uint8_t *p_q_modulus;
|
||||
const uint8_t *p_q;
|
||||
const uint8_t *modulus;
|
||||
int r;
|
||||
|
||||
DEBUG_INFO ("Keygen\r\n");
|
||||
DEBUG_BYTE (kk_byte);
|
||||
|
||||
if (kk_byte == 0xb6)
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
else if (kk_byte == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
|
||||
if (admin_authorized == BY_ADMIN)
|
||||
keystring_admin = keystring_md_pw3;
|
||||
else
|
||||
keystring_admin = NULL;
|
||||
|
||||
p_q_modulus = rsa_genkey ();
|
||||
if (p_q_modulus == NULL)
|
||||
{
|
||||
GPG_MEMORY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
p_q = p_q_modulus;
|
||||
modulus = p_q_modulus + KEY_CONTENT_LEN;
|
||||
|
||||
r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN,
|
||||
keystring_admin, modulus);
|
||||
free ((uint8_t *)p_q_modulus);
|
||||
if (r < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_INFO ("Calling gpg_do_public_key...\r\n");
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
{
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *ks;
|
||||
|
||||
/* GnuPG expects it's ready for signing. */
|
||||
/* Don't call ac_reset_pso_cds here, but load the private key */
|
||||
|
||||
if (ks_pw1)
|
||||
ks = ks_pw1+1;
|
||||
else
|
||||
{
|
||||
const uint8_t * pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
|
||||
|
||||
s2k (BY_USER, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
|
||||
ks = keystring;
|
||||
}
|
||||
|
||||
gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, ks);
|
||||
}
|
||||
else
|
||||
ac_reset_other ();
|
||||
|
||||
gpg_do_public_key (kk_byte);
|
||||
}
|
||||
#endif
|
||||
|
||||
210
src/openpgp.c
210
src/openpgp.c
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* openpgp.c -- OpenPGP card protocol support
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012, 2013
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -27,8 +28,9 @@
|
||||
#include "gnuk.h"
|
||||
#include "sys.h"
|
||||
#include "openpgp.h"
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/sha1.h"
|
||||
#include "sha256.h"
|
||||
|
||||
#define ADMIN_PASSWD_MINLEN 8
|
||||
|
||||
#define CLS(a) a.cmd_apdu_head[0]
|
||||
#define INS(a) a.cmd_apdu_head[1]
|
||||
@@ -51,7 +53,6 @@
|
||||
#define INS_PUT_DATA 0xda
|
||||
#define INS_PUT_DATA_ODD 0xdb /* For key import */
|
||||
|
||||
#define CHALLENGE_LEN 16
|
||||
static const uint8_t *challenge; /* Random bytes */
|
||||
|
||||
static const uint8_t
|
||||
@@ -108,7 +109,7 @@ gpg_fini (void)
|
||||
}
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
/*
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
@@ -118,9 +119,9 @@ get_pinpad_input (int msg_code)
|
||||
{
|
||||
int r;
|
||||
|
||||
chEvtSignal (main_thread, LED_INPUT_MODE);
|
||||
led_blink (LED_START_COMMAND);
|
||||
r = pinpad_getline (msg_code, MS2ST (8000));
|
||||
chEvtSignal (main_thread, LED_STATUS_MODE);
|
||||
led_blink (LED_FINISH_COMMAND);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
@@ -139,6 +140,27 @@ cmd_verify (void)
|
||||
len = apdu.cmd_apdu_data_len;
|
||||
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 (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));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is real authentication. */
|
||||
if (p2 == 0x81)
|
||||
r = verify_pso_cds (pw, len);
|
||||
else if (p2 == 0x82)
|
||||
@@ -221,10 +243,10 @@ cmd_change_password (void)
|
||||
uint8_t p1 = P1 (apdu); /* 0: change (old+new), 1: exchange (new) */
|
||||
uint8_t p2 = P2 (apdu);
|
||||
int len;
|
||||
const uint8_t *pw;
|
||||
const uint8_t *newpw;
|
||||
uint8_t *pw, *newpw;
|
||||
int pw_len, newpw_len;
|
||||
int who = p2 - 0x80;
|
||||
int who_old;
|
||||
int r;
|
||||
|
||||
DEBUG_INFO ("Change PW\r\n");
|
||||
@@ -235,7 +257,7 @@ cmd_change_password (void)
|
||||
|
||||
if (p1 != 0)
|
||||
{
|
||||
GPG_FUNCTION_NOT_SUPPORTED();
|
||||
GPG_FUNCTION_NOT_SUPPORTED ();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -244,6 +266,7 @@ cmd_change_password (void)
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
|
||||
pw_len = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, len, -1, ks_pw1);
|
||||
who_old = who;
|
||||
|
||||
if (pw_len < 0)
|
||||
{
|
||||
@@ -259,8 +282,18 @@ cmd_change_password (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
||||
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = len - pw_len;
|
||||
|
||||
/* Check length of password for admin-less mode. */
|
||||
if (ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|
||||
{
|
||||
DEBUG_INFO ("new password length is too short.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* PW3 (0x83) */
|
||||
@@ -283,15 +316,23 @@ cmd_change_password (void)
|
||||
{
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = len - pw_len;
|
||||
gpg_set_pw3 (newpw, newpw_len);
|
||||
if (newpw_len == 0 && admin_authorized == BY_ADMIN)
|
||||
{
|
||||
newpw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
|
||||
memcpy (newpw, OPENPGP_CARD_INITIAL_PW3, newpw_len);
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW3, NULL, 0);
|
||||
}
|
||||
else
|
||||
gpg_set_pw3 (newpw, newpw_len);
|
||||
who_old = admin_authorized;
|
||||
}
|
||||
}
|
||||
|
||||
sha1 (pw, pw_len, old_ks);
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (who_old, pw, pw_len, old_ks);
|
||||
s2k (who, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
|
||||
r = gpg_change_keystring (who, old_ks, who, new_ks);
|
||||
r = gpg_change_keystring (who_old, old_ks, who, new_ks);
|
||||
if (r <= -2)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
@@ -307,6 +348,8 @@ cmd_change_password (void)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -315,6 +358,8 @@ cmd_change_password (void)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -326,6 +371,29 @@ cmd_change_password (void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define USER_S2K_MAGIC "\xffUSER\r\n"
|
||||
#define RESETCODE_S2K_MAGIC "\xffRESET\r\n"
|
||||
|
||||
void
|
||||
s2k (int who, const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32])
|
||||
{
|
||||
sha256_context ctx;
|
||||
|
||||
sha256_start (&ctx);
|
||||
sha256_update (&ctx, input, ilen);
|
||||
if (who == BY_USER)
|
||||
sha256_update (&ctx, (unsigned char *)USER_S2K_MAGIC,
|
||||
sizeof (USER_S2K_MAGIC));
|
||||
else if (who == BY_RESETCODE)
|
||||
sha256_update (&ctx, (unsigned char *)RESETCODE_S2K_MAGIC,
|
||||
sizeof (RESETCODE_S2K_MAGIC));
|
||||
/* Not add any for BY_ADMIN */
|
||||
sha256_finish (&ctx, output);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmd_reset_user_password (void)
|
||||
{
|
||||
@@ -366,8 +434,8 @@ cmd_reset_user_password (void)
|
||||
pw_len = ks_rc[0];
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = len - pw_len;
|
||||
sha1 (pw, pw_len, old_ks);
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (BY_RESETCODE, pw, pw_len, old_ks);
|
||||
s2k (BY_USER, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks);
|
||||
if (r <= -2)
|
||||
@@ -391,6 +459,8 @@ cmd_reset_user_password (void)
|
||||
KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_RC);
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
@@ -398,8 +468,11 @@ cmd_reset_user_password (void)
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_RC);
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
@@ -418,7 +491,7 @@ cmd_reset_user_password (void)
|
||||
|
||||
newpw_len = len;
|
||||
newpw = pw;
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (BY_USER, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
r = gpg_change_keystring (admin_authorized, old_ks, BY_USER, new_ks);
|
||||
if (r <= -2)
|
||||
@@ -438,14 +511,19 @@ cmd_reset_user_password (void)
|
||||
KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -480,12 +558,15 @@ cmd_pgp_gakp (void)
|
||||
/* Get public key */
|
||||
gpg_do_public_key (apdu.cmd_apdu_data[0]);
|
||||
else
|
||||
{ /* Generate key pair */
|
||||
{
|
||||
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
|
||||
GPG_SECURITY_FAILURE ();
|
||||
|
||||
/* XXX: Not yet supported */
|
||||
GPG_ERROR ();
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
/* Generate key pair */
|
||||
gpg_do_keygen (apdu.cmd_apdu_data[0]);
|
||||
#else
|
||||
GPG_FUNCTION_NOT_SUPPORTED ();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,10 +809,15 @@ cmd_pso (void)
|
||||
|
||||
/* Skip padding 0x00 */
|
||||
len--;
|
||||
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_DECRYPTION]);
|
||||
if (r < 0)
|
||||
GPG_ERROR ();
|
||||
if (len != KEY_CONTENT_LEN)
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
else
|
||||
{
|
||||
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_DECRYPTION]);
|
||||
if (r < 0)
|
||||
GPG_ERROR ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -745,6 +831,8 @@ cmd_pso (void)
|
||||
DEBUG_INFO ("PSO done.\r\n");
|
||||
}
|
||||
|
||||
|
||||
#define MAX_DIGEST_INFO_LEN 102 /* 40% */
|
||||
static void
|
||||
cmd_internal_authenticate (void)
|
||||
{
|
||||
@@ -764,6 +852,13 @@ cmd_internal_authenticate (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (len > MAX_DIGEST_INFO_LEN)
|
||||
{
|
||||
DEBUG_INFO ("input is too long.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_AUTHENTICATION]);
|
||||
if (r < 0)
|
||||
@@ -852,6 +947,26 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3
|
||||
&& len == 0 && offset == 0)
|
||||
{
|
||||
int i;
|
||||
const uint8_t *p;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p = gpg_get_firmware_update_key (i);
|
||||
if (p[0] != 0x00 || p[1] != 0x00) /* still valid */
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 4) /* all update keys are removed */
|
||||
{
|
||||
p = gpg_get_firmware_update_key (0);
|
||||
flash_erase_page ((uint32_t)p);
|
||||
}
|
||||
}
|
||||
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
|
||||
@@ -873,25 +988,9 @@ static void
|
||||
cmd_write_binary (void)
|
||||
{
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
int i;
|
||||
const uint8_t *p;
|
||||
|
||||
DEBUG_INFO (" - WRITE BINARY\r\n");
|
||||
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p = gpg_get_firmware_update_key (i);
|
||||
if (p[0] != 0x00 || p[1] != 0x00) /* still valid */
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 4) /* all update keys are removed */
|
||||
{
|
||||
p = gpg_get_firmware_update_key (0);
|
||||
flash_erase_page ((uint32_t)p);
|
||||
}
|
||||
|
||||
DEBUG_INFO ("WRITE BINARY done.\r\n");
|
||||
}
|
||||
|
||||
@@ -901,13 +1000,13 @@ cmd_external_authenticate (void)
|
||||
{
|
||||
const uint8_t *pubkey;
|
||||
const uint8_t *signature = apdu.cmd_apdu_data;
|
||||
uint8_t *hash = apdu.cmd_apdu_data + 256;
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
uint8_t keyno = P2 (apdu);
|
||||
int r;
|
||||
|
||||
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
|
||||
|
||||
if (keyno > 4)
|
||||
if (keyno >= 4)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
@@ -921,13 +1020,12 @@ cmd_external_authenticate (void)
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (hash, unique_device_id (), 4);
|
||||
memcpy (hash+4, challenge, CHALLENGE_LEN);
|
||||
|
||||
r = rsa_verify (pubkey, challenge, signature);
|
||||
random_bytes_free (challenge);
|
||||
challenge = NULL;
|
||||
|
||||
if (rsa_verify (pubkey, hash, signature) < 0)
|
||||
if (r < 0)
|
||||
{
|
||||
GPG_SECURITY_FAILURE ();
|
||||
return;
|
||||
@@ -941,15 +1039,25 @@ cmd_external_authenticate (void)
|
||||
static void
|
||||
cmd_get_challenge (void)
|
||||
{
|
||||
int len = apdu.expected_res_size;
|
||||
|
||||
DEBUG_INFO (" - GET CHALLENGE\r\n");
|
||||
|
||||
if (len > CHALLENGE_LEN)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
else if (len == 0)
|
||||
/* Le is not specified. Return full-sized challenge by GET_RESPONSE. */
|
||||
len = CHALLENGE_LEN;
|
||||
|
||||
if (challenge)
|
||||
random_bytes_free (challenge);
|
||||
|
||||
challenge = random_bytes_get ();
|
||||
memcpy (res_APDU, unique_device_id (), 4);
|
||||
memcpy (res_APDU+4, challenge, CHALLENGE_LEN);
|
||||
res_APDU_size = CHALLENGE_LEN + 4;
|
||||
memcpy (res_APDU, challenge, len);
|
||||
res_APDU_size = len;
|
||||
GPG_SUCCESS ();
|
||||
DEBUG_INFO ("GET CHALLENGE done.\r\n");
|
||||
}
|
||||
@@ -1104,7 +1212,9 @@ GPGthread (void *arg)
|
||||
else if (m == EV_NOP)
|
||||
continue;
|
||||
|
||||
led_blink (LED_START_COMMAND);
|
||||
process_command_apdu ();
|
||||
led_blink (LED_FINISH_COMMAND);
|
||||
done:
|
||||
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
|
||||
}
|
||||
|
||||
@@ -595,7 +595,7 @@ cir_getchar (systime_t timeout)
|
||||
|
||||
static Thread *pin_thread;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
@@ -620,7 +620,7 @@ pinpad_getline (int msg_code, systime_t timeout)
|
||||
|
||||
if (ch_is_backspace (ch))
|
||||
{
|
||||
led_blink (2);
|
||||
led_blink (LED_TWOSHOTS);
|
||||
if (pin_input_len > 0)
|
||||
pin_input_len--;
|
||||
}
|
||||
@@ -628,7 +628,7 @@ pinpad_getline (int msg_code, systime_t timeout)
|
||||
break;
|
||||
else if (pin_input_len < MAX_PIN_CHARS)
|
||||
{
|
||||
led_blink (0);
|
||||
led_blink (LED_ONESHOT);
|
||||
pin_input_buffer[pin_input_len++] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ uint8_t pin_input_len;
|
||||
|
||||
#define OFF '\x00'
|
||||
#define ENTER '\x0a'
|
||||
static struct led_pattern { uint8_t c, v; } led_pattern[] =
|
||||
static struct led_pattern { uint8_t c, v; } led_pattern[] =
|
||||
{
|
||||
/* char : dp a b c d e f g */
|
||||
{ ENTER, 0xf8 }, /* |- : 1 1 1 1 1 0 0 0 (enter) */
|
||||
|
||||
@@ -41,7 +41,7 @@ uint8_t pin_input_len;
|
||||
|
||||
static Thread *pin_thread;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
@@ -71,7 +71,7 @@ pinpad_getline (int msg_code, systime_t timeout)
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
|
||||
led_blink (0);
|
||||
led_blink (LED_ONESHOT);
|
||||
if (msg != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
38
src/random.c
38
src/random.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* random.c -- get random bytes
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "gnuk.h"
|
||||
#include "neug.h"
|
||||
|
||||
#define RANDOM_BYTES_LENGTH 16
|
||||
#define RANDOM_BYTES_LENGTH 32
|
||||
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
|
||||
|
||||
void
|
||||
@@ -43,7 +43,7 @@ random_init (void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointer to random 16-byte
|
||||
* Return pointer to random 32-byte
|
||||
*/
|
||||
const uint8_t *
|
||||
random_bytes_get (void)
|
||||
@@ -53,12 +53,13 @@ random_bytes_get (void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Free pointer to random 16-byte
|
||||
* Free pointer to random 32-byte
|
||||
*/
|
||||
void
|
||||
random_bytes_free (const uint8_t *p)
|
||||
{
|
||||
(void)p;
|
||||
memset (random_word, 0, RANDOM_BYTES_LENGTH);
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
@@ -70,3 +71,32 @@ get_salt (void)
|
||||
{
|
||||
return neug_get (NEUG_KICK_FILLING);
|
||||
}
|
||||
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
/*
|
||||
* Random byte iterator
|
||||
*/
|
||||
uint8_t
|
||||
random_byte (void *arg)
|
||||
{
|
||||
uint8_t *index_p = (uint8_t *)arg;
|
||||
uint8_t index = *index_p;
|
||||
uint8_t *p = ((uint8_t *)random_word) + index;
|
||||
uint8_t v;
|
||||
|
||||
neug_wait_full ();
|
||||
|
||||
v = *p;
|
||||
|
||||
if (++index >= RANDOM_BYTES_LENGTH)
|
||||
{
|
||||
index = 0;
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
*index_p = index;
|
||||
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
221
src/sha256.c
Normal file
221
src/sha256.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* sha256.c -- Compute SHA-256 hash
|
||||
*
|
||||
* Just for little endian architecture.
|
||||
*
|
||||
* Code taken from:
|
||||
* http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
|
||||
*
|
||||
* File names are sha2.c, sha2.h, brg_types.h, brg_endian.h
|
||||
* in the archive sha2-07-01-07.zip.
|
||||
*
|
||||
* Code is modified in the style of PolarSSL API.
|
||||
*
|
||||
* See original copyright notice below.
|
||||
*/
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "sha256.h"
|
||||
|
||||
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
|
||||
|
||||
static void bswap32_buf (uint32_t *p, int n)
|
||||
{
|
||||
while (n--)
|
||||
p[n] = __builtin_bswap32 (p[n]); /* bswap32 is GCC extention */
|
||||
}
|
||||
|
||||
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
|
||||
|
||||
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
|
||||
|
||||
/* round transforms for SHA256 compression functions */
|
||||
#define vf(n,i) v[(n - i) & 7]
|
||||
|
||||
#define hf(i) (p[i & 15] += \
|
||||
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
|
||||
|
||||
#define v_cycle(i,j) \
|
||||
vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \
|
||||
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
|
||||
vf(3,i) += vf(7,i); \
|
||||
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
|
||||
|
||||
#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
|
||||
#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
|
||||
#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
|
||||
#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
|
||||
#define k_0 k256
|
||||
|
||||
const uint32_t k256[64] = {
|
||||
0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5,
|
||||
0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5,
|
||||
0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3,
|
||||
0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174,
|
||||
0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC,
|
||||
0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA,
|
||||
0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7,
|
||||
0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967,
|
||||
0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13,
|
||||
0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85,
|
||||
0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3,
|
||||
0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070,
|
||||
0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5,
|
||||
0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3,
|
||||
0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208,
|
||||
0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2,
|
||||
};
|
||||
|
||||
void
|
||||
sha256_process (sha256_context *ctx)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t *p = ctx->wbuf;
|
||||
uint32_t v[8];
|
||||
|
||||
memcpy (v, ctx->state, 8 * sizeof (uint32_t));
|
||||
|
||||
for (i = 0; i < 64; i += 16)
|
||||
{
|
||||
v_cycle ( 0, i);
|
||||
v_cycle ( 1, i);
|
||||
v_cycle ( 2, i);
|
||||
v_cycle ( 3, i);
|
||||
v_cycle ( 4, i);
|
||||
v_cycle ( 5, i);
|
||||
v_cycle ( 6, i);
|
||||
v_cycle ( 7, i);
|
||||
v_cycle ( 8, i);
|
||||
v_cycle ( 9, i);
|
||||
v_cycle (10, i);
|
||||
v_cycle (11, i);
|
||||
v_cycle (12, i);
|
||||
v_cycle (13, i);
|
||||
v_cycle (14, i);
|
||||
v_cycle (15, i);
|
||||
}
|
||||
|
||||
ctx->state[0] += v[0];
|
||||
ctx->state[1] += v[1];
|
||||
ctx->state[2] += v[2];
|
||||
ctx->state[3] += v[3];
|
||||
ctx->state[4] += v[4];
|
||||
ctx->state[5] += v[5];
|
||||
ctx->state[6] += v[6];
|
||||
ctx->state[7] += v[7];
|
||||
}
|
||||
|
||||
void
|
||||
sha256_update (sha256_context *ctx, const unsigned char *input,
|
||||
unsigned int ilen)
|
||||
{
|
||||
uint32_t left = (ctx->total[0] & SHA256_MASK);
|
||||
uint32_t fill = SHA256_BLOCK_SIZE - left;
|
||||
|
||||
ctx->total[0] += ilen;
|
||||
if (ctx->total[0] < ilen)
|
||||
ctx->total[1]++;
|
||||
|
||||
while (ilen >= fill)
|
||||
{
|
||||
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
|
||||
bswap32_buf (ctx->wbuf, SHA256_BLOCK_SIZE >> 2);
|
||||
sha256_process (ctx);
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
fill = SHA256_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
|
||||
}
|
||||
|
||||
void
|
||||
sha256_finish (sha256_context *ctx, unsigned char output[32])
|
||||
{
|
||||
uint32_t last = (ctx->total[0] & SHA256_MASK);
|
||||
|
||||
bswap32_buf (ctx->wbuf, (last + 3) >> 2);
|
||||
|
||||
ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3));
|
||||
ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3));
|
||||
|
||||
if (last > SHA256_BLOCK_SIZE - 9)
|
||||
{
|
||||
if (last < 60)
|
||||
ctx->wbuf[15] = 0;
|
||||
sha256_process (ctx);
|
||||
last = 0;
|
||||
}
|
||||
else
|
||||
last = (last >> 2) + 1;
|
||||
|
||||
while (last < 14)
|
||||
ctx->wbuf[last++] = 0;
|
||||
|
||||
ctx->wbuf[14] = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
|
||||
ctx->wbuf[15] = ctx->total[0] << 3;
|
||||
sha256_process (ctx);
|
||||
|
||||
bswap32_buf (ctx->state, SHA256_DIGEST_SIZE >> 2);
|
||||
memcpy (output, ctx->state, SHA256_DIGEST_SIZE);
|
||||
memset (ctx, 0, sizeof (sha256_context));
|
||||
}
|
||||
|
||||
const uint32_t initial_state[8] =
|
||||
{
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
void
|
||||
sha256_start (sha256_context *ctx)
|
||||
{
|
||||
ctx->total[0] = ctx->total[1] = 0;
|
||||
memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void
|
||||
sha256 (const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32])
|
||||
{
|
||||
sha256_context ctx;
|
||||
|
||||
sha256_start (&ctx);
|
||||
sha256_update (&ctx, input, ilen);
|
||||
sha256_finish (&ctx, output);
|
||||
}
|
||||
17
src/sha256.h
Normal file
17
src/sha256.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#define SHA256_BLOCK_SIZE 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total[2];
|
||||
uint32_t state[8];
|
||||
uint32_t wbuf[16];
|
||||
} sha256_context;
|
||||
|
||||
extern void sha256 (const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32]);
|
||||
extern void sha256_start (sha256_context *ctx);
|
||||
extern void sha256_finish (sha256_context *ctx, unsigned char output[32]);
|
||||
extern void sha256_update (sha256_context *ctx, const unsigned char *input,
|
||||
unsigned int ilen);
|
||||
extern void sha256_process (sha256_context *ctx);
|
||||
@@ -116,7 +116,7 @@ flash_erase_page (uint32_t addr)
|
||||
if (status == 0)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PER;
|
||||
FLASH->AR = addr;
|
||||
FLASH->AR = addr;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
|
||||
@@ -321,10 +321,8 @@ static void no_buf (struct ep_in *epi, size_t len)
|
||||
epi->buf_len = 0;
|
||||
}
|
||||
|
||||
static void set_sw1sw2 (struct ep_in *epi)
|
||||
static void set_sw1sw2 (struct ccid *c, size_t chunk_len)
|
||||
{
|
||||
struct ccid *c = (struct ccid *)epi->priv;
|
||||
|
||||
if (c->a->expected_res_size >= c->len)
|
||||
{
|
||||
c->sw1sw2[0] = 0x90;
|
||||
@@ -333,10 +331,10 @@ static void set_sw1sw2 (struct ep_in *epi)
|
||||
else
|
||||
{
|
||||
c->sw1sw2[0] = 0x61;
|
||||
if (c->len >= 256)
|
||||
if (c->len - chunk_len >= 256)
|
||||
c->sw1sw2[1] = 0;
|
||||
else
|
||||
c->sw1sw2[1] = (uint8_t)c->len;
|
||||
c->sw1sw2[1] = (uint8_t)(c->len - chunk_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,6 +801,7 @@ icc_send_status (struct ccid *c)
|
||||
c->epi->tx_done = 1;
|
||||
usb_lld_write (c->epi->ep_num, icc_reply, ICC_MSG_HEADER_SIZE);
|
||||
|
||||
led_blink (LED_SHOW_STATUS);
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("St\r\n");
|
||||
#endif
|
||||
@@ -826,36 +825,7 @@ icc_power_off (struct ccid *c)
|
||||
}
|
||||
|
||||
static void
|
||||
icc_send_data_block_0x9000 (struct ccid *c)
|
||||
{
|
||||
uint8_t p[ICC_MSG_HEADER_SIZE+2];
|
||||
size_t len = 2;
|
||||
|
||||
p[0] = ICC_DATA_BLOCK_RET;
|
||||
p[1] = len & 0xFF;
|
||||
p[2] = (len >> 8)& 0xFF;
|
||||
p[3] = (len >> 16)& 0xFF;
|
||||
p[4] = (len >> 24)& 0xFF;
|
||||
p[5] = 0x00; /* Slot */
|
||||
p[ICC_MSG_SEQ_OFFSET] = c->a->seq;
|
||||
p[ICC_MSG_STATUS_OFFSET] = 0;
|
||||
p[ICC_MSG_ERROR_OFFSET] = 0;
|
||||
p[ICC_MSG_CHAIN_OFFSET] = 0;
|
||||
p[ICC_MSG_CHAIN_OFFSET+1] = 0x90;
|
||||
p[ICC_MSG_CHAIN_OFFSET+2] = 0x00;
|
||||
|
||||
usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE + len);
|
||||
c->epi->buf = NULL;
|
||||
c->epi->tx_done = 1;
|
||||
|
||||
usb_lld_tx_enable (c->epi->ep_num, ICC_MSG_HEADER_SIZE + len);
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("DATA\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
icc_send_data_block (struct ccid *c, uint8_t status)
|
||||
icc_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
|
||||
{
|
||||
int tx_size = USB_LL_BUF_SIZE;
|
||||
uint8_t p[ICC_MSG_HEADER_SIZE];
|
||||
@@ -874,7 +844,7 @@ icc_send_data_block (struct ccid *c, uint8_t status)
|
||||
p[5] = 0x00; /* Slot */
|
||||
p[ICC_MSG_SEQ_OFFSET] = c->a->seq;
|
||||
p[ICC_MSG_STATUS_OFFSET] = status;
|
||||
p[ICC_MSG_ERROR_OFFSET] = 0;
|
||||
p[ICC_MSG_ERROR_OFFSET] = error;
|
||||
p[ICC_MSG_CHAIN_OFFSET] = 0;
|
||||
|
||||
usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE);
|
||||
@@ -932,6 +902,50 @@ icc_send_data_block (struct ccid *c, uint8_t status)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
icc_send_data_block (struct ccid *c)
|
||||
{
|
||||
icc_send_data_block_internal (c, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
icc_send_data_block_time_extension (struct ccid *c)
|
||||
{
|
||||
icc_send_data_block_internal (c, ICC_CMD_STATUS_TIMEEXT, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
icc_send_data_block_0x9000 (struct ccid *c)
|
||||
{
|
||||
uint8_t p[ICC_MSG_HEADER_SIZE+2];
|
||||
size_t len = 2;
|
||||
|
||||
p[0] = ICC_DATA_BLOCK_RET;
|
||||
p[1] = len & 0xFF;
|
||||
p[2] = (len >> 8)& 0xFF;
|
||||
p[3] = (len >> 16)& 0xFF;
|
||||
p[4] = (len >> 24)& 0xFF;
|
||||
p[5] = 0x00; /* Slot */
|
||||
p[ICC_MSG_SEQ_OFFSET] = c->a->seq;
|
||||
p[ICC_MSG_STATUS_OFFSET] = 0;
|
||||
p[ICC_MSG_ERROR_OFFSET] = 0;
|
||||
p[ICC_MSG_CHAIN_OFFSET] = 0;
|
||||
p[ICC_MSG_CHAIN_OFFSET+1] = 0x90;
|
||||
p[ICC_MSG_CHAIN_OFFSET+2] = 0x00;
|
||||
|
||||
usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE + len);
|
||||
c->epi->buf = NULL;
|
||||
c->epi->tx_done = 1;
|
||||
|
||||
usb_lld_tx_enable (c->epi->ep_num, ICC_MSG_HEADER_SIZE + len);
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("DATA\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Reply to the host for "GET RESPONSE".
|
||||
*/
|
||||
static void
|
||||
icc_send_data_block_gr (struct ccid *c, size_t chunk_len)
|
||||
{
|
||||
@@ -952,7 +966,7 @@ icc_send_data_block_gr (struct ccid *c, size_t chunk_len)
|
||||
|
||||
usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE);
|
||||
|
||||
set_sw1sw2 (c->epi);
|
||||
set_sw1sw2 (c, chunk_len);
|
||||
|
||||
if (chunk_len <= USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE)
|
||||
{
|
||||
@@ -1259,7 +1273,8 @@ icc_handle_timeout (struct ccid *c)
|
||||
switch (c->icc_state)
|
||||
{
|
||||
case ICC_STATE_EXECUTE:
|
||||
icc_send_data_block (c, ICC_CMD_STATUS_TIMEEXT);
|
||||
icc_send_data_block_time_extension (c);
|
||||
led_blink (LED_ONESHOT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1309,7 +1324,7 @@ USBthread (void *arg)
|
||||
c->sw1sw2[0] = 0x90;
|
||||
c->sw1sw2[1] = 0x00;
|
||||
c->state = APDU_STATE_RESULT;
|
||||
icc_send_data_block (c, 0);
|
||||
icc_send_data_block (c);
|
||||
c->icc_state = ICC_STATE_EXITED;
|
||||
break;
|
||||
}
|
||||
@@ -1321,7 +1336,7 @@ USBthread (void *arg)
|
||||
if (c->a->res_apdu_data_len <= c->a->expected_res_size)
|
||||
{
|
||||
c->state = APDU_STATE_RESULT;
|
||||
icc_send_data_block (c, 0);
|
||||
icc_send_data_block (c);
|
||||
c->icc_state = ICC_STATE_WAIT;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -372,7 +372,7 @@ void msc_handle_command (void)
|
||||
msc_send_result (buf, 12);
|
||||
return;
|
||||
case SCSI_START_STOP_UNIT:
|
||||
if (CBW.CBWCB[4] == 0x00 /* stop */
|
||||
if (CBW.CBWCB[4] == 0x00 /* stop */
|
||||
|| CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
|
||||
{
|
||||
msc_scsi_stop (CBW.CBWCB[4]);
|
||||
@@ -380,7 +380,7 @@ void msc_handle_command (void)
|
||||
contingent_allegiance = 1;
|
||||
keep_contingent_allegiance = 1;
|
||||
}
|
||||
/* CBW.CBWCB[4] == 0x01 *//* start */
|
||||
/* CBW.CBWCB[4] == 0x01 *//* start */
|
||||
goto success;
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
if (contingent_allegiance)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012, 2013 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -147,8 +147,8 @@ gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_reset (void)
|
||||
void
|
||||
usb_cb_device_reset (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -156,7 +156,7 @@ gnuk_device_reset (void)
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (Config_Descriptor.Descriptor[7]);
|
||||
usb_lld_set_feature (usb_initial_feature);
|
||||
|
||||
usb_lld_reset ();
|
||||
|
||||
@@ -214,9 +214,9 @@ static int download_check_crc32 (const uint32_t *end_p)
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int
|
||||
gnuk_setup (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len)
|
||||
int
|
||||
usb_cb_setup (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
@@ -310,9 +310,8 @@ gnuk_setup (uint8_t req, uint8_t req_no,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static void gnuk_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index,
|
||||
uint16_t len)
|
||||
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
|
||||
uint16_t index, uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
@@ -329,38 +328,7 @@ static void gnuk_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
{
|
||||
(void)index;
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
|
||||
Device_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
|
||||
Config_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
uint8_t desc_index = value & 0xff;
|
||||
|
||||
if (desc_index < NUM_STRING_DESC)
|
||||
{
|
||||
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
|
||||
String_Descriptors[desc_index].Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_usb_event (uint8_t event_type, uint16_t value)
|
||||
int usb_cb_handle_event (uint8_t event_type, uint16_t value)
|
||||
{
|
||||
int i;
|
||||
uint8_t current_conf;
|
||||
@@ -381,7 +349,6 @@ static int gnuk_usb_event (uint8_t event_type, uint16_t value)
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i, 0);
|
||||
bDeviceState = CONFIGURED;
|
||||
chEvtSignalI (main_thread, LED_STATUS_MODE);
|
||||
}
|
||||
else if (current_conf != value)
|
||||
{
|
||||
@@ -402,7 +369,7 @@ static int gnuk_usb_event (uint8_t event_type, uint16_t value)
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
{
|
||||
static uint8_t zero = 0;
|
||||
|
||||
@@ -430,18 +397,6 @@ static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to USB core
|
||||
*/
|
||||
|
||||
const struct usb_device_method Device_Method = {
|
||||
gnuk_device_reset,
|
||||
gnuk_ctrl_write_finish,
|
||||
gnuk_setup,
|
||||
gnuk_get_descriptor,
|
||||
gnuk_usb_event,
|
||||
gnuk_interface,
|
||||
};
|
||||
|
||||
CH_IRQ_HANDLER (Vector90)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
#include "usb_conf.h"
|
||||
#include "usb-cdc.h"
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
const uint8_t *Descriptor;
|
||||
uint16_t Descriptor_Size;
|
||||
};
|
||||
|
||||
|
||||
#define USB_ICC_INTERFACE_CLASS 0x0B
|
||||
#define USB_ICC_INTERFACE_SUBCLASS 0x00
|
||||
#define USB_ICC_INTERFACE_BULK_PROTOCOL 0x00
|
||||
@@ -53,6 +60,15 @@ static const uint8_t gnukDeviceDescriptor[] = {
|
||||
#define NUM_INTERFACES (ICC_NUM_INTERFACES+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
||||
|
||||
|
||||
|
||||
#if defined(USB_SELF_POWERED)
|
||||
#define USB_INITIAL_FEATURE 0xC0 /* bmAttributes: self powered */
|
||||
#else
|
||||
#define USB_INITIAL_FEATURE 0x80 /* bmAttributes: bus powered */
|
||||
#endif
|
||||
|
||||
const uint8_t usb_initial_feature = USB_INITIAL_FEATURE;
|
||||
|
||||
/* Configuation Descriptor */
|
||||
static const uint8_t gnukConfigDescriptor[] = {
|
||||
9, /* bLength: Configuation Descriptor size */
|
||||
@@ -61,11 +77,7 @@ static const uint8_t gnukConfigDescriptor[] = {
|
||||
NUM_INTERFACES, /* bNumInterfaces: */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||
#if defined(USB_SELF_POWERED)
|
||||
0xC0, /* bmAttributes: self powered */
|
||||
#else
|
||||
0x80, /* bmAttributes: bus powered */
|
||||
#endif
|
||||
USB_INITIAL_FEATURE, /* bmAttributes*/
|
||||
50, /* MaxPower 100 mA */
|
||||
|
||||
/* Interface Descriptor */
|
||||
@@ -258,27 +270,27 @@ static const uint8_t gnukStringLangID[] = {
|
||||
#include "usb-strings.c.inc"
|
||||
|
||||
const uint8_t gnukStringSerial[] = {
|
||||
18*2+2, /* bLength */
|
||||
19*2+2, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
/* FSIJ-0.19 */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
|
||||
'0', 0, '.', 0, '1', 0, '9', 0, /* Version number of Gnuk */
|
||||
/* FSIJ-1.0.3- */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
|
||||
'1', 0, '.', 0, '0', 0, '.', 0, '4', 0, /* Version number of Gnuk */
|
||||
'-', 0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
const struct Descriptor Device_Descriptor = {
|
||||
static const struct Descriptor Device_Descriptor = {
|
||||
gnukDeviceDescriptor,
|
||||
sizeof (gnukDeviceDescriptor)
|
||||
};
|
||||
|
||||
const struct Descriptor Config_Descriptor = {
|
||||
static const struct Descriptor Config_Descriptor = {
|
||||
gnukConfigDescriptor,
|
||||
sizeof (gnukConfigDescriptor)
|
||||
};
|
||||
|
||||
const struct Descriptor String_Descriptors[NUM_STRING_DESC] = {
|
||||
static const struct Descriptor String_Descriptors[NUM_STRING_DESC] = {
|
||||
{gnukStringLangID, sizeof (gnukStringLangID)},
|
||||
{gnukStringVendor, sizeof (gnukStringVendor)},
|
||||
{gnukStringProduct, sizeof (gnukStringProduct)},
|
||||
@@ -287,3 +299,34 @@ const struct Descriptor String_Descriptors[NUM_STRING_DESC] = {
|
||||
{gnuk_config_options, sizeof (gnuk_config_options)},
|
||||
{sys_version, sizeof (sys_version)},
|
||||
};
|
||||
|
||||
int
|
||||
usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
{
|
||||
(void)index;
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
|
||||
Device_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
|
||||
Config_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
uint8_t desc_index = value & 0xff;
|
||||
|
||||
if (desc_index < NUM_STRING_DESC)
|
||||
{
|
||||
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
|
||||
String_Descriptors[desc_index].Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
104
src/usb_lld.c
104
src/usb_lld.c
@@ -74,12 +74,10 @@ struct DEVICE_INFO
|
||||
static struct CONTROL_INFO control_info;
|
||||
static struct DEVICE_INFO device_info;
|
||||
static struct DATA_INFO data_info;
|
||||
extern const struct usb_device_method Device_Method;
|
||||
|
||||
static struct CONTROL_INFO *const ctrl_p = &control_info;
|
||||
static struct DEVICE_INFO *const dev_p = &device_info;
|
||||
static struct DATA_INFO *const data_p = &data_info;
|
||||
static const struct usb_device_method *const method_p = &Device_Method;
|
||||
|
||||
#define REG_BASE (0x40005C00UL) /* USB_IP Peripheral Registers base address */
|
||||
#define PMA_ADDR (0x40006000UL) /* USB_IP Packet Memory Area base address */
|
||||
@@ -399,7 +397,7 @@ usb_interrupt_handler (void)
|
||||
if (istr_value & ISTR_RESET)
|
||||
{
|
||||
st103_set_istr (CLR_RESET);
|
||||
method_p->reset ();
|
||||
usb_cb_device_reset ();
|
||||
}
|
||||
|
||||
if (istr_value & ISTR_DOVR)
|
||||
@@ -529,7 +527,7 @@ static int std_get_status (uint8_t req,
|
||||
if (dev_p->current_configuration == 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
r = (*method_p->interface) (USB_QUERY_INTERFACE, index, 0);
|
||||
r = usb_cb_interface (USB_QUERY_INTERFACE, index, 0);
|
||||
if (r != USB_SUCCESS)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
@@ -700,7 +698,7 @@ static int std_get_descriptor (uint8_t req, uint16_t value,
|
||||
|
||||
(void)length;
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
return (*method_p->get_descriptor) ((value >> 8), index, value);
|
||||
return usb_cb_get_descriptor ((value >> 8), index, value);
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
@@ -736,7 +734,7 @@ static int std_set_configuration (uint8_t req, uint16_t value,
|
||||
{
|
||||
int r;
|
||||
|
||||
r = (*method_p->event) (USB_EVENT_CONFIG, value);
|
||||
r = usb_cb_handle_event (USB_EVENT_CONFIG, value);
|
||||
if (r == USB_SUCCESS)
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
@@ -760,7 +758,7 @@ static int std_get_interface (uint8_t req, uint16_t value,
|
||||
if (dev_p->current_configuration == 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
return (*method_p->interface) (USB_GET_INTERFACE, index, 0);
|
||||
return usb_cb_interface (USB_GET_INTERFACE, index, 0);
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
@@ -784,7 +782,7 @@ static int std_set_interface (uint8_t req, uint16_t value,
|
||||
if (dev_p->current_configuration != 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
r = (*method_p->interface) (USB_SET_INTERFACE, index, value);
|
||||
r = usb_cb_interface (USB_SET_INTERFACE, index, value);
|
||||
if (r == USB_SUCCESS)
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
@@ -792,21 +790,6 @@ static int std_set_interface (uint8_t req, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static const HANDLER std_request_handler[TOTAL_REQUEST] = {
|
||||
std_get_status,
|
||||
std_clear_feature,
|
||||
std_none,
|
||||
std_set_feature,
|
||||
std_none,
|
||||
std_set_address,
|
||||
std_get_descriptor,
|
||||
std_none, /* set_descriptor is not supported */
|
||||
std_get_configuration,
|
||||
std_set_configuration,
|
||||
std_get_interface,
|
||||
std_set_interface,
|
||||
std_none, /* sync_frame is not supported (for now) */
|
||||
};
|
||||
|
||||
static void handle_setup0 (void)
|
||||
{
|
||||
@@ -836,14 +819,27 @@ static void handle_setup0 (void)
|
||||
{
|
||||
if (req < TOTAL_REQUEST)
|
||||
{
|
||||
handler = std_request_handler[req];
|
||||
switch (req)
|
||||
{
|
||||
case 0: handler = std_get_status; break;
|
||||
case 1: handler = std_clear_feature; break;
|
||||
case 3: handler = std_set_feature; break;
|
||||
case 5: handler = std_set_address; break;
|
||||
case 6: handler = std_get_descriptor; break;
|
||||
case 8: handler = std_get_configuration; break;
|
||||
case 9: handler = std_set_configuration; break;
|
||||
case 10: handler = std_get_interface; break;
|
||||
case 11: handler = std_set_interface; break;
|
||||
default: handler = std_none; break;
|
||||
}
|
||||
|
||||
r = (*handler) (ctrl_p->bmRequestType,
|
||||
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
r = (*method_p->setup) (ctrl_p->bmRequestType, req,
|
||||
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
|
||||
r = usb_cb_setup (ctrl_p->bmRequestType, req,
|
||||
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
|
||||
|
||||
if (r != USB_SUCCESS)
|
||||
dev_p->state = STALLED;
|
||||
@@ -852,11 +848,11 @@ static void handle_setup0 (void)
|
||||
if (USB_SETUP_GET (ctrl_p->bmRequestType))
|
||||
{
|
||||
uint32_t len = ctrl_p->wLength;
|
||||
|
||||
|
||||
/* Restrict the data length to be the one host asks for */
|
||||
if (data_p->len > len)
|
||||
data_p->len = len;
|
||||
|
||||
|
||||
if ((data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = TRUE;
|
||||
else
|
||||
@@ -871,7 +867,7 @@ static void handle_setup0 (void)
|
||||
st103_set_tx_count (ENDP0, 0);
|
||||
st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
dev_p->state = OUT_DATA;
|
||||
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
@@ -890,12 +886,12 @@ static void handle_in0 (void)
|
||||
== (STANDARD_REQUEST | DEVICE_RECIPIENT)))
|
||||
{
|
||||
st103_set_daddr (ctrl_p->wValue);
|
||||
(*method_p->event) (USB_EVENT_ADDRESS, ctrl_p->wValue);
|
||||
usb_cb_handle_event (USB_EVENT_ADDRESS, ctrl_p->wValue);
|
||||
}
|
||||
else
|
||||
(*method_p->ctrl_write_finish) (ctrl_p->bmRequestType,
|
||||
ctrl_p->bRequest, ctrl_p->wValue,
|
||||
ctrl_p->wIndex, ctrl_p->wLength);
|
||||
usb_cb_ctrl_write_finish (ctrl_p->bmRequestType,
|
||||
ctrl_p->bRequest, ctrl_p->wValue,
|
||||
ctrl_p->wIndex, ctrl_p->wLength);
|
||||
|
||||
dev_p->state = STALLED;
|
||||
}
|
||||
@@ -938,26 +934,6 @@ void WEAK EP5_OUT_Callback (void);
|
||||
void WEAK EP6_OUT_Callback (void);
|
||||
void WEAK EP7_OUT_Callback (void);
|
||||
|
||||
void (*const ep_intr_handler_IN[7]) (void) = {
|
||||
EP1_IN_Callback,
|
||||
EP2_IN_Callback,
|
||||
EP3_IN_Callback,
|
||||
EP4_IN_Callback,
|
||||
EP5_IN_Callback,
|
||||
EP6_IN_Callback,
|
||||
EP7_IN_Callback,
|
||||
};
|
||||
|
||||
void (*const ep_intr_handler_OUT[7]) (void) = {
|
||||
EP1_OUT_Callback,
|
||||
EP2_OUT_Callback,
|
||||
EP3_OUT_Callback,
|
||||
EP4_OUT_Callback,
|
||||
EP5_OUT_Callback,
|
||||
EP6_OUT_Callback,
|
||||
EP7_OUT_Callback,
|
||||
};
|
||||
|
||||
static void
|
||||
usb_handle_transfer (void)
|
||||
{
|
||||
@@ -1008,13 +984,31 @@ usb_handle_transfer (void)
|
||||
if ((ep_value & EP_CTR_RX) != 0)
|
||||
{
|
||||
st103_ep_clear_ctr_rx (ep_index);
|
||||
(*ep_intr_handler_OUT[ep_index-1]) ();
|
||||
switch ((ep_index - 1))
|
||||
{
|
||||
case 0: EP1_OUT_Callback (); break;
|
||||
case 1: EP2_OUT_Callback (); break;
|
||||
case 2: EP3_OUT_Callback (); break;
|
||||
case 3: EP4_OUT_Callback (); break;
|
||||
case 4: EP5_OUT_Callback (); break;
|
||||
case 5: EP6_OUT_Callback (); break;
|
||||
case 6: EP7_OUT_Callback (); break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ep_value & EP_CTR_TX) != 0)
|
||||
{
|
||||
st103_ep_clear_ctr_tx (ep_index);
|
||||
(*ep_intr_handler_IN[ep_index-1]) ();
|
||||
switch ((ep_index - 1))
|
||||
{
|
||||
case 0: EP1_IN_Callback (); break;
|
||||
case 1: EP2_IN_Callback (); break;
|
||||
case 2: EP3_IN_Callback (); break;
|
||||
case 3: EP4_IN_Callback (); break;
|
||||
case 4: EP5_IN_Callback (); break;
|
||||
case 5: EP6_IN_Callback (); break;
|
||||
case 6: EP7_IN_Callback (); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,29 +49,20 @@ enum DESCRIPTOR_TYPE
|
||||
#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0)
|
||||
#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0)
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
const uint8_t *Descriptor;
|
||||
uint16_t Descriptor_Size;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
USB_UNSUPPORT = 0,
|
||||
USB_SUCCESS = 1,
|
||||
};
|
||||
|
||||
struct usb_device_method
|
||||
{
|
||||
void (*reset) (void);
|
||||
void (*ctrl_write_finish) (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len);
|
||||
int (*setup) (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len);
|
||||
int (*get_descriptor) (uint8_t desc_type, uint16_t index, uint16_t value);
|
||||
int (*event) (uint8_t event_type, uint16_t value);
|
||||
int (*interface) (uint8_t cmd, uint16_t interface, uint16_t value);
|
||||
};
|
||||
void usb_cb_device_reset (void);
|
||||
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len);
|
||||
int usb_cb_setup (uint8_t req, uint8_t req_no, uint16_t value,
|
||||
uint16_t index, uint16_t len);
|
||||
int usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value);
|
||||
int usb_cb_handle_event (uint8_t event_type, uint16_t value);
|
||||
int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t value);
|
||||
|
||||
enum {
|
||||
USB_EVENT_ADDRESS,
|
||||
@@ -87,14 +78,6 @@ enum {
|
||||
USB_QUERY_INTERFACE,
|
||||
};
|
||||
|
||||
extern void USB_Cable_Config (int NewState);
|
||||
|
||||
extern const struct usb_device_method Device_Method;
|
||||
|
||||
extern const struct Descriptor Device_Descriptor;
|
||||
extern const struct Descriptor Config_Descriptor;
|
||||
extern const struct Descriptor String_Descriptors[];
|
||||
|
||||
enum DEVICE_STATE
|
||||
{
|
||||
UNCONNECTED,
|
||||
@@ -106,6 +89,7 @@ enum DEVICE_STATE
|
||||
};
|
||||
|
||||
extern uint32_t bDeviceState;
|
||||
extern const uint8_t usb_initial_feature;
|
||||
|
||||
#define STM32_USB_IRQ_PRIORITY 11
|
||||
|
||||
|
||||
20
test/README
Normal file
20
test/README
Normal file
@@ -0,0 +1,20 @@
|
||||
This is a functionality test suite for Gnuk.
|
||||
|
||||
You need python-nose, python-freshen as well as python-usb.
|
||||
|
||||
Besides, python-crypto is needed when you use generate_keys.py to
|
||||
update contents of *.key.
|
||||
|
||||
|
||||
Type:
|
||||
|
||||
$ nosetests --with-freshen
|
||||
|
||||
or
|
||||
|
||||
$ nosetests -v --with-freshen
|
||||
|
||||
to run the test suite.
|
||||
|
||||
To skip tests for key generation, add an option "--tag ~keygen". To
|
||||
stop running tests after the first error or failure, add "--stop" option.
|
||||
79
test/features/000_empty_check.feature
Normal file
79
test/features/000_empty_check.feature
Normal file
@@ -0,0 +1,79 @@
|
||||
Feature: confirm empty token
|
||||
In order to start tests
|
||||
A token should be empty (no data, no keys)
|
||||
|
||||
Scenario: data object Login
|
||||
When requesting login data: 5e
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Name
|
||||
When requesting name: 5b
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Language preference
|
||||
When requesting anguage preference: 5f2d
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Sex
|
||||
When requesting sex: 5f35
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object URL
|
||||
When requesting URL: 5f50
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object ds counter
|
||||
When requesting ds counter: 93
|
||||
Then you should get: \x00\x00\x00
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
When requesting pw1 status bytes: c4
|
||||
Then you should get: \x00\x7f\x7f\x7f\x03\x03\x03
|
||||
|
||||
Scenario: data object finger print 0
|
||||
When requesting finger print: c5
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object finger print 1
|
||||
When requesting finger print: c7
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object finger print 2
|
||||
When requesting finger print: c8
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object finger print 3
|
||||
When requesting finger print: c9
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 0
|
||||
When requesting finger print: c6
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object CA finger print 1
|
||||
When requesting finger print: ca
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 2
|
||||
When requesting finger print: cb
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 3
|
||||
When requesting finger print: cc
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 0
|
||||
When requesting date/time of key pair: cd
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object date/time of key pair 1
|
||||
When requesting date/time of key pair: ce
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 2
|
||||
When requesting date/time of key pair: cf
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 3
|
||||
When requesting date/time of key pair: d0
|
||||
Then you should get NULL
|
||||
15
test/features/001_empty_check_passphrase.feature
Normal file
15
test/features/001_empty_check_passphrase.feature
Normal file
@@ -0,0 +1,15 @@
|
||||
Feature: confirm empty token
|
||||
In order to start tests
|
||||
A token should be empty (no pass phrase)
|
||||
|
||||
Scenario: verify PW1 factory setting (1)
|
||||
Given cmd_verify with 1 and "123456"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 factory setting (2)
|
||||
Given cmd_verify with 2 and "123456"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 factory setting
|
||||
Given cmd_verify with 3 and "12345678"
|
||||
Then it should get success
|
||||
27
test/features/002_get_data_static.feature
Normal file
27
test/features/002_get_data_static.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: command GET DATA
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support all mandatory features of the specification
|
||||
|
||||
Scenario: data object historical bytes
|
||||
When requesting historical bytes: 5f52
|
||||
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00
|
||||
|
||||
Scenario: data object extended capabilities
|
||||
When requesting extended capabilities: c0
|
||||
Then data should match: \x70\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
|
||||
Scenario: data object algorithm attributes 1
|
||||
When requesting algorithm attributes 1: c1
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object algorithm attributes 2
|
||||
When requesting algorithm attributes 2: c2
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object algorithm attributes 3
|
||||
When requesting algorighm attributes 3: c3
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object AID
|
||||
When requesting AID: 4f
|
||||
Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00
|
||||
63
test/features/010_setup_passphrase.feature
Normal file
63
test/features/010_setup_passphrase.feature
Normal file
@@ -0,0 +1,63 @@
|
||||
Feature: setup pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: setup PW1 (admin-less mode)
|
||||
Given cmd_change_reference_data with 1 and "123456user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1)
|
||||
Given cmd_verify with 1 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2)
|
||||
Given cmd_verify with 2 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode)
|
||||
Given cmd_verify with 3 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-less mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-less mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode) again
|
||||
Given cmd_verify with 3 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "new user pass phraseadmin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-full mode)
|
||||
Given cmd_put_data with d3 and "another reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 0 and "another reset code 000another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
27
test/features/020_personalization_write.feature
Normal file
27
test/features/020_personalization_write.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: personalize token write
|
||||
In order to use a token
|
||||
A token should be personalized with name, sex, url, etc.
|
||||
|
||||
Scenario: data object Login
|
||||
Given cmd_put_data with 5e and "gpg_user"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Name
|
||||
Given cmd_put_data with 5b and "GnuPG User"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Language preference
|
||||
Given cmd_put_data with 5f2d and "ja"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Sex
|
||||
Given cmd_put_data with 5f35 and "1"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object URL
|
||||
Given cmd_put_data with 5f50 and "http://www.fsij.org/gnuk/"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
Given cmd_put_data with c4 and "\x01"
|
||||
Then it should get success
|
||||
27
test/features/021_personalization_read.feature
Normal file
27
test/features/021_personalization_read.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: personalize token read
|
||||
In order to use a token
|
||||
A token should be personalized with name, sex, url, etc.
|
||||
|
||||
Scenario: data object Login
|
||||
When requesting login data: 5e
|
||||
Then you should get: gpg_user
|
||||
|
||||
Scenario: data object Name
|
||||
When requesting name: 5b
|
||||
Then you should get: GnuPG User
|
||||
|
||||
Scenario: data object Language preference
|
||||
When requesting anguage preference: 5f2d
|
||||
Then you should get: ja
|
||||
|
||||
Scenario: data object Sex
|
||||
When requesting sex: 5f35
|
||||
Then you should get: 1
|
||||
|
||||
Scenario: data object URL
|
||||
When requesting URL: 5f50
|
||||
Then you should get: http://www.fsij.org/gnuk/
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
When requesting pw1 status bytes: c4
|
||||
Then you should get: \x01\x7f\x7f\x7f\x03\x03\x03
|
||||
56
test/features/030_key_registration.feature
Normal file
56
test/features/030_key_registration.feature
Normal file
@@ -0,0 +1,56 @@
|
||||
Feature: import keys to token
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: importing OPENPGP.1 key (sign)
|
||||
Given a RSA key pair 0
|
||||
And importing it to the token as OPENPGP.1
|
||||
Then it should get success
|
||||
|
||||
Scenario: importing OPENPGP.2 key (decrypt)
|
||||
Given a RSA key pair 1
|
||||
And importing it to the token as OPENPGP.2
|
||||
Then it should get success
|
||||
|
||||
Scenario: importing OPENPGP.3 key (authentication)
|
||||
Given a RSA key pair 2
|
||||
And importing it to the token as OPENPGP.3
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print sig
|
||||
Given a fingerprint of OPENPGP.1 key
|
||||
And put the data to c7
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print dec
|
||||
Given a fingerprint of OPENPGP.2 key
|
||||
And put the data to c8
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print aut
|
||||
Given a fingerprint of OPENPGP.3 key
|
||||
And put the data to c9
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time sig
|
||||
Given a timestamp of OPENPGP.1 key
|
||||
And put the data to ce
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time dec
|
||||
Given a timestamp of OPENPGP.2 key
|
||||
And put the data to cf
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time aut
|
||||
Given a timestamp of OPENPGP.3 key
|
||||
And put the data to d0
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
71
test/features/040_passphrase_change.feature
Normal file
71
test/features/040_passphrase_change.feature
Normal file
@@ -0,0 +1,71 @@
|
||||
Feature: change pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code again (in admin-full mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "admin pass phraseanother admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "another admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by admin (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "another admin pass phraseadmin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "admin pass phrase"
|
||||
Then it should get success
|
||||
31
test/features/100_compute_signature.feature
Normal file
31
test/features/100_compute_signature.feature
Normal file
@@ -0,0 +1,31 @@
|
||||
Feature: compute digital signature
|
||||
In order to use a token
|
||||
A token should compute digital signature properly
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (1)
|
||||
Given a message "This is a test message."
|
||||
And let a token compute digital signature
|
||||
And compute digital signature on host with RSA key pair 0
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And let a token compute digital signature
|
||||
And compute digital signature on host with RSA key pair 0
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (1)
|
||||
Given a message "This is a test message."
|
||||
And let a token authenticate
|
||||
And compute digital signature on host with RSA key pair 2
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And let a token authenticate
|
||||
And compute digital signature on host with RSA key pair 2
|
||||
Then results should be same
|
||||
|
||||
Scenario: data object ds counter
|
||||
When requesting ds counter: 93
|
||||
Then you should get: \x00\x00\x02
|
||||
16
test/features/101_decryption.feature
Normal file
16
test/features/101_decryption.feature
Normal file
@@ -0,0 +1,16 @@
|
||||
Feature: decryption
|
||||
In order to use a token
|
||||
A token should decrypt encrypted data
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (1)
|
||||
Given a plain text "This is a test message."
|
||||
And encrypt it on host with RSA key pair 1
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (2)
|
||||
Given a plain text "RSA decryption is as easy as pie."
|
||||
And encrypt it on host with RSA key pair 1
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
40
test/features/200_key_removal.feature
Normal file
40
test/features/200_key_removal.feature
Normal file
@@ -0,0 +1,40 @@
|
||||
@keygen
|
||||
Feature: key removal
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: remove OPENPGP.1 key (sign)
|
||||
When removing a key OPENPGP.1
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.2 key (decrypt)
|
||||
When removing a key OPENPGP.2
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.3 key (authentication)
|
||||
When removing a key OPENPGP.3
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print sig
|
||||
Given cmd_put_data with c7 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print dec
|
||||
Given cmd_put_data with c8 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print aut
|
||||
Given cmd_put_data with c9 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time sig
|
||||
Given cmd_put_data with ce and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time dec
|
||||
Given cmd_put_data with cf and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time aut
|
||||
Given cmd_put_data with d0 and ""
|
||||
Then it should get success
|
||||
32
test/features/201_setup_passphrase.feature
Normal file
32
test/features/201_setup_passphrase.feature
Normal file
@@ -0,0 +1,32 @@
|
||||
@keygen
|
||||
Feature: setup pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: setup PW1 (admin-full mode)
|
||||
Given cmd_change_reference_data with 1 and "123456user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1)
|
||||
Given cmd_verify with 1 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2)
|
||||
Given cmd_verify with 2 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-full mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
37
test/features/202_keygen.feature
Normal file
37
test/features/202_keygen.feature
Normal file
@@ -0,0 +1,37 @@
|
||||
@keygen
|
||||
Feature: key generation
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: generate OPENPGP.1 key (sign)
|
||||
When generating a key of OPENPGP.1
|
||||
And put the first data to c7
|
||||
And put the second data to ce
|
||||
Then it should get success
|
||||
|
||||
Scenario: generate OPENPGP.2 key (decrypt)
|
||||
When generating a key of OPENPGP.2
|
||||
And put the first data to c8
|
||||
And put the second data to cf
|
||||
Then it should get success
|
||||
|
||||
Scenario: generate OPENPGP.3 key (authentication)
|
||||
When generating a key of OPENPGP.3
|
||||
And put the first data to c9
|
||||
And put the second data to d0
|
||||
Then it should get success
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (1)
|
||||
Given a message "GnuPG assumes that PW1 keeps valid after keygen."
|
||||
And a public key from token for OPENPGP.1
|
||||
And let a token compute digital signature
|
||||
And verify signature
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) after keygen
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) after keygen
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
71
test/features/203_passphrase_change.feature
Normal file
71
test/features/203_passphrase_change.feature
Normal file
@@ -0,0 +1,71 @@
|
||||
Feature: change pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code again (in admin-full mode)
|
||||
Given cmd_put_data with d3 and "example reset code 111"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 111new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "admin pass phraseanother admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "another admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by admin (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "another admin pass phraseadmin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "admin pass phrase"
|
||||
Then it should get success
|
||||
36
test/features/210_compute_signature.feature
Normal file
36
test/features/210_compute_signature.feature
Normal file
@@ -0,0 +1,36 @@
|
||||
@keygen
|
||||
Feature: compute digital signature
|
||||
In order to use a token
|
||||
A token should compute digital signature properly
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (1)
|
||||
Given a message "This is a test message."
|
||||
And a public key from token for OPENPGP.1
|
||||
And let a token compute digital signature
|
||||
And verify signature
|
||||
Then it should get success
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And a public key from token for OPENPGP.1
|
||||
And let a token compute digital signature
|
||||
And verify signature
|
||||
Then it should get success
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (1)
|
||||
Given a message "This is a test message."
|
||||
And a public key from token for OPENPGP.3
|
||||
And let a token authenticate
|
||||
And verify signature
|
||||
Then it should get success
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And a public key from token for OPENPGP.3
|
||||
And let a token authenticate
|
||||
And verify signature
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object ds counter
|
||||
When requesting ds counter: 93
|
||||
Then data should match: \x00\x00(\x02|\x03)
|
||||
19
test/features/211_decryption.feature
Normal file
19
test/features/211_decryption.feature
Normal file
@@ -0,0 +1,19 @@
|
||||
@keygen
|
||||
Feature: decryption
|
||||
In order to use a token
|
||||
A token should decrypt encrypted data
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (1)
|
||||
Given a plain text "This is a test message."
|
||||
And a public key from token for OPENPGP.2
|
||||
And encrypt it on host
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (2)
|
||||
Given a plain text "RSA decryption is as easy as pie."
|
||||
And a public key from token for OPENPGP.2
|
||||
And encrypt it on host
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
39
test/features/370_key_removal.feature
Normal file
39
test/features/370_key_removal.feature
Normal file
@@ -0,0 +1,39 @@
|
||||
Feature: key removal
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: remove OPENPGP.1 key (sign)
|
||||
When removing a key OPENPGP.1
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.2 key (decrypt)
|
||||
When removing a key OPENPGP.2
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.3 key (authentication)
|
||||
When removing a key OPENPGP.3
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print sig
|
||||
Given cmd_put_data with c7 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print dec
|
||||
Given cmd_put_data with c8 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print aut
|
||||
Given cmd_put_data with c9 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time sig
|
||||
Given cmd_put_data with ce and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time dec
|
||||
Given cmd_put_data with cf and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time aut
|
||||
Given cmd_put_data with d0 and ""
|
||||
Then it should get success
|
||||
27
test/features/380_personalization_reset.feature
Normal file
27
test/features/380_personalization_reset.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: removal of data objects
|
||||
In order to use a token
|
||||
A token should have personalized data
|
||||
|
||||
Scenario: remove data object Login
|
||||
Given cmd_put_data with 5e and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Name
|
||||
Given cmd_put_data with 5b and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Language preference
|
||||
Given cmd_put_data with 5f2d and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Sex
|
||||
Given cmd_put_data with 5f35 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object URL
|
||||
Given cmd_put_data with 5f50 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object pw1 status bytes
|
||||
Given cmd_put_data with c4 and "\x00"
|
||||
Then it should get success
|
||||
7
test/features/390_reset_passphrase.feature
Normal file
7
test/features/390_reset_passphrase.feature
Normal file
@@ -0,0 +1,7 @@
|
||||
Feature: reset pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: setup PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "admin pass phrase"
|
||||
Then it should get success
|
||||
79
test/features/400_empty_check.feature
Normal file
79
test/features/400_empty_check.feature
Normal file
@@ -0,0 +1,79 @@
|
||||
Feature: confirm empty token
|
||||
In order to start tests
|
||||
A token should be empty (no data, no keys)
|
||||
|
||||
Scenario: data object Login
|
||||
When requesting login data: 5e
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Name
|
||||
When requesting name: 5b
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Language preference
|
||||
When requesting anguage preference: 5f2d
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Sex
|
||||
When requesting sex: 5f35
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object URL
|
||||
When requesting URL: 5f50
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object ds counter
|
||||
When requesting ds counter: 93
|
||||
Then you should get: \x00\x00\x00
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
When requesting pw1 status bytes: c4
|
||||
Then you should get: \x00\x7f\x7f\x7f\x03\x03\x03
|
||||
|
||||
Scenario: data object finger print 0
|
||||
When requesting finger print: c5
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object finger print 1
|
||||
When requesting finger print: c7
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object finger print 2
|
||||
When requesting finger print: c8
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object finger print 3
|
||||
When requesting finger print: c9
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 0
|
||||
When requesting finger print: c6
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object CA finger print 1
|
||||
When requesting finger print: ca
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 2
|
||||
When requesting finger print: cb
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 3
|
||||
When requesting finger print: cc
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 0
|
||||
When requesting date/time of key pair: cd
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object date/time of key pair 1
|
||||
When requesting date/time of key pair: ce
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 2
|
||||
When requesting date/time of key pair: cf
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 3
|
||||
When requesting date/time of key pair: d0
|
||||
Then you should get NULL
|
||||
15
test/features/401_empty_check_passphrase.feature
Normal file
15
test/features/401_empty_check_passphrase.feature
Normal file
@@ -0,0 +1,15 @@
|
||||
Feature: confirm empty token
|
||||
In order to start tests
|
||||
A token should be empty (no pass phrase)
|
||||
|
||||
Scenario: verify PW1 factory setting (1)
|
||||
Given cmd_verify with 1 and "123456"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 factory setting (2)
|
||||
Given cmd_verify with 2 and "123456"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 factory setting
|
||||
Given cmd_verify with 3 and "12345678"
|
||||
Then it should get success
|
||||
27
test/features/402_get_data_static.feature
Normal file
27
test/features/402_get_data_static.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: command GET DATA
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support all mandatory features of the specification
|
||||
|
||||
Scenario: data object historical bytes
|
||||
When requesting historical bytes: 5f52
|
||||
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00
|
||||
|
||||
Scenario: data object extended capabilities
|
||||
When requesting extended capabilities: c0
|
||||
Then data should match: \x70\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
|
||||
Scenario: data object algorithm attributes 1
|
||||
When requesting algorithm attributes 1: c1
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object algorithm attributes 2
|
||||
When requesting algorithm attributes 2: c2
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object algorithm attributes 3
|
||||
When requesting algorighm attributes 3: c3
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object AID
|
||||
When requesting AID: 4f
|
||||
Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00
|
||||
55
test/features/410_setup_passphrase.feature
Normal file
55
test/features/410_setup_passphrase.feature
Normal file
@@ -0,0 +1,55 @@
|
||||
Feature: setup pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: setup PW1 (admin-less mode)
|
||||
Given cmd_change_reference_data with 1 and "123456user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1)
|
||||
Given cmd_verify with 1 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2)
|
||||
Given cmd_verify with 2 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode)
|
||||
Given cmd_verify with 3 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-less mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-less mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode) again
|
||||
Given cmd_verify with 3 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode) again
|
||||
Given cmd_verify with 3 and "another user pass phrase"
|
||||
Then it should get success
|
||||
27
test/features/420_personalization_write.feature
Normal file
27
test/features/420_personalization_write.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: personalize token write
|
||||
In order to use a token
|
||||
A token should be personalized with name, sex, url, etc.
|
||||
|
||||
Scenario: data object Login
|
||||
Given cmd_put_data with 5e and "gpg_user"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Name
|
||||
Given cmd_put_data with 5b and "GnuPG User"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Language preference
|
||||
Given cmd_put_data with 5f2d and "ja"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Sex
|
||||
Given cmd_put_data with 5f35 and "1"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object URL
|
||||
Given cmd_put_data with 5f50 and "http://www.fsij.org/gnuk/"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
Given cmd_put_data with c4 and "\x01"
|
||||
Then it should get success
|
||||
27
test/features/421_personalization_read.feature
Normal file
27
test/features/421_personalization_read.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: personalize token read
|
||||
In order to use a token
|
||||
A token should be personalized with name, sex, url, etc.
|
||||
|
||||
Scenario: data object Login
|
||||
When requesting login data: 5e
|
||||
Then you should get: gpg_user
|
||||
|
||||
Scenario: data object Name
|
||||
When requesting name: 5b
|
||||
Then you should get: GnuPG User
|
||||
|
||||
Scenario: data object Language preference
|
||||
When requesting anguage preference: 5f2d
|
||||
Then you should get: ja
|
||||
|
||||
Scenario: data object Sex
|
||||
When requesting sex: 5f35
|
||||
Then you should get: 1
|
||||
|
||||
Scenario: data object URL
|
||||
When requesting URL: 5f50
|
||||
Then you should get: http://www.fsij.org/gnuk/
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
When requesting pw1 status bytes: c4
|
||||
Then you should get: \x01\x7f\x7f\x7f\x03\x03\x03
|
||||
56
test/features/430_key_registration.feature
Normal file
56
test/features/430_key_registration.feature
Normal file
@@ -0,0 +1,56 @@
|
||||
Feature: import keys to token
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: importing OPENPGP.1 key (sign)
|
||||
Given a RSA key pair 0
|
||||
And importing it to the token as OPENPGP.1
|
||||
Then it should get success
|
||||
|
||||
Scenario: importing OPENPGP.2 key (decrypt)
|
||||
Given a RSA key pair 1
|
||||
And importing it to the token as OPENPGP.2
|
||||
Then it should get success
|
||||
|
||||
Scenario: importing OPENPGP.3 key (authentication)
|
||||
Given a RSA key pair 2
|
||||
And importing it to the token as OPENPGP.3
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print sig
|
||||
Given a fingerprint of OPENPGP.1 key
|
||||
And put the data to c7
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print dec
|
||||
Given a fingerprint of OPENPGP.2 key
|
||||
And put the data to c8
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print aut
|
||||
Given a fingerprint of OPENPGP.3 key
|
||||
And put the data to c9
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time sig
|
||||
Given a timestamp of OPENPGP.1 key
|
||||
And put the data to ce
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time dec
|
||||
Given a timestamp of OPENPGP.2 key
|
||||
And put the data to cf
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time aut
|
||||
Given a timestamp of OPENPGP.3 key
|
||||
And put the data to d0
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
51
test/features/440_passphrase_change.feature
Normal file
51
test/features/440_passphrase_change.feature
Normal file
@@ -0,0 +1,51 @@
|
||||
Feature: change pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: change PW1 (in admin-less mode)
|
||||
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode)
|
||||
Given cmd_verify with 3 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code again (in admin-less mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-less mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode)
|
||||
Given cmd_verify with 3 and "another user pass phrase"
|
||||
Then it should get success
|
||||
31
test/features/500_compute_signature.feature
Normal file
31
test/features/500_compute_signature.feature
Normal file
@@ -0,0 +1,31 @@
|
||||
Feature: compute digital signature
|
||||
In order to use a token
|
||||
A token should compute digital signature properly
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (1)
|
||||
Given a message "This is a test message."
|
||||
And let a token compute digital signature
|
||||
And compute digital signature on host with RSA key pair 0
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And let a token compute digital signature
|
||||
And compute digital signature on host with RSA key pair 0
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (1)
|
||||
Given a message "This is a test message."
|
||||
And let a token authenticate
|
||||
And compute digital signature on host with RSA key pair 2
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And let a token authenticate
|
||||
And compute digital signature on host with RSA key pair 2
|
||||
Then results should be same
|
||||
|
||||
Scenario: data object ds counter
|
||||
When requesting ds counter: 93
|
||||
Then you should get: \x00\x00\x02
|
||||
16
test/features/501_decryption.feature
Normal file
16
test/features/501_decryption.feature
Normal file
@@ -0,0 +1,16 @@
|
||||
Feature: decryption
|
||||
In order to use a token
|
||||
A token should decrypt encrypted data
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (1)
|
||||
Given a plain text "This is a test message."
|
||||
And encrypt it on host with RSA key pair 1
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (2)
|
||||
Given a plain text "RSA decryption is as easy as pie."
|
||||
And encrypt it on host with RSA key pair 1
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
44
test/features/600_key_removal.feature
Normal file
44
test/features/600_key_removal.feature
Normal file
@@ -0,0 +1,44 @@
|
||||
@keygen
|
||||
Feature: key removal
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: remove OPENPGP.1 key (sign)
|
||||
When removing a key OPENPGP.1
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.2 key (decrypt)
|
||||
When removing a key OPENPGP.2
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.3 key (authentication)
|
||||
When removing a key OPENPGP.3
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode)
|
||||
Given cmd_verify with 3 and "12345678"
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print sig
|
||||
Given cmd_put_data with c7 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print dec
|
||||
Given cmd_put_data with c8 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print aut
|
||||
Given cmd_put_data with c9 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time sig
|
||||
Given cmd_put_data with ce and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time dec
|
||||
Given cmd_put_data with cf and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time aut
|
||||
Given cmd_put_data with d0 and ""
|
||||
Then it should get success
|
||||
40
test/features/601_setup_passphrase.feature
Normal file
40
test/features/601_setup_passphrase.feature
Normal file
@@ -0,0 +1,40 @@
|
||||
@keygen
|
||||
Feature: setup pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: setup PW1 (admin-less mode)
|
||||
Given cmd_change_reference_data with 1 and "123456user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1)
|
||||
Given cmd_verify with 1 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2)
|
||||
Given cmd_verify with 2 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode)
|
||||
Given cmd_verify with 3 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-less mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-less mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode) again
|
||||
Given cmd_verify with 3 and "another user pass phrase"
|
||||
Then it should get success
|
||||
37
test/features/602_keygen.feature
Normal file
37
test/features/602_keygen.feature
Normal file
@@ -0,0 +1,37 @@
|
||||
@keygen
|
||||
Feature: key generation
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: generate OPENPGP.1 key (sign)
|
||||
When generating a key of OPENPGP.1
|
||||
And put the first data to c7
|
||||
And put the second data to ce
|
||||
Then it should get success
|
||||
|
||||
Scenario: generate OPENPGP.2 key (decrypt)
|
||||
When generating a key of OPENPGP.2
|
||||
And put the first data to c8
|
||||
And put the second data to cf
|
||||
Then it should get success
|
||||
|
||||
Scenario: generate OPENPGP.3 key (authentication)
|
||||
When generating a key of OPENPGP.3
|
||||
And put the first data to c9
|
||||
And put the second data to d0
|
||||
Then it should get success
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (1)
|
||||
Given a message "GnuPG assumes that PW1 keeps valid after keygen."
|
||||
And a public key from token for OPENPGP.1
|
||||
And let a token compute digital signature
|
||||
And verify signature
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) after keygen
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) after keygen
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user