Compare commits

...

102 Commits

Author SHA1 Message Date
NIIBE Yutaka
4af98308e0 Version 1.2.17.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-25 15:46:02 +09:00
NIIBE Yutaka
baec3a1c1e Fix the previous commit. 2021-02-25 14:26:31 +09:00
NIIBE Yutaka
4f1325794d Require KDF Data Object for GNU/Linux emulation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-22 10:52:44 +09:00
NIIBE Yutaka
0acf6485ae Prepare next release.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-19 16:37:08 +09:00
NIIBE Yutaka
4d15700580 Python3 update things.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-19 13:12:48 +09:00
NIIBE Yutaka
8822fcae77 Update AUTHORS.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-19 12:07:15 +09:00
NIIBE Yutaka
20a2f99691 Update Chopstx.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-19 12:07:02 +09:00
NIIBE Yutaka
acfccb729d Add changelog entries.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-18 16:00:13 +09:00
Vincent Pelletier
5283506755 tests/card_reader.py: Ignore CCID devices which report card absence.
Helps running tests on computers which have a "real" card reader in
addition to the ICC to be tested.
2021-02-18 14:42:47 +09:00
Vincent Pelletier
c688df7c2c {tests/card_reader.py,tool/gnuk_token.py}: Extend timeout.
Some devices are slow at generating RSA4096 after a key settings change,
and may take time to notice a later change to a shorter key size.

Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com>
2021-02-18 14:28:32 +09:00
Vincent Pelletier
594896ac57 test/feature/202_setup_passphease.feature: Fix expected PW1 value.
Since 040_passphrase_change.feature, PW1 has this value and not the reset
default.

Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com>
2021-02-18 14:28:27 +09:00
Vincent Pelletier
dfe046e08d tool/gnuk_token.py: Detect CCID bulk endpoints addresses.
Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com>
2021-02-18 14:28:23 +09:00
Vincent Pelletier
c66b01e74b test{,s}/rka_keys.py: Add missing char escape specifiers.
Removes a 2-bytes trailer to the private key template, fitting in the
2-bytes length (which itself lacked an hexadecimal escape specifier, but
without effect on the result).
Fixes the length of the DigestInfo outermost list, from 25 to the intended
49.

Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com>
2021-02-18 14:28:17 +09:00
NIIBE Yutaka
21a46306ae Make GNU/Linux emulation work again, with initialization support.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-18 14:04:21 +09:00
NIIBE Yutaka
e5158572ee Version 1.2.16.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-09-10 11:55:16 +09:00
NIIBE Yutaka
2142d0aa35 Don't use memmove, but use memcpy with dummy memory area.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-09-09 08:55:09 +09:00
NIIBE Yutaka
dd47cf4312 Avoid compiler optimization removing memmove.
Thanks to Szczepan Zalega.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-09-08 09:22:40 +09:00
NIIBE Yutaka
ffbb754fc0 Use an array for _updatekey_store.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-09-07 09:45:28 +09:00
NIIBE Yutaka
d85750d791 Fix use of memcpy to memmove.
memcpy doesn't allow memory areas overlap.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-09-07 09:44:28 +09:00
NIIBE Yutaka
d20e9e9b1e Add 0x00FA data object (Algorithm Information).
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-09-04 13:28:28 +09:00
NIIBE Yutaka
bf30144144 Remove Ed25519 signing condition against EDDSA_HASH_LEN_MAX.
See GnuPG bug report: https://dev.gnupg.org/T5041

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-09-03 10:42:20 +09:00
NIIBE Yutaka
934daf3585 For admin-less mode, make sure the passphrase is long enough.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-08-28 09:53:16 +09:00
NIIBE Yutaka
22420ed1f4 Fix cmd_verify with AC_OTHER_AUTHORIZED for signing key only case.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-08-26 11:24:15 +09:00
NIIBE Yutaka
e97e3b1810 tests: Fix a test for OpenPGP card version 3.3.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-08-26 09:38:41 +09:00
NIIBE Yutaka
49f2544918 Version 1.2.15.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2020-01-24 12:48:49 +09:00
NIIBE Yutaka
d156fc6261 Add ChangeLog. 2020-01-23 15:09:45 +09:00
Bertrand Jacquin
81d6945081 tool: switch to python3
python2 is no longer maintained upstream
2020-01-14 14:07:55 +09:00
NIIBE Yutaka
c3e9db14e8 Update Chopstx to 1.18.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-30 11:03:49 +09:00
NIIBE Yutaka
9180c35420 Fix bn.c. 2019-06-18 11:10:33 +09:00
NIIBE Yutaka
cc0d59cfe6 tests: Power off the reader at the end of test suite. 2019-04-09 10:55:38 +09:00
NIIBE Yutaka
9c1368fdd0 tests: Fix time extension S block responce to TPDU reader. 2019-04-04 15:44:58 +09:00
NIIBE Yutaka
2dd5a76002 tests: Fix timer extension handling. 2019-04-03 17:03:35 +09:00
NIIBE Yutaka
f68ff0bddc tests: Support keygen by OpenPGP card. 2019-04-03 17:02:37 +09:00
NIIBE Yutaka
add3299306 tests: KDF feature is Gnuk only. 2019-04-03 17:01:11 +09:00
NIIBE Yutaka
e28ec2c4c4 tests: Skip Gnuk only tests. 2019-04-03 14:51:32 +09:00
NIIBE Yutaka
1ba05a0f0f tests: factor out tests into classes. 2019-04-03 13:49:55 +09:00
NIIBE Yutaka
2d50795d0a tests: Skip Gnuk only test. 2019-04-03 09:45:06 +09:00
NIIBE Yutaka
fd493562c3 Add OpenPGP card v3.3 card factory reset setup. 2019-04-02 17:29:56 +09:00
NIIBE Yutaka
16c6af215a tests: Use 3.3V for the card. 2019-04-02 13:19:56 +09:00
NIIBE Yutaka
177ef67edf Version 1.2.14. 2019-03-04 11:36:18 +09:00
NIIBE Yutaka
126283b1ac Add count for tool/gnuk_get_random.py. 2019-02-24 15:12:12 +09:00
NIIBE Yutaka
076d727061 Fix timeout initialization at receiving command. 2019-02-24 13:59:59 +09:00
NIIBE Yutaka
41fa424450 Fix for ack button. 2019-02-24 13:04:28 +09:00
NIIBE Yutaka
940332c47f Change for firmware upgrade and ack-button. 2019-02-22 19:53:52 +09:00
NIIBE Yutaka
aedf8267ec Change the constant values for eventflag.
I misunderstood semantics of __builtin_ffs function which prefers
less significant 1-bit.
2019-02-22 14:26:46 +09:00
NIIBE Yutaka
e9d9de3ae2 Implement timeout for the user interaction. 2019-02-22 09:21:11 +09:00
NIIBE Yutaka
fc109fd8af Add GnuPG e.V.'s VID:PID. 2019-02-21 11:39:37 +09:00
NIIBE Yutaka
3d06051a32 Comment in the commit log fix.
In the commit of e760d5b780, I wrote
wrong comment.  The nvic_system_reset function lets MCU go through by
the vectors at 0x08000000.  Thanks to Peter Lebbing to confirm this
fact.
2018-12-31 19:07:33 +09:00
NIIBE Yutaka
b7368e41e9 Version 1.2.13. 2018-12-26 14:14:11 +09:00
NIIBE Yutaka
e760d5b780 Add ChangeLog entry for Peter's changes.
Note that the call of nvic_system_reset from device_initialize_once
uses the old RESET vector.
2018-12-26 14:10:20 +09:00
Peter Lebbing
b57c33c204 Fix make {,dist}clean 2018-12-22 14:42:34 +01:00
Peter Lebbing
ca3312eb25 DFU fix: Copy initial MSP, reset after protect 2018-12-22 14:08:54 +01:00
NIIBE Yutaka
6a1f50abda Add ChangeLog entries for Peter's changes. 2018-12-21 10:30:16 +09:00
Peter Lebbing
66f39c57cd DFU support: overwrite DFU with SYS and protect flash 2018-12-21 10:10:57 +09:00
Peter Lebbing
4b5f93624e Build standalone SYS 2018-12-21 09:57:04 +09:00
Peter Lebbing
0ef687ea4c Add ORIGIN_REAL, emit more configure variables
ORIGIN{,_REAL} is made available to C and USE_DFU is made available to
make.
2018-12-21 09:53:12 +09:00
Peter Lebbing
786b4adc42 Use different ORIGIN for DFU on Maple Mini 2018-12-21 09:49:43 +09:00
NIIBE Yutaka
385261c9a0 Update Chopstx to 1.13. 2018-12-20 14:02:30 +09:00
NIIBE Yutaka
65689199e7 Fix order of EV_* for CCID thread.
Since openpgp thread has lower priority than CCID thread, there is no
case where two consecutive messages EV_EXEC_ACK_REQUIRED and
EV_EXEC_FINISHED are handled simultaneously (openpgp thread needs to
work some time to send EV_EXEC_FINISHED, after sending
EV_EXEC_ACK_REQUIRED).  But just in case, when there are two messages
at once, EV_EXEC_ACK_REQUIRED should been handled before
EV_EXEC_FINISHED.
2018-12-07 08:35:27 +09:00
NIIBE Yutaka
8d15086d06 Really fix the last race condition.
Fixes the commit of fc36773.
2018-12-06 12:09:42 +09:00
NIIBE Yutaka
c17fd5401b Support Ack button for firmware update. 2018-12-05 15:36:16 +09:00
NIIBE Yutaka
56cd4ae7b5 Fix for UIF DO. 2018-12-04 17:22:04 +09:00
NIIBE Yutaka
fc36773c6a Fix hopefully the last race condition for tx_busy handling. 2018-12-01 23:28:19 +09:00
NIIBE Yutaka
7249775c17 Version 1.2.12. 2018-11-25 14:37:09 +09:00
NIIBE Yutaka
980cff0a2f Fix another race condition around ack button and usb communication. 2018-11-21 14:56:56 +09:00
NIIBE Yutaka
8f44f5d3c6 Unique 96-bit looks different on GD32F103.
Depending on MHZ, we change how we get the 96-bits.
2018-11-17 19:01:59 +09:00
NIIBE Yutaka
37a84ed218 Version 1.2.11. 2018-11-12 14:44:18 +09:00
NIIBE Yutaka
6c72147248 Always enable ACKBTN support. 2018-11-12 14:25:22 +09:00
NIIBE Yutaka
3d37003d8c Fix tool/kdf_calc.py. 2018-11-09 20:52:15 +09:00
NIIBE Yutaka
becf8fabc5 Fix synchronous sending. 2018-11-09 20:50:35 +09:00
NIIBE Yutaka
17492287f3 Fix cmd_pso and cmd_internal_authenticate. 2018-11-09 18:57:51 +09:00
NIIBE Yutaka
c800dee95e Sending from Gnuk Token is now synchronous. 2018-11-09 16:38:14 +09:00
NIIBE Yutaka
2c390dc763 Minor fixes for usb-ccid.c. 2018-11-09 15:23:33 +09:00
NIIBE Yutaka
5aee75fd4b Remove unused CCID_STATE_RECEIVE and CCID_STATE_SEND state.
It was used before when Gnuk uses extended APDU exchange (7 years ago).
2018-11-09 12:57:41 +09:00
NIIBE Yutaka
69e8c0f334 It also works with Python3. 2018-10-22 14:26:21 +09:00
NIIBE Yutaka
317cc2036d Fix UIF interaction. 2018-10-12 11:54:41 +09:00
NIIBE Yutaka
312d15c3fa Tweak stack size. 2018-10-02 19:10:56 +09:00
NIIBE Yutaka
d356f1b1e0 doc: Fix by Fabio Utzig for scdaemon. 2018-10-02 13:31:03 +09:00
NIIBE Yutaka
9cb6591491 Update Chopstx to 1.11. 2018-10-02 13:30:51 +09:00
NIIBE Yutaka
ebec8ee156 UI change for LED blink. 2018-10-01 14:36:56 +09:00
NIIBE Yutaka
f810fb83d3 Allow parallel execution waiting ACK. 2018-10-01 14:06:31 +09:00
NIIBE Yutaka
12079974fd Fix UIF DO handling. 2018-09-27 22:29:49 +09:00
NIIBE Yutaka
ca79f5421f Fix rw_uif. 2018-09-27 16:38:07 +09:00
NIIBE Yutaka
c438367d67 Add UIF Data Object support for Acknowledge Button. 2018-09-27 15:02:43 +09:00
NIIBE Yutaka
4c6511231c Blink LED rapidly when asking ACK from user. 2018-09-27 13:16:51 +09:00
NIIBE Yutaka
ba750d153d Fix for ack button driver and configuration. 2018-09-27 11:29:46 +09:00
NIIBE Yutaka
72647f01d0 Remove ack-button.c to use the driver in Chopstx. 2018-09-27 10:46:18 +09:00
NIIBE Yutaka
c6e32a36fb Experimental Ack-button feature added (not yet finished). 2018-09-27 07:30:17 +09:00
NIIBE Yutaka
c3a0eb1439 Doc fix for udev rules (use ATTR instead of ATTRS). 2018-09-26 13:57:42 +09:00
NIIBE Yutaka
030a9c576d Update for new Chopstx API. 2018-09-26 13:24:19 +09:00
NIIBE Yutaka
8a5e0eb783 Fix README about -no-vidpid file name. 2018-08-23 14:30:07 +09:00
NIIBE Yutaka
bce53546e7 Fix for GCC 7. 2018-08-20 16:09:13 +09:00
NIIBE Yutaka
b2b19e1ad4 Add ChangeLog entry. 2018-07-13 16:28:29 +09:00
Szczepan Zalega
58fa773bb7 Fix typo
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2018-07-13 16:24:06 +09:00
Szczepan Zalega
ea88c3da66 Catch exception, when no KDF data is found
While updating from GNUK 1.2.6, upgrade_by_passwd.py script shows
exception about not found referenced data:
  File "./upgrade_by_passwd.py", line 55, in main
    kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tostring()
  File "/home/sz/work/nitrokey-start-firmware/tool/gnuk_token.py", line 320, in cmd_get_data
    raise ValueError("%02x%02x" % (sw[0], sw[1]))
