Compare commits
102 Commits
release/1.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4af98308e0 | ||
|
|
baec3a1c1e | ||
|
|
4f1325794d | ||
|
|
0acf6485ae | ||
|
|
4d15700580 | ||
|
|
8822fcae77 | ||
|
|
20a2f99691 | ||
|
|
acfccb729d | ||
|
|
5283506755 | ||
|
|
c688df7c2c | ||
|
|
594896ac57 | ||
|
|
dfe046e08d | ||
|
|
c66b01e74b | ||
|
|
21a46306ae | ||
|
|
e5158572ee | ||
|
|
2142d0aa35 | ||
|
|
dd47cf4312 | ||
|
|
ffbb754fc0 | ||
|
|
d85750d791 | ||
|
|
d20e9e9b1e | ||
|
|
bf30144144 | ||
|
|
934daf3585 | ||
|
|
22420ed1f4 | ||
|
|
e97e3b1810 | ||
|
|
49f2544918 | ||
|
|
d156fc6261 | ||
|
|
81d6945081 | ||
|
|
c3e9db14e8 | ||
|
|
9180c35420 | ||
|
|
cc0d59cfe6 | ||
|
|
9c1368fdd0 | ||
|
|
2dd5a76002 | ||
|
|
f68ff0bddc | ||
|
|
add3299306 | ||
|
|
e28ec2c4c4 | ||
|
|
1ba05a0f0f | ||
|
|
2d50795d0a | ||
|
|
fd493562c3 | ||
|
|
16c6af215a | ||
|
|
177ef67edf | ||
|
|
126283b1ac | ||
|
|
076d727061 | ||
|
|
41fa424450 | ||
|
|
940332c47f | ||
|
|
aedf8267ec | ||
|
|
e9d9de3ae2 | ||
|
|
fc109fd8af | ||
|
|
3d06051a32 | ||
|
|
b7368e41e9 | ||
|
|
e760d5b780 | ||
|
|
b57c33c204 | ||
|
|
ca3312eb25 | ||
|
|
6a1f50abda | ||
|
|
66f39c57cd | ||
|
|
4b5f93624e | ||
|
|
0ef687ea4c | ||
|
|
786b4adc42 | ||
|
|
385261c9a0 | ||
|
|
65689199e7 | ||
|
|
8d15086d06 | ||
|
|
c17fd5401b | ||
|
|
56cd4ae7b5 | ||
|
|
fc36773c6a | ||
|
|
7249775c17 | ||
|
|
980cff0a2f | ||
|
|
8f44f5d3c6 | ||
|
|
37a84ed218 | ||
|
|
6c72147248 | ||
|
|
3d37003d8c | ||
|
|
becf8fabc5 | ||
|
|
17492287f3 | ||
|
|
c800dee95e | ||
|
|
2c390dc763 | ||
|
|
5aee75fd4b | ||
|
|
69e8c0f334 | ||
|
|
317cc2036d | ||
|
|
312d15c3fa | ||
|
|
d356f1b1e0 | ||
|
|
9cb6591491 | ||
|
|
ebec8ee156 | ||
|
|
f810fb83d3 | ||
|
|
12079974fd | ||
|
|
ca79f5421f | ||
|
|
c438367d67 | ||
|
|
4c6511231c | ||
|
|
ba750d153d | ||
|
|
72647f01d0 | ||
|
|
c6e32a36fb | ||
|
|
c3a0eb1439 | ||
|
|
030a9c576d | ||
|
|
8a5e0eb783 | ||
|
|
bce53546e7 | ||
|
|
b2b19e1ad4 | ||
|
|
58fa773bb7 | ||
|
|
ea88c3da66 | ||
|
|
b905b4802f | ||
|
|
40f2c6c49e | ||
|
|
61a7f9602b | ||
|
|
5465fda927 | ||
|
|
f7c46a6c55 | ||
|
|
4550458806 | ||
|
|
93a2bac94b |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,7 @@ src/.dep
|
|||||||
src/config.mk
|
src/config.mk
|
||||||
src/config.h
|
src/config.h
|
||||||
src/gnuk.ld
|
src/gnuk.ld
|
||||||
|
src/stdaln-sys.ld
|
||||||
src/board.h
|
src/board.h
|
||||||
src/build/*
|
src/build/*
|
||||||
src/*.inc
|
src/*.inc
|
||||||
@@ -16,3 +17,4 @@ regnual/regnual.elf
|
|||||||
doc/_build
|
doc/_build
|
||||||
tests/.cache
|
tests/.cache
|
||||||
tests/__pycache__
|
tests/__pycache__
|
||||||
|
tests/.pytest_cache
|
||||||
|
|||||||
27
AUTHORS
27
AUTHORS
@@ -11,6 +11,16 @@ Anthony Romano:
|
|||||||
src/main.c
|
src/main.c
|
||||||
src/mod.c
|
src/mod.c
|
||||||
|
|
||||||
|
Bertrand Jacquin
|
||||||
|
Modified:
|
||||||
|
tool/add_openpgp_authkey_from_gpgssh.py
|
||||||
|
tool/calc_precompute_table_ecc.py
|
||||||
|
tool/dfuse.py
|
||||||
|
tool/dump_mem.py
|
||||||
|
tool/get_raw_public_key.py
|
||||||
|
tool/pageant_proxy_to_gpg.py
|
||||||
|
tool/pinpadtest.py
|
||||||
|
|
||||||
Jeremy Drake:
|
Jeremy Drake:
|
||||||
Modified:
|
Modified:
|
||||||
regnual/regnual.c
|
regnual/regnual.c
|
||||||
@@ -65,3 +75,20 @@ NIIBE Yutaka:
|
|||||||
src/usb_lld.h
|
src/usb_lld.h
|
||||||
*
|
*
|
||||||
and others.
|
and others.
|
||||||
|
|
||||||
|
Peter Lebbing:
|
||||||
|
Modified:
|
||||||
|
src/config.h.in
|
||||||
|
src/configure
|
||||||
|
src/main.c
|
||||||
|
src/Makefile
|
||||||
|
Wrote:
|
||||||
|
src/stdaln-sys.ld.in
|
||||||
|
|
||||||
|
Vincent Pelletier:
|
||||||
|
Modified:
|
||||||
|
test/features/202_setup_passphrase.feature
|
||||||
|
test/rsa_keys.py
|
||||||
|
tests/card_reader.py
|
||||||
|
tests/rsa_keys.py
|
||||||
|
tool/gnuk_token.py
|
||||||
|
|||||||
365
ChangeLog
365
ChangeLog
@@ -1,3 +1,368 @@
|
|||||||
|
2021-02-25 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.17.
|
||||||
|
|
||||||
|
2021-02-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/config.h.in (@KDF_DO_REQUIRED_DEFINE@): New.
|
||||||
|
|
||||||
|
* src/configure (KDF_DO_REQUIRED_DEFINE): New for GNU/Linux.
|
||||||
|
|
||||||
|
* src/openpgp-do.c (gpg_do_kdf_check): When LEN==0, check if
|
||||||
|
KDO data object is available.
|
||||||
|
[KDF_DO_REQUIRED] (proc_key_import): Refuse the key import when
|
||||||
|
KDF data object is not available.
|
||||||
|
|
||||||
|
* src/openpgp.c [KDF_DO_REQUIRED] (cmd_pgp_gakp): Refuse key
|
||||||
|
generation when KDF data object is not available.
|
||||||
|
|
||||||
|
2021-02-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* tool/gnuk-emulation-setup: Remove.
|
||||||
|
|
||||||
|
* tool/upgrade_by_passwd.py (main): Use tobytes.
|
||||||
|
* tool/gnuk_get_random.py: Likewise.
|
||||||
|
* tool/gnuk_remove_keys_libusb.py (main): Likewise.
|
||||||
|
Switch to Python3.
|
||||||
|
* tool/gnuk_put_binary_libusb.py (main): Use tobytes.
|
||||||
|
Switch to Python3.
|
||||||
|
* tool/gnuk_upgrade.py (main): Use tobytes.
|
||||||
|
Switch to Python3.
|
||||||
|
|
||||||
|
* chopstx: Update to 1.19.
|
||||||
|
|
||||||
|
2021-02-18 Vincent Pelletier <plr.vincent@gmail.com>
|
||||||
|
|
||||||
|
* test/features/202_setup_passphrase.feature: Fix.
|
||||||
|
* test/rsa_keys.py: Fix escape.
|
||||||
|
* tests/card_reader.py: Extend the timeout.
|
||||||
|
Handle no card.
|
||||||
|
* tests/rsa_keys.py: Fix escape.
|
||||||
|
* tool/gnuk_token.py: Avoid hard-coding the endpoints.
|
||||||
|
Longer timeout.
|
||||||
|
|
||||||
|
2021-02-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/configure [GNU_LINUX_EMULATION] (def_mhz): Define.
|
||||||
|
(output_vendor_product_serial_strings): Output ARCH.
|
||||||
|
|
||||||
|
* GNUK_USB_DEVICE_ID: Use "Gnuk Token" for emulation, too.
|
||||||
|
|
||||||
|
* src/main.c [GNU_LINUX_EMULATION] (main): Add initialization of
|
||||||
|
the .gnuk-flash-image file.
|
||||||
|
(gnuk_sbrk): Rename from sbrk.
|
||||||
|
|
||||||
|
2020-09-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.16.
|
||||||
|
|
||||||
|
2020-09-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/modp256k1.c (modp256k1_add, modp256k1_sub): Use memcpy with
|
||||||
|
dummy memory area.
|
||||||
|
* src/modp256r1.c (modp256r1_add, modp256r1_sub)
|
||||||
|
(modp256r1_reduce): Likewise.
|
||||||
|
|
||||||
|
2020-09-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/modp256k1.c (modp256k1_add, modp256k1_reduce): Avoid
|
||||||
|
optimization to remove call of memmove.
|
||||||
|
* src/modp256r1.c (modp256r1_add, modp256r1_sub)
|
||||||
|
(modp256r1_reduce): Likewise.
|
||||||
|
|
||||||
|
2020-09-07 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/openpgp.c (gpg_get_firmware_update_key): Use an array.
|
||||||
|
|
||||||
|
* src/modp256k1.c (modp256k1_add, modp256k1_sub): Use memmove.
|
||||||
|
* src/modp256r1.c (modp256r1_add, modp256r1_sub)
|
||||||
|
(modp256r1_reduce): Likewise.
|
||||||
|
|
||||||
|
2020-09-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/openpgp-do.c (GPG_DO_ALG_INFO): New.
|
||||||
|
(do_fp_all, do_cafp_all, do_kgtime_all, do_openpgpcard_aid)
|
||||||
|
(do_ds_count): Return nothing.
|
||||||
|
(copy_do): Change the API for DO_PROC_READ.
|
||||||
|
(do_alg_info): New for GPG_DO_ALG_INFO.
|
||||||
|
(gpg_do_table): Add an entry for GPG_DO_ALG_INFO.
|
||||||
|
|
||||||
|
2020-09-03 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/openpgp.c (cmd_internal_authenticate): Remove checking
|
||||||
|
against EDDSA_HASH_LEN_MAX.
|
||||||
|
(cmd_pso): Likewise.
|
||||||
|
|
||||||
|
2020-08-28 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/openpgp.c (cmd_reset_user_password): Add passphrase length
|
||||||
|
check.
|
||||||
|
|
||||||
|
2020-08-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/ac.c (verify_user_0): Fix for a use case of having
|
||||||
|
signing key only.
|
||||||
|
(verify_admin_00): Clean up.
|
||||||
|
|
||||||
|
* tests/test_000_empty_card.py (test_name_lang_sex): Support
|
||||||
|
OpenPGP card version 3.3.
|
||||||
|
|
||||||
|
2020-01-24 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.15.
|
||||||
|
|
||||||
|
2020-01-11 Bertrand Jacquin <bertrand@jacquin.bzh>
|
||||||
|
|
||||||
|
* tool/add_openpgp_authkey_from_gpgssh.py: Switch to Python3.
|
||||||
|
* tool/calc_precompute_table_ecc.py: Likewise.
|
||||||
|
* tool/dfuse.py: Likewise.
|
||||||
|
* tool/dump_mem.py: Likewise.
|
||||||
|
* tool/get_raw_public_key.py: Likewise.
|
||||||
|
* tool/pageant_proxy_to_gpg.py: Likewise.
|
||||||
|
|
||||||
|
2019-12-30 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx: Update to 1.18.
|
||||||
|
|
||||||
|
2019-06-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/bn.c (bn256_random): More portable.
|
||||||
|
|
||||||
|
2019-04-03 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* tests: Factor out tests into classes.
|
||||||
|
|
||||||
|
2019-03-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.14.
|
||||||
|
|
||||||
|
* chopstx: Update to 1.14.
|
||||||
|
|
||||||
|
* tool/gnuk_token.py: Add 1209:2440.
|
||||||
|
|
||||||
|
2019-02-24 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/usb-ccid.c (ccid_thread): Clean up the ack button state
|
||||||
|
at reset (by SET_INTERFACE).
|
||||||
|
|
||||||
|
* tool/gnuk_token.py (gnuk_token.__init__): Add back
|
||||||
|
setAltInterface to issue SET_INTERFACE control transfer.
|
||||||
|
|
||||||
|
2019-02-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* tool/gnuk_get_random.py: New.
|
||||||
|
|
||||||
|
* src/openpgp.c (cmd_external_authenticate): move
|
||||||
|
ACKBTN_SUPPORT to...
|
||||||
|
(cmd_get_challenge): ... here.
|
||||||
|
|
||||||
|
* src/gnuk.h (EV_*): Change the values.
|
||||||
|
|
||||||
|
* src/usb-ccid.c (GPG_ACK_TIMEOUT): New.
|
||||||
|
(ccid_thread): Implement timout for the user interaction.
|
||||||
|
|
||||||
|
2019-02-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* GNUK_USB_DEVICE_ID: Add 1209:2440.
|
||||||
|
|
||||||
|
2018-12-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.13.
|
||||||
|
|
||||||
|
2018-12-22 Peter Lebbing <peter@digitalbrains.com>
|
||||||
|
|
||||||
|
* src/main.c (device_initialize_once): Fill the stack address and
|
||||||
|
reset vector of Gnuk application (was the one of old SYS).
|
||||||
|
Reset the board after updating the first five pages of flash.
|
||||||
|
|
||||||
|
2018-12-21 Peter Lebbing <peter@digitalbrains.com>
|
||||||
|
|
||||||
|
* src/main.c [DFU_SUPPORT] (flash_write_any): New.
|
||||||
|
(device_initialize_once): Overwrite DFU bootloader by SYS.
|
||||||
|
(main): Use SYS at ORIGIN_REAL.
|
||||||
|
|
||||||
|
* src/stdaln-sys.ld.in: New.
|
||||||
|
|
||||||
|
* src/Makefile [USE_DFU] (OBJS_ADD): Add standalone SYS object.
|
||||||
|
Add rules for stdaln-sys-bin.o and src/stdaln-sys.ld.
|
||||||
|
|
||||||
|
* src/configure: Generate stdaln-sys.ld.
|
||||||
|
[MAPLE_MINI]: Tweak ORIGIN and FLASH_SIZE.
|
||||||
|
(ORIGIN_DEFINE, ORIGIN_REAL_DEFINE): New macros.
|
||||||
|
(USE_DFU): New make variable.
|
||||||
|
|
||||||
|
* src/config.h.in (ORIGIN_DEFINE, ORIGIN_REAL_DEFINE): New.
|
||||||
|
|
||||||
|
2018-12-20 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx: Update to 1.13.
|
||||||
|
|
||||||
|
2018-12-07 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/gnuk.h (EV_EXEC_ACK_REQUIRED): Have precedence
|
||||||
|
than EV_EXEC_FINISHED.
|
||||||
|
|
||||||
|
2018-12-06 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/usb-ccid.c (ccid_thread): Priority of handling
|
||||||
|
EV_TX_FINISHED is most important. Don't handle
|
||||||
|
Ack button event when c->tx_busy = 1.
|
||||||
|
|
||||||
|
2018-12-05 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/openpgp.c (cmd_external_authenticate): Support
|
||||||
|
ACK button for firmware update.
|
||||||
|
|
||||||
|
2018-12-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/openpgp-do.c (gpg_data_copy): Fix for NR_DO_UIF_SIG.
|
||||||
|
|
||||||
|
2018-11-25 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.12.
|
||||||
|
|
||||||
|
2018-11-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/usb-ccid.c (ccid_thread): Fix a race condition sending
|
||||||
|
result APDU by ack button, time out, sending time extension block
|
||||||
|
again while tx_busy=1.
|
||||||
|
|
||||||
|
2018-11-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/main.c (device_initialize_once): Depends on MHZ to
|
||||||
|
distinguish GD32F103.
|
||||||
|
* src/openpgp-do.c (do_openpgpcard_aid): Ditto.
|
||||||
|
|
||||||
|
2018-11-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.11.
|
||||||
|
|
||||||
|
* chopstx: Update to 1.12.
|
||||||
|
* src/configure (ackbtn_support): Always yes.
|
||||||
|
* src/usb-ccid.c: Fix comma separator.
|
||||||
|
|
||||||
|
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* tool/kdf_calc.py (kdf_calc): Use libgcrypt.so.20.
|
||||||
|
|
||||||
|
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/openpgp.c (cmd_pso, cmd_internal_authenticate): Use
|
||||||
|
ccid_comm.
|
||||||
|
|
||||||
|
* src/usb-ccid.c (struct ccid): New field tx_busy.
|
||||||
|
(ccid_error, ccid_power_on, ccid_send_status, ccid_power_off)
|
||||||
|
(ccid_send_data_block_internal, ccid_send_data_block_0x9000)
|
||||||
|
(ccid_send_data_block_gr, ccid_send_params): Set c->tx_busy.
|
||||||
|
(ccid_state_p): Remove.
|
||||||
|
(ccid_get_ccid_state): New.
|
||||||
|
(ccid_thread): Only handle EV_TX_FINISHED event when c->tx_busy.
|
||||||
|
|
||||||
|
* src/usb_ctrl.c (usb_setup, usb_ctrl_write_finish): Use
|
||||||
|
ccid_get_ccid_state.
|
||||||
|
* src/main.c (display_status_code): Likewise.
|
||||||
|
|
||||||
|
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/usb-ccid.c (ccid_handle_data): Set c->state for pinpad input.
|
||||||
|
(ccid_send_data_block_internal): Fix the case of len == 0.
|
||||||
|
|
||||||
|
* src/main.c (display_status_code): There is
|
||||||
|
no case where ccid_state == CCID_STATE_RECEIVE.
|
||||||
|
* src/gnuk.h (CCID_STATE_RECEIVE): Remove.
|
||||||
|
(CCID_STATE_SEND): Remove.
|
||||||
|
|
||||||
|
2018-10-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/usb-ccid.c (ccid_thread): Notify host about ack button.
|
||||||
|
|
||||||
|
2018-10-02 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/stack-def.h (SIZE_0): Increase.
|
||||||
|
|
||||||
|
* chopstx: Update to 1.11.
|
||||||
|
|
||||||
|
2018-10-01 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/gnuk.h (EV_EXEC_ACK_REQUIRED): New.
|
||||||
|
(EV_EXEC_FINISHED_ACK): Remove.
|
||||||
|
(CCID_STATE_CONFIRM_ACK): Remove.
|
||||||
|
(CCID_STATE_ACK_REQUIRED_0, CCID_STATE_ACK_REQUIRED_1): New.
|
||||||
|
* src/openpgp.c (cmd_pso): Send EV_EXEC_ACK_REQUIRED, if needed.
|
||||||
|
(cmd_internal_authenticate): Likewise.
|
||||||
|
(process_command_apdu): No return value.
|
||||||
|
(openpgp_card_thread): Always send EV_EXEC_FINISHED.
|
||||||
|
* src/usb-ccid.c (ccid_send_data_block_time_extension): Follow the
|
||||||
|
change of state.
|
||||||
|
(ccid_handle_data, ccid_handle_timeout): Likewise.
|
||||||
|
(ccid_thread): Handle EV_EXEC_ACK_REQUIRED.
|
||||||
|
Change for LED blink.
|
||||||
|
* src/main.c (main): LED blink during waiting ACK.
|
||||||
|
|
||||||
|
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/gnuk.h (NR_DO_UIF_SIG, NR_DO_UIF_DEC, NR_DO_UIF_AUT): New.
|
||||||
|
* src/openpgp-do.c (rw_uif) [ACKBTN_SUPPORT]: New.
|
||||||
|
(GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT): New.
|
||||||
|
(feature_mngmnt) [ACKBTN_SUPPORT]: New.
|
||||||
|
(cmp_app_data, cmp_discretionary): Add ACKBTN_SUPPORT.
|
||||||
|
(gpg_do_table): Add for GPG_DO_UIF_SIG, GPG_DO_UIF_DEC,
|
||||||
|
GPG_DO_UIF_AUT, and GPG_DO_FEATURE_MNGMNT.
|
||||||
|
(gpg_do_get_uif) [ACKBTN_SUPPORT]: New.
|
||||||
|
(gpg_data_scan): Handle uif_flags.
|
||||||
|
* src/openpgp.c (process_command_apdu) [ACKBTN_SUPPORT]: Add user
|
||||||
|
interaction handling.
|
||||||
|
|
||||||
|
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/gnuk.h (LED_WAIT_FOR_BUTTON): New.
|
||||||
|
* src/main.c (main): Blink rapidly when asking ACK.
|
||||||
|
* src/usb-ccid.c (ccid_thread): Use LED_WAIT_FOR_BUTTON.
|
||||||
|
|
||||||
|
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/config.h.in: Add @ACKBTN_DEFINE@.
|
||||||
|
* src/configure: Add ACKBTN_SUPPORT.
|
||||||
|
* src/gnuk.h (EV_EXEC_FINISHED_ACK): New.
|
||||||
|
(CCID_STATE_CONFIRM_ACK): New.
|
||||||
|
* src/openpgp.c (process_command_apdu): Change for cmd_pso, and
|
||||||
|
cmd_internal_authenticate.
|
||||||
|
* src/usb-ccid.c (ccid_send_data_block_time_extension): Report
|
||||||
|
time extension differently when waiting ack button.
|
||||||
|
(ccid_handle_data): Support case of CCID_STATE_CONFIRM_ACK.
|
||||||
|
(ccid_handle_timeout): Likewise.
|
||||||
|
(ack_intr) [ACKBTN_SUPPORT]: New.
|
||||||
|
(ccid_thread) [ACKBTN_SUPPORT]: Add ack button handling.
|
||||||
|
|
||||||
|
2018-09-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx: Update.
|
||||||
|
* src/usb-ccid.c (usb_event_handle): Fix for chopstx_intr_done.
|
||||||
|
* src/pin-cir.c (tim_main, ext_main): Likewise.
|
||||||
|
|
||||||
|
* src/configure (FST_01SZ): Set MHZ=96.
|
||||||
|
|
||||||
|
2018-07-04 Szczepan Zalega <szczepan@nitrokey.com>
|
||||||
|
|
||||||
|
* tool/upgrade_by_passwd.py: Catch exception, when no KDF data is
|
||||||
|
found.
|
||||||
|
Output 'second' for 1 second.
|
||||||
|
|
||||||
|
2018-05-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.2.10.
|
||||||
|
|
||||||
|
* src/Makefile (build/gnuk.elf): New target.
|
||||||
|
(build/gnuk-vidpid.elf): Remove.
|
||||||
|
|
||||||
|
* chopstx: Update to 1.9.
|
||||||
|
|
||||||
|
2018-04-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* src/usb_ctrl.c (usb_device_reset): Don't stop the endpoints.
|
||||||
|
|
||||||
|
* src/configure (MHZ, def_mhz): New.
|
||||||
|
|
||||||
2018-04-05 NIIBE Yutaka <gniibe@fsij.org>
|
2018-04-05 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
* VERSION: 1.2.9.
|
* VERSION: 1.2.9.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# VID:PID bcdDev Product_STRING Vendor_STRING
|
# VID:PID bcdDev Product_STRING Vendor_STRING
|
||||||
0000:0000 0200 Gnuk Emulation Free Software Initiative of Japan
|
0000:0000 0200 Gnuk Token Free Software Initiative of Japan
|
||||||
234b:0000 0200 Gnuk Token Free Software Initiative of Japan
|
234b:0000 0200 Gnuk Token Free Software Initiative of Japan
|
||||||
20a0:4211 0200 Nitrokey Start Nitrokey
|
20a0:4211 0200 Nitrokey Start Nitrokey
|
||||||
|
1209:2440 0200 Gnuk Token GnuPG e.V.
|
||||||
##########<TAB> ##<TAB> ##########<TAB> #################
|
##########<TAB> ##<TAB> ##########<TAB> #################
|
||||||
|
|||||||
131
NEWS
131
NEWS
@@ -1,5 +1,129 @@
|
|||||||
Gnuk NEWS - User visible changes
|
Gnuk NEWS - User visible changes
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.17
|
||||||
|
|
||||||
|
Released 2021-02-25, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** GNU/Linux: KDF Data Object is required before keygen and key import
|
||||||
|
For GNU/Linux emulation, KDF Data Object is required before keygen and
|
||||||
|
key import.
|
||||||
|
|
||||||
|
** GNU/Linux emulation
|
||||||
|
Since 1.2.10, it was not build-able because of MHZ definition. It is
|
||||||
|
build-able again, and its USB product string is now "Gnuk Token". It
|
||||||
|
has ACK button support using terminal. It now has start-up message,
|
||||||
|
and its driver show useful information to setup USBIP. When no file
|
||||||
|
for the .gnuk-flash-image file, it is automatically created.
|
||||||
|
|
||||||
|
** Removal of tool/gnuk-emulation-setup
|
||||||
|
Because it is automatically created, the tool is not needed any more.
|
||||||
|
|
||||||
|
** Upgrade of Chopstx
|
||||||
|
We use Chopstx 1.19.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.16
|
||||||
|
|
||||||
|
Released 2020-09-10, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** New Data Object (Algorithm Information) of OpenPGP card v3.4
|
||||||
|
The tag is 0x00FA. This is useful for user interaction to show which
|
||||||
|
algorithms are supported by the device.
|
||||||
|
|
||||||
|
** Ed25519 signing allowing longer message
|
||||||
|
For OpenPGP, it does hashing on host side before requesting signing to
|
||||||
|
the device. Thus, the length of message to be signed is limited and
|
||||||
|
determined by the hash algorithm. That's good feature of OpenPGP. On
|
||||||
|
the other hand, there is a use case, like OpenSSH certificate signing,
|
||||||
|
where the length of message is a kind of arbitrary. Even though Gnuk
|
||||||
|
(or OpenPGP card protocol itself) has limitation, we removed the
|
||||||
|
length check against EDDSA_HASH_LEN_MAX at cmd_pso.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.15
|
||||||
|
|
||||||
|
Released 2020-01-24, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** Switch to Python3
|
||||||
|
Scripts under tool/ are switched to Python3.
|
||||||
|
Thanks to Bertrand Jacquin.
|
||||||
|
|
||||||
|
** Upgrade of Chopstx
|
||||||
|
We use Chopstx 1.18.
|
||||||
|
|
||||||
|
** Tests also support OpenPGPcard
|
||||||
|
Now, a test suite under "tests" may be used to OpenPGPcard.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.14
|
||||||
|
|
||||||
|
Released 2019-03-05, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** Timeout for ACK button support
|
||||||
|
When a user doesn't acknowledge (> 15 seconds), the operation
|
||||||
|
timeouts, and authentication state is cleared.
|
||||||
|
|
||||||
|
** Upgrade of Chopstx
|
||||||
|
We use Chopstx 1.14.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.13
|
||||||
|
|
||||||
|
Released 2018-12-26, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** DFU support and its firmware upgrade fix
|
||||||
|
DFU support was not well maintained, and firmware upgrade was not
|
||||||
|
possible for boards with DFU. Now, at least for Maple Mini, it is
|
||||||
|
tested. Note that using Gnuk with DFU on a board is only for an
|
||||||
|
experiment, because DFU can access the content of flash ROM. DFU
|
||||||
|
should be killed by upgrading to normal Gnuk, so that you can have
|
||||||
|
your private keys.
|
||||||
|
|
||||||
|
** Fix for UIF Data Object
|
||||||
|
When flash ROM is full and coping to new page, UIF DO was not properly
|
||||||
|
copied. This bug resulted losing the flag for user interaction. Now,
|
||||||
|
it's properly copied, keeping the setting of the feature.
|
||||||
|
|
||||||
|
** Upgrade of Chopstx
|
||||||
|
We use Chopstx 1.13.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.12
|
||||||
|
|
||||||
|
Released 2018-11-25, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** FST-01SZ fixes
|
||||||
|
Fixes for Ack button support and serial number.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.11
|
||||||
|
|
||||||
|
Released 2018-11-12, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** Experimental ACK button support with FST-01SZ
|
||||||
|
While OpenPGP card specification verison 3 has description for the
|
||||||
|
"user interaction" button and data objects, there were no
|
||||||
|
implementation. To evaluate the feature, experimental support is
|
||||||
|
added.
|
||||||
|
|
||||||
|
** Upgrade of Chopstx
|
||||||
|
We use Chopstx 1.12, which comes with ACK button driver and supports
|
||||||
|
FST-01SZ.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Gnuk 1.2.10
|
||||||
|
|
||||||
|
Released 2018-05-10, by NIIBE Yutaka
|
||||||
|
|
||||||
|
** No inclusion of VID:PID in gnuk-no-vidpid.elf
|
||||||
|
Now, we have new file named gnuk-no-vidpid.elf with no VID:PID. The
|
||||||
|
file gnuk.elf has the VID:PID, like version 1.2.7 or older.
|
||||||
|
|
||||||
|
** Upgrade of Chopstx
|
||||||
|
We use Chopstx 1.9, which supports GD32F103.
|
||||||
|
|
||||||
|
|
||||||
* Major changes in Gnuk 1.2.9
|
* Major changes in Gnuk 1.2.9
|
||||||
|
|
||||||
Released 2018-04-05, by NIIBE Yutaka
|
Released 2018-04-05, by NIIBE Yutaka
|
||||||
@@ -851,6 +975,7 @@ Gnuk Token could run with GPG4WIN on MS Windows. GPG4WIN runs with
|
|||||||
|
|
||||||
** This is initial release. Only it supports digital signing.
|
** This is initial release. Only it supports digital signing.
|
||||||
|
|
||||||
Local Variables:
|
|
||||||
mode: outline
|
# Local Variables:
|
||||||
End:
|
# mode: outline
|
||||||
|
# End:
|
||||||
|
|||||||
117
README
117
README
@@ -1,33 +1,35 @@
|
|||||||
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
|
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
|
||||||
|
|
||||||
Version 1.2.9
|
Version 1.2.17
|
||||||
2018-04-05
|
2021-02-25
|
||||||
Niibe Yutaka
|
Niibe Yutaka
|
||||||
Free Software Initiative of Japan
|
Free Software Initiative of Japan
|
||||||
|
|
||||||
Release Notes
|
Release Notes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the release of Gnuk, version 1.2.9, which has major
|
This is the release of Gnuk, version 1.2.17, which has major
|
||||||
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
|
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
|
||||||
overriding key import, but importing keys (or generating keys) results
|
overriding key import, but importing keys (or generating keys) results
|
||||||
password reset. Also, you need to import private keys before changing
|
password reset. Also, you need to import private keys before changing
|
||||||
your password. Please update your documentation for Gnuk Token, so
|
your password. Please update your documentation for Gnuk Token, so
|
||||||
that the instruction of importing keys won't cause any confusion.
|
that the instruction of importing keys won't cause any confusion.
|
||||||
|
|
||||||
It has supports of EdDSA, ECDSA (with NIST P256 and secp256k1), and
|
It has supports of Ed25519 and X25519 (ECDH on Curve25519). It also
|
||||||
ECDH (with X25519, NIST P256 and secp256k1), but this ECC feature is
|
has experimental support of ECDSA (on NIST P256 and secp256k1) and
|
||||||
somehow experimental, and it requires modern GnuPG 2.2 with libgcrypt
|
ECDH (on NIST P256 and secp256k1).
|
||||||
1.7.0 or later.
|
|
||||||
|
|
||||||
It also supports RSA-4096, but users should know that it takes more
|
It also supports RSA-4096, but users should know that it takes more
|
||||||
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
|
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
|
||||||
because the device doesn't have enough memory.
|
because the device doesn't have enough memory.
|
||||||
|
|
||||||
It supports new KDF-DO feature. Please note that this is
|
It supports new KDF-DO feature. Please note that this is
|
||||||
experimental. To use the feature, you need to use newer GnuPG
|
experimental. To use the feature, you need to use newer GnuPG (2.2.6
|
||||||
(forthcoming 2.2.6 or later). You need to prepare the KDF-DO on your
|
or later). You need to prepare the KDF-DO on your token by the
|
||||||
token by the card-edit/kdf-setup command.
|
card-edit/kdf-setup command.
|
||||||
|
|
||||||
|
With FST-01SZ and GNU/Linux emulation, experimental ack button support
|
||||||
|
is available for test.
|
||||||
|
|
||||||
|
|
||||||
What's Gnuk?
|
What's Gnuk?
|
||||||
@@ -35,7 +37,7 @@ What's Gnuk?
|
|||||||
|
|
||||||
Gnuk is an implementation of USB cryptographic token for GNU Privacy
|
Gnuk is an implementation of USB cryptographic token for GNU Privacy
|
||||||
Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on
|
Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on
|
||||||
STM32F103 processor.
|
STM32F103 processor (and its compatible).
|
||||||
|
|
||||||
I wish that Gnuk will be a developer's soother who uses GnuPG. I have
|
I wish that Gnuk will be a developer's soother who uses GnuPG. I have
|
||||||
been nervous of storing secret key(s) on usual secondary storage.
|
been nervous of storing secret key(s) on usual secondary storage.
|
||||||
@@ -52,7 +54,7 @@ FAQ
|
|||||||
===
|
===
|
||||||
|
|
||||||
Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
|
Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
|
||||||
card 2.0, YubiKey, etc.) ?
|
card 2.0/3.3/3.4, YubiKey, etc.) ?
|
||||||
https://www.g10code.de/p-card.html
|
https://www.g10code.de/p-card.html
|
||||||
https://www.yubico.com/
|
https://www.yubico.com/
|
||||||
A0: Good points of Gnuk are:
|
A0: Good points of Gnuk are:
|
||||||
@@ -73,18 +75,16 @@ A1: Gnuk version 1.0 only supports RSA-2048.
|
|||||||
|
|
||||||
Q2: How long does it take for digital signing?
|
Q2: How long does it take for digital signing?
|
||||||
A2: It takes a second and a half or so for RSA-2048.
|
A2: It takes a second and a half or so for RSA-2048.
|
||||||
It takes more than 8 secondd for RSA-4096.
|
It takes more than 8 seconds for RSA-4096.
|
||||||
|
|
||||||
Q3: What's your recommendation for target board?
|
Q3: What's your recommendation for target board?
|
||||||
A3: Orthodox choice is Olimex STM32-H103.
|
A3: Orthodox choice is Olimex STM32-H103.
|
||||||
FST-01 (Flying Stone Tiny 01) is available for sale, and it is a
|
FST-01SZ (Flying Stone Tiny 01 SZ) is available for sale, and it
|
||||||
kind of the best choice, hopefully.
|
is a kind of the best choice, hopefully. If you have a skill of
|
||||||
If you have a skill of electronics, STM32 Nucleo F103 is the best
|
electronics, STM32 Nucleo F103 is the best choice for experiment.
|
||||||
choice for experiment.
|
|
||||||
|
|
||||||
Q4: What's version of GnuPG are you using?
|
Q4: What's version of GnuPG are you using?
|
||||||
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.18 in
|
A4: In Debian GNU/Linux system, I use GnuPG modern 2.2.23.
|
||||||
unstable.
|
|
||||||
|
|
||||||
Q5: What's version of pcscd and libccid are you using?
|
Q5: What's version of pcscd and libccid are you using?
|
||||||
A5: I don't use them, pcscd and libccid are optional, you can use Gnuk
|
A5: I don't use them, pcscd and libccid are optional, you can use Gnuk
|
||||||
@@ -145,14 +145,20 @@ Ac: That's because gnome-keyring-daemon interferes GnuPG. Please
|
|||||||
Qd: Do you know a good SWD debugger to connect FST-01 or something?
|
Qd: Do you know a good SWD debugger to connect FST-01 or something?
|
||||||
Ad: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
|
Ad: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
|
||||||
writer program. STM32 Nucleo F103 comes with the valiant of
|
writer program. STM32 Nucleo F103 comes with the valiant of
|
||||||
ST-Link/V2. However, the firmware of ST-Link/V2 is proprietary.
|
ST-Link/V2. Note that the firmware of ST-Link/V2 is proprietary.
|
||||||
Now, I develop BBG-SWD, SWD debugger by BeagleBone Green.
|
So, in case of transparency matters, ST-Link/V2 would not be your
|
||||||
|
choice.
|
||||||
|
I care transparency for our process of manufacturing FST-01SZ (and
|
||||||
|
better control by Free Software, in general), thus, I develop
|
||||||
|
BBG-SWD, SWD debugger by BeagleBone Green.
|
||||||
|
I use ST-Link/V2 for daily development. For serious task like
|
||||||
|
flashing product, I use BBG-SWD.
|
||||||
|
|
||||||
|
|
||||||
Tested features
|
Tested features
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Gnuk is tested by test suite. Please see the test directory.
|
Gnuk is tested by test suite. Please see the "tests" directory.
|
||||||
|
|
||||||
* Personalization of the card
|
* Personalization of the card
|
||||||
* Changing Login name, URL, Name, Sex, Language, etc.
|
* Changing Login name, URL, Name, Sex, Language, etc.
|
||||||
@@ -178,15 +184,6 @@ Original features of Gnuk, tested manually lightly:
|
|||||||
* Card holder certificate (write by UPDATE BINARY)
|
* Card holder certificate (write by UPDATE BINARY)
|
||||||
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
|
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
|
||||||
|
|
||||||
It is known not-working well:
|
|
||||||
|
|
||||||
* It is known that the specific combination of libccid 1.4.1
|
|
||||||
(or newer) with libusb 1.0.8 (or older) had a minor problem.
|
|
||||||
It is rare but it is possible for USB communication to be
|
|
||||||
failed, because of a bug in libusb implementation. Use
|
|
||||||
libusbx 1.0.9 or newer, or don't use PC/SC, but use internal
|
|
||||||
CCID driver of GnuPG.
|
|
||||||
|
|
||||||
|
|
||||||
Targets
|
Targets
|
||||||
=======
|
=======
|
||||||
@@ -198,16 +195,6 @@ DfuSe is for experiment only, because it is impossible for DfuSe to
|
|||||||
disable read from flash. For real use, please consider killing DfuSe
|
disable read from flash. For real use, please consider killing DfuSe
|
||||||
and enabling read protection using JTAG debugger.
|
and enabling read protection using JTAG debugger.
|
||||||
|
|
||||||
For experimental PIN-pad support, I connect a consumer IR receive
|
|
||||||
module to FST-01, and use controller for TV. PIN verification is
|
|
||||||
supported by this configuration. Yes, it is not secure at all, since
|
|
||||||
it is very easy to monitor IR output of the controllers. It is just
|
|
||||||
an experiment. Note that hardware needed for this experiment is only
|
|
||||||
a consumer IR receive module which is as cheap as 50 JPY.
|
|
||||||
|
|
||||||
Note that you need pinpad support for GnuPG to use PIN-pad enabled
|
|
||||||
Gnuk. The pinpad support for GnuPG is only available in version 2.
|
|
||||||
|
|
||||||
|
|
||||||
Build system and Host system
|
Build system and Host system
|
||||||
============================
|
============================
|
||||||
@@ -218,8 +205,8 @@ If your bash is not installed as /bin/bash, you need to run configure
|
|||||||
script prepending 'bash' before './configure'.
|
script prepending 'bash' before './configure'.
|
||||||
|
|
||||||
Some tools are written in Python. If your Python is not installed as
|
Some tools are written in Python. If your Python is not installed as
|
||||||
/usr/bin/python, please prepend 'python' for your command invocation.
|
/usr/bin/python, please prepend 'python' or 'python3' for your command
|
||||||
Python 2.7 and PyUSB 0.4.3 is assumed.
|
invocation. I use Python 3.8 and PyUSB 1.0.2.
|
||||||
|
|
||||||
|
|
||||||
Source code
|
Source code
|
||||||
@@ -256,7 +243,7 @@ External source code
|
|||||||
|
|
||||||
Gnuk is distributed with external source code.
|
Gnuk is distributed with external source code.
|
||||||
|
|
||||||
* chopstx/ -- Chopstx 1.8
|
* chopstx/ -- Chopstx 1.19
|
||||||
|
|
||||||
We use Chopstx as the kernel for Gnuk.
|
We use Chopstx as the kernel for Gnuk.
|
||||||
|
|
||||||
@@ -375,13 +362,13 @@ How to compile
|
|||||||
|
|
||||||
You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
||||||
|
|
||||||
On Debian we can install the packages of gcc-arm-none-eabi,
|
On Debian we can install the packages of gcc-arm-none-eabi
|
||||||
gdb-arm-none-eabi and its friends. I'm using:
|
and its friends. I'm using:
|
||||||
|
|
||||||
binutils-arm-none-eabi 2.28-4+9+b3
|
binutils-arm-none-eabi 2.35.1-7+14+b1
|
||||||
gcc-arm-none-eabi 15:6.3.1+svn253039-1
|
gcc-arm-none-eabi 15:8-2019-q3-1+b1
|
||||||
gdb-arm-none-eabi 7.12-6+9+b2
|
libnewlib-arm-none-eabi 3.3.0-1
|
||||||
libnewlib-arm-none-eabi 2.4.0.20160527-3
|
gdb-multiarch 10.1-1.7
|
||||||
|
|
||||||
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
|
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
|
||||||
GNU Toolchain for 'arm-none-eabi' target.
|
GNU Toolchain for 'arm-none-eabi' target.
|
||||||
@@ -405,9 +392,11 @@ Then, type:
|
|||||||
|
|
||||||
Then, we will have "gnuk.elf" under src/build directory.
|
Then, we will have "gnuk.elf" under src/build directory.
|
||||||
|
|
||||||
Next, we can get the final image by running following command.
|
If you are not the authorized vendor, please never distribute this
|
||||||
|
file of "gnuk.elf", which includes VID:PID in the image. If you would
|
||||||
$ make build/gnuk-vidpid.elf
|
like to distribute the image (for example, to check if it's
|
||||||
|
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
|
||||||
|
VID:PID.
|
||||||
|
|
||||||
|
|
||||||
How to install
|
How to install
|
||||||
@@ -417,11 +406,11 @@ Olimex STM32-H103 board
|
|||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD
|
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD
|
||||||
and write "gnuk-vidpid.elf" to Flash ROM:
|
and write "gnuk.elf" to Flash ROM:
|
||||||
|
|
||||||
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \
|
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \
|
||||||
-f board/olimex_stm32_h103.cfg \
|
-f board/olimex_stm32_h103.cfg \
|
||||||
-c "program build/gnuk-vidpid.elf verify reset exit"
|
-c "program build/gnuk.elf verify reset exit"
|
||||||
|
|
||||||
Command invocation is assumed in src/ directory.
|
Command invocation is assumed in src/ directory.
|
||||||
|
|
||||||
@@ -434,18 +423,20 @@ If you are using Flying Stone Tiny 01, you need a SWD writer.
|
|||||||
OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
|
OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
|
||||||
|
|
||||||
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
|
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
|
||||||
-c "program build/gnuk-vidpid.elf verify reset exit"
|
-c "program build/gnuk.elf verify reset exit"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
STBee
|
STBee
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
Note that this is only for your experiment; Your private key materials
|
||||||
|
on the board can be accessed by DfuSe.
|
||||||
|
|
||||||
Reset the board with "USER" switch pushed. Type following to write
|
Reset the board with "USER" switch pushed. Type following to write
|
||||||
to flash:
|
to flash:
|
||||||
|
|
||||||
# cd ../tool
|
# cd ../tool
|
||||||
# ./dfuse.py ../src/build/gnuk-vidpid.hex
|
# ./dfuse.py ../src/build/gnuk.hex
|
||||||
|
|
||||||
Then, reset the board.
|
Then, reset the board.
|
||||||
|
|
||||||
@@ -479,7 +470,7 @@ protect, killing DfuSe and accessing by JTAG debugger is recommended.
|
|||||||
This is completely optional.
|
This is completely optional.
|
||||||
|
|
||||||
For this procedure, you need python and pyscard (python-pyscard
|
For this procedure, you need python and pyscard (python-pyscard
|
||||||
package in Debian) or PyUSB 0.4.3 (python-usb package in Debian).
|
package in Debian) or PyUSB (python-usb package in Debian).
|
||||||
|
|
||||||
(1) [pyscard] Stop scdaemon
|
(1) [pyscard] Stop scdaemon
|
||||||
[PyUSB] Stop the pcsc daemon.
|
[PyUSB] Stop the pcsc daemon.
|
||||||
@@ -491,7 +482,7 @@ Exception" by "Sharing violation".
|
|||||||
|
|
||||||
In case of PyUSB tool, you need to stop pcscd.
|
In case of PyUSB tool, you need to stop pcscd.
|
||||||
|
|
||||||
# /etc/init.d/pcscd stop
|
# systemctl stop pcscd
|
||||||
|
|
||||||
|
|
||||||
(2) [Optional] Write fixed serial number
|
(2) [Optional] Write fixed serial number
|
||||||
@@ -535,8 +526,8 @@ Type following command to see Gnuk runs:
|
|||||||
$ gpg --card-status
|
$ gpg --card-status
|
||||||
|
|
||||||
|
|
||||||
Besides, there is a functionality test under test/ directory. See
|
Besides, there is a functionality test under tests/ directory. See
|
||||||
test/README.
|
tests/README.
|
||||||
|
|
||||||
|
|
||||||
Personalize the Token, import keys, and change the password
|
Personalize the Token, import keys, and change the password
|
||||||
@@ -604,7 +595,7 @@ You can get it by:
|
|||||||
$ git clone https://salsa.debian.org/gnuk-team/gnuk/gnuk.git
|
$ git clone https://salsa.debian.org/gnuk-team/gnuk/gnuk.git
|
||||||
|
|
||||||
It's also available at: www.gniibe.org
|
It's also available at: www.gniibe.org
|
||||||
You can browse at: https://git.gniibe.org/gitweb?p=gnuk/gnuk.git;a=summary
|
You can browse at: https://git.gniibe.org/cgit/gnuk/gnuk.git/
|
||||||
|
|
||||||
I put Chopstx as a submodule of Git. Please do this:
|
I put Chopstx as a submodule of Git. Please do this:
|
||||||
|
|
||||||
|
|||||||
3
THANKS
3
THANKS
@@ -17,6 +17,7 @@ Bertrand Jacquin bertrand@jacquin.bzh
|
|||||||
Clint Adams clint@softwarefreedom.org
|
Clint Adams clint@softwarefreedom.org
|
||||||
Daniel Kahn Gillmor dkg@fifthhorseman.net
|
Daniel Kahn Gillmor dkg@fifthhorseman.net
|
||||||
Elliott Mitchell
|
Elliott Mitchell
|
||||||
|
Fabio Utzig utzig@apache.org
|
||||||
Hironobu SUZUKI hironobu@h2np.net
|
Hironobu SUZUKI hironobu@h2np.net
|
||||||
Jan Suhr jan@suhr.info
|
Jan Suhr jan@suhr.info
|
||||||
Jeremy Drake jeremydrake+gnuk@eacceleration.com
|
Jeremy Drake jeremydrake+gnuk@eacceleration.com
|
||||||
@@ -34,10 +35,12 @@ Nico Rikken nico@nicorikken.eu
|
|||||||
NOKUBI Takatsugu knok@daionet.gr.jp
|
NOKUBI Takatsugu knok@daionet.gr.jp
|
||||||
Paul Fertser
|
Paul Fertser
|
||||||
Paul Bakker polarssl_maintainer@polarssl.org
|
Paul Bakker polarssl_maintainer@polarssl.org
|
||||||
|
Peter Lebbing peter@digitalbrains.com
|
||||||
Santiago Ruano Rincón santiago@debian.org
|
Santiago Ruano Rincón santiago@debian.org
|
||||||
Shane Coughlan scoughlan@openinventionnetwork.com
|
Shane Coughlan scoughlan@openinventionnetwork.com
|
||||||
Stanislas Bach sbach@0g.re
|
Stanislas Bach sbach@0g.re
|
||||||
Szczepan Zalega szczepan@nitrokey.com
|
Szczepan Zalega szczepan@nitrokey.com
|
||||||
Vasily Evseenko
|
Vasily Evseenko
|
||||||
|
Vincent Pelletier plr.vincent@gmail.com
|
||||||
Werner Koch wk@gnupg.org
|
Werner Koch wk@gnupg.org
|
||||||
Yuji Imai ug@xcast.jp
|
Yuji Imai ug@xcast.jp
|
||||||
|
|||||||
2
chopstx
2
chopstx
Submodule chopstx updated: aa63ac79bc...71cc5a8f32
@@ -58,6 +58,8 @@ Type: ::
|
|||||||
|
|
||||||
Then, we will have "gnuk.elf" under src/build directory.
|
Then, we will have "gnuk.elf" under src/build directory.
|
||||||
|
|
||||||
Next, we can get the final image by running following command. ::
|
If you are not the authorized vendor, please never distribute this
|
||||||
|
file of "gnuk.elf", which includes VID:PID in the image. If you would
|
||||||
$ make build/gnuk-vidpid.elf
|
like to distribute the image (for example, to check if it's
|
||||||
|
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
|
||||||
|
VID:PID.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ In addition to settings of Gnuk, I create a file
|
|||||||
|
|
||||||
# For updating firmware, permission settings are needed.
|
# For updating firmware, permission settings are needed.
|
||||||
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
|
||||||
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
|
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ Invoking firmware update
|
|||||||
|
|
||||||
We specify reGNUal binary and Gnuk binary.
|
We specify reGNUal binary and Gnuk binary.
|
||||||
|
|
||||||
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk-vidpid.bin
|
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk.bin
|
||||||
|
|
||||||
|
|
||||||
Two or more tokens
|
Two or more tokens
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ setting). It should have lines something like: ::
|
|||||||
# Gnuk Token by FSIJ
|
# Gnuk Token by FSIJ
|
||||||
|
|
||||||
SUBSYSTEMS=="usb", ACTION=="add", \
|
SUBSYSTEMS=="usb", ACTION=="add", \
|
||||||
ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
|
||||||
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||||
|
|
||||||
I have those lines in /etc/udev/rules.d/69-gnuk.rules.
|
I have those lines in /etc/udev/rules.d/69-gnuk.rules.
|
||||||
@@ -78,14 +78,15 @@ is FST-01.
|
|||||||
|
|
||||||
Then you get build/gnuk.elf.
|
Then you get build/gnuk.elf.
|
||||||
|
|
||||||
Next, we can get the final image by running following command.
|
If you are not the authorized vendor, please never distribute this
|
||||||
|
file of "gnuk.elf", which includes VID:PID in the image. If you would
|
||||||
$ make build/gnuk-vidpid.elf
|
like to distribute the image (for example, to check if it's
|
||||||
|
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
|
||||||
|
VID:PID.
|
||||||
|
|
||||||
Invoking configure with FSIJ's USB ID (234b:0000) and generating
|
Invoking configure with FSIJ's USB ID (234b:0000) and generating
|
||||||
gnuk-vidpid.elf means that you are using FSIJ's USB ID (for reGNUal in
|
gnuk.elf means that you are using FSIJ's USB ID (for reGNUal in this
|
||||||
this case). Please note that FSIJ only allows use of its USB ID for
|
case). Please note that FSIJ only allows use of its USB ID for
|
||||||
specific situations. Please read README of Gnuk about that.
|
specific situations. Please read README of Gnuk about that.
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ your environment for Gnuk Token.
|
|||||||
How to run the script: ::
|
How to run the script: ::
|
||||||
|
|
||||||
$ cd tool
|
$ cd tool
|
||||||
$ ./upgrade_by_passwd.py ../regnual/regnual.bin ../src/build/gnuk-vidpid.bin
|
$ ./upgrade_by_passwd.py ../regnual/regnual.bin ../src/build/gnuk.bin
|
||||||
|
|
||||||
Then, the script on your host PC invoke the steps described above, and
|
Then, the script on your host PC invoke the steps described above, and
|
||||||
you will get new version of Gnuk installed.
|
you will get new version of Gnuk installed.
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ command.
|
|||||||
|
|
||||||
Or, you can use ``gpgconf`` command. Type::
|
Or, you can use ``gpgconf`` command. Type::
|
||||||
|
|
||||||
$ gpgconf --reload scdameon
|
$ gpgconf --reload scdaemon
|
||||||
|
|
||||||
will do the same thing.
|
will do the same thing.
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ When we only install "gnupg2" package for 2.0 (with no "gnupg" package),
|
|||||||
there will be no udev rules (there is a bug report #543217 for this issue).
|
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::
|
In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules::
|
||||||
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
|
||||||
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||||
|
|
||||||
Usually, udev daemon automatically handles for the changes of configuration
|
Usually, udev daemon automatically handles for the changes of configuration
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ regnual-no-vidpid.elf: $(OBJS) $(LDSCRIPT)
|
|||||||
$(CC) $(LDFLAGS) -o regnual-no-vidpid.elf $(OBJS)
|
$(CC) $(LDFLAGS) -o regnual-no-vidpid.elf $(OBJS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin *.lst
|
-rm -f $(OBJS) regnual-no-vidpid.elf regnual.elf regnual.hex regnual.bin \
|
||||||
|
*.lst
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
|
|||||||
28
src/Makefile
28
src/Makefile
@@ -53,6 +53,10 @@ ifeq ($(CHIP),stm32f103)
|
|||||||
CSRC += mcu-stm32f103.c
|
CSRC += mcu-stm32f103.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(USE_DFU),)
|
||||||
|
OBJS_ADD += build/stdaln-sys-bin.o
|
||||||
|
endif
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
CC = $(CROSS)gcc
|
CC = $(CROSS)gcc
|
||||||
LD = $(CROSS)gcc
|
LD = $(CROSS)gcc
|
||||||
@@ -72,16 +76,26 @@ sys.c: board.h
|
|||||||
|
|
||||||
build/bignum.o: OPT = -O3 -g
|
build/bignum.o: OPT = -O3 -g
|
||||||
|
|
||||||
|
build/stdaln-sys.elf: build/sys-$(CHIP).o stdaln-sys.ld
|
||||||
|
@echo
|
||||||
|
$(LD) -v $< $(MCFLAGS) -nostartfiles -Tstdaln-sys.ld -Wl,--no-warn-mismatch,--gc-sections $(LLIBDIR) -o $@
|
||||||
|
|
||||||
|
build/stdaln-sys-bin.o: build/stdaln-sys.elf
|
||||||
|
@echo
|
||||||
|
$(OBJCOPY) -O binary -j .sys $< build/stdaln-sys.bin
|
||||||
|
$(OBJCOPY) -I binary -O default --rename-section .data=.rodata \
|
||||||
|
build/stdaln-sys.bin $@
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
-rm -f gnuk.ld config.h board.h config.mk \
|
-rm -f gnuk.ld stdaln-sys.ld config.h board.h config.mk \
|
||||||
usb-strings.c.inc usb-vid-pid-ver.c.inc
|
usb-strings.c.inc put-vid-pid-ver.sh
|
||||||
|
|
||||||
ifeq ($(EMULATION),)
|
ifeq ($(EMULATION),)
|
||||||
build/gnuk-vidpid.elf: build/gnuk.elf binary-edit.sh put-vid-pid-ver.sh
|
build/gnuk.elf: build/gnuk-no-vidpid.elf binary-edit.sh put-vid-pid-ver.sh
|
||||||
cp -p build/gnuk.elf build/gnuk-vidpid.elf
|
cp -p build/gnuk-no-vidpid.elf build/gnuk.elf
|
||||||
env FILE="build/gnuk-vidpid.elf" bash put-vid-pid-ver.sh
|
env FILE="build/gnuk.elf" bash put-vid-pid-ver.sh
|
||||||
$(OBJCOPY) -O ihex build/gnuk-vidpid.elf build/gnuk-vidpid.hex
|
$(OBJCOPY) -O ihex build/gnuk.elf build/gnuk.hex
|
||||||
$(OBJCOPY) -O binary build/gnuk-vidpid.elf build/gnuk-vidpid.bin
|
$(OBJCOPY) -O binary build/gnuk.elf build/gnuk.bin
|
||||||
else
|
else
|
||||||
# By specifying DESTDIR on invocation of "make", you can install
|
# By specifying DESTDIR on invocation of "make", you can install
|
||||||
# program to different ROOT.
|
# program to different ROOT.
|
||||||
|
|||||||
39
src/ac.c
39
src/ac.c
@@ -63,7 +63,7 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
|||||||
const uint8_t *ks_pw1, int save_ks)
|
const uint8_t *ks_pw1, int save_ks)
|
||||||
{
|
{
|
||||||
int pw_len;
|
int pw_len;
|
||||||
int r1, r2;
|
int r;
|
||||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||||
const uint8_t *salt;
|
const uint8_t *salt;
|
||||||
int salt_len;
|
int salt_len;
|
||||||
@@ -99,21 +99,31 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
|||||||
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
|
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
|
||||||
|
|
||||||
if (access == AC_PSO_CDS_AUTHORIZED)
|
if (access == AC_PSO_CDS_AUTHORIZED)
|
||||||
{
|
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
|
||||||
r2 = 0;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int r1, r2;
|
||||||
|
|
||||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring);
|
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring);
|
||||||
r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, keystring);
|
r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, keystring);
|
||||||
|
|
||||||
|
if (r1 < 0 || r2 < 0)
|
||||||
|
r = -1;
|
||||||
|
else if (r1 == 0)
|
||||||
|
{
|
||||||
|
if (r2 == 0)
|
||||||
|
/* No encryption/authentication keys, then, check signing key. */
|
||||||
|
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||||
|
else
|
||||||
|
r = r2;
|
||||||
|
}
|
||||||
|
else if (r2 == 0)
|
||||||
|
r = r1;
|
||||||
|
else
|
||||||
|
r = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r1 < 0 || r2 < 0
|
if (r < 0)
|
||||||
|| (r1 == 0 && r2 == 0 && ks_pw1 != NULL
|
|
||||||
&& ((ks_pw1[0] & PW_LEN_KEYSTRING_BIT) == 0
|
|
||||||
|| memcmp (KS_GET_KEYSTRING (ks_pw1),
|
|
||||||
keystring, KEYSTRING_MD_SIZE) != 0)))
|
|
||||||
{
|
{
|
||||||
failure:
|
failure:
|
||||||
gpg_pw_increment_err_counter (PW_ERR_PW1);
|
gpg_pw_increment_err_counter (PW_ERR_PW1);
|
||||||
@@ -163,7 +173,7 @@ verify_admin_00 (const uint8_t *pw, int buf_len, int pw_len_known,
|
|||||||
const uint8_t *ks, int save_ks)
|
const uint8_t *ks, int save_ks)
|
||||||
{
|
{
|
||||||
int pw_len;
|
int pw_len;
|
||||||
int r1, r2;
|
int r;
|
||||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||||
const uint8_t *salt;
|
const uint8_t *salt;
|
||||||
int salt_len;
|
int salt_len;
|
||||||
@@ -179,12 +189,11 @@ verify_admin_00 (const uint8_t *pw, int buf_len, int pw_len_known,
|
|||||||
if (save_ks)
|
if (save_ks)
|
||||||
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
|
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
|
||||||
|
|
||||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring);
|
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring);
|
||||||
r2 = 0;
|
|
||||||
|
|
||||||
if (r1 < 0 || r2 < 0)
|
if (r < 0)
|
||||||
return -1;
|
return -1;
|
||||||
else if (r1 == 0 && r2 == 0)
|
else if (r == 0)
|
||||||
if ((ks[0] & PW_LEN_KEYSTRING_BIT) == 0
|
if ((ks[0] & PW_LEN_KEYSTRING_BIT) == 0
|
||||||
|| memcmp (KS_GET_KEYSTRING (ks), keystring, KEYSTRING_MD_SIZE) != 0)
|
|| memcmp (KS_GET_KEYSTRING (ks), keystring, KEYSTRING_MD_SIZE) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
21
src/bn.c
21
src/bn.c
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* bn.c -- 256-bit (and 512-bit) bignum calculation
|
* bn.c -- 256-bit (and 512-bit) bignum calculation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
|
* Copyright (C) 2011, 2013, 2014, 2019
|
||||||
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -412,17 +413,15 @@ bn256_cmp (const bn256 *A, const bn256 *B)
|
|||||||
void
|
void
|
||||||
bn256_random (bn256 *X)
|
bn256_random (bn256 *X)
|
||||||
{
|
{
|
||||||
const uint8_t *rand = random_bytes_get ();
|
int i, j;
|
||||||
|
const uint8_t *rand;
|
||||||
X->word[7] = ((uint32_t *)rand)[7];
|
|
||||||
X->word[6] = ((uint32_t *)rand)[6];
|
|
||||||
X->word[5] = ((uint32_t *)rand)[5];
|
|
||||||
X->word[4] = ((uint32_t *)rand)[4];
|
|
||||||
X->word[3] = ((uint32_t *)rand)[3];
|
|
||||||
X->word[2] = ((uint32_t *)rand)[2];
|
|
||||||
X->word[1] = ((uint32_t *)rand)[1];
|
|
||||||
X->word[0] = ((uint32_t *)rand)[0];
|
|
||||||
|
|
||||||
|
for (i = 0; i < 256/256; i++)
|
||||||
|
{
|
||||||
|
rand = random_bytes_get ();
|
||||||
|
for (j = 0; j < BN256_WORDS; j++)
|
||||||
|
X->word[i*BN256_WORDS+j] = ((uint32_t *)rand)[j];
|
||||||
random_bytes_free (rand);
|
random_bytes_free (rand);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,9 +3,13 @@
|
|||||||
#define ENABLE_VIRTUAL_COM_PORT 1
|
#define ENABLE_VIRTUAL_COM_PORT 1
|
||||||
#endif
|
#endif
|
||||||
@DFU_DEFINE@
|
@DFU_DEFINE@
|
||||||
|
@ORIGIN_DEFINE@
|
||||||
|
@ORIGIN_REAL_DEFINE@
|
||||||
@PINPAD_DEFINE@
|
@PINPAD_DEFINE@
|
||||||
@PINPAD_MORE_DEFINE@
|
@PINPAD_MORE_DEFINE@
|
||||||
@CERTDO_DEFINE@
|
@CERTDO_DEFINE@
|
||||||
@HID_CARD_CHANGE_DEFINE@
|
@HID_CARD_CHANGE_DEFINE@
|
||||||
@SERIALNO_STR_LEN_DEFINE@
|
|
||||||
@LIFE_CYCLE_MANAGEMENT_DEFINE@
|
@LIFE_CYCLE_MANAGEMENT_DEFINE@
|
||||||
|
@ACKBTN_DEFINE@
|
||||||
|
@SERIALNO_STR_LEN_DEFINE@
|
||||||
|
@KDF_DO_REQUIRED_DEFINE@
|
||||||
|
|||||||
61
src/configure
vendored
61
src/configure
vendored
@@ -6,7 +6,7 @@ nl=$'\n'
|
|||||||
#
|
#
|
||||||
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
|
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
|
||||||
#
|
#
|
||||||
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2021
|
||||||
# Free Software Initiative of Japan
|
# Free Software Initiative of Japan
|
||||||
#
|
#
|
||||||
# This file is a part of Gnuk, a GnuPG USB Token implementation.
|
# This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -44,7 +44,9 @@ pinpad=no
|
|||||||
certdo=no
|
certdo=no
|
||||||
hid_card_change=no
|
hid_card_change=no
|
||||||
factory_reset=no
|
factory_reset=no
|
||||||
|
ackbtn_support=yes
|
||||||
flash_override=""
|
flash_override=""
|
||||||
|
kdf_do_required=no
|
||||||
# For emulation
|
# For emulation
|
||||||
prefix=/usr/local
|
prefix=/usr/local
|
||||||
exec_prefix='${prefix}'
|
exec_prefix='${prefix}'
|
||||||
@@ -135,6 +137,7 @@ Configuration:
|
|||||||
supported targets are:
|
supported targets are:
|
||||||
FST_01
|
FST_01
|
||||||
FST_01G
|
FST_01G
|
||||||
|
FST_01SZ
|
||||||
OLIMEX_STM32_H103
|
OLIMEX_STM32_H103
|
||||||
MAPLE_MINI
|
MAPLE_MINI
|
||||||
ST_DONGLE
|
ST_DONGLE
|
||||||
@@ -167,6 +170,8 @@ BOARD_HEADER_FILE=board-$(echo $target | tr '_[:upper:]' '-[:lower:]').h
|
|||||||
echo "Header file is: $BOARD_HEADER_FILE"
|
echo "Header file is: $BOARD_HEADER_FILE"
|
||||||
ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h
|
ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h
|
||||||
|
|
||||||
|
# Frequency
|
||||||
|
MHZ=72
|
||||||
# Flash page size in byte
|
# Flash page size in byte
|
||||||
FLASH_PAGE_SIZE=1024
|
FLASH_PAGE_SIZE=1024
|
||||||
# Flash memory size in KiB
|
# Flash memory size in KiB
|
||||||
@@ -196,16 +201,25 @@ STBEE)
|
|||||||
if test "$with_dfu" = "default"; then
|
if test "$with_dfu" = "default"; then
|
||||||
with_dfu=yes;
|
with_dfu=yes;
|
||||||
fi ;;
|
fi ;;
|
||||||
|
BLUE_PILL_G)
|
||||||
|
MHZ=96
|
||||||
|
;;
|
||||||
|
FST_01SZ)
|
||||||
|
MHZ=96
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
def_mhz="-DMHZ=$MHZ"
|
||||||
if test "$target" = "GNU_LINUX"; then
|
if test "$target" = "GNU_LINUX"; then
|
||||||
ldscript=""
|
ldscript=""
|
||||||
chip="gnu-linux"
|
chip="gnu-linux"
|
||||||
|
arch="gnu-linux"
|
||||||
emulation="yes"
|
emulation="yes"
|
||||||
cross=""
|
cross=""
|
||||||
mcu="none"
|
mcu="none"
|
||||||
|
kdf_do_require=yes
|
||||||
def_emulation="-DGNU_LINUX_EMULATION"
|
def_emulation="-DGNU_LINUX_EMULATION"
|
||||||
def_memory_size="-DMEMORY_SIZE=1024"
|
def_memory_size="-DMEMORY_SIZE=1024"
|
||||||
enable_hexoutput=""
|
enable_hexoutput=""
|
||||||
@@ -213,6 +227,7 @@ if test "$target" = "GNU_LINUX"; then
|
|||||||
else
|
else
|
||||||
ldscript="gnuk.ld"
|
ldscript="gnuk.ld"
|
||||||
chip="stm32f103"
|
chip="stm32f103"
|
||||||
|
arch="cortex-m"
|
||||||
emulation=""
|
emulation=""
|
||||||
cross="arm-none-eabi-"
|
cross="arm-none-eabi-"
|
||||||
mcu="cortex-m3"
|
mcu="cortex-m3"
|
||||||
@@ -248,6 +263,8 @@ else
|
|||||||
echo "Debug option disabled"
|
echo "Debug option disabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ORIGIN_REAL=0x08000000
|
||||||
|
ORIGIN_REAL_DEFINE="#define ORIGIN_REAL $ORIGIN_REAL"
|
||||||
# --with-dfu option
|
# --with-dfu option
|
||||||
if test "$with_dfu" = "yes"; then
|
if test "$with_dfu" = "yes"; then
|
||||||
if test "$target" = "FST_01" -o "$target" = "FST_01G" \
|
if test "$target" = "FST_01" -o "$target" = "FST_01G" \
|
||||||
@@ -256,15 +273,23 @@ if test "$with_dfu" = "yes"; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "Configured for DFU"
|
echo "Configured for DFU"
|
||||||
|
if test "$target" = "MAPLE_MINI"; then
|
||||||
|
# Note that the default bootloader is too large, need for instance
|
||||||
|
# STM32duino for DFU on Maple Mini
|
||||||
|
ORIGIN=0x08002000
|
||||||
|
FLASH_SIZE=$((FLASH_SIZE - 8))
|
||||||
|
else
|
||||||
ORIGIN=0x08003000
|
ORIGIN=0x08003000
|
||||||
FLASH_SIZE=$((FLASH_SIZE - 12))
|
FLASH_SIZE=$((FLASH_SIZE - 12))
|
||||||
|
fi
|
||||||
DFU_DEFINE="#define DFU_SUPPORT 1"
|
DFU_DEFINE="#define DFU_SUPPORT 1"
|
||||||
else
|
else
|
||||||
with_dfu=no
|
with_dfu=no
|
||||||
echo "Configured for bare system (no-DFU)"
|
echo "Configured for bare system (no-DFU)"
|
||||||
ORIGIN=0x08000000
|
ORIGIN=${ORIGIN_REAL}
|
||||||
DFU_DEFINE="#undef DFU_SUPPORT"
|
DFU_DEFINE="#undef DFU_SUPPORT"
|
||||||
fi
|
fi
|
||||||
|
ORIGIN_DEFINE="#define ORIGIN $ORIGIN"
|
||||||
|
|
||||||
# --enable-pinpad option
|
# --enable-pinpad option
|
||||||
if test "$pinpad" = "no"; then
|
if test "$pinpad" = "no"; then
|
||||||
@@ -306,6 +331,23 @@ else
|
|||||||
echo "Life cycle management is NOT supported"
|
echo "Life cycle management is NOT supported"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Acknowledge button support
|
||||||
|
if test "$ackbtn_support" = "yes"; then
|
||||||
|
ACKBTN_DEFINE="#define ACKBTN_SUPPORT 1"
|
||||||
|
echo "Acknowledge button is supported"
|
||||||
|
else
|
||||||
|
ACKBTN_DEFINE="#undef ACKBTN_SUPPORT"
|
||||||
|
echo "Acknowledge button is not supported"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# KDF Data Object is always required for GNU/Linux emulation
|
||||||
|
if test "$kdf_do_required" = "yes"; then
|
||||||
|
KDF_DO_REQUIRED_DEFINE="#define KDF_DO_REQUIRED 1"
|
||||||
|
echo "KDF DO is required before key import/generation"
|
||||||
|
else
|
||||||
|
KDF_DO_REQUIRED_DEFINE="#undef KDF_DO_REQUIRED"
|
||||||
|
fi
|
||||||
|
|
||||||
### !!! Replace following string of "FSIJ" to yours !!! ####
|
### !!! Replace following string of "FSIJ" to yours !!! ####
|
||||||
SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
|
SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
|
||||||
|
|
||||||
@@ -439,16 +481,23 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
(echo "CHIP=$chip";
|
(echo "CHIP=$chip";
|
||||||
|
echo "ARCH=$arch";
|
||||||
echo "EMULATION=$emulation";
|
echo "EMULATION=$emulation";
|
||||||
echo "CROSS=$cross";
|
echo "CROSS=$cross";
|
||||||
echo "MCU=$mcu";
|
echo "MCU=$mcu";
|
||||||
echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size";
|
echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size $def_mhz";
|
||||||
echo "LDSCRIPT=$ldscript";
|
echo "LDSCRIPT=$ldscript";
|
||||||
echo "LIBS=$libs";
|
echo "LIBS=$libs";
|
||||||
echo "$DEBUG_MAKE_OPTION";
|
echo "$DEBUG_MAKE_OPTION";
|
||||||
echo "$PINPAD_MAKE_OPTION";
|
echo "$PINPAD_MAKE_OPTION";
|
||||||
echo "ENABLE_FRAUCHEKY=$enable_fraucheky";
|
echo "ENABLE_FRAUCHEKY=$enable_fraucheky";
|
||||||
echo "ENABLE_OUTPUT_HEX=$enable_hexoutput"
|
echo "ENABLE_OUTPUT_HEX=$enable_hexoutput"
|
||||||
|
if test "$ackbtn_support" = "yes"; then
|
||||||
|
echo "USE_ACKBTN=yes"
|
||||||
|
fi
|
||||||
|
if test "$with_dfu" = "yes"; then
|
||||||
|
echo "USE_DFU=yes"
|
||||||
|
fi
|
||||||
if test "$emulation" = "yes"; then
|
if test "$emulation" = "yes"; then
|
||||||
echo "prefix=$prefix"
|
echo "prefix=$prefix"
|
||||||
echo "exec_prefix=$exec_prefix"
|
echo "exec_prefix=$exec_prefix"
|
||||||
@@ -469,13 +518,19 @@ else
|
|||||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||||
< gnuk.ld.in > gnuk.ld
|
< gnuk.ld.in > gnuk.ld
|
||||||
fi
|
fi
|
||||||
|
sed -e "s/@ORIGIN_REAL@/$ORIGIN_REAL/" -e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
|
||||||
|
< stdaln-sys.ld.in > stdaln-sys.ld
|
||||||
sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
|
sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
|
||||||
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
|
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
|
||||||
|
-e "s/@ORIGIN_DEFINE@/$ORIGIN_DEFINE/" \
|
||||||
|
-e "s/@ORIGIN_REAL_DEFINE@/$ORIGIN_REAL_DEFINE/" \
|
||||||
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
|
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
|
||||||
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
|
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
|
||||||
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
|
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
|
||||||
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
|
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
|
||||||
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
|
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
|
||||||
|
-e "s/@ACKBTN_DEFINE@/$ACKBTN_DEFINE/" \
|
||||||
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
|
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
|
||||||
|
-e "s/@KDF_DO_REQUIRED_DEFINE@/$KDF_DO_REQUIRED_DEFINE/" \
|
||||||
< config.h.in > config.h
|
< config.h.in > config.h
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ static const uint8_t *data_pool;
|
|||||||
static uint8_t *last_p;
|
static uint8_t *last_p;
|
||||||
|
|
||||||
/* The first halfword is generation for the data page (little endian) */
|
/* The first halfword is generation for the data page (little endian) */
|
||||||
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
|
const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
|
||||||
0x00, 0x00, 0xff, 0xff
|
0x00, 0x00, 0xff, 0xff
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
48
src/gnuk.h
48
src/gnuk.h
@@ -24,17 +24,18 @@ extern struct apdu apdu;
|
|||||||
void ccid_card_change_signal (int how);
|
void ccid_card_change_signal (int how);
|
||||||
|
|
||||||
/* CCID thread */
|
/* CCID thread */
|
||||||
#define EV_RX_DATA_READY 1 /* USB Rx data available */
|
#define EV_CARD_CHANGE 1
|
||||||
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */
|
#define EV_TX_FINISHED 2 /* CCID Tx finished */
|
||||||
#define EV_TX_FINISHED 4 /* CCID Tx finished */
|
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
|
||||||
#define EV_CARD_CHANGE 8
|
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
|
||||||
|
#define EV_RX_DATA_READY 16 /* USB Rx data available */
|
||||||
|
|
||||||
/* OpenPGPcard thread */
|
/* OpenPGPcard thread */
|
||||||
#define EV_PINPAD_INPUT_DONE 1
|
#define EV_MODIFY_CMD_AVAILABLE 1
|
||||||
#define EV_EXIT 2
|
#define EV_VERIFY_CMD_AVAILABLE 2
|
||||||
#define EV_CMD_AVAILABLE 4
|
#define EV_CMD_AVAILABLE 4
|
||||||
#define EV_VERIFY_CMD_AVAILABLE 8
|
#define EV_EXIT 8
|
||||||
#define EV_MODIFY_CMD_AVAILABLE 16
|
#define EV_PINPAD_INPUT_DONE 16
|
||||||
|
|
||||||
/* Maximum cmd apdu data is key import 24+4+256+256 (proc_key_import) */
|
/* Maximum cmd apdu data is key import 24+4+256+256 (proc_key_import) */
|
||||||
#define MAX_CMD_APDU_DATA_SIZE (24+4+256+256) /* without header */
|
#define MAX_CMD_APDU_DATA_SIZE (24+4+256+256) /* without header */
|
||||||
@@ -53,17 +54,17 @@ enum ccid_state {
|
|||||||
CCID_STATE_NOCARD, /* No card available */
|
CCID_STATE_NOCARD, /* No card available */
|
||||||
CCID_STATE_START, /* Initial */
|
CCID_STATE_START, /* Initial */
|
||||||
CCID_STATE_WAIT, /* Waiting APDU */
|
CCID_STATE_WAIT, /* Waiting APDU */
|
||||||
/* Busy1, Busy2, Busy3, Busy5 */
|
|
||||||
CCID_STATE_EXECUTE, /* Busy4 */
|
|
||||||
CCID_STATE_RECEIVE, /* APDU Received Partially */
|
|
||||||
CCID_STATE_SEND, /* APDU Sent Partially */
|
|
||||||
|
|
||||||
CCID_STATE_EXITED, /* ICC Thread Terminated */
|
CCID_STATE_EXECUTE, /* Executing command */
|
||||||
|
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
|
||||||
|
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
|
||||||
|
|
||||||
|
CCID_STATE_EXITED, /* CCID Thread Terminated */
|
||||||
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
|
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern enum ccid_state *const ccid_state_p;
|
enum ccid_state ccid_get_ccid_state (void);
|
||||||
|
|
||||||
extern volatile uint8_t auth_status;
|
extern volatile uint8_t auth_status;
|
||||||
#define AC_NONE_AUTHORIZED 0x00
|
#define AC_NONE_AUTHORIZED 0x00
|
||||||
@@ -123,8 +124,8 @@ const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
|
|||||||
|
|
||||||
enum kind_of_key {
|
enum kind_of_key {
|
||||||
GPG_KEY_FOR_SIGNING = 0,
|
GPG_KEY_FOR_SIGNING = 0,
|
||||||
GPG_KEY_FOR_DECRYPTION,
|
GPG_KEY_FOR_DECRYPTION = 1,
|
||||||
GPG_KEY_FOR_AUTHENTICATION,
|
GPG_KEY_FOR_AUTHENTICATION = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum size_of_key {
|
enum size_of_key {
|
||||||
@@ -296,6 +297,7 @@ void gpg_increment_digital_signature_counter (void);
|
|||||||
void gpg_do_get_initial_pw_setting (int is_pw3, int *r_len,
|
void gpg_do_get_initial_pw_setting (int is_pw3, int *r_len,
|
||||||
const uint8_t **r_p);
|
const uint8_t **r_p);
|
||||||
int gpg_do_kdf_check (int len, int how_many);
|
int gpg_do_kdf_check (int len, int how_many);
|
||||||
|
int gpg_do_get_uif (enum kind_of_key kk);
|
||||||
|
|
||||||
|
|
||||||
void fatal (uint8_t code) __attribute__ ((noreturn));
|
void fatal (uint8_t code) __attribute__ ((noreturn));
|
||||||
@@ -378,7 +380,17 @@ extern uint8_t admin_authorized;
|
|||||||
#define NR_KEY_ALGO_ATTR_DEC 0xf2
|
#define NR_KEY_ALGO_ATTR_DEC 0xf2
|
||||||
#define NR_KEY_ALGO_ATTR_AUT 0xf3
|
#define NR_KEY_ALGO_ATTR_AUT 0xf3
|
||||||
/*
|
/*
|
||||||
* NR_UINT_SOMETHING could be here... Use 0xf[456789abcd]
|
* Representation of User Interaction Flag:
|
||||||
|
* 0 (UIF disabled): 0xf?00 or No record in flash memory
|
||||||
|
* 1 (UIF enabled): 0xf?01
|
||||||
|
* 2 (UIF permanently enabled): 0xf?02
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define NR_DO_UIF_SIG 0xf6
|
||||||
|
#define NR_DO_UIF_DEC 0xf7
|
||||||
|
#define NR_DO_UIF_AUT 0xf8
|
||||||
|
/*
|
||||||
|
* NR_UINT_SOMETHING could be here... Use 0xf[459abcd]
|
||||||
*/
|
*/
|
||||||
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
||||||
/*
|
/*
|
||||||
@@ -434,6 +446,7 @@ extern const uint8_t gnuk_string_serial[];
|
|||||||
#define LED_GNUK_EXEC 32
|
#define LED_GNUK_EXEC 32
|
||||||
#define LED_START_COMMAND 64
|
#define LED_START_COMMAND 64
|
||||||
#define LED_FINISH_COMMAND 128
|
#define LED_FINISH_COMMAND 128
|
||||||
|
#define LED_WAIT_FOR_BUTTON 256
|
||||||
#define LED_OFF LED_FINISH_COMMAND
|
#define LED_OFF LED_FINISH_COMMAND
|
||||||
void led_blink (int spec);
|
void led_blink (int spec);
|
||||||
|
|
||||||
@@ -461,6 +474,7 @@ int pinpad_getline (int msg_code, uint32_t timeout_usec);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
extern uint8_t _regnual_start, __heap_end__[];
|
extern uint8_t _regnual_start, __heap_end__[];
|
||||||
|
|
||||||
uint8_t * sram_address (uint32_t offset);
|
uint8_t * sram_address (uint32_t offset);
|
||||||
|
|||||||
149
src/main.c
149
src/main.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* main.c - main routine of Gnuk
|
* main.c - main routine of Gnuk
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017
|
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018, 2021
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -36,6 +36,11 @@
|
|||||||
#include "usb-cdc.h"
|
#include "usb-cdc.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#ifdef GNU_LINUX_EMULATION
|
#ifdef GNU_LINUX_EMULATION
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#define main emulated_main
|
#define main emulated_main
|
||||||
@@ -51,6 +56,28 @@
|
|||||||
#define LED_TIMEOUT_ONE (100*1000)
|
#define LED_TIMEOUT_ONE (100*1000)
|
||||||
#define LED_TIMEOUT_STOP (200*1000)
|
#define LED_TIMEOUT_STOP (200*1000)
|
||||||
|
|
||||||
|
#ifdef DFU_SUPPORT
|
||||||
|
static int
|
||||||
|
flash_write_any (uintptr_t dst_addr, const uint8_t *src, size_t len)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
uint16_t hw = *src++;
|
||||||
|
|
||||||
|
hw |= (*src++ << 8);
|
||||||
|
status = flash_program_halfword (dst_addr, hw);
|
||||||
|
if (status != 0)
|
||||||
|
return 0; /* error return */
|
||||||
|
|
||||||
|
dst_addr += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef GNU_LINUX_EMULATION
|
#ifdef GNU_LINUX_EMULATION
|
||||||
uint8_t *flash_addr_key_storage_start;
|
uint8_t *flash_addr_key_storage_start;
|
||||||
@@ -68,7 +95,7 @@ device_initialize_once (void)
|
|||||||
* This is the first time invocation.
|
* This is the first time invocation.
|
||||||
* Setup serial number by unique device ID.
|
* Setup serial number by unique device ID.
|
||||||
*/
|
*/
|
||||||
const uint8_t *u = unique_device_id () + 8;
|
const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
@@ -83,6 +110,55 @@ device_initialize_once (void)
|
|||||||
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
||||||
flash_put_data_internal (&p[i*4+2], nibble);
|
flash_put_data_internal (&p[i*4+2], nibble);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DFU_SUPPORT
|
||||||
|
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
|
||||||
|
/*
|
||||||
|
* Overwrite DFU bootloader with a copy of SYS linked to ORIGIN_REAL.
|
||||||
|
* Then protect flash from readout.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
extern uint8_t _binary_build_stdaln_sys_bin_start;
|
||||||
|
extern uint8_t _binary_build_stdaln_sys_bin_size;
|
||||||
|
size_t stdaln_sys_size = (size_t) &_binary_build_stdaln_sys_bin_size;
|
||||||
|
extern const uint32_t FT0[256], FT1[256], FT2[256];
|
||||||
|
extern handler vector_table[];
|
||||||
|
uintptr_t addr;
|
||||||
|
uint32_t flash_page_size = 1024; /* 1KiB default */
|
||||||
|
|
||||||
|
if (((*CHIP_ID_REG)&0x07) == 0x04) /* High density device. */
|
||||||
|
flash_page_size = 2048; /* It's 2KiB. */
|
||||||
|
|
||||||
|
/* Kill DFU */
|
||||||
|
for (addr = ORIGIN_REAL; addr < ORIGIN;
|
||||||
|
addr += flash_page_size)
|
||||||
|
flash_erase_page (addr);
|
||||||
|
|
||||||
|
/* Copy SYS */
|
||||||
|
addr = ORIGIN_REAL;
|
||||||
|
flash_write_any(addr, &_binary_build_stdaln_sys_bin_start,
|
||||||
|
stdaln_sys_size);
|
||||||
|
addr += stdaln_sys_size;
|
||||||
|
flash_write_any(addr, (const uint8_t *) &FT0, sizeof(FT0));
|
||||||
|
addr += sizeof(FT0);
|
||||||
|
flash_write_any(addr, (const uint8_t *) &FT1, sizeof(FT1));
|
||||||
|
addr += sizeof(FT1);
|
||||||
|
flash_write_any(addr, (const uint8_t *) &FT2, sizeof(FT2));
|
||||||
|
|
||||||
|
addr = ORIGIN_REAL + 0x1000;
|
||||||
|
if (addr < ORIGIN) {
|
||||||
|
/* Need to patch top of stack and reset vector there */
|
||||||
|
handler *new_vector = (handler *) addr;
|
||||||
|
flash_write((uintptr_t) &new_vector[0], (const uint8_t *)
|
||||||
|
&vector_table[0], sizeof(handler));
|
||||||
|
flash_write((uintptr_t) &new_vector[1], (const uint8_t *)
|
||||||
|
&vector[1], sizeof(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_protect();
|
||||||
|
nvic_system_reset();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -146,7 +222,7 @@ emit_led (uint32_t on_time, uint32_t off_time)
|
|||||||
static void
|
static void
|
||||||
display_status_code (void)
|
display_status_code (void)
|
||||||
{
|
{
|
||||||
enum ccid_state ccid_state = *ccid_state_p;
|
enum ccid_state ccid_state = ccid_get_ccid_state ();
|
||||||
uint32_t usec;
|
uint32_t usec;
|
||||||
|
|
||||||
if (ccid_state == CCID_STATE_START)
|
if (ccid_state == CCID_STATE_START)
|
||||||
@@ -170,8 +246,7 @@ display_status_code (void)
|
|||||||
{
|
{
|
||||||
usec = LED_TIMEOUT_INTERVAL;
|
usec = LED_TIMEOUT_INTERVAL;
|
||||||
chopstx_poll (&usec, 1, led_event_poll);
|
chopstx_poll (&usec, 1, led_event_poll);
|
||||||
emit_led (ccid_state == CCID_STATE_RECEIVE?
|
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
||||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,6 +313,7 @@ main (int argc, const char *argv[])
|
|||||||
uintptr_t entry;
|
uintptr_t entry;
|
||||||
#endif
|
#endif
|
||||||
chopstx_t ccid_thd;
|
chopstx_t ccid_thd;
|
||||||
|
int wait_for_ack = 0;
|
||||||
|
|
||||||
chopstx_conf_idle (1);
|
chopstx_conf_idle (1);
|
||||||
|
|
||||||
@@ -301,6 +377,34 @@ main (int argc, const char *argv[])
|
|||||||
else
|
else
|
||||||
flash_image_path = argv[1];
|
flash_image_path = argv[1];
|
||||||
|
|
||||||
|
if (access (flash_image_path, F_OK) < 0)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[8192];
|
||||||
|
|
||||||
|
memset (buf, 0xff, sizeof buf);
|
||||||
|
memset (buf+4*1024, 0, 2);
|
||||||
|
fd = open (flash_image_path, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
perror ("creating flash file");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write (fd, buf, sizeof buf) != sizeof buf)
|
||||||
|
{
|
||||||
|
perror ("initializing flash file");
|
||||||
|
close (fd);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
puts ("Gnuk (emulation with USBIP), a GnuPG USB Token implementation");
|
||||||
|
puts ("Copyright (C) 2021 Free Software Initiative of Japan");
|
||||||
|
puts ("This is free software under GPLv3+.");
|
||||||
|
|
||||||
flash_addr = flash_init (flash_image_path);
|
flash_addr = flash_init (flash_image_path);
|
||||||
flash_addr_key_storage_start = (uint8_t *)flash_addr;
|
flash_addr_key_storage_start = (uint8_t *)flash_addr;
|
||||||
flash_addr_data_storage_start = (uint8_t *)flash_addr + 4096;
|
flash_addr_data_storage_start = (uint8_t *)flash_addr + 4096;
|
||||||
@@ -354,7 +458,11 @@ main (int argc, const char *argv[])
|
|||||||
{
|
{
|
||||||
eventmask_t m;
|
eventmask_t m;
|
||||||
|
|
||||||
|
if (wait_for_ack)
|
||||||
|
m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL);
|
||||||
|
else
|
||||||
m = eventflag_wait (&led_event);
|
m = eventflag_wait (&led_event);
|
||||||
|
|
||||||
switch (m)
|
switch (m)
|
||||||
{
|
{
|
||||||
case LED_ONESHOT:
|
case LED_ONESHOT:
|
||||||
@@ -375,8 +483,11 @@ main (int argc, const char *argv[])
|
|||||||
break;
|
break;
|
||||||
case LED_GNUK_EXEC:
|
case LED_GNUK_EXEC:
|
||||||
goto exec;
|
goto exec;
|
||||||
|
case LED_WAIT_FOR_BUTTON:
|
||||||
|
wait_for_ack ^= 1;
|
||||||
|
/* fall through */
|
||||||
default:
|
default:
|
||||||
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_ZERO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,26 +506,10 @@ main (int argc, const char *argv[])
|
|||||||
SCB->VTOR = (uintptr_t)&_regnual_start;
|
SCB->VTOR = (uintptr_t)&_regnual_start;
|
||||||
entry = calculate_regnual_entry_address (&_regnual_start);
|
entry = calculate_regnual_entry_address (&_regnual_start);
|
||||||
#ifdef DFU_SUPPORT
|
#ifdef DFU_SUPPORT
|
||||||
#define FLASH_SYS_START_ADDR 0x08000000
|
|
||||||
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
|
|
||||||
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
|
|
||||||
{
|
{
|
||||||
extern uint8_t _sys;
|
/* Use SYS at ORIGIN_REAL instead of the one at ORIGIN */
|
||||||
uintptr_t addr;
|
handler *new_vector = (handler *)ORIGIN_REAL;
|
||||||
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
|
|
||||||
void (*func) (void (*)(void)) = (void (*)(void (*)(void))) new_vector[9];
|
void (*func) (void (*)(void)) = (void (*)(void (*)(void))) new_vector[9];
|
||||||
uint32_t flash_page_size = 1024; /* 1KiB default */
|
|
||||||
|
|
||||||
if ((*CHIP_ID_REG)&0x07 == 0x04) /* High dencity device. */
|
|
||||||
flash_page_size = 2048; /* It's 2KiB. */
|
|
||||||
|
|
||||||
/* Kill DFU */
|
|
||||||
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
|
|
||||||
addr += flash_page_size)
|
|
||||||
flash_erase_page (addr);
|
|
||||||
|
|
||||||
/* copy system service routines */
|
|
||||||
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
|
|
||||||
|
|
||||||
/* Leave Gnuk to exec reGNUal */
|
/* Leave Gnuk to exec reGNUal */
|
||||||
(*func) ((void (*)(void))entry);
|
(*func) ((void (*)(void))entry);
|
||||||
@@ -501,11 +596,11 @@ gnuk_malloc_init (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
sbrk (size_t size)
|
gnuk_sbrk (intptr_t size)
|
||||||
{
|
{
|
||||||
void *p = (void *)heap_p;
|
void *p = (void *)heap_p;
|
||||||
|
|
||||||
if ((size_t)(HEAP_END - heap_p) < size)
|
if ((HEAP_END - heap_p) < size)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
heap_p += size;
|
heap_p += size;
|
||||||
@@ -541,7 +636,7 @@ gnuk_malloc (size_t size)
|
|||||||
{
|
{
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
{
|
{
|
||||||
m = (struct mem_head *)sbrk (size);
|
m = (struct mem_head *)gnuk_sbrk (size);
|
||||||
if (m)
|
if (m)
|
||||||
m->size = size;
|
m->size = size;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* modp256k1.c -- modulo arithmetic for p256k1
|
* modp256k1.c -- modulo arithmetic for p256k1
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014, 2016 Free Software Initiative of Japan
|
* Copyright (C) 2014, 2016, 2020 Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -71,14 +71,12 @@ modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B)
|
|||||||
{
|
{
|
||||||
uint32_t cond;
|
uint32_t cond;
|
||||||
bn256 tmp[1];
|
bn256 tmp[1];
|
||||||
|
bn256 dummy[1];
|
||||||
|
|
||||||
cond = (bn256_add (X, A, B) == 0);
|
cond = (bn256_add (X, A, B) == 0);
|
||||||
cond &= bn256_sub (tmp, X, P256K1);
|
cond &= bn256_sub (tmp, X, P256K1);
|
||||||
if (cond)
|
memcpy (cond?dummy:X, tmp, sizeof (bn256));
|
||||||
/* No-carry AND borrow */
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
memcpy (tmp, tmp, sizeof (bn256));
|
|
||||||
else
|
|
||||||
memcpy (X, tmp, sizeof (bn256));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,13 +87,12 @@ modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B)
|
|||||||
{
|
{
|
||||||
uint32_t borrow;
|
uint32_t borrow;
|
||||||
bn256 tmp[1];
|
bn256 tmp[1];
|
||||||
|
bn256 dummy[1];
|
||||||
|
|
||||||
borrow = bn256_sub (X, A, B);
|
borrow = bn256_sub (X, A, B);
|
||||||
bn256_add (tmp, X, P256K1);
|
bn256_add (tmp, X, P256K1);
|
||||||
if (borrow)
|
memcpy (borrow?X:dummy, tmp, sizeof (bn256));
|
||||||
memcpy (X, tmp, sizeof (bn256));
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
else
|
|
||||||
memcpy (tmp, tmp, sizeof (bn256));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* modp256r1.c -- modulo arithmetic for p256r1
|
* modp256r1.c -- modulo arithmetic for p256r1
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011, 2013, 2014, 2016
|
* Copyright (C) 2011, 2013, 2014, 2016, 2020
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -66,14 +66,12 @@ modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B)
|
|||||||
{
|
{
|
||||||
uint32_t cond;
|
uint32_t cond;
|
||||||
bn256 tmp[1];
|
bn256 tmp[1];
|
||||||
|
bn256 dummy[1];
|
||||||
|
|
||||||
cond = (bn256_add (X, A, B) == 0);
|
cond = (bn256_add (X, A, B) == 0);
|
||||||
cond &= bn256_sub (tmp, X, P256R1);
|
cond &= bn256_sub (tmp, X, P256R1);
|
||||||
if (cond)
|
memcpy (cond?dummy:X, tmp, sizeof (bn256));
|
||||||
/* No-carry AND borrow */
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
memcpy (tmp, tmp, sizeof (bn256));
|
|
||||||
else
|
|
||||||
memcpy (X, tmp, sizeof (bn256));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,13 +82,12 @@ modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B)
|
|||||||
{
|
{
|
||||||
uint32_t borrow;
|
uint32_t borrow;
|
||||||
bn256 tmp[1];
|
bn256 tmp[1];
|
||||||
|
bn256 dummy[1];
|
||||||
|
|
||||||
borrow = bn256_sub (X, A, B);
|
borrow = bn256_sub (X, A, B);
|
||||||
bn256_add (tmp, X, P256R1);
|
bn256_add (tmp, X, P256R1);
|
||||||
if (borrow)
|
memcpy (borrow?X:dummy, tmp, sizeof (bn256));
|
||||||
memcpy (X, tmp, sizeof (bn256));
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
else
|
|
||||||
memcpy (tmp, tmp, sizeof (bn256));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,6 +97,7 @@ void
|
|||||||
modp256r1_reduce (bn256 *X, const bn512 *A)
|
modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||||
{
|
{
|
||||||
bn256 tmp[1], tmp0[1];
|
bn256 tmp[1], tmp0[1];
|
||||||
|
bn256 dummy[1];
|
||||||
uint32_t borrow;
|
uint32_t borrow;
|
||||||
|
|
||||||
#define S1 X
|
#define S1 X
|
||||||
@@ -121,10 +119,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
|||||||
S1->word[1] = A->word[1];
|
S1->word[1] = A->word[1];
|
||||||
S1->word[0] = A->word[0];
|
S1->word[0] = A->word[0];
|
||||||
borrow = bn256_sub (tmp0, S1, P256R1);
|
borrow = bn256_sub (tmp0, S1, P256R1);
|
||||||
if (borrow)
|
memcpy (borrow?dummy:S1, tmp0, sizeof (bn256));
|
||||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
else
|
|
||||||
memcpy (S1, tmp0, sizeof (bn256));
|
|
||||||
/* X = S1 */
|
/* X = S1 */
|
||||||
|
|
||||||
S2->word[7] = A->word[15];
|
S2->word[7] = A->word[15];
|
||||||
@@ -165,10 +161,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
|||||||
S5->word[1] = A->word[10];
|
S5->word[1] = A->word[10];
|
||||||
S5->word[0] = A->word[9];
|
S5->word[0] = A->word[9];
|
||||||
borrow = bn256_sub (tmp0, S5, P256R1);
|
borrow = bn256_sub (tmp0, S5, P256R1);
|
||||||
if (borrow)
|
memcpy (borrow?dummy:S5, tmp0, sizeof (bn256));
|
||||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
else
|
|
||||||
memcpy (S5, tmp0, sizeof (bn256));
|
|
||||||
/* X += S5 */
|
/* X += S5 */
|
||||||
modp256r1_add (X, X, S5);
|
modp256r1_add (X, X, S5);
|
||||||
|
|
||||||
@@ -179,10 +173,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
|||||||
S6->word[1] = A->word[12];
|
S6->word[1] = A->word[12];
|
||||||
S6->word[0] = A->word[11];
|
S6->word[0] = A->word[11];
|
||||||
borrow = bn256_sub (tmp0, S6, P256R1);
|
borrow = bn256_sub (tmp0, S6, P256R1);
|
||||||
if (borrow)
|
memcpy (borrow?dummy:S6, tmp0, sizeof (bn256));
|
||||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
else
|
|
||||||
memcpy (S6, tmp0, sizeof (bn256));
|
|
||||||
/* X -= S6 */
|
/* X -= S6 */
|
||||||
modp256r1_sub (X, X, S6);
|
modp256r1_sub (X, X, S6);
|
||||||
|
|
||||||
@@ -194,10 +186,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
|||||||
S7->word[1] = A->word[13];
|
S7->word[1] = A->word[13];
|
||||||
S7->word[0] = A->word[12];
|
S7->word[0] = A->word[12];
|
||||||
borrow = bn256_sub (tmp0, S7, P256R1);
|
borrow = bn256_sub (tmp0, S7, P256R1);
|
||||||
if (borrow)
|
memcpy (borrow?dummy:S7, tmp0, sizeof (bn256));
|
||||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||||
else
|
|
||||||
memcpy (S7, tmp0, sizeof (bn256));
|
|
||||||
/* X -= S7 */
|
/* X -= S7 */
|
||||||
modp256r1_sub (X, X, S7);
|
modp256r1_sub (X, X, S7);
|
||||||
|
|
||||||
|
|||||||
189
src/openpgp-do.c
189
src/openpgp-do.c
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
|
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
|
||||||
|
* 2020
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -135,6 +136,14 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
|
|||||||
0x01, 0x00,
|
0x01, 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
/* General Feature Management */
|
||||||
|
static const uint8_t feature_mngmnt[] __attribute__ ((aligned (1))) = {
|
||||||
|
3,
|
||||||
|
0x81, 0x01, 0x20,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Algorithm Attributes */
|
/* Algorithm Attributes */
|
||||||
#define OPENPGP_ALGO_RSA 0x01
|
#define OPENPGP_ALGO_RSA 0x01
|
||||||
#define OPENPGP_ALGO_ECDH 0x12
|
#define OPENPGP_ALGO_ECDH 0x12
|
||||||
@@ -458,6 +467,7 @@ static const struct do_table_entry *get_do_entry (uint16_t tag);
|
|||||||
#define GPG_DO_UIF_DEC 0x00d7
|
#define GPG_DO_UIF_DEC 0x00d7
|
||||||
#define GPG_DO_UIF_AUT 0x00d8
|
#define GPG_DO_UIF_AUT 0x00d8
|
||||||
#define GPG_DO_KDF 0x00f9
|
#define GPG_DO_KDF 0x00f9
|
||||||
|
#define GPG_DO_ALG_INFO 0x00fa
|
||||||
#define GPG_DO_KEY_IMPORT 0x3fff
|
#define GPG_DO_KEY_IMPORT 0x3fff
|
||||||
#define GPG_DO_LANGUAGE 0x5f2d
|
#define GPG_DO_LANGUAGE 0x5f2d
|
||||||
#define GPG_DO_SEX 0x5f35
|
#define GPG_DO_SEX 0x5f35
|
||||||
@@ -524,7 +534,7 @@ copy_tag (uint16_t tag)
|
|||||||
#define SIZE_FP 20
|
#define SIZE_FP 20
|
||||||
#define SIZE_KGTIME 4
|
#define SIZE_KGTIME 4
|
||||||
|
|
||||||
static int
|
static void
|
||||||
do_fp_all (uint16_t tag, int with_tag)
|
do_fp_all (uint16_t tag, int with_tag)
|
||||||
{
|
{
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
@@ -555,10 +565,9 @@ do_fp_all (uint16_t tag, int with_tag)
|
|||||||
else
|
else
|
||||||
memset (res_p, 0, SIZE_FP);
|
memset (res_p, 0, SIZE_FP);
|
||||||
res_p += SIZE_FP;
|
res_p += SIZE_FP;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
do_cafp_all (uint16_t tag, int with_tag)
|
do_cafp_all (uint16_t tag, int with_tag)
|
||||||
{
|
{
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
@@ -589,10 +598,9 @@ do_cafp_all (uint16_t tag, int with_tag)
|
|||||||
else
|
else
|
||||||
memset (res_p, 0, SIZE_FP);
|
memset (res_p, 0, SIZE_FP);
|
||||||
res_p += SIZE_FP;
|
res_p += SIZE_FP;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
do_kgtime_all (uint16_t tag, int with_tag)
|
do_kgtime_all (uint16_t tag, int with_tag)
|
||||||
{
|
{
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
@@ -623,7 +631,6 @@ do_kgtime_all (uint16_t tag, int with_tag)
|
|||||||
else
|
else
|
||||||
memset (res_p, 0, SIZE_KGTIME);
|
memset (res_p, 0, SIZE_KGTIME);
|
||||||
res_p += SIZE_KGTIME;
|
res_p += SIZE_KGTIME;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t openpgpcard_aid[] = {
|
const uint8_t openpgpcard_aid[] = {
|
||||||
@@ -635,7 +642,7 @@ const uint8_t openpgpcard_aid[] = {
|
|||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static void
|
||||||
do_openpgpcard_aid (uint16_t tag, int with_tag)
|
do_openpgpcard_aid (uint16_t tag, int with_tag)
|
||||||
{
|
{
|
||||||
const volatile uint8_t *p = openpgpcard_aid;
|
const volatile uint8_t *p = openpgpcard_aid;
|
||||||
@@ -649,7 +656,7 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
|
|||||||
|
|
||||||
if (vid == 0xffff || vid == 0x0000)
|
if (vid == 0xffff || vid == 0x0000)
|
||||||
{
|
{
|
||||||
const uint8_t *u = unique_device_id () + 8;
|
const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
|
||||||
|
|
||||||
memcpy (res_p, openpgpcard_aid, 8);
|
memcpy (res_p, openpgpcard_aid, 8);
|
||||||
res_p += 8;
|
res_p += 8;
|
||||||
@@ -671,11 +678,9 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
|
|||||||
|
|
||||||
*res_p++ = 0;
|
*res_p++ = 0;
|
||||||
*res_p++ = 0;
|
*res_p++ = 0;
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
do_ds_count (uint16_t tag, int with_tag)
|
do_ds_count (uint16_t tag, int with_tag)
|
||||||
{
|
{
|
||||||
if (with_tag)
|
if (with_tag)
|
||||||
@@ -687,7 +692,37 @@ do_ds_count (uint16_t tag, int with_tag)
|
|||||||
*res_p++ = (digital_signature_counter >> 16) & 0xff;
|
*res_p++ = (digital_signature_counter >> 16) & 0xff;
|
||||||
*res_p++ = (digital_signature_counter >> 8) & 0xff;
|
*res_p++ = (digital_signature_counter >> 8) & 0xff;
|
||||||
*res_p++ = digital_signature_counter & 0xff;
|
*res_p++ = digital_signature_counter & 0xff;
|
||||||
return 1;
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_alg_info (uint16_t tag, int with_tag)
|
||||||
|
{
|
||||||
|
uint8_t *len_p = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (with_tag)
|
||||||
|
{
|
||||||
|
copy_tag (tag);
|
||||||
|
len_p = res_p;
|
||||||
|
*res_p++ = 0; /* Filled later, assuming length is <= 127 */
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
uint16_t tag_algo = GPG_DO_ALG_SIG + i;
|
||||||
|
|
||||||
|
copy_do_1 (tag_algo, algorithm_attr_rsa2k, 1);
|
||||||
|
copy_do_1 (tag_algo, algorithm_attr_rsa4k, 1);
|
||||||
|
copy_do_1 (tag_algo, algorithm_attr_p256r1, 1);
|
||||||
|
copy_do_1 (tag_algo, algorithm_attr_p256k1, 1);
|
||||||
|
if (i == 0 || i == 2)
|
||||||
|
copy_do_1 (tag_algo, algorithm_attr_ed25519, 1);
|
||||||
|
if (i == 1)
|
||||||
|
copy_do_1 (tag_algo, algorithm_attr_cv25519, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (len_p)
|
||||||
|
*len_p = res_p - len_p - 1; /* Actually, it's 127-byte long. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -807,6 +842,64 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t uif_flags; /* Six bits of flags */
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
int
|
||||||
|
gpg_do_get_uif (enum kind_of_key kk)
|
||||||
|
{
|
||||||
|
return ((uif_flags >> (kk * 2)) & 3) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rw_uif (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
|
||||||
|
{
|
||||||
|
uint8_t nr;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (tag != GPG_DO_UIF_SIG && tag != GPG_DO_UIF_DEC && tag != GPG_DO_UIF_AUT)
|
||||||
|
return 0; /* Failure */
|
||||||
|
|
||||||
|
nr = (tag - GPG_DO_UIF_SIG) + NR_DO_UIF_SIG;
|
||||||
|
v = (uif_flags >> ((tag - GPG_DO_UIF_SIG) * 2)) & 3;
|
||||||
|
if (is_write)
|
||||||
|
{
|
||||||
|
const uint8_t *p;
|
||||||
|
|
||||||
|
if (len != 2 || data[1] != 0x20)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (v == 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (data[0] != 0x00 && data[0] != 0x01 && data[0] != 0x02)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p = flash_enum_write (nr, data[0]);
|
||||||
|
if (p == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
|
||||||
|
uif_flags |= (data[0] & 3) << ((nr - NR_DO_UIF_SIG) * 2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (with_tag)
|
||||||
|
{
|
||||||
|
copy_tag (tag);
|
||||||
|
*res_p++ = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
*res_p++ = v;
|
||||||
|
*res_p++ = 0x20;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define SIZE_OF_KDF_DO_MIN 90
|
#define SIZE_OF_KDF_DO_MIN 90
|
||||||
#define SIZE_OF_KDF_DO_MAX 110
|
#define SIZE_OF_KDF_DO_MAX 110
|
||||||
#define OPENPGP_KDF_ITERSALTED_S2K 3
|
#define OPENPGP_KDF_ITERSALTED_S2K 3
|
||||||
@@ -893,11 +986,25 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check LEN is valid for HOW_MANY of passphrase string.
|
||||||
|
*
|
||||||
|
* HOW_MANY = 1: LEN is valid for a single passphrase string.
|
||||||
|
* HOW_MANY = 2: LEN is valid for two single passphrase strings.
|
||||||
|
* This is used to change passphrase.
|
||||||
|
* The second passphrase may be nothing.
|
||||||
|
*
|
||||||
|
* LEN = 0: Check if KDF-DO is available.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
gpg_do_kdf_check (int len, int how_many)
|
gpg_do_kdf_check (int len, int how_many)
|
||||||
{
|
{
|
||||||
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
|
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return kdf_do != NULL;
|
||||||
|
|
||||||
if (kdf_do)
|
if (kdf_do)
|
||||||
{
|
{
|
||||||
const uint8_t *kdf_spec = kdf_do+1;
|
const uint8_t *kdf_spec = kdf_do+1;
|
||||||
@@ -1505,6 +1612,13 @@ proc_key_import (const uint8_t *data, int len)
|
|||||||
const uint8_t *p = data;
|
const uint8_t *p = data;
|
||||||
uint8_t pubkey[512];
|
uint8_t pubkey[512];
|
||||||
|
|
||||||
|
#ifdef KDF_DO_REQUIRED
|
||||||
|
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
|
||||||
|
|
||||||
|
if (kdf_do == NULL)
|
||||||
|
return 0; /* Error. */
|
||||||
|
#endif
|
||||||
|
|
||||||
if (admin_authorized == BY_ADMIN)
|
if (admin_authorized == BY_ADMIN)
|
||||||
keystring_admin = keystring_md_pw3;
|
keystring_admin = keystring_md_pw3;
|
||||||
else
|
else
|
||||||
@@ -1614,18 +1728,32 @@ static const uint16_t cmp_ch_data[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t cmp_app_data[] = {
|
static const uint16_t cmp_app_data[] = {
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
4,
|
||||||
|
#else
|
||||||
3,
|
3,
|
||||||
|
#endif
|
||||||
GPG_DO_AID,
|
GPG_DO_AID,
|
||||||
GPG_DO_HIST_BYTES,
|
GPG_DO_HIST_BYTES,
|
||||||
GPG_DO_DISCRETIONARY,
|
GPG_DO_DISCRETIONARY,
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
GPG_DO_FEATURE_MNGMNT,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t cmp_discretionary[] = {
|
static const uint16_t cmp_discretionary[] = {
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
11,
|
||||||
|
#else
|
||||||
8,
|
8,
|
||||||
|
#endif
|
||||||
GPG_DO_EXTCAP,
|
GPG_DO_EXTCAP,
|
||||||
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
|
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
|
||||||
GPG_DO_PW_STATUS,
|
GPG_DO_PW_STATUS,
|
||||||
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL
|
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL,
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
|
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
|
||||||
@@ -1655,6 +1783,7 @@ gpg_do_table[] = {
|
|||||||
/* Pseudo DO READ: calculated, not changeable by user */
|
/* Pseudo DO READ: calculated, not changeable by user */
|
||||||
{ GPG_DO_DS_COUNT, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_ds_count },
|
{ GPG_DO_DS_COUNT, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_ds_count },
|
||||||
{ GPG_DO_AID, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_openpgpcard_aid },
|
{ GPG_DO_AID, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_openpgpcard_aid },
|
||||||
|
{ GPG_DO_ALG_INFO, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_alg_info },
|
||||||
/* Pseudo DO READ/WRITE: calculated */
|
/* Pseudo DO READ/WRITE: calculated */
|
||||||
{ GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
{ GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||||
rw_pw_status },
|
rw_pw_status },
|
||||||
@@ -1664,11 +1793,19 @@ gpg_do_table[] = {
|
|||||||
rw_algorithm_attr },
|
rw_algorithm_attr },
|
||||||
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||||
rw_algorithm_attr },
|
rw_algorithm_attr },
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
{ GPG_DO_UIF_SIG, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||||
|
{ GPG_DO_UIF_DEC, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||||
|
{ GPG_DO_UIF_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||||
|
#endif
|
||||||
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||||
rw_kdf },
|
rw_kdf },
|
||||||
/* Fixed data */
|
/* Fixed data */
|
||||||
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
|
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
|
||||||
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
|
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
{ GPG_DO_FEATURE_MNGMNT, DO_FIXED, AC_ALWAYS, AC_NEVER, feature_mngmnt },
|
||||||
|
#endif
|
||||||
/* Compound data: Read access only */
|
/* Compound data: Read access only */
|
||||||
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
|
{ 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_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
|
||||||
@@ -1707,6 +1844,11 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
|
|||||||
pw_err_counter_p[PW_ERR_PW3] = NULL;
|
pw_err_counter_p[PW_ERR_PW3] = NULL;
|
||||||
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
|
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
|
||||||
digital_signature_counter = 0;
|
digital_signature_counter = 0;
|
||||||
|
uif_flags = 0;
|
||||||
|
|
||||||
|
/* Clear all data objects. */
|
||||||
|
for (i = 0; i < NR_DO__LAST__; i++)
|
||||||
|
do_ptr[i] = NULL;
|
||||||
|
|
||||||
/* When the card is terminated no data objects are valid. */
|
/* When the card is terminated no data objects are valid. */
|
||||||
if (do_start == NULL)
|
if (do_start == NULL)
|
||||||
@@ -1765,6 +1907,13 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
|
|||||||
algo_attr_aut_p = p - 1;
|
algo_attr_aut_p = p - 1;
|
||||||
p++;
|
p++;
|
||||||
break;
|
break;
|
||||||
|
case NR_DO_UIF_SIG:
|
||||||
|
case NR_DO_UIF_DEC:
|
||||||
|
case NR_DO_UIF_AUT:
|
||||||
|
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
|
||||||
|
uif_flags |= (second_byte & 3) << ((nr - NR_DO_UIF_SIG) * 2);
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
case NR_COUNTER_123:
|
case NR_COUNTER_123:
|
||||||
p++;
|
p++;
|
||||||
if (second_byte <= PW_ERR_PW3)
|
if (second_byte <= PW_ERR_PW3)
|
||||||
@@ -1864,6 +2013,13 @@ gpg_data_copy (const uint8_t *p_start)
|
|||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
if ((v = (uif_flags >> (i * 2)) & 3))
|
||||||
|
{
|
||||||
|
flash_enum_write_internal (p, NR_DO_UIF_SIG + i, v);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
|
||||||
data_objects_number_of_bytes = 0;
|
data_objects_number_of_bytes = 0;
|
||||||
for (i = 0; i < NR_DO__LAST__; i++)
|
for (i = 0; i < NR_DO__LAST__; i++)
|
||||||
if (do_ptr[i] != NULL)
|
if (do_ptr[i] != NULL)
|
||||||
@@ -1977,9 +2133,10 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
|
|||||||
}
|
}
|
||||||
case DO_PROC_READ:
|
case DO_PROC_READ:
|
||||||
{
|
{
|
||||||
int (*do_func)(uint16_t, int) = (int (*)(uint16_t, int))do_p->obj;
|
void (*do_func)(uint16_t, int) = (void (*)(uint16_t, int))do_p->obj;
|
||||||
|
|
||||||
return do_func (do_p->tag, with_tag);
|
do_func (do_p->tag, with_tag);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
case DO_PROC_READWRITE:
|
case DO_PROC_READWRITE:
|
||||||
{
|
{
|
||||||
|
|||||||
118
src/openpgp.c
118
src/openpgp.c
@@ -2,6 +2,7 @@
|
|||||||
* openpgp.c -- OpenPGP card protocol support
|
* openpgp.c -- OpenPGP card protocol support
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||||
|
* 2019
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -145,7 +146,7 @@ get_pinpad_input (int msg_code)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_verify (void)
|
cmd_verify (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
uint8_t p1 = P1 (apdu);
|
uint8_t p1 = P1 (apdu);
|
||||||
@@ -153,6 +154,7 @@ cmd_verify (void)
|
|||||||
int r;
|
int r;
|
||||||
const uint8_t *pw;
|
const uint8_t *pw;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - VERIFY\r\n");
|
DEBUG_INFO (" - VERIFY\r\n");
|
||||||
DEBUG_BYTE (p2);
|
DEBUG_BYTE (p2);
|
||||||
|
|
||||||
@@ -275,7 +277,7 @@ gpg_change_keystring (int who_old, const uint8_t *old_ks,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_change_password (void)
|
cmd_change_password (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
uint8_t old_ks[KEYSTRING_MD_SIZE];
|
uint8_t old_ks[KEYSTRING_MD_SIZE];
|
||||||
uint8_t new_ks0[KEYSTRING_SIZE];
|
uint8_t new_ks0[KEYSTRING_SIZE];
|
||||||
@@ -295,6 +297,7 @@ cmd_change_password (void)
|
|||||||
int salt_len;
|
int salt_len;
|
||||||
const uint8_t *ks_pw3;
|
const uint8_t *ks_pw3;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO ("Change PW\r\n");
|
DEBUG_INFO ("Change PW\r\n");
|
||||||
DEBUG_BYTE (who);
|
DEBUG_BYTE (who);
|
||||||
|
|
||||||
@@ -547,7 +550,7 @@ s2k (const unsigned char *salt, size_t slen,
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_reset_user_password (void)
|
cmd_reset_user_password (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
uint8_t p1 = P1 (apdu);
|
uint8_t p1 = P1 (apdu);
|
||||||
int len;
|
int len;
|
||||||
@@ -558,9 +561,11 @@ cmd_reset_user_password (void)
|
|||||||
uint8_t new_ks0[KEYSTRING_SIZE];
|
uint8_t new_ks0[KEYSTRING_SIZE];
|
||||||
uint8_t *new_ks = KS_GET_KEYSTRING (new_ks0);
|
uint8_t *new_ks = KS_GET_KEYSTRING (new_ks0);
|
||||||
uint8_t *new_salt = KS_GET_SALT (new_ks0);
|
uint8_t *new_salt = KS_GET_SALT (new_ks0);
|
||||||
|
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
||||||
const uint8_t *salt;
|
const uint8_t *salt;
|
||||||
int salt_len;
|
int salt_len;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO ("Reset PW1\r\n");
|
DEBUG_INFO ("Reset PW1\r\n");
|
||||||
DEBUG_BYTE (p1);
|
DEBUG_BYTE (p1);
|
||||||
|
|
||||||
@@ -571,7 +576,6 @@ cmd_reset_user_password (void)
|
|||||||
{
|
{
|
||||||
const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
|
const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
|
||||||
uint8_t old_ks[KEYSTRING_MD_SIZE];
|
uint8_t old_ks[KEYSTRING_MD_SIZE];
|
||||||
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
|
||||||
|
|
||||||
if (gpg_do_kdf_check (len, 2) == 0)
|
if (gpg_do_kdf_check (len, 2) == 0)
|
||||||
{
|
{
|
||||||
@@ -661,6 +665,16 @@ cmd_reset_user_password (void)
|
|||||||
|
|
||||||
newpw_len = len;
|
newpw_len = len;
|
||||||
newpw = pw;
|
newpw = pw;
|
||||||
|
|
||||||
|
/* Check length of new password */
|
||||||
|
if ((ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|
||||||
|
|| newpw_len < USER_PASSWD_MINLEN)
|
||||||
|
{
|
||||||
|
DEBUG_INFO ("new password length is too short.");
|
||||||
|
GPG_CONDITION_NOT_SATISFIED ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
random_get_salt (new_salt);
|
random_get_salt (new_salt);
|
||||||
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
|
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
|
||||||
new_ks0[0] = newpw_len;
|
new_ks0[0] = newpw_len;
|
||||||
@@ -695,12 +709,13 @@ cmd_reset_user_password (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_put_data (void)
|
cmd_put_data (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
uint16_t tag;
|
uint16_t tag;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - PUT DATA\r\n");
|
DEBUG_INFO (" - PUT DATA\r\n");
|
||||||
|
|
||||||
tag = ((P1 (apdu)<<8) | P2 (apdu));
|
tag = ((P1 (apdu)<<8) | P2 (apdu));
|
||||||
@@ -710,8 +725,9 @@ cmd_put_data (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_pgp_gakp (void)
|
cmd_pgp_gakp (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
|
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
|
||||||
DEBUG_BYTE (P1 (apdu));
|
DEBUG_BYTE (P1 (apdu));
|
||||||
|
|
||||||
@@ -722,6 +738,12 @@ cmd_pgp_gakp (void)
|
|||||||
{
|
{
|
||||||
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
|
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
|
||||||
GPG_SECURITY_FAILURE ();
|
GPG_SECURITY_FAILURE ();
|
||||||
|
#ifdef KDF_DO_REQUIRED
|
||||||
|
else if (!gpg_do_kdf_check (0, 0))
|
||||||
|
GPG_CONDITION_NOT_SATISFIED ();
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
gpg_do_keygen (&apdu.cmd_apdu_data[0]);
|
||||||
gpg_do_keygen (&apdu.cmd_apdu_data[0]);
|
gpg_do_keygen (&apdu.cmd_apdu_data[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -730,10 +752,10 @@ cmd_pgp_gakp (void)
|
|||||||
const uint8_t *
|
const uint8_t *
|
||||||
gpg_get_firmware_update_key (uint8_t keyno)
|
gpg_get_firmware_update_key (uint8_t keyno)
|
||||||
{
|
{
|
||||||
extern uint8_t _updatekey_store;
|
extern uint8_t _updatekey_store[1024];
|
||||||
const uint8_t *p;
|
const uint8_t *p;
|
||||||
|
|
||||||
p = &_updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
|
p = _updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -745,12 +767,13 @@ gpg_get_firmware_update_key (uint8_t keyno)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_read_binary (void)
|
cmd_read_binary (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int is_short_EF = (P1 (apdu) & 0x80) != 0;
|
int is_short_EF = (P1 (apdu) & 0x80) != 0;
|
||||||
uint8_t file_id;
|
uint8_t file_id;
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - Read binary\r\n");
|
DEBUG_INFO (" - Read binary\r\n");
|
||||||
|
|
||||||
if (is_short_EF)
|
if (is_short_EF)
|
||||||
@@ -821,8 +844,9 @@ cmd_read_binary (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_select_file (void)
|
cmd_select_file (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
|
(void)ccid_comm;
|
||||||
if (P1 (apdu) == 4) /* Selection by DF name */
|
if (P1 (apdu) == 4) /* Selection by DF name */
|
||||||
{
|
{
|
||||||
DEBUG_INFO (" - select DF by name\r\n");
|
DEBUG_INFO (" - select DF by name\r\n");
|
||||||
@@ -891,10 +915,11 @@ cmd_select_file (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_get_data (void)
|
cmd_get_data (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
|
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - Get Data\r\n");
|
DEBUG_INFO (" - Get Data\r\n");
|
||||||
|
|
||||||
gpg_do_get_data (tag, 0);
|
gpg_do_get_data (tag, 0);
|
||||||
@@ -909,7 +934,7 @@ cmd_get_data (void)
|
|||||||
#define ECC_CIPHER_DO_HEADER_SIZE 7
|
#define ECC_CIPHER_DO_HEADER_SIZE 7
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_pso (void)
|
cmd_pso (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int len = apdu.cmd_apdu_data_len;
|
int len = apdu.cmd_apdu_data_len;
|
||||||
int r = -1;
|
int r = -1;
|
||||||
@@ -936,6 +961,11 @@ cmd_pso (void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING))
|
||||||
|
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
||||||
{
|
{
|
||||||
/* Check size of digestInfo */
|
/* Check size of digestInfo */
|
||||||
@@ -981,13 +1011,6 @@ cmd_pso (void)
|
|||||||
{
|
{
|
||||||
uint32_t output[64/4]; /* Require 4-byte alignment. */
|
uint32_t output[64/4]; /* Require 4-byte alignment. */
|
||||||
|
|
||||||
if (len > EDDSA_HASH_LEN_MAX)
|
|
||||||
{
|
|
||||||
DEBUG_INFO ("wrong hash length.");
|
|
||||||
GPG_CONDITION_NOT_SATISFIED ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cs = chopstx_setcancelstate (0);
|
cs = chopstx_setcancelstate (0);
|
||||||
result_len = EDDSA_SIGNATURE_LENGTH;
|
result_len = EDDSA_SIGNATURE_LENGTH;
|
||||||
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
|
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
|
||||||
@@ -1027,6 +1050,13 @@ cmd_pso (void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
if (gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION))
|
||||||
|
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||||
|
#else
|
||||||
|
(void)ccid_comm;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
||||||
{
|
{
|
||||||
/* Skip padding 0x00 */
|
/* Skip padding 0x00 */
|
||||||
@@ -1103,7 +1133,7 @@ cmd_pso (void)
|
|||||||
|
|
||||||
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
|
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
|
||||||
static void
|
static void
|
||||||
cmd_internal_authenticate (void)
|
cmd_internal_authenticate (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
|
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
|
||||||
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
|
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
|
||||||
@@ -1133,6 +1163,13 @@ cmd_internal_authenticate (void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
if (gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
|
||||||
|
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||||
|
#else
|
||||||
|
(void)ccid_comm;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
||||||
{
|
{
|
||||||
if (len > MAX_RSA_DIGEST_INFO_LEN)
|
if (len > MAX_RSA_DIGEST_INFO_LEN)
|
||||||
@@ -1180,13 +1217,6 @@ cmd_internal_authenticate (void)
|
|||||||
{
|
{
|
||||||
uint32_t output[64/4]; /* Require 4-byte alignment. */
|
uint32_t output[64/4]; /* Require 4-byte alignment. */
|
||||||
|
|
||||||
if (len > EDDSA_HASH_LEN_MAX)
|
|
||||||
{
|
|
||||||
DEBUG_INFO ("wrong hash length.");
|
|
||||||
GPG_CONDITION_NOT_SATISFIED ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cs = chopstx_setcancelstate (0);
|
cs = chopstx_setcancelstate (0);
|
||||||
result_len = EDDSA_SIGNATURE_LENGTH;
|
result_len = EDDSA_SIGNATURE_LENGTH;
|
||||||
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
|
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
|
||||||
@@ -1309,10 +1339,11 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
|
|||||||
|
|
||||||
#if defined(CERTDO_SUPPORT)
|
#if defined(CERTDO_SUPPORT)
|
||||||
static void
|
static void
|
||||||
cmd_update_binary (void)
|
cmd_update_binary (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int len = apdu.cmd_apdu_data_len;
|
int len = apdu.cmd_apdu_data_len;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - UPDATE BINARY\r\n");
|
DEBUG_INFO (" - UPDATE BINARY\r\n");
|
||||||
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
|
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
|
||||||
DEBUG_INFO ("UPDATE BINARY done.\r\n");
|
DEBUG_INFO ("UPDATE BINARY done.\r\n");
|
||||||
@@ -1321,10 +1352,11 @@ cmd_update_binary (void)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_write_binary (void)
|
cmd_write_binary (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int len = apdu.cmd_apdu_data_len;
|
int len = apdu.cmd_apdu_data_len;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - WRITE BINARY\r\n");
|
DEBUG_INFO (" - WRITE BINARY\r\n");
|
||||||
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
|
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
|
||||||
DEBUG_INFO ("WRITE BINARY done.\r\n");
|
DEBUG_INFO ("WRITE BINARY done.\r\n");
|
||||||
@@ -1333,7 +1365,7 @@ cmd_write_binary (void)
|
|||||||
|
|
||||||
#ifdef FLASH_UPGRADE_SUPPORT
|
#ifdef FLASH_UPGRADE_SUPPORT
|
||||||
static void
|
static void
|
||||||
cmd_external_authenticate (void)
|
cmd_external_authenticate (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
const uint8_t *pubkey;
|
const uint8_t *pubkey;
|
||||||
const uint8_t *signature = apdu.cmd_apdu_data;
|
const uint8_t *signature = apdu.cmd_apdu_data;
|
||||||
@@ -1341,6 +1373,7 @@ cmd_external_authenticate (void)
|
|||||||
uint8_t keyno = P2 (apdu);
|
uint8_t keyno = P2 (apdu);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
|
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
|
||||||
|
|
||||||
if (keyno >= 4)
|
if (keyno >= 4)
|
||||||
@@ -1376,10 +1409,11 @@ cmd_external_authenticate (void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_get_challenge (void)
|
cmd_get_challenge (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int len = apdu.expected_res_size;
|
int len = apdu.expected_res_size;
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
DEBUG_INFO (" - GET CHALLENGE\r\n");
|
DEBUG_INFO (" - GET CHALLENGE\r\n");
|
||||||
|
|
||||||
if (len > CHALLENGE_LEN)
|
if (len > CHALLENGE_LEN)
|
||||||
@@ -1394,6 +1428,13 @@ cmd_get_challenge (void)
|
|||||||
if (challenge)
|
if (challenge)
|
||||||
random_bytes_free (challenge);
|
random_bytes_free (challenge);
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING)
|
||||||
|
|| gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION)
|
||||||
|
|| gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
|
||||||
|
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||||
|
#endif
|
||||||
|
|
||||||
challenge = random_bytes_get ();
|
challenge = random_bytes_get ();
|
||||||
memcpy (res_APDU, challenge, len);
|
memcpy (res_APDU, challenge, len);
|
||||||
res_APDU_size = len;
|
res_APDU_size = len;
|
||||||
@@ -1404,8 +1445,9 @@ cmd_get_challenge (void)
|
|||||||
|
|
||||||
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
|
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
|
||||||
static void
|
static void
|
||||||
cmd_activate_file (void)
|
cmd_activate_file (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
|
(void)ccid_comm;
|
||||||
if (file_selection != FILE_CARD_TERMINATED)
|
if (file_selection != FILE_CARD_TERMINATED)
|
||||||
{
|
{
|
||||||
GPG_NO_RECORD ();
|
GPG_NO_RECORD ();
|
||||||
@@ -1418,13 +1460,13 @@ cmd_activate_file (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_terminate_df (void)
|
cmd_terminate_df (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
const uint8_t *ks_pw3;
|
const uint8_t *ks_pw3;
|
||||||
|
|
||||||
uint8_t p1 = P1 (apdu);
|
uint8_t p1 = P1 (apdu);
|
||||||
uint8_t p2 = P2 (apdu);
|
uint8_t p2 = P2 (apdu);
|
||||||
|
|
||||||
|
(void)ccid_comm;
|
||||||
if (file_selection != FILE_DF_OPENPGP)
|
if (file_selection != FILE_DF_OPENPGP)
|
||||||
{
|
{
|
||||||
GPG_NO_RECORD ();
|
GPG_NO_RECORD ();
|
||||||
@@ -1468,7 +1510,7 @@ cmd_terminate_df (void)
|
|||||||
struct command
|
struct command
|
||||||
{
|
{
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
void (*cmd_handler) (void);
|
void (*cmd_handler) (struct eventflag *ccid_comm);
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct command cmds[] = {
|
const struct command cmds[] = {
|
||||||
@@ -1502,7 +1544,7 @@ const struct command cmds[] = {
|
|||||||
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
|
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_command_apdu (void)
|
process_command_apdu (struct eventflag *ccid_comm)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t cmd = INS (apdu);
|
uint8_t cmd = INS (apdu);
|
||||||
@@ -1526,7 +1568,7 @@ process_command_apdu (void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
chopstx_setcancelstate (1);
|
chopstx_setcancelstate (1);
|
||||||
cmds[i].cmd_handler ();
|
cmds[i].cmd_handler (ccid_comm);
|
||||||
chopstx_setcancelstate (0);
|
chopstx_setcancelstate (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1640,7 +1682,7 @@ openpgp_card_thread (void *arg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
led_blink (LED_START_COMMAND);
|
led_blink (LED_START_COMMAND);
|
||||||
process_command_apdu ();
|
process_command_apdu (ccid_comm);
|
||||||
led_blink (LED_FINISH_COMMAND);
|
led_blink (LED_FINISH_COMMAND);
|
||||||
done:
|
done:
|
||||||
eventflag_signal (ccid_comm, EV_EXEC_FINISHED);
|
eventflag_signal (ccid_comm, EV_EXEC_FINISHED);
|
||||||
|
|||||||
@@ -986,6 +986,7 @@ tim_main (void *arg)
|
|||||||
{
|
{
|
||||||
chopstx_intr_wait (&interrupt);
|
chopstx_intr_wait (&interrupt);
|
||||||
cir_timer_interrupt ();
|
cir_timer_interrupt ();
|
||||||
|
chopstx_intr_done (&interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1006,6 +1007,7 @@ ext_main (void *arg)
|
|||||||
{
|
{
|
||||||
chopstx_intr_wait (&interrupt);
|
chopstx_intr_wait (&interrupt);
|
||||||
cir_ext_interrupt ();
|
cir_ext_interrupt ();
|
||||||
|
chopstx_intr_done (&interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#define SIZE_2 4096
|
#define SIZE_2 4096
|
||||||
#define SIZE_3 (5 * 4096)
|
#define SIZE_3 (5 * 4096)
|
||||||
#else
|
#else
|
||||||
#define SIZE_0 0x0150 /* Main */
|
#define SIZE_0 0x0160 /* Main */
|
||||||
#define SIZE_1 0x01a0 /* CCID */
|
#define SIZE_1 0x01a0 /* CCID */
|
||||||
#define SIZE_2 0x0180 /* RNG */
|
#define SIZE_2 0x0180 /* RNG */
|
||||||
#if MEMORY_SIZE >= 32
|
#if MEMORY_SIZE >= 32
|
||||||
|
|||||||
39
src/stdaln-sys.ld.in
Normal file
39
src/stdaln-sys.ld.in
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* ST32F103 memory setup.
|
||||||
|
*/
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
flash0 : org = @ORIGIN_REAL@, len = 4k
|
||||||
|
ram : org = 0x20000000, len = @MEMORY_SIZE@k
|
||||||
|
}
|
||||||
|
|
||||||
|
__ram_start__ = ORIGIN(ram);
|
||||||
|
__ram_size__ = LENGTH(ram);
|
||||||
|
__ram_end__ = __ram_start__ + __ram_size__;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0;
|
||||||
|
|
||||||
|
.sys : ALIGN(4) SUBALIGN(4)
|
||||||
|
{
|
||||||
|
_sys = .;
|
||||||
|
KEEP(*(.vectors))
|
||||||
|
. = ALIGN(16);
|
||||||
|
KEEP(*(.sys.version))
|
||||||
|
KEEP(*(.sys.board_id))
|
||||||
|
KEEP(*(.sys.board_name))
|
||||||
|
build/sys-*.o(.text)
|
||||||
|
build/sys-*.o(.text.*)
|
||||||
|
build/sys-*.o(.rodata)
|
||||||
|
build/sys-*.o(.rodata.*)
|
||||||
|
. = ALIGN(1024);
|
||||||
|
} > flash0
|
||||||
|
|
||||||
|
.aesft : ALIGN(4) SUBALIGN(4)
|
||||||
|
{
|
||||||
|
*(.sys.0)
|
||||||
|
*(.sys.1)
|
||||||
|
*(.sys.2)
|
||||||
|
} > flash0
|
||||||
|
}
|
||||||
164
src/usb-ccid.c
164
src/usb-ccid.c
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* usb-ccid.c -- USB CCID protocol handling
|
* usb-ccid.c -- USB CCID protocol handling
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
|
||||||
|
* 2019
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -29,6 +30,10 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
#include <contrib/ackbtn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include "usb-cdc.h"
|
#include "usb-cdc.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -182,9 +187,11 @@ struct ccid_header {
|
|||||||
|
|
||||||
/* Data structure handled by CCID layer */
|
/* Data structure handled by CCID layer */
|
||||||
struct ccid {
|
struct ccid {
|
||||||
enum ccid_state ccid_state;
|
uint32_t ccid_state : 4;
|
||||||
uint8_t state;
|
uint32_t state : 4;
|
||||||
uint8_t err;
|
uint32_t err : 1;
|
||||||
|
uint32_t tx_busy : 1;
|
||||||
|
uint32_t timeout_cnt: 3;
|
||||||
|
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -241,6 +248,7 @@ struct ccid {
|
|||||||
static void ccid_reset (struct ccid *c)
|
static void ccid_reset (struct ccid *c)
|
||||||
{
|
{
|
||||||
c->err = 0;
|
c->err = 0;
|
||||||
|
c->tx_busy = 0;
|
||||||
c->state = APDU_STATE_WAIT_COMMAND;
|
c->state = APDU_STATE_WAIT_COMMAND;
|
||||||
c->p = c->a->cmd_apdu_data;
|
c->p = c->a->cmd_apdu_data;
|
||||||
c->len = MAX_CMD_APDU_DATA_SIZE;
|
c->len = MAX_CMD_APDU_DATA_SIZE;
|
||||||
@@ -252,10 +260,11 @@ static void ccid_init (struct ccid *c, struct ep_in *epi, struct ep_out *epo,
|
|||||||
struct apdu *a)
|
struct apdu *a)
|
||||||
{
|
{
|
||||||
c->ccid_state = CCID_STATE_START;
|
c->ccid_state = CCID_STATE_START;
|
||||||
|
c->err = 0;
|
||||||
|
c->tx_busy = 0;
|
||||||
c->state = APDU_STATE_WAIT_COMMAND;
|
c->state = APDU_STATE_WAIT_COMMAND;
|
||||||
c->p = a->cmd_apdu_data;
|
c->p = a->cmd_apdu_data;
|
||||||
c->len = MAX_CMD_APDU_DATA_SIZE;
|
c->len = MAX_CMD_APDU_DATA_SIZE;
|
||||||
c->err = 0;
|
|
||||||
memset (&c->ccid_header, 0, sizeof (struct ccid_header));
|
memset (&c->ccid_header, 0, sizeof (struct ccid_header));
|
||||||
c->sw1sw2[0] = 0x90;
|
c->sw1sw2[0] = 0x90;
|
||||||
c->sw1sw2[1] = 0x00;
|
c->sw1sw2[1] = 0x00;
|
||||||
@@ -765,6 +774,7 @@ usb_tx_done (uint8_t ep_num, uint16_t len)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ATR (Answer To Reset) string
|
* ATR (Answer To Reset) string
|
||||||
*
|
*
|
||||||
@@ -820,6 +830,7 @@ static void ccid_error (struct ccid *c, int offset)
|
|||||||
#else
|
#else
|
||||||
usb_lld_write (c->epi->ep_num, ccid_reply, CCID_MSG_HEADER_SIZE);
|
usb_lld_write (c->epi->ep_num, ccid_reply, CCID_MSG_HEADER_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
c->tx_busy = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void *openpgp_card_thread (void *arg);
|
extern void *openpgp_card_thread (void *arg);
|
||||||
@@ -893,7 +904,7 @@ ccid_power_on (struct ccid *c)
|
|||||||
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE + size_atr);
|
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE + size_atr);
|
||||||
#endif
|
#endif
|
||||||
DEBUG_INFO ("ON\r\n");
|
DEBUG_INFO ("ON\r\n");
|
||||||
|
c->tx_busy = 1;
|
||||||
return CCID_STATE_WAIT;
|
return CCID_STATE_WAIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -934,6 +945,7 @@ ccid_send_status (struct ccid *c)
|
|||||||
#ifdef DEBUG_MORE
|
#ifdef DEBUG_MORE
|
||||||
DEBUG_INFO ("St\r\n");
|
DEBUG_INFO ("St\r\n");
|
||||||
#endif
|
#endif
|
||||||
|
c->tx_busy = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum ccid_state
|
static enum ccid_state
|
||||||
@@ -949,6 +961,7 @@ ccid_power_off (struct ccid *c)
|
|||||||
c->ccid_state = CCID_STATE_START; /* This status change should be here */
|
c->ccid_state = CCID_STATE_START; /* This status change should be here */
|
||||||
ccid_send_status (c);
|
ccid_send_status (c);
|
||||||
DEBUG_INFO ("OFF\r\n");
|
DEBUG_INFO ("OFF\r\n");
|
||||||
|
c->tx_busy = 1;
|
||||||
return CCID_STATE_START;
|
return CCID_STATE_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -982,12 +995,16 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
|
|||||||
#endif
|
#endif
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
|
c->epi->buf = NULL;
|
||||||
|
c->epi->tx_done = 1;
|
||||||
|
|
||||||
#ifdef GNU_LINUX_EMULATION
|
#ifdef GNU_LINUX_EMULATION
|
||||||
usb_lld_tx_enable_buf (c->epi->ep_num, endp1_tx_buf,
|
usb_lld_tx_enable_buf (c->epi->ep_num, endp1_tx_buf,
|
||||||
CCID_MSG_HEADER_SIZE);
|
CCID_MSG_HEADER_SIZE);
|
||||||
#else
|
#else
|
||||||
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE);
|
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
c->tx_busy = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1065,6 +1082,7 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
|
|||||||
#ifdef DEBUG_MORE
|
#ifdef DEBUG_MORE
|
||||||
DEBUG_INFO ("DATA\r\n");
|
DEBUG_INFO ("DATA\r\n");
|
||||||
#endif
|
#endif
|
||||||
|
c->tx_busy = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1076,7 +1094,8 @@ ccid_send_data_block (struct ccid *c)
|
|||||||
static void
|
static void
|
||||||
ccid_send_data_block_time_extension (struct ccid *c)
|
ccid_send_data_block_time_extension (struct ccid *c)
|
||||||
{
|
{
|
||||||
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT, 1);
|
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT,
|
||||||
|
c->ccid_state == CCID_STATE_EXECUTE? 1: 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1115,6 +1134,7 @@ ccid_send_data_block_0x9000 (struct ccid *c)
|
|||||||
#ifdef DEBUG_MORE
|
#ifdef DEBUG_MORE
|
||||||
DEBUG_INFO ("DATA\r\n");
|
DEBUG_INFO ("DATA\r\n");
|
||||||
#endif
|
#endif
|
||||||
|
c->tx_busy = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1211,6 +1231,7 @@ ccid_send_data_block_gr (struct ccid *c, size_t chunk_len)
|
|||||||
#ifdef DEBUG_MORE
|
#ifdef DEBUG_MORE
|
||||||
DEBUG_INFO ("DATA\r\n");
|
DEBUG_INFO ("DATA\r\n");
|
||||||
#endif
|
#endif
|
||||||
|
c->tx_busy = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1259,6 +1280,7 @@ ccid_send_params (struct ccid *c)
|
|||||||
#ifdef DEBUG_MORE
|
#ifdef DEBUG_MORE
|
||||||
DEBUG_INFO ("PARAMS\r\n");
|
DEBUG_INFO ("PARAMS\r\n");
|
||||||
#endif
|
#endif
|
||||||
|
c->tx_busy = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1413,6 +1435,7 @@ ccid_handle_data (struct ccid *c)
|
|||||||
c->a->res_apdu_data_len = 0;
|
c->a->res_apdu_data_len = 0;
|
||||||
c->a->res_apdu_data = &c->p[5];
|
c->a->res_apdu_data = &c->p[5];
|
||||||
|
|
||||||
|
c->state = APDU_STATE_COMMAND_RECEIVED;
|
||||||
eventflag_signal (&c->openpgp_comm, EV_VERIFY_CMD_AVAILABLE);
|
eventflag_signal (&c->openpgp_comm, EV_VERIFY_CMD_AVAILABLE);
|
||||||
next_state = CCID_STATE_EXECUTE;
|
next_state = CCID_STATE_EXECUTE;
|
||||||
}
|
}
|
||||||
@@ -1447,6 +1470,7 @@ ccid_handle_data (struct ccid *c)
|
|||||||
c->a->res_apdu_data_len = 0;
|
c->a->res_apdu_data_len = 0;
|
||||||
c->a->res_apdu_data = &ccid_buffer[5];
|
c->a->res_apdu_data = &ccid_buffer[5];
|
||||||
|
|
||||||
|
c->state = APDU_STATE_COMMAND_RECEIVED;
|
||||||
eventflag_signal (&c->openpgp_comm, EV_MODIFY_CMD_AVAILABLE);
|
eventflag_signal (&c->openpgp_comm, EV_MODIFY_CMD_AVAILABLE);
|
||||||
next_state = CCID_STATE_EXECUTE;
|
next_state = CCID_STATE_EXECUTE;
|
||||||
}
|
}
|
||||||
@@ -1461,6 +1485,8 @@ ccid_handle_data (struct ccid *c)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CCID_STATE_EXECUTE:
|
case CCID_STATE_EXECUTE:
|
||||||
|
case CCID_STATE_ACK_REQUIRED_0:
|
||||||
|
case CCID_STATE_ACK_REQUIRED_1:
|
||||||
if (c->ccid_header.msg_type == CCID_POWER_OFF)
|
if (c->ccid_header.msg_type == CCID_POWER_OFF)
|
||||||
next_state = ccid_power_off (c);
|
next_state = ccid_power_off (c);
|
||||||
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
|
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
|
||||||
@@ -1489,6 +1515,8 @@ ccid_handle_timeout (struct ccid *c)
|
|||||||
switch (c->ccid_state)
|
switch (c->ccid_state)
|
||||||
{
|
{
|
||||||
case CCID_STATE_EXECUTE:
|
case CCID_STATE_EXECUTE:
|
||||||
|
case CCID_STATE_ACK_REQUIRED_0:
|
||||||
|
case CCID_STATE_ACK_REQUIRED_1:
|
||||||
ccid_send_data_block_time_extension (c);
|
ccid_send_data_block_time_extension (c);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1500,7 +1528,13 @@ ccid_handle_timeout (struct ccid *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct ccid ccid;
|
static struct ccid ccid;
|
||||||
enum ccid_state *const ccid_state_p = &ccid.ccid_state;
|
|
||||||
|
enum ccid_state
|
||||||
|
ccid_get_ccid_state (void)
|
||||||
|
{
|
||||||
|
return ccid.ccid_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ccid_card_change_signal (int how)
|
ccid_card_change_signal (int how)
|
||||||
@@ -1545,7 +1579,7 @@ ccid_notify_slot_change (struct ccid *c)
|
|||||||
#define USB_CCID_TIMEOUT (1950*1000)
|
#define USB_CCID_TIMEOUT (1950*1000)
|
||||||
|
|
||||||
#define GPG_THREAD_TERMINATED 0xffff
|
#define GPG_THREAD_TERMINATED 0xffff
|
||||||
|
#define GPG_ACK_TIMEOUT 0x6600
|
||||||
|
|
||||||
extern uint32_t bDeviceState;
|
extern uint32_t bDeviceState;
|
||||||
extern void usb_device_reset (struct usb_dev *dev);
|
extern void usb_device_reset (struct usb_dev *dev);
|
||||||
@@ -1561,6 +1595,10 @@ extern int usb_get_descriptor (struct usb_dev *dev);
|
|||||||
extern void random_init (void);
|
extern void random_init (void);
|
||||||
extern void random_fini (void);
|
extern void random_fini (void);
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
static chopstx_intr_t ack_intr;
|
||||||
|
#endif
|
||||||
|
static chopstx_intr_t usb_intr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return 0 for normal USB event
|
* Return 0 for normal USB event
|
||||||
@@ -1575,6 +1613,7 @@ usb_event_handle (struct usb_dev *dev)
|
|||||||
|
|
||||||
e = usb_lld_event_handler (dev);
|
e = usb_lld_event_handler (dev);
|
||||||
ep_num = USB_EVENT_ENDP (e);
|
ep_num = USB_EVENT_ENDP (e);
|
||||||
|
chopstx_intr_done (&usb_intr);
|
||||||
|
|
||||||
/* Transfer to endpoint (not control endpoint) */
|
/* Transfer to endpoint (not control endpoint) */
|
||||||
if (ep_num != 0)
|
if (ep_num != 0)
|
||||||
@@ -1674,11 +1713,13 @@ usb_event_handle (struct usb_dev *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static chopstx_intr_t interrupt;
|
|
||||||
static chopstx_poll_cond_t ccid_event_poll_desc;
|
static chopstx_poll_cond_t ccid_event_poll_desc;
|
||||||
static struct chx_poll_head *const ccid_poll[] = {
|
static struct chx_poll_head *const ccid_poll[] = {
|
||||||
(struct chx_poll_head *const)&interrupt,
|
(struct chx_poll_head *const)&usb_intr,
|
||||||
(struct chx_poll_head *const)&ccid_event_poll_desc
|
(struct chx_poll_head *const)&ccid_event_poll_desc,
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
(struct chx_poll_head *const)&ack_intr
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
|
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
|
||||||
|
|
||||||
@@ -1689,6 +1730,7 @@ ccid_thread (void *arg)
|
|||||||
struct usb_dev dev;
|
struct usb_dev dev;
|
||||||
struct ccid *c = &ccid;
|
struct ccid *c = &ccid;
|
||||||
uint32_t *timeout_p;
|
uint32_t *timeout_p;
|
||||||
|
int ackbtn_active = 0;
|
||||||
|
|
||||||
(void)arg;
|
(void)arg;
|
||||||
|
|
||||||
@@ -1696,9 +1738,12 @@ ccid_thread (void *arg)
|
|||||||
eventflag_init (&ccid.openpgp_comm);
|
eventflag_init (&ccid.openpgp_comm);
|
||||||
|
|
||||||
usb_lld_init (&dev, USB_INITIAL_FEATURE);
|
usb_lld_init (&dev, USB_INITIAL_FEATURE);
|
||||||
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
|
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||||
usb_event_handle (&dev); /* For old SYS < 3.0 */
|
usb_event_handle (&dev); /* For old SYS < 3.0 */
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
ackbtn_init (&ack_intr);
|
||||||
|
#endif
|
||||||
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
|
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
@@ -1707,6 +1752,13 @@ ccid_thread (void *arg)
|
|||||||
struct ep_out *epo = &endpoint_out;
|
struct ep_out *epo = &endpoint_out;
|
||||||
struct apdu *a = &apdu;
|
struct apdu *a = &apdu;
|
||||||
|
|
||||||
|
if (ackbtn_active)
|
||||||
|
{
|
||||||
|
ackbtn_active = 0;
|
||||||
|
ackbtn_disable ();
|
||||||
|
led_blink (LED_WAIT_FOR_BUTTON);
|
||||||
|
}
|
||||||
|
|
||||||
epi_init (epi, ENDP1, c);
|
epi_init (epi, ENDP1, c);
|
||||||
epo_init (epo, ENDP1, c);
|
epo_init (epo, ENDP1, c);
|
||||||
apdu_init (a);
|
apdu_init (a);
|
||||||
@@ -1724,14 +1776,21 @@ ccid_thread (void *arg)
|
|||||||
{
|
{
|
||||||
eventmask_t m;
|
eventmask_t m;
|
||||||
|
|
||||||
if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
|
if (!c->tx_busy && bDeviceState == USB_DEVICE_STATE_CONFIGURED)
|
||||||
timeout_p = &timeout;
|
timeout_p = &timeout;
|
||||||
else
|
else
|
||||||
timeout_p = NULL;
|
timeout_p = NULL;
|
||||||
|
|
||||||
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
|
eventflag_set_mask (&c->ccid_comm, c->tx_busy ? EV_TX_FINISHED : ~0);
|
||||||
|
|
||||||
if (interrupt.ready)
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
chopstx_poll (timeout_p, CCID_POLL_NUM - (c->tx_busy || !ackbtn_active),
|
||||||
|
ccid_poll);
|
||||||
|
#else
|
||||||
|
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (usb_intr.ready)
|
||||||
{
|
{
|
||||||
if (usb_event_handle (&dev) == 0)
|
if (usb_event_handle (&dev) == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -1751,7 +1810,26 @@ ccid_thread (void *arg)
|
|||||||
goto reset;
|
goto reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
if (!c->tx_busy && ack_intr.ready)
|
||||||
|
{
|
||||||
|
ackbtn_active = 0;
|
||||||
|
ackbtn_disable ();
|
||||||
|
led_blink (LED_WAIT_FOR_BUTTON);
|
||||||
|
chopstx_intr_done (&ack_intr);
|
||||||
|
if (c->ccid_state == CCID_STATE_ACK_REQUIRED_1)
|
||||||
|
goto exec_done;
|
||||||
|
|
||||||
|
c->ccid_state = CCID_STATE_EXECUTE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (timeout == 0)
|
||||||
|
{
|
||||||
timeout = USB_CCID_TIMEOUT;
|
timeout = USB_CCID_TIMEOUT;
|
||||||
|
c->timeout_cnt++;
|
||||||
|
}
|
||||||
m = eventflag_get (&c->ccid_comm);
|
m = eventflag_get (&c->ccid_comm);
|
||||||
|
|
||||||
if (m == EV_CARD_CHANGE)
|
if (m == EV_CARD_CHANGE)
|
||||||
@@ -1774,10 +1852,17 @@ ccid_thread (void *arg)
|
|||||||
ccid_notify_slot_change (c);
|
ccid_notify_slot_change (c);
|
||||||
}
|
}
|
||||||
else if (m == EV_RX_DATA_READY)
|
else if (m == EV_RX_DATA_READY)
|
||||||
|
{
|
||||||
c->ccid_state = ccid_handle_data (c);
|
c->ccid_state = ccid_handle_data (c);
|
||||||
|
timeout = 0;
|
||||||
|
c->timeout_cnt = 0;
|
||||||
|
}
|
||||||
else if (m == EV_EXEC_FINISHED)
|
else if (m == EV_EXEC_FINISHED)
|
||||||
if (c->ccid_state == CCID_STATE_EXECUTE)
|
if (c->ccid_state == CCID_STATE_EXECUTE)
|
||||||
{
|
{
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
exec_done:
|
||||||
|
#endif
|
||||||
if (c->a->sw == GPG_THREAD_TERMINATED)
|
if (c->a->sw == GPG_THREAD_TERMINATED)
|
||||||
{
|
{
|
||||||
c->sw1sw2[0] = 0x90;
|
c->sw1sw2[0] = 0x90;
|
||||||
@@ -1807,21 +1892,35 @@ ccid_thread (void *arg)
|
|||||||
c->ccid_state = CCID_STATE_WAIT;
|
c->ccid_state = CCID_STATE_WAIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
else if (c->ccid_state == CCID_STATE_ACK_REQUIRED_0)
|
||||||
|
c->ccid_state = CCID_STATE_ACK_REQUIRED_1;
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_INFO ("ERR07\r\n");
|
DEBUG_INFO ("ERR05\r\n");
|
||||||
}
|
}
|
||||||
|
#ifdef ACKBTN_SUPPORT
|
||||||
|
else if (m == EV_EXEC_ACK_REQUIRED)
|
||||||
|
if (c->ccid_state == CCID_STATE_EXECUTE)
|
||||||
|
{
|
||||||
|
ackbtn_enable ();
|
||||||
|
ackbtn_active = 1;
|
||||||
|
led_blink (LED_WAIT_FOR_BUTTON);
|
||||||
|
c->ccid_state = CCID_STATE_ACK_REQUIRED_0;
|
||||||
|
ccid_send_data_block_time_extension (c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG_INFO ("ERR06\r\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else if (m == EV_TX_FINISHED)
|
else if (m == EV_TX_FINISHED)
|
||||||
{
|
{
|
||||||
if (c->state == APDU_STATE_RESULT)
|
if (c->state == APDU_STATE_RESULT)
|
||||||
{
|
ccid_reset (c);
|
||||||
c->state = APDU_STATE_WAIT_COMMAND;
|
else
|
||||||
c->p = c->a->cmd_apdu_data;
|
c->tx_busy = 0;
|
||||||
c->len = MAX_CMD_APDU_DATA_SIZE;
|
|
||||||
c->err = 0;
|
|
||||||
c->a->cmd_apdu_data_len = 0;
|
|
||||||
c->a->expected_res_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->state == APDU_STATE_WAIT_COMMAND
|
if (c->state == APDU_STATE_WAIT_COMMAND
|
||||||
|| c->state == APDU_STATE_COMMAND_CHAINING
|
|| c->state == APDU_STATE_COMMAND_CHAINING
|
||||||
@@ -1829,8 +1928,21 @@ ccid_thread (void *arg)
|
|||||||
ccid_prepare_receive (c);
|
ccid_prepare_receive (c);
|
||||||
}
|
}
|
||||||
else /* Timeout */
|
else /* Timeout */
|
||||||
|
{
|
||||||
|
if (c->timeout_cnt == 7
|
||||||
|
&& c->ccid_state == CCID_STATE_ACK_REQUIRED_1)
|
||||||
|
{
|
||||||
|
ackbtn_active = 0;
|
||||||
|
ackbtn_disable ();
|
||||||
|
led_blink (LED_WAIT_FOR_BUTTON);
|
||||||
|
c->a->sw = GPG_ACK_TIMEOUT;
|
||||||
|
c->a->res_apdu_data_len = 0;
|
||||||
|
goto exec_done;
|
||||||
|
}
|
||||||
|
else
|
||||||
c->ccid_state = ccid_handle_timeout (c);
|
c->ccid_state = ccid_handle_timeout (c);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c->application)
|
if (c->application)
|
||||||
{
|
{
|
||||||
@@ -1841,7 +1953,7 @@ ccid_thread (void *arg)
|
|||||||
/* Loading reGNUal. */
|
/* Loading reGNUal. */
|
||||||
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
|
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
|
||||||
{
|
{
|
||||||
chopstx_intr_wait (&interrupt);
|
chopstx_intr_wait (&usb_intr);
|
||||||
usb_event_handle (&dev);
|
usb_event_handle (&dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017
|
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -202,8 +202,6 @@ gnuk_setup_endpoints_for_interface (struct usb_dev *dev,
|
|||||||
void
|
void
|
||||||
usb_device_reset (struct usb_dev *dev)
|
usb_device_reset (struct usb_dev *dev)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
usb_lld_reset (dev, USB_INITIAL_FEATURE);
|
usb_lld_reset (dev, USB_INITIAL_FEATURE);
|
||||||
|
|
||||||
/* Initialize Endpoint 0 */
|
/* Initialize Endpoint 0 */
|
||||||
@@ -214,10 +212,6 @@ usb_device_reset (struct usb_dev *dev)
|
|||||||
64);
|
64);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Stop the interface */
|
|
||||||
for (i = 0; i < NUM_INTERFACES; i++)
|
|
||||||
gnuk_setup_endpoints_for_interface (dev, i, 1);
|
|
||||||
|
|
||||||
bDeviceState = USB_DEVICE_STATE_DEFAULT;
|
bDeviceState = USB_DEVICE_STATE_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +281,7 @@ usb_setup (struct usb_dev *dev)
|
|||||||
if (arg->request == USB_FSIJ_GNUK_DOWNLOAD)
|
if (arg->request == USB_FSIJ_GNUK_DOWNLOAD)
|
||||||
{
|
{
|
||||||
#ifdef FLASH_UPGRADE_SUPPORT
|
#ifdef FLASH_UPGRADE_SUPPORT
|
||||||
if (*ccid_state_p != CCID_STATE_EXITED)
|
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (addr < &_regnual_start || addr + arg->len > __heap_end__)
|
if (addr < &_regnual_start || addr + arg->len > __heap_end__)
|
||||||
@@ -305,7 +299,7 @@ usb_setup (struct usb_dev *dev)
|
|||||||
else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0)
|
else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0)
|
||||||
{
|
{
|
||||||
#ifdef FLASH_UPGRADE_SUPPORT
|
#ifdef FLASH_UPGRADE_SUPPORT
|
||||||
if (*ccid_state_p != CCID_STATE_EXITED)
|
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (((uintptr_t)addr & 0x03))
|
if (((uintptr_t)addr & 0x03))
|
||||||
@@ -410,7 +404,7 @@ usb_ctrl_write_finish (struct usb_dev *dev)
|
|||||||
{
|
{
|
||||||
if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC)
|
if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC)
|
||||||
{
|
{
|
||||||
if (*ccid_state_p != CCID_STATE_EXITED)
|
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Feature: setup pass phrase
|
|||||||
A token should support pass phrase: PW1, PW3 and reset code
|
A token should support pass phrase: PW1, PW3 and reset code
|
||||||
|
|
||||||
Scenario: setup PW1 (admin-full mode)
|
Scenario: setup PW1 (admin-full mode)
|
||||||
Given cmd_change_reference_data with 1 and "123456user pass phrase"
|
Given cmd_change_reference_data with 1 and "another user pass phraseuser pass phrase"
|
||||||
Then it should get success
|
Then it should get success
|
||||||
|
|
||||||
Scenario: verify PW1 (1)
|
Scenario: verify PW1 (1)
|
||||||
|
|||||||
@@ -70,11 +70,11 @@ def build_privkey_template_for_remove(openpgp_keyno):
|
|||||||
keyspec = b'\xb8'
|
keyspec = b'\xb8'
|
||||||
else:
|
else:
|
||||||
keyspec = b'\xa4'
|
keyspec = b'\xa4'
|
||||||
return b'\x4d\02' + keyspec + b'\0x00'
|
return b'\x4d\x02' + keyspec + b'\x00'
|
||||||
|
|
||||||
def compute_digestinfo(msg):
|
def compute_digestinfo(msg):
|
||||||
digest = sha256(msg).digest()
|
digest = sha256(msg).digest()
|
||||||
prefix = b'\x30\31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
|
prefix = b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
|
||||||
return prefix + digest
|
return prefix + digest
|
||||||
|
|
||||||
# egcd and modinv are from wikibooks
|
# egcd and modinv are from wikibooks
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
card_reader.py - a library for smartcard reader
|
card_reader.py - a library for smartcard reader
|
||||||
|
|
||||||
Copyright (C) 2016, 2017 Free Software Initiative of Japan
|
Copyright (C) 2016, 2017, 2019 Free Software Initiative of Japan
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -25,6 +25,7 @@ from struct import pack
|
|||||||
from usb.util import find_descriptor, claim_interface, get_string, \
|
from usb.util import find_descriptor, claim_interface, get_string, \
|
||||||
endpoint_type, endpoint_direction, \
|
endpoint_type, endpoint_direction, \
|
||||||
ENDPOINT_TYPE_BULK, ENDPOINT_OUT, ENDPOINT_IN
|
ENDPOINT_TYPE_BULK, ENDPOINT_OUT, ENDPOINT_IN
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
# USB class, subclass, protocol
|
# USB class, subclass, protocol
|
||||||
CCID_CLASS = 0x0B
|
CCID_CLASS = 0x0B
|
||||||
@@ -125,9 +126,12 @@ class CardReader(object):
|
|||||||
# intf.extra_descriptors[41]
|
# intf.extra_descriptors[41]
|
||||||
|
|
||||||
self.__dev = dev
|
self.__dev = dev
|
||||||
self.__timeout = 10000
|
self.__timeout = 100000
|
||||||
self.__seq = 0
|
self.__seq = 0
|
||||||
|
|
||||||
|
if self.ccid_get_status() & 0x03 not in (0, 1):
|
||||||
|
raise ValueError("Card absent")
|
||||||
|
|
||||||
def get_string(self, num):
|
def get_string(self, num):
|
||||||
return get_string(self.__dev, num)
|
return get_string(self.__dev, num)
|
||||||
|
|
||||||
@@ -168,7 +172,7 @@ class CardReader(object):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def ccid_power_on(self):
|
def ccid_power_on(self):
|
||||||
msg = ccid_compose(0x62, self.__seq, rsv=1) # Vcc=5V
|
msg = ccid_compose(0x62, self.__seq, rsv=2) # Vcc=3.3V
|
||||||
self.__dev.write(self.__bulkout, msg, self.__timeout)
|
self.__dev.write(self.__bulkout, msg, self.__timeout)
|
||||||
self.increment_seq()
|
self.increment_seq()
|
||||||
status, chain, data = self.ccid_get_result()
|
status, chain, data = self.ccid_get_result()
|
||||||
@@ -237,16 +241,21 @@ class CardReader(object):
|
|||||||
|
|
||||||
def send_tpdu(self, info=None, more=0, response_time_ext=0,
|
def send_tpdu(self, info=None, more=0, response_time_ext=0,
|
||||||
edc_error=0, no_error=0):
|
edc_error=0, no_error=0):
|
||||||
|
rsv = 0
|
||||||
if info:
|
if info:
|
||||||
data = compose_i_block(self.ns, info, more)
|
data = compose_i_block(self.ns, info, more)
|
||||||
elif response_time_ext:
|
elif response_time_ext:
|
||||||
# compose S-block
|
# compose S-block response
|
||||||
data = b"\x00\xE3\x00\xE3"
|
pcb = 0xe3
|
||||||
|
bwi_byte = bytes([response_time_ext])
|
||||||
|
edc = compute_edc(pcb, bwi_byte)
|
||||||
|
data = bytes([0, pcb, 1]) + bwi_byte + bytes([edc])
|
||||||
|
rsv = response_time_ext
|
||||||
elif edc_error:
|
elif edc_error:
|
||||||
data = compose_r_block(self.nr, edc_error=1)
|
data = compose_r_block(self.nr, edc_error=1)
|
||||||
elif no_error:
|
elif no_error:
|
||||||
data = compose_r_block(self.nr)
|
data = compose_r_block(self.nr)
|
||||||
msg = ccid_compose(0x6f, self.__seq, data=data)
|
msg = ccid_compose(0x6f, self.__seq, rsv=rsv, data=data)
|
||||||
self.__dev.write(self.__bulkout, msg, self.__timeout)
|
self.__dev.write(self.__bulkout, msg, self.__timeout)
|
||||||
self.increment_seq()
|
self.increment_seq()
|
||||||
|
|
||||||
@@ -277,7 +286,7 @@ class CardReader(object):
|
|||||||
res = b""
|
res = b""
|
||||||
while True:
|
while True:
|
||||||
if is_s_block_time_ext(blk):
|
if is_s_block_time_ext(blk):
|
||||||
self.send_tpdu(response_time_ext=1)
|
self.send_tpdu(response_time_ext=blk[3])
|
||||||
elif is_i_block_last(blk):
|
elif is_i_block_last(blk):
|
||||||
self.nr = self.nr ^ 1
|
self.nr = self.nr ^ 1
|
||||||
if is_edc_error(blk):
|
if is_edc_error(blk):
|
||||||
|
|||||||
36
tests/card_test_kdf_full.py
Normal file
36
tests/card_test_kdf_full.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
"""
|
||||||
|
card_test_kdf_full.py - test KDF data object
|
||||||
|
|
||||||
|
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from card_const import *
|
||||||
|
from constants_for_test import *
|
||||||
|
|
||||||
|
class Test_Card_KDF_full(object):
|
||||||
|
|
||||||
|
def test_verify_pw3(self, card):
|
||||||
|
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_kdf_put_full(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xf9, KDF_FULL)
|
||||||
|
if r:
|
||||||
|
card.configure_with_kdf()
|
||||||
|
assert r
|
||||||
35
tests/card_test_kdf_single.py
Normal file
35
tests/card_test_kdf_single.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
"""
|
||||||
|
card_test_kdf_single.py - test KDF data object
|
||||||
|
|
||||||
|
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from card_const import *
|
||||||
|
from constants_for_test import *
|
||||||
|
|
||||||
|
class Test_Card_KDF_Single(object):
|
||||||
|
def test_verify_pw3(self, card):
|
||||||
|
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_kdf_put_single(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xf9, KDF_SINGLE)
|
||||||
|
if r:
|
||||||
|
card.configure_with_kdf()
|
||||||
|
assert r
|
||||||
84
tests/card_test_keygen.py
Normal file
84
tests/card_test_keygen.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
"""
|
||||||
|
card_test_keygen.py - test key generation
|
||||||
|
|
||||||
|
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from binascii import hexlify
|
||||||
|
import rsa_keys
|
||||||
|
from card_const import *
|
||||||
|
|
||||||
|
class Test_Card_Keygen(object):
|
||||||
|
def test_keygen_1(self, card):
|
||||||
|
pk = card.cmd_genkey(1)
|
||||||
|
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||||
|
r = card.cmd_put_data(0x00, 0xc7, fpr_date[0])
|
||||||
|
if r:
|
||||||
|
r = card.cmd_put_data(0x00, 0xce, fpr_date[1])
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_keygen_2(self, card):
|
||||||
|
pk = card.cmd_genkey(2)
|
||||||
|
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||||
|
r = card.cmd_put_data(0x00, 0xc8, fpr_date[0])
|
||||||
|
if r:
|
||||||
|
r = card.cmd_put_data(0x00, 0xcf, fpr_date[1])
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_keygen_3(self, card):
|
||||||
|
pk = card.cmd_genkey(3)
|
||||||
|
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||||
|
r = card.cmd_put_data(0x00, 0xc9, fpr_date[0])
|
||||||
|
if r:
|
||||||
|
r = card.cmd_put_data(0x00, 0xd0, fpr_date[1])
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1(self, card):
|
||||||
|
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_signature_sigkey(self, card):
|
||||||
|
msg = b"Sign me please"
|
||||||
|
pk = card.cmd_get_public_key(1)
|
||||||
|
pk_info = (pk[9:9+256], pk[9+256+2:])
|
||||||
|
digest = rsa_keys.compute_digestinfo(msg)
|
||||||
|
sig = int(hexlify(card.cmd_pso(0x9e, 0x9a, digest)),16)
|
||||||
|
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_2(self, card):
|
||||||
|
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_decryption(self, card):
|
||||||
|
msg = b"encrypt me please"
|
||||||
|
pk = card.cmd_get_public_key(2)
|
||||||
|
pk_info = (pk[9:9+256], pk[9+256+2:])
|
||||||
|
ciphertext = rsa_keys.encrypt_with_pubkey(pk_info, msg)
|
||||||
|
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||||
|
assert r == msg
|
||||||
|
|
||||||
|
def test_signature_authkey(self, card):
|
||||||
|
msg = b"Sign me please to authenticate"
|
||||||
|
pk = card.cmd_get_public_key(3)
|
||||||
|
pk_info = (pk[9:9+256], pk[9+256+2:])
|
||||||
|
digest = rsa_keys.compute_digestinfo(msg)
|
||||||
|
sig = int(hexlify(card.cmd_internal_authenticate(digest)),16)
|
||||||
|
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
||||||
|
assert r
|
||||||
312
tests/card_test_personalize_admin_less.py
Normal file
312
tests/card_test_personalize_admin_less.py
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
"""
|
||||||
|
card_test_personalize_admin_less.py - test admin-less mode
|
||||||
|
|
||||||
|
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from struct import pack
|
||||||
|
from re import match, DOTALL
|
||||||
|
from util import *
|
||||||
|
import rsa_keys
|
||||||
|
from card_const import *
|
||||||
|
from constants_for_test import *
|
||||||
|
|
||||||
|
class Test_Card_Personalize_Adminless(object):
|
||||||
|
def test_verify_pw3_0(self, card):
|
||||||
|
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_rsa_import_key_1(self, card):
|
||||||
|
t = rsa_keys.build_privkey_template(1, 0)
|
||||||
|
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_rsa_import_key_2(self, card):
|
||||||
|
t = rsa_keys.build_privkey_template(2, 1)
|
||||||
|
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_rsa_import_key_3(self, card):
|
||||||
|
t = rsa_keys.build_privkey_template(3, 2)
|
||||||
|
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_fingerprint_1_put(self, card):
|
||||||
|
fpr1 = rsa_keys.fpr[0]
|
||||||
|
r = card.cmd_put_data(0x00, 0xc7, fpr1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_fingerprint_2_put(self, card):
|
||||||
|
fpr2 = rsa_keys.fpr[1]
|
||||||
|
r = card.cmd_put_data(0x00, 0xc8, fpr2)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_fingerprint_3_put(self, card):
|
||||||
|
fpr3 = rsa_keys.fpr[2]
|
||||||
|
r = card.cmd_put_data(0x00, 0xc9, fpr3)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_timestamp_1_put(self, card):
|
||||||
|
timestamp1 = rsa_keys.timestamp[0]
|
||||||
|
r = card.cmd_put_data(0x00, 0xce, timestamp1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_timestamp_2_put(self, card):
|
||||||
|
timestamp2 = rsa_keys.timestamp[1]
|
||||||
|
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_timestamp_3_put(self, card):
|
||||||
|
timestamp3 = rsa_keys.timestamp[2]
|
||||||
|
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_ds_counter_0(self, card):
|
||||||
|
c = get_data_object(card, 0x7a)
|
||||||
|
assert c == b'\x93\x03\x00\x00\x00'
|
||||||
|
|
||||||
|
def test_pw1_status(self, card):
|
||||||
|
s = get_data_object(card, 0xc4)
|
||||||
|
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||||
|
|
||||||
|
def test_app_data(self, card):
|
||||||
|
app_data = get_data_object(card, 0x6e)
|
||||||
|
hist_len = app_data[20]
|
||||||
|
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
|
||||||
|
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
|
||||||
|
app_data[18:18+2] == b"\x5f\x52"
|
||||||
|
|
||||||
|
def test_public_key_1(self, card):
|
||||||
|
pk = card.cmd_get_public_key(1)
|
||||||
|
assert rsa_keys.key[0][0] == pk[9:9+256]
|
||||||
|
|
||||||
|
def test_public_key_2(self, card):
|
||||||
|
pk = card.cmd_get_public_key(2)
|
||||||
|
assert rsa_keys.key[1][0] == pk[9:9+256]
|
||||||
|
|
||||||
|
def test_public_key_3(self, card):
|
||||||
|
pk = card.cmd_get_public_key(3)
|
||||||
|
assert rsa_keys.key[2][0] == pk[9:9+256]
|
||||||
|
|
||||||
|
# Changing PW1 to admin-less mode
|
||||||
|
|
||||||
|
def test_setup_pw1_0(self, card):
|
||||||
|
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
# Now, it's admin-less mode, auth-status admin cleared
|
||||||
|
|
||||||
|
def test_verify_pw3_fail_1(self, card):
|
||||||
|
try:
|
||||||
|
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||||
|
except ValueError as e:
|
||||||
|
v = False
|
||||||
|
assert not v
|
||||||
|
|
||||||
|
def test_verify_pw1_0(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST0)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_0_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST0)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw1_1(self, card):
|
||||||
|
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_1(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_1_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw3_admin_less_1(self, card):
|
||||||
|
v = card.verify(3, PW1_TEST1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_reset_code(self, card):
|
||||||
|
r = card.setup_reset_code(RESETCODE_TEST)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_reset_code(self, card):
|
||||||
|
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
# Changing PW1, auth status for admin cleared
|
||||||
|
def test_login_put_fail(self, card):
|
||||||
|
try:
|
||||||
|
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||||
|
except ValueError as e:
|
||||||
|
r = e.args[0]
|
||||||
|
assert r == "6982"
|
||||||
|
|
||||||
|
def test_verify_pw1_2(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST2)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_2_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST2)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw3_fail_2(self, card):
|
||||||
|
try:
|
||||||
|
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||||
|
except ValueError as e:
|
||||||
|
v = e.args[0]
|
||||||
|
assert v == "6982"
|
||||||
|
|
||||||
|
def test_sign_0(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||||
|
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||||
|
sig = rsa_keys.compute_signature(0, digestinfo)
|
||||||
|
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||||
|
assert r == sig_bytes
|
||||||
|
|
||||||
|
# Since forcesig setting, failed
|
||||||
|
def test_sign_1(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||||
|
try:
|
||||||
|
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||||
|
except ValueError as e:
|
||||||
|
r = e.args[0]
|
||||||
|
assert r == "6982"
|
||||||
|
|
||||||
|
def test_ds_counter_1(self, card):
|
||||||
|
c = get_data_object(card, 0x7a)
|
||||||
|
assert c == b'\x93\x03\x00\x00\x01'
|
||||||
|
|
||||||
|
def test_sign_auth_0(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||||
|
r = card.cmd_internal_authenticate(digestinfo)
|
||||||
|
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||||
|
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||||
|
assert r == sig_bytes
|
||||||
|
|
||||||
|
def test_sign_auth_1(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||||
|
r = card.cmd_internal_authenticate(digestinfo)
|
||||||
|
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||||
|
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||||
|
assert r == sig_bytes
|
||||||
|
|
||||||
|
def test_decrypt_0(self, card):
|
||||||
|
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
|
||||||
|
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||||
|
assert r == PLAIN_TEXT0
|
||||||
|
|
||||||
|
def test_decrypt_1(self, card):
|
||||||
|
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
|
||||||
|
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||||
|
assert r == PLAIN_TEXT1
|
||||||
|
|
||||||
|
def test_verify_pw3_admin_less_2(self, card):
|
||||||
|
v = card.verify(3, PW1_TEST2)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_login_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_name_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_lang_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_sex_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x35, b"1")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_url_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_pw1_status_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_login(self, card):
|
||||||
|
login = get_data_object(card, 0x5e)
|
||||||
|
assert login == b"gpg_user"
|
||||||
|
|
||||||
|
def test_name_lang_sex(self, card):
|
||||||
|
name = b"GnuPG User"
|
||||||
|
lang = b"ja"
|
||||||
|
sex = b"1"
|
||||||
|
expected = b'\x5b' + pack('B', len(name)) + name \
|
||||||
|
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
||||||
|
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||||
|
name_lang_sex = get_data_object(card, 0x65)
|
||||||
|
assert name_lang_sex == expected
|
||||||
|
|
||||||
|
def test_url(self, card):
|
||||||
|
url = get_data_object(card, 0x5f50)
|
||||||
|
assert url == b"https://www.fsij.org/gnuk/"
|
||||||
|
|
||||||
|
def test_pw1_status(self, card):
|
||||||
|
s = get_data_object(card, 0xc4)
|
||||||
|
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||||
|
|
||||||
|
# Setting PW3, changed to admin-full mode
|
||||||
|
|
||||||
|
def test_setup_pw3_1(self, card):
|
||||||
|
r = card.change_passwd(3, PW1_TEST2, PW3_TEST1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw3_1(self, card):
|
||||||
|
v = card.verify(3, PW3_TEST1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_reset_userpass_admin(self, card):
|
||||||
|
r = card.reset_passwd_by_admin(PW1_TEST3)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_3(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_3_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw1_4(self, card):
|
||||||
|
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_4(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST4)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_4_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST4)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw3_2(self, card):
|
||||||
|
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw3_2(self, card):
|
||||||
|
v = card.verify(3, PW3_TEST0)
|
||||||
|
assert v
|
||||||
|
|
||||||
277
tests/card_test_personalize_card.py
Normal file
277
tests/card_test_personalize_card.py
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
"""
|
||||||
|
card_test_personalize_card.py - test personalizing card
|
||||||
|
|
||||||
|
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from struct import pack
|
||||||
|
from re import match, DOTALL
|
||||||
|
from util import *
|
||||||
|
import rsa_keys
|
||||||
|
from card_const import *
|
||||||
|
from constants_for_test import *
|
||||||
|
|
||||||
|
class Test_Card_Personalize_Card(object):
|
||||||
|
def test_setup_pw3_0(self, card):
|
||||||
|
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, PW3_TEST0)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw3_0(self, card):
|
||||||
|
v = card.verify(3, PW3_TEST0)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_login_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_name_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_lang_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_sex_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x35, b"1")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_url_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_pw1_status_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_login(self, card):
|
||||||
|
login = get_data_object(card, 0x5e)
|
||||||
|
assert login == b"gpg_user"
|
||||||
|
|
||||||
|
def test_name_lang_sex(self, card):
|
||||||
|
name = b"GnuPG User"
|
||||||
|
lang = b"ja"
|
||||||
|
sex = b"1"
|
||||||
|
expected = b'\x5b' + pack('B', len(name)) + name \
|
||||||
|
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
||||||
|
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||||
|
name_lang_sex = get_data_object(card, 0x65)
|
||||||
|
assert name_lang_sex == expected
|
||||||
|
|
||||||
|
def test_url(self, card):
|
||||||
|
url = get_data_object(card, 0x5f50)
|
||||||
|
assert url == b"https://www.fsij.org/gnuk/"
|
||||||
|
|
||||||
|
def test_pw1_status(self, card):
|
||||||
|
s = get_data_object(card, 0xc4)
|
||||||
|
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||||
|
|
||||||
|
def test_rsa_import_key_1(self, card):
|
||||||
|
t = rsa_keys.build_privkey_template(1, 0)
|
||||||
|
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_rsa_import_key_2(self, card):
|
||||||
|
t = rsa_keys.build_privkey_template(2, 1)
|
||||||
|
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_rsa_import_key_3(self, card):
|
||||||
|
t = rsa_keys.build_privkey_template(3, 2)
|
||||||
|
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_fingerprint_1_put(self, card):
|
||||||
|
fpr1 = rsa_keys.fpr[0]
|
||||||
|
r = card.cmd_put_data(0x00, 0xc7, fpr1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_fingerprint_2_put(self, card):
|
||||||
|
fpr2 = rsa_keys.fpr[1]
|
||||||
|
r = card.cmd_put_data(0x00, 0xc8, fpr2)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_fingerprint_3_put(self, card):
|
||||||
|
fpr3 = rsa_keys.fpr[2]
|
||||||
|
r = card.cmd_put_data(0x00, 0xc9, fpr3)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_timestamp_1_put(self, card):
|
||||||
|
timestamp1 = rsa_keys.timestamp[0]
|
||||||
|
r = card.cmd_put_data(0x00, 0xce, timestamp1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_timestamp_2_put(self, card):
|
||||||
|
timestamp2 = rsa_keys.timestamp[1]
|
||||||
|
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_timestamp_3_put(self, card):
|
||||||
|
timestamp3 = rsa_keys.timestamp[2]
|
||||||
|
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_ds_counter_0(self, card):
|
||||||
|
c = get_data_object(card, 0x7a)
|
||||||
|
assert c == b'\x93\x03\x00\x00\x00'
|
||||||
|
|
||||||
|
def test_pw1_status(self, card):
|
||||||
|
s = get_data_object(card, 0xc4)
|
||||||
|
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||||
|
|
||||||
|
def test_app_data(self, card):
|
||||||
|
app_data = get_data_object(card, 0x6e)
|
||||||
|
hist_len = app_data[20]
|
||||||
|
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
|
||||||
|
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
|
||||||
|
app_data[18:18+2] == b"\x5f\x52"
|
||||||
|
|
||||||
|
def test_public_key_1(self, card):
|
||||||
|
pk = card.cmd_get_public_key(1)
|
||||||
|
assert rsa_keys.key[0][0] == pk[9:9+256]
|
||||||
|
|
||||||
|
def test_public_key_2(self, card):
|
||||||
|
pk = card.cmd_get_public_key(2)
|
||||||
|
assert rsa_keys.key[1][0] == pk[9:9+256]
|
||||||
|
|
||||||
|
def test_public_key_3(self, card):
|
||||||
|
pk = card.cmd_get_public_key(3)
|
||||||
|
assert rsa_keys.key[2][0] == pk[9:9+256]
|
||||||
|
|
||||||
|
def test_setup_pw1_0(self, card):
|
||||||
|
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_0(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST0)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_0_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST0)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw1_1(self, card):
|
||||||
|
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_1(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_1_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_reset_code(self, card):
|
||||||
|
r = card.setup_reset_code(RESETCODE_TEST)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_reset_code(self, card):
|
||||||
|
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_2(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST2)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_2_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST2)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw3_1(self, card):
|
||||||
|
r = card.change_passwd(3, PW3_TEST0, PW3_TEST1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw3_1(self, card):
|
||||||
|
v = card.verify(3, PW3_TEST1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_reset_userpass_admin(self, card):
|
||||||
|
r = card.reset_passwd_by_admin(PW1_TEST3)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_3(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_3_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw1_4(self, card):
|
||||||
|
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_4(self, card):
|
||||||
|
v = card.verify(1, PW1_TEST4)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_4_2(self, card):
|
||||||
|
v = card.verify(2, PW1_TEST4)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw3_2(self, card):
|
||||||
|
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw3_2(self, card):
|
||||||
|
v = card.verify(3, PW3_TEST0)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_sign_0(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||||
|
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||||
|
sig = rsa_keys.compute_signature(0, digestinfo)
|
||||||
|
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||||
|
assert r == sig_bytes
|
||||||
|
|
||||||
|
def test_sign_1(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||||
|
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||||
|
sig = rsa_keys.compute_signature(0, digestinfo)
|
||||||
|
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||||
|
assert r == sig_bytes
|
||||||
|
|
||||||
|
def test_ds_counter_1(self, card):
|
||||||
|
c = get_data_object(card, 0x7a)
|
||||||
|
assert c == b'\x93\x03\x00\x00\x02'
|
||||||
|
|
||||||
|
def test_sign_auth_0(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||||
|
r = card.cmd_internal_authenticate(digestinfo)
|
||||||
|
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||||
|
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||||
|
assert r == sig_bytes
|
||||||
|
|
||||||
|
def test_sign_auth_1(self, card):
|
||||||
|
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||||
|
r = card.cmd_internal_authenticate(digestinfo)
|
||||||
|
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||||
|
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||||
|
assert r == sig_bytes
|
||||||
|
|
||||||
|
def test_decrypt_0(self, card):
|
||||||
|
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
|
||||||
|
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||||
|
assert r == PLAIN_TEXT0
|
||||||
|
|
||||||
|
def test_decrypt_1(self, card):
|
||||||
|
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
|
||||||
|
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||||
|
assert r == PLAIN_TEXT1
|
||||||
82
tests/card_test_personalize_reset.py
Normal file
82
tests/card_test_personalize_reset.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
"""
|
||||||
|
card_test_personalize_reset.py - test resetting personalization of card
|
||||||
|
|
||||||
|
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from struct import pack
|
||||||
|
from re import match, DOTALL
|
||||||
|
from util import *
|
||||||
|
import rsa_keys
|
||||||
|
from card_const import *
|
||||||
|
from constants_for_test import *
|
||||||
|
|
||||||
|
class Test_Personalize_Reset(object):
|
||||||
|
def test_login_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0x5e, b"")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_name_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0x5b, b"")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_lang_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x2d, b"")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_sex_put(self, card):
|
||||||
|
try:
|
||||||
|
# Gnuk
|
||||||
|
r = card.cmd_put_data(0x5f, 0x35, b"")
|
||||||
|
except ValueError:
|
||||||
|
# OpenPGP card which doesn't allow b""
|
||||||
|
r = card.cmd_put_data(0x5f, 0x35, b"9")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_url_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x5f, 0x50, b"")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_pw1_status_put(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xc4, b"\x00")
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_setup_pw3_0(self, card):
|
||||||
|
r = card.change_passwd(3, PW3_TEST0, FACTORY_PASSPHRASE_PW3)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw3_0(self, card):
|
||||||
|
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_setup_pw1_0(self, card):
|
||||||
|
r = card.change_passwd(1, PW1_TEST4, FACTORY_PASSPHRASE_PW1)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_verify_pw1_0(self, card):
|
||||||
|
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_0_2(self, card):
|
||||||
|
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_delete_reset_code(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xd3, b"")
|
||||||
|
assert r
|
||||||
45
tests/card_test_remove_keys.py
Normal file
45
tests/card_test_remove_keys.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
card_test_remove_keys.py - test removing keys on card
|
||||||
|
|
||||||
|
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Remove a key material on card by changing algorithm attributes of the key
|
||||||
|
|
||||||
|
from card_const import *
|
||||||
|
|
||||||
|
class Test_Remove_Keys(object):
|
||||||
|
|
||||||
|
def test_rsa_keyattr_change_1(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
|
||||||
|
if r:
|
||||||
|
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_rsa_keyattr_change_2(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
|
||||||
|
if r:
|
||||||
|
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
def test_rsa_keyattr_change_3(self, card):
|
||||||
|
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
|
||||||
|
if r:
|
||||||
|
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)
|
||||||
|
assert r
|
||||||
46
tests/card_test_reset_pw3.py
Normal file
46
tests/card_test_reset_pw3.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
card_test_reset_pw3.py - test resetting pw3
|
||||||
|
|
||||||
|
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||||
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
|
||||||
|
Gnuk is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from card_const import *
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
class Test_Reset_PW3(object):
|
||||||
|
# Gnuk specific feature of clear PW3
|
||||||
|
def test_setup_pw3_null(self, card):
|
||||||
|
if card.is_gnuk:
|
||||||
|
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, None)
|
||||||
|
assert r
|
||||||
|
else:
|
||||||
|
pytest.skip("Gnuk only feature of clearing PW3")
|
||||||
|
|
||||||
|
def test_verify_pw3(self, card):
|
||||||
|
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
# Check PW1 again to see the possiblity of admin-less mode
|
||||||
|
def test_verify_pw1(self, card):
|
||||||
|
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
||||||
|
assert v
|
||||||
|
|
||||||
|
def test_verify_pw1_2(self, card):
|
||||||
|
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||||
|
assert v
|
||||||
@@ -16,3 +16,4 @@ def card():
|
|||||||
card.cmd_select_openpgp()
|
card.cmd_select_openpgp()
|
||||||
yield card
|
yield card
|
||||||
del card
|
del card
|
||||||
|
reader.ccid_power_off()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
openpgp_card.py - a library for OpenPGP card
|
openpgp_card.py - a library for OpenPGP card
|
||||||
|
|
||||||
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018
|
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018, 2019
|
||||||
Free Software Initiative of Japan
|
Free Software Initiative of Japan
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
@@ -59,6 +59,7 @@ class OpenPGP_Card(object):
|
|||||||
self.__kdf_salt_user = None
|
self.__kdf_salt_user = None
|
||||||
self.__kdf_salt_reset = None
|
self.__kdf_salt_reset = None
|
||||||
self.__kdf_salt_admin = None
|
self.__kdf_salt_admin = None
|
||||||
|
self.is_gnuk = (reader.get_string(2) == "Gnuk Token")
|
||||||
|
|
||||||
def configure_with_kdf(self):
|
def configure_with_kdf(self):
|
||||||
kdf_data = self.cmd_get_data(0x00, 0xf9)
|
kdf_data = self.cmd_get_data(0x00, 0xf9)
|
||||||
@@ -338,16 +339,20 @@ class OpenPGP_Card(object):
|
|||||||
data = b'\xb8\x00'
|
data = b'\xb8\x00'
|
||||||
else:
|
else:
|
||||||
data = b'\xa4\x00'
|
data = b'\xa4\x00'
|
||||||
|
if self.__reader.is_tpdu_reader():
|
||||||
|
cmd_data = iso7816_compose(0x47, 0x80, 0, data, le=512)
|
||||||
|
else:
|
||||||
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
|
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
|
||||||
sw = self.__reader.send_cmd(cmd_data)
|
sw = self.__reader.send_cmd(cmd_data)
|
||||||
if len(sw) != 2:
|
if len(sw) < 2:
|
||||||
raise ValueError(sw)
|
raise ValueError(sw)
|
||||||
if sw[0] == 0x90 and sw[1] == 0x00:
|
if sw[-2] == 0x61:
|
||||||
return b""
|
|
||||||
elif sw[0] != 0x61:
|
|
||||||
raise ValueError("%02x%02x" % (sw[0], sw[1]))
|
|
||||||
pk = self.cmd_get_response(sw[1])
|
pk = self.cmd_get_response(sw[1])
|
||||||
return (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
elif sw[-2] == 0x90 and sw[-1] == 0x00:
|
||||||
|
pk = sw
|
||||||
|
else:
|
||||||
|
raise ValueError("%02x%02x" % (sw[0], sw[1]))
|
||||||
|
return (pk[9:9+256], pk[9+256+2:-2])
|
||||||
|
|
||||||
def cmd_get_public_key(self, keyno):
|
def cmd_get_public_key(self, keyno):
|
||||||
if keyno == 1:
|
if keyno == 1:
|
||||||
@@ -358,7 +363,6 @@ class OpenPGP_Card(object):
|
|||||||
data = b'\xa4\x00'
|
data = b'\xa4\x00'
|
||||||
if self.__reader.is_tpdu_reader():
|
if self.__reader.is_tpdu_reader():
|
||||||
cmd_data = iso7816_compose(0x47, 0x81, 0, data, le=512)
|
cmd_data = iso7816_compose(0x47, 0x81, 0, data, le=512)
|
||||||
r = self.__reader.send_cmd(cmd_data)
|
|
||||||
else:
|
else:
|
||||||
cmd_data = iso7816_compose(0x47, 0x81, 0, data)
|
cmd_data = iso7816_compose(0x47, 0x81, 0, data)
|
||||||
r = self.__reader.send_cmd(cmd_data)
|
r = self.__reader.send_cmd(cmd_data)
|
||||||
|
|||||||
@@ -70,11 +70,11 @@ def build_privkey_template_for_remove(openpgp_keyno):
|
|||||||
keyspec = b'\xb8'
|
keyspec = b'\xb8'
|
||||||
else:
|
else:
|
||||||
keyspec = b'\xa4'
|
keyspec = b'\xa4'
|
||||||
return b'\x4d\02' + keyspec + b'\0x00'
|
return b'\x4d\x02' + keyspec + b'\x00'
|
||||||
|
|
||||||
def compute_digestinfo(msg):
|
def compute_digestinfo(msg):
|
||||||
digest = sha256(msg).digest()
|
digest = sha256(msg).digest()
|
||||||
prefix = b'\x30\31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
|
prefix = b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
|
||||||
return prefix + digest
|
return prefix + digest
|
||||||
|
|
||||||
# egcd and modinv are from wikibooks
|
# egcd and modinv are from wikibooks
|
||||||
|
|||||||
6
tests/skip_gnuk_only_tests.py
Normal file
6
tests/skip_gnuk_only_tests.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module",autouse=True)
|
||||||
|
def check_gnuk(card):
|
||||||
|
if not card.is_gnuk:
|
||||||
|
pytest.skip("Gnuk only feature", allow_module_level=True)
|
||||||
@@ -50,12 +50,21 @@ def test_sex(card):
|
|||||||
def test_name_lang_sex(card):
|
def test_name_lang_sex(card):
|
||||||
name = b""
|
name = b""
|
||||||
lang = b""
|
lang = b""
|
||||||
|
lang_de = b"de"
|
||||||
sex = b"9"
|
sex = b"9"
|
||||||
|
sex_alt = b"0"
|
||||||
expected = b'\x5b' + pack('B', len(name)) + name \
|
expected = b'\x5b' + pack('B', len(name)) + name \
|
||||||
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
||||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||||
|
expected_de = b'\x5b' + pack('B', len(name)) + name \
|
||||||
|
+ b'\x5f\x2d' + pack('B', len(lang_de)) + lang_de \
|
||||||
|
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||||
|
expected_de_alt = b'\x5b' + pack('B', len(name)) + name \
|
||||||
|
+ b'\x5f\x2d' + pack('B', len(lang_de)) + lang_de \
|
||||||
|
+ b'\x5f\x35' + pack('B', len(sex_alt)) + sex_alt
|
||||||
name_lang_sex = get_data_object(card, 0x65)
|
name_lang_sex = get_data_object(card, 0x65)
|
||||||
assert name_lang_sex == b'' or name_lang_sex == expected
|
assert name_lang_sex == b'' or name_lang_sex == expected \
|
||||||
|
or name_lang_sex == expected_de or name_lang_sex == expected_de_alt
|
||||||
|
|
||||||
def test_app_data(card):
|
def test_app_data(card):
|
||||||
app_data = get_data_object(card, 0x6e)
|
app_data = get_data_object(card, 0x6e)
|
||||||
@@ -140,7 +149,8 @@ def test_historical_bytes(card):
|
|||||||
h = get_data_object(card, 0x5f52)
|
h = get_data_object(card, 0x5f52)
|
||||||
assert h == b'\x001\xc5s\xc0\x01@\x05\x90\x00' or \
|
assert h == b'\x001\xc5s\xc0\x01@\x05\x90\x00' or \
|
||||||
h == b'\x00\x31\x84\x73\x80\x01\x80\x00\x90\x00' or \
|
h == b'\x00\x31\x84\x73\x80\x01\x80\x00\x90\x00' or \
|
||||||
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00'
|
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00' or \
|
||||||
|
h == b'\x00\x31\xf5\x73\xc0\x01\x60\x05\x90\x00'
|
||||||
|
|
||||||
def test_extended_capabilities(card):
|
def test_extended_capabilities(card):
|
||||||
a = get_data_object(card, 0xc0)
|
a = get_data_object(card, 0xc0)
|
||||||
|
|||||||
@@ -1,276 +1 @@
|
|||||||
"""
|
from card_test_personalize_card import *
|
||||||
test_personalize_card.py - test personalizing card
|
|
||||||
|
|
||||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
||||||
|
|
||||||
Gnuk is free software: you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from struct import pack
|
|
||||||
from re import match, DOTALL
|
|
||||||
from util import *
|
|
||||||
import rsa_keys
|
|
||||||
from card_const import *
|
|
||||||
from constants_for_test import *
|
|
||||||
|
|
||||||
def test_setup_pw3_0(card):
|
|
||||||
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, PW3_TEST0)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw3_0(card):
|
|
||||||
v = card.verify(3, PW3_TEST0)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_login_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_name_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_lang_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_sex_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x35, b"1")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_url_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_pw1_status_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_login(card):
|
|
||||||
login = get_data_object(card, 0x5e)
|
|
||||||
assert login == b"gpg_user"
|
|
||||||
|
|
||||||
def test_name_lang_sex(card):
|
|
||||||
name = b"GnuPG User"
|
|
||||||
lang = b"ja"
|
|
||||||
sex = b"1"
|
|
||||||
expected = b'\x5b' + pack('B', len(name)) + name \
|
|
||||||
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
|
||||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
|
||||||
name_lang_sex = get_data_object(card, 0x65)
|
|
||||||
assert name_lang_sex == expected
|
|
||||||
|
|
||||||
def test_url(card):
|
|
||||||
url = get_data_object(card, 0x5f50)
|
|
||||||
assert url == b"https://www.fsij.org/gnuk/"
|
|
||||||
|
|
||||||
def test_pw1_status(card):
|
|
||||||
s = get_data_object(card, 0xc4)
|
|
||||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
|
||||||
|
|
||||||
def test_rsa_import_key_1(card):
|
|
||||||
t = rsa_keys.build_privkey_template(1, 0)
|
|
||||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_rsa_import_key_2(card):
|
|
||||||
t = rsa_keys.build_privkey_template(2, 1)
|
|
||||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_rsa_import_key_3(card):
|
|
||||||
t = rsa_keys.build_privkey_template(3, 2)
|
|
||||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_fingerprint_1_put(card):
|
|
||||||
fpr1 = rsa_keys.fpr[0]
|
|
||||||
r = card.cmd_put_data(0x00, 0xc7, fpr1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_fingerprint_2_put(card):
|
|
||||||
fpr2 = rsa_keys.fpr[1]
|
|
||||||
r = card.cmd_put_data(0x00, 0xc8, fpr2)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_fingerprint_3_put(card):
|
|
||||||
fpr3 = rsa_keys.fpr[2]
|
|
||||||
r = card.cmd_put_data(0x00, 0xc9, fpr3)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_timestamp_1_put(card):
|
|
||||||
timestamp1 = rsa_keys.timestamp[0]
|
|
||||||
r = card.cmd_put_data(0x00, 0xce, timestamp1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_timestamp_2_put(card):
|
|
||||||
timestamp2 = rsa_keys.timestamp[1]
|
|
||||||
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_timestamp_3_put(card):
|
|
||||||
timestamp3 = rsa_keys.timestamp[2]
|
|
||||||
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_ds_counter_0(card):
|
|
||||||
c = get_data_object(card, 0x7a)
|
|
||||||
assert c == b'\x93\x03\x00\x00\x00'
|
|
||||||
|
|
||||||
def test_pw1_status(card):
|
|
||||||
s = get_data_object(card, 0xc4)
|
|
||||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
|
||||||
|
|
||||||
def test_app_data(card):
|
|
||||||
app_data = get_data_object(card, 0x6e)
|
|
||||||
hist_len = app_data[20]
|
|
||||||
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
|
|
||||||
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
|
|
||||||
app_data[18:18+2] == b"\x5f\x52"
|
|
||||||
|
|
||||||
def test_public_key_1(card):
|
|
||||||
pk = card.cmd_get_public_key(1)
|
|
||||||
assert rsa_keys.key[0][0] == pk[9:9+256]
|
|
||||||
|
|
||||||
def test_public_key_2(card):
|
|
||||||
pk = card.cmd_get_public_key(2)
|
|
||||||
assert rsa_keys.key[1][0] == pk[9:9+256]
|
|
||||||
|
|
||||||
def test_public_key_3(card):
|
|
||||||
pk = card.cmd_get_public_key(3)
|
|
||||||
assert rsa_keys.key[2][0] == pk[9:9+256]
|
|
||||||
|
|
||||||
def test_setup_pw1_0(card):
|
|
||||||
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_0(card):
|
|
||||||
v = card.verify(1, PW1_TEST0)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_0_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST0)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw1_1(card):
|
|
||||||
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_1(card):
|
|
||||||
v = card.verify(1, PW1_TEST1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_1_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_reset_code(card):
|
|
||||||
r = card.setup_reset_code(RESETCODE_TEST)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_reset_code(card):
|
|
||||||
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_2(card):
|
|
||||||
v = card.verify(1, PW1_TEST2)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_2_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST2)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw3_1(card):
|
|
||||||
r = card.change_passwd(3, PW3_TEST0, PW3_TEST1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw3_1(card):
|
|
||||||
v = card.verify(3, PW3_TEST1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_reset_userpass_admin(card):
|
|
||||||
r = card.reset_passwd_by_admin(PW1_TEST3)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_3(card):
|
|
||||||
v = card.verify(1, PW1_TEST3)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_3_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST3)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw1_4(card):
|
|
||||||
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_4(card):
|
|
||||||
v = card.verify(1, PW1_TEST4)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_4_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST4)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw3_2(card):
|
|
||||||
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw3_2(card):
|
|
||||||
v = card.verify(3, PW3_TEST0)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_sign_0(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
|
||||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
|
||||||
sig = rsa_keys.compute_signature(0, digestinfo)
|
|
||||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
|
||||||
assert r == sig_bytes
|
|
||||||
|
|
||||||
def test_sign_1(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
|
||||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
|
||||||
sig = rsa_keys.compute_signature(0, digestinfo)
|
|
||||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
|
||||||
assert r == sig_bytes
|
|
||||||
|
|
||||||
def test_ds_counter_1(card):
|
|
||||||
c = get_data_object(card, 0x7a)
|
|
||||||
assert c == b'\x93\x03\x00\x00\x02'
|
|
||||||
|
|
||||||
def test_sign_auth_0(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
|
||||||
r = card.cmd_internal_authenticate(digestinfo)
|
|
||||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
|
||||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
|
||||||
assert r == sig_bytes
|
|
||||||
|
|
||||||
def test_sign_auth_1(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
|
||||||
r = card.cmd_internal_authenticate(digestinfo)
|
|
||||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
|
||||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
|
||||||
assert r == sig_bytes
|
|
||||||
|
|
||||||
def test_decrypt_0(card):
|
|
||||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
|
|
||||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
|
||||||
assert r == PLAIN_TEXT0
|
|
||||||
|
|
||||||
def test_decrypt_1(card):
|
|
||||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
|
|
||||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
|
||||||
assert r == PLAIN_TEXT1
|
|
||||||
|
|||||||
@@ -1,81 +1 @@
|
|||||||
"""
|
from card_test_personalize_reset import *
|
||||||
test_personalize_reset.py - test resetting personalization of card
|
|
||||||
|
|
||||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
||||||
|
|
||||||
Gnuk is free software: you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from struct import pack
|
|
||||||
from re import match, DOTALL
|
|
||||||
from util import *
|
|
||||||
import rsa_keys
|
|
||||||
from card_const import *
|
|
||||||
from constants_for_test import *
|
|
||||||
|
|
||||||
def test_login_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0x5e, b"")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_name_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0x5b, b"")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_lang_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x2d, b"")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_sex_put(card):
|
|
||||||
try:
|
|
||||||
# Gnuk
|
|
||||||
r = card.cmd_put_data(0x5f, 0x35, b"")
|
|
||||||
except ValueError:
|
|
||||||
# OpenPGP card which doesn't allow b""
|
|
||||||
r = card.cmd_put_data(0x5f, 0x35, b"9")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_url_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x50, b"")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_pw1_status_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0xc4, b"\x00")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_setup_pw3_0(card):
|
|
||||||
r = card.change_passwd(3, PW3_TEST0, FACTORY_PASSPHRASE_PW3)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw3_0(card):
|
|
||||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw1_0(card):
|
|
||||||
r = card.change_passwd(1, PW1_TEST4, FACTORY_PASSPHRASE_PW1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_0(card):
|
|
||||||
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_0_2(card):
|
|
||||||
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_delete_reset_code(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0xd3, b"")
|
|
||||||
assert r
|
|
||||||
|
|||||||
@@ -1,43 +1 @@
|
|||||||
"""
|
from card_test_remove_keys import *
|
||||||
test_remove_keys.py - test removing keys on card
|
|
||||||
|
|
||||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
||||||
|
|
||||||
Gnuk is free software: you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Remove a key material on card by changing algorithm attributes of the key
|
|
||||||
|
|
||||||
from card_const import *
|
|
||||||
|
|
||||||
def test_rsa_keyattr_change_1(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
|
|
||||||
if r:
|
|
||||||
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_rsa_keyattr_change_2(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
|
|
||||||
if r:
|
|
||||||
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_rsa_keyattr_change_3(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
|
|
||||||
if r:
|
|
||||||
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)
|
|
||||||
assert r
|
|
||||||
|
|||||||
@@ -1,41 +1 @@
|
|||||||
"""
|
from card_test_reset_pw3 import *
|
||||||
test_004_reset_pw3.py - test resetting pw3
|
|
||||||
|
|
||||||
Copyright (C) 2018 g10 Code GmbH
|
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
||||||
|
|
||||||
Gnuk is free software: you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from card_const import *
|
|
||||||
|
|
||||||
# Gnuk specific feature of clear PW3
|
|
||||||
def test_setup_pw3_null(card):
|
|
||||||
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, None)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw3(card):
|
|
||||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
# Check PW1 again to see the possiblity of admin-less mode
|
|
||||||
def test_verify_pw1(card):
|
|
||||||
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_2(card):
|
|
||||||
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
|
||||||
assert v
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
test_005_personalize_admin_less.py - test admin-less mode
|
test_005_personalize_admin_less.py - test admin-less mode
|
||||||
|
|
||||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -20,291 +20,9 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from struct import pack
|
from skip_gnuk_only_tests import *
|
||||||
from re import match, DOTALL
|
|
||||||
from util import *
|
|
||||||
import rsa_keys
|
|
||||||
from card_const import *
|
|
||||||
from constants_for_test import *
|
|
||||||
|
|
||||||
def test_verify_pw3_0(card):
|
from card_test_personalize_admin_less import *
|
||||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
from card_test_personalize_reset import *
|
||||||
assert v
|
from card_test_remove_keys import *
|
||||||
|
from card_test_reset_pw3 import *
|
||||||
def test_rsa_import_key_1(card):
|
|
||||||
t = rsa_keys.build_privkey_template(1, 0)
|
|
||||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_rsa_import_key_2(card):
|
|
||||||
t = rsa_keys.build_privkey_template(2, 1)
|
|
||||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_rsa_import_key_3(card):
|
|
||||||
t = rsa_keys.build_privkey_template(3, 2)
|
|
||||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_fingerprint_1_put(card):
|
|
||||||
fpr1 = rsa_keys.fpr[0]
|
|
||||||
r = card.cmd_put_data(0x00, 0xc7, fpr1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_fingerprint_2_put(card):
|
|
||||||
fpr2 = rsa_keys.fpr[1]
|
|
||||||
r = card.cmd_put_data(0x00, 0xc8, fpr2)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_fingerprint_3_put(card):
|
|
||||||
fpr3 = rsa_keys.fpr[2]
|
|
||||||
r = card.cmd_put_data(0x00, 0xc9, fpr3)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_timestamp_1_put(card):
|
|
||||||
timestamp1 = rsa_keys.timestamp[0]
|
|
||||||
r = card.cmd_put_data(0x00, 0xce, timestamp1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_timestamp_2_put(card):
|
|
||||||
timestamp2 = rsa_keys.timestamp[1]
|
|
||||||
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_timestamp_3_put(card):
|
|
||||||
timestamp3 = rsa_keys.timestamp[2]
|
|
||||||
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_ds_counter_0(card):
|
|
||||||
c = get_data_object(card, 0x7a)
|
|
||||||
assert c == b'\x93\x03\x00\x00\x00'
|
|
||||||
|
|
||||||
def test_pw1_status(card):
|
|
||||||
s = get_data_object(card, 0xc4)
|
|
||||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
|
||||||
|
|
||||||
def test_app_data(card):
|
|
||||||
app_data = get_data_object(card, 0x6e)
|
|
||||||
hist_len = app_data[20]
|
|
||||||
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
|
|
||||||
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
|
|
||||||
app_data[18:18+2] == b"\x5f\x52"
|
|
||||||
|
|
||||||
def test_public_key_1(card):
|
|
||||||
pk = card.cmd_get_public_key(1)
|
|
||||||
assert rsa_keys.key[0][0] == pk[9:9+256]
|
|
||||||
|
|
||||||
def test_public_key_2(card):
|
|
||||||
pk = card.cmd_get_public_key(2)
|
|
||||||
assert rsa_keys.key[1][0] == pk[9:9+256]
|
|
||||||
|
|
||||||
def test_public_key_3(card):
|
|
||||||
pk = card.cmd_get_public_key(3)
|
|
||||||
assert rsa_keys.key[2][0] == pk[9:9+256]
|
|
||||||
|
|
||||||
# Changing PW1 to admin-less mode
|
|
||||||
|
|
||||||
def test_setup_pw1_0(card):
|
|
||||||
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
# Now, it's admin-less mode, auth-status admin cleared
|
|
||||||
|
|
||||||
def test_verify_pw3_fail_1(card):
|
|
||||||
try:
|
|
||||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
|
||||||
except ValueError as e:
|
|
||||||
v = False
|
|
||||||
assert not v
|
|
||||||
|
|
||||||
def test_verify_pw1_0(card):
|
|
||||||
v = card.verify(1, PW1_TEST0)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_0_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST0)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw1_1(card):
|
|
||||||
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_1(card):
|
|
||||||
v = card.verify(1, PW1_TEST1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_1_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw3_admin_less_1(card):
|
|
||||||
v = card.verify(3, PW1_TEST1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_reset_code(card):
|
|
||||||
r = card.setup_reset_code(RESETCODE_TEST)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_reset_code(card):
|
|
||||||
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
# Changing PW1, auth status for admin cleared
|
|
||||||
def test_login_put_fail(card):
|
|
||||||
try:
|
|
||||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
|
||||||
except ValueError as e:
|
|
||||||
r = e.args[0]
|
|
||||||
assert r == "6982"
|
|
||||||
|
|
||||||
def test_verify_pw1_2(card):
|
|
||||||
v = card.verify(1, PW1_TEST2)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_2_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST2)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw3_fail_2(card):
|
|
||||||
try:
|
|
||||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
|
||||||
except ValueError as e:
|
|
||||||
v = e.args[0]
|
|
||||||
assert v == "6982"
|
|
||||||
|
|
||||||
def test_sign_0(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
|
||||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
|
||||||
sig = rsa_keys.compute_signature(0, digestinfo)
|
|
||||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
|
||||||
assert r == sig_bytes
|
|
||||||
|
|
||||||
# Since forcesig setting, failed
|
|
||||||
def test_sign_1(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
|
||||||
try:
|
|
||||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
|
||||||
except ValueError as e:
|
|
||||||
r = e.args[0]
|
|
||||||
assert r == "6982"
|
|
||||||
|
|
||||||
def test_ds_counter_1(card):
|
|
||||||
c = get_data_object(card, 0x7a)
|
|
||||||
assert c == b'\x93\x03\x00\x00\x01'
|
|
||||||
|
|
||||||
def test_sign_auth_0(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
|
||||||
r = card.cmd_internal_authenticate(digestinfo)
|
|
||||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
|
||||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
|
||||||
assert r == sig_bytes
|
|
||||||
|
|
||||||
def test_sign_auth_1(card):
|
|
||||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
|
||||||
r = card.cmd_internal_authenticate(digestinfo)
|
|
||||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
|
||||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
|
||||||
assert r == sig_bytes
|
|
||||||
|
|
||||||
def test_decrypt_0(card):
|
|
||||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
|
|
||||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
|
||||||
assert r == PLAIN_TEXT0
|
|
||||||
|
|
||||||
def test_decrypt_1(card):
|
|
||||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
|
|
||||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
|
||||||
assert r == PLAIN_TEXT1
|
|
||||||
|
|
||||||
def test_verify_pw3_admin_less_2(card):
|
|
||||||
v = card.verify(3, PW1_TEST2)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_login_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_name_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_lang_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_sex_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x35, b"1")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_url_put(card):
|
|
||||||
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_pw1_status_put(card):
|
|
||||||
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_login(card):
|
|
||||||
login = get_data_object(card, 0x5e)
|
|
||||||
assert login == b"gpg_user"
|
|
||||||
|
|
||||||
def test_name_lang_sex(card):
|
|
||||||
name = b"GnuPG User"
|
|
||||||
lang = b"ja"
|
|
||||||
sex = b"1"
|
|
||||||
expected = b'\x5b' + pack('B', len(name)) + name \
|
|
||||||
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
|
||||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
|
||||||
name_lang_sex = get_data_object(card, 0x65)
|
|
||||||
assert name_lang_sex == expected
|
|
||||||
|
|
||||||
def test_url(card):
|
|
||||||
url = get_data_object(card, 0x5f50)
|
|
||||||
assert url == b"https://www.fsij.org/gnuk/"
|
|
||||||
|
|
||||||
def test_pw1_status(card):
|
|
||||||
s = get_data_object(card, 0xc4)
|
|
||||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
|
||||||
|
|
||||||
# Setting PW3, changed to admin-full mode
|
|
||||||
|
|
||||||
def test_setup_pw3_1(card):
|
|
||||||
r = card.change_passwd(3, PW1_TEST2, PW3_TEST1)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw3_1(card):
|
|
||||||
v = card.verify(3, PW3_TEST1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_reset_userpass_admin(card):
|
|
||||||
r = card.reset_passwd_by_admin(PW1_TEST3)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_3(card):
|
|
||||||
v = card.verify(1, PW1_TEST3)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_3_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST3)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw1_4(card):
|
|
||||||
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_4(card):
|
|
||||||
v = card.verify(1, PW1_TEST4)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_verify_pw1_4_2(card):
|
|
||||||
v = card.verify(2, PW1_TEST4)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_setup_pw3_2(card):
|
|
||||||
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw3_2(card):
|
|
||||||
v = card.verify(3, PW3_TEST0)
|
|
||||||
assert v
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
test_002_personalize_reset.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_003_remove_keys.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_004_reset_pw3.py
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
test_005_keygen.py - test key generation
|
test_005_keygen.py - test key generation
|
||||||
|
|
||||||
Copyright (C) 2018 g10 Code GmbH
|
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -20,64 +20,5 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from binascii import hexlify
|
from card_test_keygen import *
|
||||||
import rsa_keys
|
from card_test_remove_keys import *
|
||||||
from card_const import *
|
|
||||||
|
|
||||||
def test_keygen_1(card):
|
|
||||||
pk = card.cmd_genkey(1)
|
|
||||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
|
||||||
r = card.cmd_put_data(0x00, 0xc7, fpr_date[0])
|
|
||||||
if r:
|
|
||||||
r = card.cmd_put_data(0x00, 0xce, fpr_date[1])
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_keygen_2(card):
|
|
||||||
pk = card.cmd_genkey(2)
|
|
||||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
|
||||||
r = card.cmd_put_data(0x00, 0xc8, fpr_date[0])
|
|
||||||
if r:
|
|
||||||
r = card.cmd_put_data(0x00, 0xcf, fpr_date[1])
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_keygen_3(card):
|
|
||||||
pk = card.cmd_genkey(3)
|
|
||||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
|
||||||
r = card.cmd_put_data(0x00, 0xc9, fpr_date[0])
|
|
||||||
if r:
|
|
||||||
r = card.cmd_put_data(0x00, 0xd0, fpr_date[1])
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1(card):
|
|
||||||
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_signature_sigkey(card):
|
|
||||||
msg = b"Sign me please"
|
|
||||||
pk = card.cmd_get_public_key(1)
|
|
||||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
|
||||||
digest = rsa_keys.compute_digestinfo(msg)
|
|
||||||
sig = int(hexlify(card.cmd_pso(0x9e, 0x9a, digest)),16)
|
|
||||||
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
def test_verify_pw1_2(card):
|
|
||||||
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
|
|
||||||
assert v
|
|
||||||
|
|
||||||
def test_decryption(card):
|
|
||||||
msg = b"encrypt me please"
|
|
||||||
pk = card.cmd_get_public_key(2)
|
|
||||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
|
||||||
ciphertext = rsa_keys.encrypt_with_pubkey(pk_info, msg)
|
|
||||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
|
||||||
assert r == msg
|
|
||||||
|
|
||||||
def test_signature_authkey(card):
|
|
||||||
msg = b"Sign me please to authenticate"
|
|
||||||
pk = card.cmd_get_public_key(3)
|
|
||||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
|
||||||
digest = rsa_keys.compute_digestinfo(msg)
|
|
||||||
sig = int(hexlify(card.cmd_internal_authenticate(digest)),16)
|
|
||||||
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
|
||||||
assert r
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
test_003_remove_keys.py
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
test_007_kdf_full.py - test KDF data object
|
test_007_kdf_full.py - test KDF data object
|
||||||
|
|
||||||
Copyright (C) 2018 g10 Code GmbH
|
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -20,15 +20,10 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from card_const import *
|
from skip_gnuk_only_tests import *
|
||||||
from constants_for_test import *
|
|
||||||
|
|
||||||
def test_verify_pw3(card):
|
from card_test_kdf_full import *
|
||||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
from card_test_personalize_card import *
|
||||||
assert v
|
from card_test_personalize_reset import *
|
||||||
|
from card_test_remove_keys import *
|
||||||
def test_kdf_put_full(card):
|
from card_test_reset_pw3 import *
|
||||||
r = card.cmd_put_data(0x00, 0xf9, KDF_FULL)
|
|
||||||
if r:
|
|
||||||
card.configure_with_kdf()
|
|
||||||
assert r
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
test_001_personalize_card.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_002_personalize_reset.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_003_remove_keys.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_004_reset_pw3.py
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
test_012_kdf_single.py - test KDF data object
|
test_012_kdf_single.py - test KDF data object
|
||||||
|
|
||||||
Copyright (C) 2018 g10 Code GmbH
|
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -20,15 +20,10 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from card_const import *
|
from skip_gnuk_only_tests import *
|
||||||
from constants_for_test import *
|
|
||||||
|
|
||||||
def test_verify_pw3(card):
|
from card_test_kdf_single import *
|
||||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
from card_test_personalize_card import *
|
||||||
assert v
|
from card_test_personalize_reset import *
|
||||||
|
from card_test_remove_keys import *
|
||||||
def test_kdf_put_single(card):
|
from card_test_reset_pw3 import *
|
||||||
r = card.cmd_put_data(0x00, 0xf9, KDF_SINGLE)
|
|
||||||
if r:
|
|
||||||
card.configure_with_kdf()
|
|
||||||
assert r
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
test_001_personalize_card.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_002_personalize_reset.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_003_remove_keys.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_004_reset_pw3.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_005_personalize_admin_less.py
|
|
||||||
1
tests/test_021_personalize_admin_less.py
Normal file
1
tests/test_021_personalize_admin_less.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from test_005_personalize_admin_less import *
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_002_personalize_reset.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_003_remove_keys.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
test_004_reset_pw3.py
|
|
||||||
@@ -20,6 +20,8 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from skip_gnuk_only_tests import *
|
||||||
|
|
||||||
from card_const import *
|
from card_const import *
|
||||||
from constants_for_test import *
|
from constants_for_test import *
|
||||||
|
|
||||||
|
|||||||
@@ -109,15 +109,15 @@ def build_rsakey_from_ssh_key_under_gpg_agent(g, timestamp=None):
|
|||||||
# The information is in SEXP format, extract N and E
|
# The information is in SEXP format, extract N and E
|
||||||
s = sexp(pubkey_info_str)
|
s = sexp(pubkey_info_str)
|
||||||
if s[0] != 'public-key':
|
if s[0] != 'public-key':
|
||||||
print s
|
print(s)
|
||||||
exit(1)
|
exit(1)
|
||||||
rsa = s[1]
|
rsa = s[1]
|
||||||
if rsa[0] != 'rsa':
|
if rsa[0] != 'rsa':
|
||||||
print rsa
|
print(rsa)
|
||||||
exit(1)
|
exit(1)
|
||||||
n_x = rsa[1]
|
n_x = rsa[1]
|
||||||
if n_x[0] != 'n':
|
if n_x[0] != 'n':
|
||||||
print n_x
|
print(n_x)
|
||||||
exit(1)
|
exit(1)
|
||||||
n_byte_str = n_x[1]
|
n_byte_str = n_x[1]
|
||||||
while n_byte_str[0] == '\x00':
|
while n_byte_str[0] == '\x00':
|
||||||
@@ -125,7 +125,7 @@ def build_rsakey_from_ssh_key_under_gpg_agent(g, timestamp=None):
|
|||||||
n = n_byte_str
|
n = n_byte_str
|
||||||
e_x = rsa[2]
|
e_x = rsa[2]
|
||||||
if e_x[0] != 'e':
|
if e_x[0] != 'e':
|
||||||
print e_x
|
print(e_x)
|
||||||
exit(1)
|
exit(1)
|
||||||
e = e_x[1]
|
e = e_x[1]
|
||||||
if not timestamp:
|
if not timestamp:
|
||||||
|
|||||||
@@ -8,21 +8,21 @@ def print_nG(n):
|
|||||||
nGy_str = "%064x" % nG.y()
|
nGy_str = "%064x" % nG.y()
|
||||||
print256(nGx_str)
|
print256(nGx_str)
|
||||||
print256(nGy_str)
|
print256(nGy_str)
|
||||||
print
|
print()
|
||||||
|
|
||||||
def print256(s):
|
def print256(s):
|
||||||
print("0x%s, 0x%s, 0x%s, 0x%s," % (s[56:64], s[48:56], s[40:48], s[32:40]))
|
print("0x%s, 0x%s, 0x%s, 0x%s," % (s[56:64], s[48:56], s[40:48], s[32:40]))
|
||||||
print("0x%s, 0x%s, 0x%s, 0x%s" % (s[24:32], s[16:24], s[8:16], s[0:8]))
|
print("0x%s, 0x%s, 0x%s, 0x%s" % (s[24:32], s[16:24], s[8:16], s[0:8]))
|
||||||
print
|
print()
|
||||||
|
|
||||||
|
|
||||||
for i in range(1,16):
|
for i in range(1,16):
|
||||||
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
|
n = (i & 1) + (i & 2) * 0x8000000000000000 + (i & 4) * 0x40000000000000000000000000000000 + (i & 8) * 0x200000000000000000000000000000000000000000000000
|
||||||
print "%064x" % n
|
print("%064x" % n)
|
||||||
print_nG(n)
|
print_nG(n)
|
||||||
|
|
||||||
for i in range(1,16):
|
for i in range(1,16):
|
||||||
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
|
n = (i & 1) + (i & 2) * 0x8000000000000000 + (i & 4) * 0x40000000000000000000000000000000 + (i & 8) * 0x200000000000000000000000000000000000000000000000
|
||||||
n = n * 0x100000000L
|
n = n * 0x100000000
|
||||||
print "%064x" % n
|
print("%064x" % n)
|
||||||
print_nG(n)
|
print_nG(n)
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ class DFU_STM32(object):
|
|||||||
interface: usb.Interface object representing the interface and altenate setting.
|
interface: usb.Interface object representing the interface and altenate setting.
|
||||||
"""
|
"""
|
||||||
if interface.interfaceClass != DFU_CLASS:
|
if interface.interfaceClass != DFU_CLASS:
|
||||||
raise ValueError, "Wrong interface class"
|
raise ValueError("Wrong interface class")
|
||||||
if interface.interfaceSubClass != DFU_SUBCLASS:
|
if interface.interfaceSubClass != DFU_SUBCLASS:
|
||||||
raise ValueError, "Wrong interface sub class"
|
raise ValueError("Wrong interface sub class")
|
||||||
self.__protocol = interface.interfaceProtocol
|
self.__protocol = interface.interfaceProtocol
|
||||||
self.__devhandle = device.open()
|
self.__devhandle = device.open()
|
||||||
self.__devhandle.setConfiguration(configuration)
|
self.__devhandle.setConfiguration(configuration)
|
||||||
@@ -170,7 +170,7 @@ class DFU_STM32(object):
|
|||||||
while s[4] == STATE_DFU_DOWNLOAD_BUSY:
|
while s[4] == STATE_DFU_DOWNLOAD_BUSY:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
s = self.ll_get_status()
|
s = self.ll_get_status()
|
||||||
raise ValueError, "Read memory failed (%d)" % s[0]
|
raise ValueError("Read memory failed (%d)" % s[0])
|
||||||
|
|
||||||
def dfuse_set_address_pointer(self, address):
|
def dfuse_set_address_pointer(self, address):
|
||||||
bytes = get_four_bytes (address)
|
bytes = get_four_bytes (address)
|
||||||
@@ -181,7 +181,7 @@ class DFU_STM32(object):
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
s = self.ll_get_status()
|
s = self.ll_get_status()
|
||||||
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
|
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
|
||||||
raise ValueError, "Set Address Pointer failed"
|
raise ValueError("Set Address Pointer failed")
|
||||||
|
|
||||||
def dfuse_erase(self, address):
|
def dfuse_erase(self, address):
|
||||||
bytes = get_four_bytes (address)
|
bytes = get_four_bytes (address)
|
||||||
@@ -191,7 +191,7 @@ class DFU_STM32(object):
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
s = self.ll_get_status()
|
s = self.ll_get_status()
|
||||||
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
|
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
|
||||||
raise ValueError, "Erase failed"
|
raise ValueError("Erase failed")
|
||||||
|
|
||||||
def dfuse_write_memory(self, block):
|
def dfuse_write_memory(self, block):
|
||||||
blocknum = self.__blocknum
|
blocknum = self.__blocknum
|
||||||
@@ -202,7 +202,7 @@ class DFU_STM32(object):
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
s = self.ll_get_status()
|
s = self.ll_get_status()
|
||||||
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
|
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
|
||||||
raise ValueError, "Write memory failed"
|
raise ValueError("Write memory failed")
|
||||||
|
|
||||||
def download(self, ih):
|
def download(self, ih):
|
||||||
# First, erase pages
|
# First, erase pages
|
||||||
@@ -280,7 +280,7 @@ class DFU_STM32(object):
|
|||||||
elif s[4] == STATE_DFU_MANIFEST_WAIT_RESET:
|
elif s[4] == STATE_DFU_MANIFEST_WAIT_RESET:
|
||||||
self.__devhandle.reset()
|
self.__devhandle.reset()
|
||||||
elif s[4] != STATE_DFU_IDLE:
|
elif s[4] != STATE_DFU_IDLE:
|
||||||
raise ValueError, "write failed (%d)." % s[4]
|
raise ValueError("write failed (%d)." % s[4])
|
||||||
else:
|
else:
|
||||||
self.ll_clear_status()
|
self.ll_clear_status()
|
||||||
self.ll_clear_status()
|
self.ll_clear_status()
|
||||||
@@ -315,7 +315,7 @@ class DFU_STM32(object):
|
|||||||
j = 0
|
j = 0
|
||||||
for c in data[0:(addr + 1024 - start_addr)]:
|
for c in data[0:(addr + 1024 - start_addr)]:
|
||||||
if (ord(c)&0xff) != block[j + start_addr - addr]:
|
if (ord(c)&0xff) != block[j + start_addr - addr]:
|
||||||
raise ValueError, "verify failed at %08x" % (addr + i*1024+j)
|
raise ValueError("verify failed at %08x" % (addr + i*1024+j))
|
||||||
j += 1
|
j += 1
|
||||||
data = data[(addr + 1024 - start_addr):]
|
data = data[(addr + 1024 - start_addr):]
|
||||||
addr += 1024
|
addr += 1024
|
||||||
@@ -330,7 +330,7 @@ class DFU_STM32(object):
|
|||||||
j = 0
|
j = 0
|
||||||
for c in data[i*1024:(i+1)*1024]:
|
for c in data[i*1024:(i+1)*1024]:
|
||||||
if (ord(c)&0xff) != block[j]:
|
if (ord(c)&0xff) != block[j]:
|
||||||
raise ValueError, "verify failed at %08x" % (addr + i*1024+j)
|
raise ValueError("verify failed at %08x" % (addr + i*1024+j))
|
||||||
j += 1
|
j += 1
|
||||||
if i & 0x03 == 0x03:
|
if i & 0x03 == 0x03:
|
||||||
sys.stdout.write("#")
|
sys.stdout.write("#")
|
||||||
@@ -367,25 +367,25 @@ def get_device():
|
|||||||
(alt.interfaceProtocol == DFU_STM32PROTOCOL_0 or \
|
(alt.interfaceProtocol == DFU_STM32PROTOCOL_0 or \
|
||||||
alt.interfaceProtocol == DFU_STM32PROTOCOL_2):
|
alt.interfaceProtocol == DFU_STM32PROTOCOL_2):
|
||||||
return dev, config, alt
|
return dev, config, alt
|
||||||
raise ValueError, "Device not found"
|
raise ValueError("Device not found")
|
||||||
|
|
||||||
def main(filename):
|
def main(filename):
|
||||||
dev, config, intf = get_device()
|
dev, config, intf = get_device()
|
||||||
print "Device:", dev.filename
|
print("Device:", dev.filename)
|
||||||
print "Configuration", config.value
|
print("Configuration", config.value)
|
||||||
print "Interface", intf.interfaceNumber
|
print("Interface", intf.interfaceNumber)
|
||||||
dfu = DFU_STM32(dev, config, intf)
|
dfu = DFU_STM32(dev, config, intf)
|
||||||
print dfu.ll_get_string(intf.iInterface)
|
print(dfu.ll_get_string(intf.iInterface))
|
||||||
s = dfu.ll_get_status()
|
s = dfu.ll_get_status()
|
||||||
if s[4] == STATE_DFU_ERROR:
|
if s[4] == STATE_DFU_ERROR:
|
||||||
dfu.ll_clear_status()
|
dfu.ll_clear_status()
|
||||||
s = dfu.ll_get_status()
|
s = dfu.ll_get_status()
|
||||||
print s
|
print(s)
|
||||||
if s[4] == STATE_DFU_IDLE:
|
if s[4] == STATE_DFU_IDLE:
|
||||||
exit
|
exit
|
||||||
transfer_size = 1024
|
transfer_size = 1024
|
||||||
if s[0] != DFU_STATUS_OK:
|
if s[0] != DFU_STATUS_OK:
|
||||||
print s
|
print(s)
|
||||||
exit
|
exit
|
||||||
ih = intel_hex(filename)
|
ih = intel_hex(filename)
|
||||||
dfu.download(ih)
|
dfu.download(ih)
|
||||||
|
|||||||
@@ -27,22 +27,22 @@ from dfuse import *
|
|||||||
|
|
||||||
dev, config, intf = get_device()
|
dev, config, intf = get_device()
|
||||||
dfu = DFU_STM32(dev, config, intf)
|
dfu = DFU_STM32(dev, config, intf)
|
||||||
print dfu.ll_get_string(intf.iInterface)
|
print(dfu.ll_get_string(intf.iInterface))
|
||||||
s = dfu.ll_get_status()
|
s = dfu.ll_get_status()
|
||||||
dfu.ll_clear_status()
|
dfu.ll_clear_status()
|
||||||
s = dfu.ll_get_status()
|
s = dfu.ll_get_status()
|
||||||
print s
|
print(s)
|
||||||
dfu.dfuse_set_address_pointer(int(sys.argv[1], 16))
|
dfu.dfuse_set_address_pointer(int(sys.argv[1], 16))
|
||||||
s = dfu.ll_get_status()
|
s = dfu.ll_get_status()
|
||||||
dfu.ll_clear_status()
|
dfu.ll_clear_status()
|
||||||
s = dfu.ll_get_status()
|
s = dfu.ll_get_status()
|
||||||
dfu.ll_clear_status()
|
dfu.ll_clear_status()
|
||||||
s = dfu.ll_get_status()
|
s = dfu.ll_get_status()
|
||||||
print s
|
print(s)
|
||||||
block = dfu.dfuse_read_memory()
|
block = dfu.dfuse_read_memory()
|
||||||
count = 0
|
count = 0
|
||||||
for d in block:
|
for d in block:
|
||||||
print "%02x" % d,
|
print("%02x" % d)
|
||||||
if count & 0x0f == 0x0f:
|
if count & 0x0f == 0x0f:
|
||||||
print
|
print
|
||||||
count += 1
|
count += 1
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ def get_gpg_public_key(keygrip):
|
|||||||
pos_last = key.index(")(1:e3:")
|
pos_last = key.index(")(1:e3:")
|
||||||
key = key[pos:pos_last]
|
key = key[pos:pos_last]
|
||||||
if len(key) != 256:
|
if len(key) != 256:
|
||||||
raise ValueError, binascii.hexlify(key)
|
raise ValueError(binascii.hexlify(key))
|
||||||
return key
|
return key
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
#! /bin/sh
|
|
||||||
#
|
|
||||||
# gnuk-emulation-setup - Generate flash image for Gnuk
|
|
||||||
#
|
|
||||||
# Copyright (C) 2017 Free Software Initiative of Japan
|
|
||||||
# Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
#
|
|
||||||
# This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
||||||
#
|
|
||||||
# Gnuk is free software: you can redistribute it and/or modify it
|
|
||||||
# under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
# License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
if test "$1" = "--help"; then
|
|
||||||
echo "Usage:"
|
|
||||||
echo " $0 [output-file]"
|
|
||||||
echo " Generate Gnuk flash image"
|
|
||||||
echo " $0 --help"
|
|
||||||
echo " Show this message"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
OUTPUT_FILE=${1:-$HOME/.gnuk-flash-image}
|
|
||||||
|
|
||||||
# Generate 8192-byte flash data into OUTPUT_FILE
|
|
||||||
|
|
||||||
exec > $OUTPUT_FILE
|
|
||||||
|
|
||||||
for i in $(seq 512); do
|
|
||||||
/bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff'
|
|
||||||
done
|
|
||||||
|
|
||||||
/bin/echo -n -e '\x00\x00\xff\xff\xff\xff\xff\xff'
|
|
||||||
|
|
||||||
for i in $(seq 511); do
|
|
||||||
/bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff'
|
|
||||||
done
|
|
||||||
|
|
||||||
chmod og-rw $OUTPUT_FILE
|
|
||||||
21
tool/gnuk_get_random.py
Executable file
21
tool/gnuk_get_random.py
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
from gnuk_token import get_gnuk_device, gnuk_token
|
||||||
|
from binascii import hexlify
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
count = 0
|
||||||
|
gnuk = get_gnuk_device()
|
||||||
|
gnuk.cmd_select_openpgp()
|
||||||
|
looping = (len(sys.argv) > 1)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
challenge = gnuk.cmd_get_challenge().tobytes()
|
||||||
|
except Exception as e:
|
||||||
|
print(count)
|
||||||
|
raise e
|
||||||
|
print(hexlify(challenge))
|
||||||
|
count = count + 1
|
||||||
|
if not looping:
|
||||||
|
break
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#! /usr/bin/python
|
#! /usr/bin/python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
gnuk_put_binary.py - a tool to put binary to Gnuk Token
|
gnuk_put_binary.py - a tool to put binary to Gnuk Token
|
||||||
This tool is for importing certificate, writing serial number, etc.
|
This tool is for importing certificate, writing serial number, etc.
|
||||||
|
|
||||||
Copyright (C) 2011, 2012 Free Software Initiative of Japan
|
Copyright (C) 2011, 2012, 2021 Free Software Initiative of Japan
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -56,7 +56,7 @@ def main(fileid, is_update, data, passwd):
|
|||||||
if fileid == 0:
|
if fileid == 0:
|
||||||
data_in_device = gnuk.cmd_get_data(0x00, 0x4f)
|
data_in_device = gnuk.cmd_get_data(0x00, 0x4f)
|
||||||
print(' '.join([ "%02x" % d for d in data_in_device ]))
|
print(' '.join([ "%02x" % d for d in data_in_device ]))
|
||||||
compare(data + b'\x00\x00', data_in_device[8:].tostring())
|
compare(data + b'\x00\x00', data_in_device[8:].tobytes())
|
||||||
elif fileid >= 1 and fileid <= 4:
|
elif fileid >= 1 and fileid <= 4:
|
||||||
data_in_device = gnuk.cmd_read_binary(fileid)
|
data_in_device = gnuk.cmd_read_binary(fileid)
|
||||||
compare(data, data_in_device)
|
compare(data, data_in_device)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#! /usr/bin/python
|
#! /usr/bin/python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
gnuk_remove_keys_libusb.py - a tool to remove keys in Gnuk Token
|
gnuk_remove_keys_libusb.py - a tool to remove keys in Gnuk Token
|
||||||
|
|
||||||
Copyright (C) 2012, 2018 Free Software Initiative of Japan
|
Copyright (C) 2012, 2018, 2021 Free Software Initiative of Japan
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -51,7 +51,7 @@ def main(passwd):
|
|||||||
gnuk.icc_power_on()
|
gnuk.icc_power_on()
|
||||||
gnuk.cmd_select_openpgp()
|
gnuk.cmd_select_openpgp()
|
||||||
# Compute passwd data
|
# Compute passwd data
|
||||||
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tostring()
|
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tobytes()
|
||||||
if kdf_data == b"":
|
if kdf_data == b"":
|
||||||
passwd_data = passwd.encode('UTF-8')
|
passwd_data = passwd.encode('UTF-8')
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from array import array
|
|||||||
USB_PRODUCT_LIST=[
|
USB_PRODUCT_LIST=[
|
||||||
{ 'vendor' : 0x234b, 'product' : 0x0000 }, # FSIJ Gnuk Token
|
{ 'vendor' : 0x234b, 'product' : 0x0000 }, # FSIJ Gnuk Token
|
||||||
{ 'vendor' : 0x20a0, 'product' : 0x4211 }, # Nitrokey Start
|
{ 'vendor' : 0x20a0, 'product' : 0x4211 }, # Nitrokey Start
|
||||||
|
{ 'vendor' : 0x1209, 'product' : 0x2440 }, # GnuPG e.V.
|
||||||
]
|
]
|
||||||
|
|
||||||
# USB class, subclass, protocol
|
# USB class, subclass, protocol
|
||||||
@@ -74,6 +75,7 @@ class gnuk_token(object):
|
|||||||
raise ValueError("Wrong interface sub class")
|
raise ValueError("Wrong interface sub class")
|
||||||
self.__devhandle = device.open()
|
self.__devhandle = device.open()
|
||||||
self.__devhandle.claimInterface(interface)
|
self.__devhandle.claimInterface(interface)
|
||||||
|
self.__devhandle.setAltInterface(interface)
|
||||||
|
|
||||||
self.__intf = interface.interfaceNumber
|
self.__intf = interface.interfaceNumber
|
||||||
self.__alt = interface.alternateSetting
|
self.__alt = interface.alternateSetting
|
||||||
@@ -86,11 +88,17 @@ class gnuk_token(object):
|
|||||||
alt.interfaceSubClass == HID_SUBCLASS_NO_BOOT and \
|
alt.interfaceSubClass == HID_SUBCLASS_NO_BOOT and \
|
||||||
alt.interfaceProtocol == HID_PROTOCOL_0:
|
alt.interfaceProtocol == HID_PROTOCOL_0:
|
||||||
self.__hid_intf = alt.interfaceNumber
|
self.__hid_intf = alt.interfaceNumber
|
||||||
|
elif alt.interfaceClass == CCID_CLASS and \
|
||||||
|
alt.interfaceSubClass == CCID_SUBCLASS and \
|
||||||
|
alt.interfaceProtocol == CCID_PROTOCOL_0:
|
||||||
|
for endpoint in alt.endpoints:
|
||||||
|
if endpoint.type == usb.ENDPOINT_TYPE_BULK:
|
||||||
|
if endpoint.address & usb.ENDPOINT_DIR_MASK == usb.ENDPOINT_IN:
|
||||||
|
self.__bulkin = endpoint.address
|
||||||
|
else:
|
||||||
|
self.__bulkout = endpoint.address
|
||||||
|
|
||||||
self.__bulkout = 1
|
self.__timeout = 100000
|
||||||
self.__bulkin = 0x81
|
|
||||||
|
|
||||||
self.__timeout = 10000
|
|
||||||
self.__seq = 0
|
self.__seq = 0
|
||||||
|
|
||||||
def get_string(self, num):
|
def get_string(self, num):
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#! /usr/bin/python
|
#! /usr/bin/python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
gnuk_upgrade.py - a tool to upgrade firmware of Gnuk Token
|
gnuk_upgrade.py - a tool to upgrade firmware of Gnuk Token
|
||||||
|
|
||||||
Copyright (C) 2012, 2015 Free Software Initiative of Japan
|
Copyright (C) 2012, 2015, 2021 Free Software Initiative of Japan
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
@@ -91,7 +91,7 @@ def main(keyno,keygrip, data_regnual, data_upgrade):
|
|||||||
elif icc.icc_get_status() == 1:
|
elif icc.icc_get_status() == 1:
|
||||||
icc.icc_power_on()
|
icc.icc_power_on()
|
||||||
icc.cmd_select_openpgp()
|
icc.cmd_select_openpgp()
|
||||||
challenge = icc.cmd_get_challenge().tostring()
|
challenge = icc.cmd_get_challenge().tobytes()
|
||||||
signed = gpg_sign(keygrip, binascii.hexlify(challenge))
|
signed = gpg_sign(keygrip, binascii.hexlify(challenge))
|
||||||
icc.cmd_external_authenticate(keyno, signed)
|
icc.cmd_external_authenticate(keyno, signed)
|
||||||
icc.stop_gnuk()
|
icc.stop_gnuk()
|
||||||
@@ -107,17 +107,19 @@ def main(keyno,keygrip, data_regnual, data_upgrade):
|
|||||||
del icc
|
del icc
|
||||||
icc = None
|
icc = None
|
||||||
#
|
#
|
||||||
print("Wait 3 seconds...")
|
|
||||||
time.sleep(3)
|
|
||||||
# Then, send upgrade program...
|
|
||||||
reg = None
|
reg = None
|
||||||
|
print("Waiting for device to appear:")
|
||||||
|
while reg == None:
|
||||||
|
print(" Wait {} second{}...".format(wait_e, 's' if wait_e > 1 else ''))
|
||||||
|
time.sleep(wait_e)
|
||||||
for dev in gnuk_devices_by_vidpid():
|
for dev in gnuk_devices_by_vidpid():
|
||||||
try:
|
try:
|
||||||
reg = regnual(dev)
|
reg = regnual(dev)
|
||||||
print("Device: %d" % dev.filename)
|
print("Device: %s" % dev.filename)
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
# Then, send upgrade program...
|
||||||
mem_info = reg.mem_info()
|
mem_info = reg.mem_info()
|
||||||
print("%08x:%08x" % mem_info)
|
print("%08x:%08x" % mem_info)
|
||||||
print("Downloading the program")
|
print("Downloading the program")
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ GCRY_MD_SHA256 = 8
|
|||||||
def kdf_calc(pw_string, salt_byte, iterations):
|
def kdf_calc(pw_string, salt_byte, iterations):
|
||||||
ffi = FFI()
|
ffi = FFI()
|
||||||
ffi.cdef(DEF_gcry_kdf_derive)
|
ffi.cdef(DEF_gcry_kdf_derive)
|
||||||
libgcrypt = ffi.dlopen("libgcrypt.so")
|
libgcrypt = ffi.dlopen("libgcrypt.so.20")
|
||||||
if isinstance(pw_string, str):
|
if isinstance(pw_string, str):
|
||||||
pw_byte = pw_string.encode('UTF-8')
|
pw_byte = pw_string.encode('UTF-8')
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from sexp import sexp
|
|||||||
# Assume it's only OPENPGP.3 key and it's 2048-bit
|
# Assume it's only OPENPGP.3 key and it's 2048-bit
|
||||||
|
|
||||||
def debug(string):
|
def debug(string):
|
||||||
print "DEBUG: %s" % string
|
print("DEBUG: %s" % string)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
def get_keygrip_list(keyinfo_result):
|
def get_keygrip_list(keyinfo_result):
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class Card(object):
|
|||||||
elif code == FEATURE_MODIFY_PIN_DIRECT:
|
elif code == FEATURE_MODIFY_PIN_DIRECT:
|
||||||
self.modify_ioctl = ioctl
|
self.modify_ioctl = ioctl
|
||||||
if self.verify_ioctl == -1:
|
if self.verify_ioctl == -1:
|
||||||
raise ValueError, "Not supported"
|
raise ValueError("Not supported")
|
||||||
|
|
||||||
def cmd_select_openpgp(self):
|
def cmd_select_openpgp(self):
|
||||||
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
|
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
|
||||||
@@ -90,7 +90,7 @@ class Card(object):
|
|||||||
if sw1 == 0x61: # More data
|
if sw1 == 0x61: # More data
|
||||||
response, sw1, sw2 = self.connection.transmit([0x00, 0xc0, 0, 0, sw2])
|
response, sw1, sw2 = self.connection.transmit([0x00, 0xc0, 0, 0, sw2])
|
||||||
elif not (sw1 == 0x90 and sw2 == 0x00):
|
elif not (sw1 == 0x90 and sw2 == 0x00):
|
||||||
raise ValueError, ("cmd_select_openpgp %02x %02x" % (sw1, sw2))
|
raise ValueError("cmd_select_openpgp %02x %02x" % (sw1, sw2))
|
||||||
|
|
||||||
def possibly_add_dummy_byte(self):
|
def possibly_add_dummy_byte(self):
|
||||||
if self.another_byte:
|
if self.another_byte:
|
||||||
@@ -135,11 +135,11 @@ class Card(object):
|
|||||||
sw1 = data[0]
|
sw1 = data[0]
|
||||||
sw2 = data[1]
|
sw2 = data[1]
|
||||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||||
raise ValueError, ("cmd_verify_pinpad %02x %02x" % (sw1, sw2))
|
raise ValueError("cmd_verify_pinpad %02x %02x" % (sw1, sw2))
|
||||||
|
|
||||||
def send_modify_pinpad(self, apdu, single_step, command):
|
def send_modify_pinpad(self, apdu, single_step, command):
|
||||||
if self.modify_ioctl == -1:
|
if self.modify_ioctl == -1:
|
||||||
raise ValueError, "Not supported"
|
raise ValueError("Not supported")
|
||||||
pin_modify = [ 0x00, # bTimerOut
|
pin_modify = [ 0x00, # bTimerOut
|
||||||
0x00, # bTimerOut2
|
0x00, # bTimerOut2
|
||||||
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
|
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
|
||||||
@@ -171,7 +171,7 @@ class Card(object):
|
|||||||
sw1 = data[0]
|
sw1 = data[0]
|
||||||
sw2 = data[1]
|
sw2 = data[1]
|
||||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||||
raise ValueError, ("%s %02x %02x" % (command, sw1, sw2))
|
raise ValueError("%s %02x %02x" % (command, sw1, sw2))
|
||||||
|
|
||||||
def cmd_reset_retry_counter(self, who, data):
|
def cmd_reset_retry_counter(self, who, data):
|
||||||
if who == BY_ADMIN:
|
if who == BY_ADMIN:
|
||||||
@@ -180,7 +180,7 @@ class Card(object):
|
|||||||
apdu = [0x00, 0x2c, 0x00, 0x81, len(data) ] + data # BY_USER with resetcode
|
apdu = [0x00, 0x2c, 0x00, 0x81, len(data) ] + data # BY_USER with resetcode
|
||||||
response, sw1, sw2 = self.connection.transmit(apdu)
|
response, sw1, sw2 = self.connection.transmit(apdu)
|
||||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||||
raise ValueError, ("cmd_reset_retry_counter %02x %02x" % (sw1, sw2))
|
raise ValueError("cmd_reset_retry_counter %02x %02x" % (sw1, sw2))
|
||||||
|
|
||||||
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
|
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
|
||||||
def cmd_reset_retry_counter_pinpad(self, who):
|
def cmd_reset_retry_counter_pinpad(self, who):
|
||||||
@@ -195,7 +195,7 @@ class Card(object):
|
|||||||
apdu = [0x00, 0xda, 0x00, 0xd3, len(data) ] + data # BY_ADMIN
|
apdu = [0x00, 0xda, 0x00, 0xd3, len(data) ] + data # BY_ADMIN
|
||||||
response, sw1, sw2 = self.connection.transmit(apdu)
|
response, sw1, sw2 = self.connection.transmit(apdu)
|
||||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||||
raise ValueError, ("cmd_put_resetcode %02x %02x" % (sw1, sw2))
|
raise ValueError("cmd_put_resetcode %02x %02x" % (sw1, sw2))
|
||||||
|
|
||||||
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
|
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
|
||||||
def cmd_put_resetcode_pinpad(self):
|
def cmd_put_resetcode_pinpad(self):
|
||||||
@@ -225,8 +225,8 @@ def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed):
|
|||||||
card.connection.connect()
|
card.connection.connect()
|
||||||
|
|
||||||
ident = card.connection.getReader()
|
ident = card.connection.getReader()
|
||||||
print "Reader/Token:", ident
|
print("Reader/Token:", ident)
|
||||||
print "ATR:", toHexString( card.connection.getATR() )
|
print("ATR:", toHexString( card.connection.getATR() ))
|
||||||
|
|
||||||
if ident == COVADIS_VEGA_ALPHA:
|
if ident == COVADIS_VEGA_ALPHA:
|
||||||
card.cmd_vega_alpha_disable_empty_verify()
|
card.cmd_vega_alpha_disable_empty_verify()
|
||||||
@@ -236,29 +236,29 @@ def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed):
|
|||||||
card.cmd_select_openpgp()
|
card.cmd_select_openpgp()
|
||||||
if method == "verify":
|
if method == "verify":
|
||||||
if who == BY_USER:
|
if who == BY_USER:
|
||||||
print "Please input User's PIN"
|
print("Please input User's PIN")
|
||||||
else:
|
else:
|
||||||
print "Please input Admin's PIN"
|
print("Please input Admin's PIN")
|
||||||
card.cmd_verify_pinpad(who)
|
card.cmd_verify_pinpad(who)
|
||||||
elif method == "change":
|
elif method == "change":
|
||||||
if change_by_two_steps:
|
if change_by_two_steps:
|
||||||
if who == BY_USER:
|
if who == BY_USER:
|
||||||
print "Please input User's PIN"
|
print("Please input User's PIN")
|
||||||
else:
|
else:
|
||||||
print "Please input Admin's PIN"
|
print("Please input Admin's PIN")
|
||||||
card.cmd_verify_pinpad(who)
|
card.cmd_verify_pinpad(who)
|
||||||
if who == BY_USER:
|
if who == BY_USER:
|
||||||
print "Please input New User's PIN twice"
|
print("Please input New User's PIN twice")
|
||||||
else:
|
else:
|
||||||
print "Please input New Admin's PIN twice"
|
print("Please input New Admin's PIN twice")
|
||||||
card.cmd_change_reference_data_pinpad(who, True)
|
card.cmd_change_reference_data_pinpad(who, True)
|
||||||
else:
|
else:
|
||||||
if who == BY_USER:
|
if who == BY_USER:
|
||||||
print "Please input User's PIN"
|
print("Please input User's PIN")
|
||||||
print "and New User's PIN twice"
|
print("and New User's PIN twice")
|
||||||
else:
|
else:
|
||||||
print "Please input Admin's PIN"
|
print("Please input Admin's PIN")
|
||||||
print "and New Admin's PIN twice"
|
print("and New Admin's PIN twice")
|
||||||
card.cmd_change_reference_data_pinpad(who, False)
|
card.cmd_change_reference_data_pinpad(who, False)
|
||||||
elif method == "unblock":
|
elif method == "unblock":
|
||||||
if change_by_two_steps:
|
if change_by_two_steps:
|
||||||
@@ -268,66 +268,66 @@ def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed):
|
|||||||
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
|
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
|
||||||
card.cmd_reset_retry_counter(who,resetcode+newpin)
|
card.cmd_reset_retry_counter(who,resetcode+newpin)
|
||||||
else:
|
else:
|
||||||
print "Please input Admin's PIN"
|
print("Please input Admin's PIN")
|
||||||
card.cmd_verify_pinpad(BY_ADMIN)
|
card.cmd_verify_pinpad(BY_ADMIN)
|
||||||
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
|
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
|
||||||
card.cmd_reset_retry_counter(who,newpin)
|
card.cmd_reset_retry_counter(who,newpin)
|
||||||
else:
|
else:
|
||||||
if who == BY_USER:
|
if who == BY_USER:
|
||||||
print "Please input reset code"
|
print("Please input reset code")
|
||||||
print "and New User's PIN twice"
|
print("and New User's PIN twice")
|
||||||
else:
|
else:
|
||||||
print "Please input Admin's PIN"
|
print("Please input Admin's PIN")
|
||||||
card.cmd_verify_pinpad(BY_ADMIN)
|
card.cmd_verify_pinpad(BY_ADMIN)
|
||||||
print "Please input New User's PIN twice"
|
print("Please input New User's PIN twice")
|
||||||
card.cmd_reset_retry_counter_pinpad(who)
|
card.cmd_reset_retry_counter_pinpad(who)
|
||||||
elif method == "put":
|
elif method == "put":
|
||||||
if change_by_two_steps:
|
if change_by_two_steps:
|
||||||
# It means using keyboard for new PIN
|
# It means using keyboard for new PIN
|
||||||
print "Please input Admin's PIN"
|
print("Please input Admin's PIN")
|
||||||
card.cmd_verify_pinpad(BY_ADMIN)
|
card.cmd_verify_pinpad(BY_ADMIN)
|
||||||
resetcode=s2l(getpass("Please input New Reset Code from keyboard: "))
|
resetcode=s2l(getpass("Please input New Reset Code from keyboard: "))
|
||||||
card.cmd_put_resetcode(resetcode)
|
card.cmd_put_resetcode(resetcode)
|
||||||
else:
|
else:
|
||||||
print "Please input Admin's PIN"
|
print("Please input Admin's PIN")
|
||||||
card.cmd_verify_pinpad(BY_ADMIN)
|
card.cmd_verify_pinpad(BY_ADMIN)
|
||||||
print "Please input New Reset Code twice"
|
print("Please input New Reset Code twice")
|
||||||
card.cmd_put_resetcode_pinpad()
|
card.cmd_put_resetcode_pinpad()
|
||||||
else:
|
else:
|
||||||
raise ValueError, method
|
raise ValueError(method)
|
||||||
card.connection.disconnect()
|
card.connection.disconnect()
|
||||||
|
|
||||||
print "OK."
|
print("OK.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def print_usage():
|
def print_usage():
|
||||||
print "pinpad-test: testing pinentry of PC/SC card reader"
|
print("pinpad-test: testing pinentry of PC/SC card reader")
|
||||||
print " help:"
|
print(" help:")
|
||||||
print "\t--help:\t\tthis message"
|
print("\t--help:\t\tthis message")
|
||||||
print " method:\t\t\t\t\t\t\t[verify]"
|
print(" method:\t\t\t\t\t\t\t[verify]")
|
||||||
print "\t--verify:\tverify PIN"
|
print("\t--verify:\tverify PIN")
|
||||||
print "\t--change:\tchange PIN (old PIN, new PIN twice)"
|
print("\t--change:\tchange PIN (old PIN, new PIN twice)")
|
||||||
print "\t--change2:\tchange PIN by two steps (old PIN, new PIN twice)"
|
print("\t--change2:\tchange PIN by two steps (old PIN, new PIN twice)")
|
||||||
print "\t--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)"
|
print("\t--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)")
|
||||||
print "\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)"
|
print("\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)")
|
||||||
print "\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)"
|
print("\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)")
|
||||||
print "\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)"
|
print("\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)")
|
||||||
print " options:"
|
print(" options:")
|
||||||
print "\t--fixed N:\tUse fixed length input"
|
print("\t--fixed N:\tUse fixed length input")
|
||||||
print "\t--admin:\tby administrator\t\t\t[False]"
|
print("\t--admin:\tby administrator\t\t\t[False]")
|
||||||
print "\t--add:\t\tadd a dummy byte at the end of APDU\t[False]"
|
print("\t--add:\t\tadd a dummy byte at the end of APDU\t[False]")
|
||||||
print "\t--pinmin:\tspecify minimum length of PIN\t\t[6]"
|
print("\t--pinmin:\tspecify minimum length of PIN\t\t[6]")
|
||||||
print "\t--pinmax:\tspecify maximum length of PIN\t\t[15]"
|
print("\t--pinmax:\tspecify maximum length of PIN\t\t[15]")
|
||||||
print "EXAMPLES:"
|
print("EXAMPLES:")
|
||||||
print " $ pinpad-test # verify user's PIN "
|
print(" $ pinpad-test # verify user's PIN ")
|
||||||
print " $ pinpad-test --admin # verify admin's PIN "
|
print(" $ pinpad-test --admin # verify admin's PIN ")
|
||||||
print " $ pinpad-test --change # change user's PIN "
|
print(" $ pinpad-test --change # change user's PIN ")
|
||||||
print " $ pinpad-test --change --admin # change admin's PIN "
|
print(" $ pinpad-test --change --admin # change admin's PIN ")
|
||||||
print " $ pinpad-test --change2 # change user's PIN by two steps"
|
print(" $ pinpad-test --change2 # change user's PIN by two steps")
|
||||||
print " $ pinpad-test --change2 --admin # change admin's PIN by two steps"
|
print(" $ pinpad-test --change2 --admin # change admin's PIN by two steps")
|
||||||
print " $ pinpad-test --unblock # change user's PIN by reset code"
|
print(" $ pinpad-test --unblock # change user's PIN by reset code")
|
||||||
print " $ pinpad-test --unblock --admin # change user's PIN by admin's PIN"
|
print(" $ pinpad-test --unblock --admin # change user's PIN by admin's PIN")
|
||||||
print " $ pinpad-test --put # setup resetcode "
|
print(" $ pinpad-test --put # setup resetcode ")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
who = BY_USER
|
who = BY_USER
|
||||||
@@ -374,7 +374,7 @@ if __name__ == '__main__':
|
|||||||
print_usage()
|
print_usage()
|
||||||
exit(0)
|
exit(0)
|
||||||
else:
|
else:
|
||||||
raise ValueError, option
|
raise ValueError(option)
|
||||||
main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed)
|
main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed)
|
||||||
|
|
||||||
# Failure
|
# Failure
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#! /usr/bin/python
|
#! /usr/bin/python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token
|
upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token
|
||||||
which is just shipped from factory
|
which is just shipped from factory
|
||||||
|
|
||||||
Copyright (C) 2012, 2013, 2015, 2018
|
Copyright (C) 2012, 2013, 2015, 2018, 2021
|
||||||
Free Software Initiative of Japan
|
Free Software Initiative of Japan
|
||||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
@@ -51,7 +51,10 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
|
|||||||
gnuk = get_gnuk_device()
|
gnuk = get_gnuk_device()
|
||||||
gnuk.cmd_select_openpgp()
|
gnuk.cmd_select_openpgp()
|
||||||
# Compute passwd data
|
# Compute passwd data
|
||||||
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tostring()
|
try:
|
||||||
|
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tobytes()
|
||||||
|
except:
|
||||||
|
kdf_data = b""
|
||||||
if kdf_data == b"":
|
if kdf_data == b"":
|
||||||
passwd_data = passwd.encode('UTF-8')
|
passwd_data = passwd.encode('UTF-8')
|
||||||
else:
|
else:
|
||||||
@@ -67,7 +70,7 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
|
|||||||
gnuk.cmd_write_binary(1+keyno, rsa_raw_pubkey, False)
|
gnuk.cmd_write_binary(1+keyno, rsa_raw_pubkey, False)
|
||||||
|
|
||||||
gnuk.cmd_select_openpgp()
|
gnuk.cmd_select_openpgp()
|
||||||
challenge = gnuk.cmd_get_challenge().tostring()
|
challenge = gnuk.cmd_get_challenge().tobytes()
|
||||||
digestinfo = binascii.unhexlify(SHA256_OID_PREFIX) + challenge
|
digestinfo = binascii.unhexlify(SHA256_OID_PREFIX) + challenge
|
||||||
signed = rsa.compute_signature(rsa_key, digestinfo)
|
signed = rsa.compute_signature(rsa_key, digestinfo)
|
||||||
signed_bytes = rsa.integer_to_bytes_256(signed)
|
signed_bytes = rsa.integer_to_bytes_256(signed)
|
||||||
@@ -89,7 +92,7 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
|
|||||||
reg = None
|
reg = None
|
||||||
print("Waiting for device to appear:")
|
print("Waiting for device to appear:")
|
||||||
while reg == None:
|
while reg == None:
|
||||||
print(" Wait %d seconds..." % wait_e)
|
print(" Wait {} second{}...".format(wait_e, 's' if wait_e > 1 else ''))
|
||||||
time.sleep(wait_e)
|
time.sleep(wait_e)
|
||||||
for dev in gnuk_devices_by_vidpid():
|
for dev in gnuk_devices_by_vidpid():
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user