ValueError: 6a88

While it is checked, whether the KDF DO is empty, there is no
exception catch for not found object. This patch adds it.
Tested update paths 1.2.6 -> 1.2.10, 1.2.6 -> 1.2.6, 1.2.10 -> 1.2.10, 1.2.10 -> 1.2.6.

Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2018-07-13 16:23:58 +09:00
NIIBE Yutaka
b905b4802f Version 1.2.10. 2018-05-10 13:54:21 +09:00
NIIBE Yutaka
40f2c6c49e Version 1.2.10. 2018-05-10 13:53:09 +09:00
NIIBE Yutaka
61a7f9602b gnuk.elf is the target with VID:PID. New target gnuk-no-vidpid.elf. 2018-05-10 12:09:19 +09:00
NIIBE Yutaka
5465fda927 Update Chopstx to 1.9. 2018-05-10 12:04:37 +09:00
NIIBE Yutaka
f7c46a6c55 More usb_device_reset fix. 2018-04-26 21:23:44 +09:00
NIIBE Yutaka
4550458806 Fix USB initialization.
After USB RESET, all endpoints registers are being reset.  So,
there is no need to let each endpoint stall (it's disabled).
Actually, it's wrong to call usb_lld_stall_rx or usb_lld_stall_tx
before usb_lld_setup_endpoint, because other fields of endpoint
register are not specified after RESET.
2018-04-26 21:22:36 +09:00
NIIBE Yutaka
93a2bac94b Support GD32F103. 2018-04-26 17:33:48 +09:00
88 changed files with 2499 additions and 1326 deletions

2
.gitignore vendored
View File

@@ -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
View File

@@ -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
View File

@@ -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.

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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

View File

@@ -1 +1 @@
release/1.2.9 release/1.2.17

Submodule chopstx updated: aa63ac79bc...71cc5a8f32

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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;

View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -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
}; };

View File

@@ -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);

View File

@@ -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;

View File

@@ -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));
} }
/** /**

View File

@@ -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);

View File

@@ -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:
{ {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
View 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
}

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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):

View 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

View 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
View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View 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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1 +0,0 @@
test_002_personalize_reset.py

View File

@@ -1 +0,0 @@
test_003_remove_keys.py

View File

@@ -1 +0,0 @@
test_004_reset_pw3.py

View File

@@ -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

View File

@@ -1 +0,0 @@
test_003_remove_keys.py

View File

@@ -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

View File

@@ -1 +0,0 @@
test_001_personalize_card.py

View File

@@ -1 +0,0 @@
test_002_personalize_reset.py

View File

@@ -1 +0,0 @@
test_003_remove_keys.py

View File

@@ -1 +0,0 @@
test_004_reset_pw3.py

View File

@@ -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

View File

@@ -1 +0,0 @@
test_001_personalize_card.py

View File

@@ -1 +0,0 @@
test_002_personalize_reset.py

View File

@@ -1 +0,0 @@
test_003_remove_keys.py

View File

@@ -1 +0,0 @@
test_004_reset_pw3.py

View File

@@ -1 +0,0 @@
test_005_personalize_admin_less.py

View File

@@ -0,0 +1 @@
from test_005_personalize_admin_less import *

View File

@@ -1 +0,0 @@
test_002_personalize_reset.py

View File

@@ -1 +0,0 @@
test_003_remove_keys.py

View File

@@ -1 +0,0 @@
test_004_reset_pw3.py

View File

@@ -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 *

View File

@@ -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:

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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__':

View File

@@ -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
View 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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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):

View File

@@ -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")

View File

@@ -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:

View File

@@ -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):

View File

@@ -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

View File

@@ -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: