Compare commits

...

127 Commits

Author SHA1 Message Date
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
NIIBE Yutaka
24adc09406 Version 1.2.9. 2018-04-05 14:00:50 +09:00
NIIBE Yutaka
bf9fc628b3 More tests for admin-less mode. 2018-04-05 13:06:13 +09:00
NIIBE Yutaka
d76534dd3a Fix admin-less mode -> admin-full mode change. 2018-04-05 12:13:45 +09:00
NIIBE Yutaka
d9c5dcf206 Update ChangeLog. 2018-04-04 19:33:56 +09:00
NIIBE Yutaka
26448d58ee Update copyright year. 2018-04-04 19:29:35 +09:00
NIIBE Yutaka
9cfeb817bd More check for length of PW1. 2018-04-04 19:28:42 +09:00
NIIBE Yutaka
b6534dceba Fix removal of resetting code. 2018-04-04 18:59:28 +09:00
NIIBE Yutaka
b47bd693ba More tests (3). 2018-04-04 17:42:14 +09:00
NIIBE Yutaka
1a7d3a698f More tests (2). 2018-04-04 16:34:51 +09:00
NIIBE Yutaka
f7b03f7fb5 More tests. 2018-04-04 16:34:07 +09:00
NIIBE Yutaka
44971541fe More test suite improvement. Add experimental KDF DO tests. 2018-04-04 15:44:34 +09:00
NIIBE Yutaka
53ed5e0a42 Test suite improvement. 2018-04-04 15:10:52 +09:00
NIIBE Yutaka
63eccda0a1 Add a test case to reset PW3. 2018-04-04 10:51:32 +09:00
NIIBE Yutaka
f430c90715 Rename tests. 2018-04-04 08:48:40 +09:00
NIIBE Yutaka
1f18ec1d63 Clear all keystrings when KDF DO is written. 2018-04-03 20:24:28 +09:00
NIIBE Yutaka
ec7423f493 Fix tool/. 2018-04-03 17:17:51 +09:00
NIIBE Yutaka
e50dda28d1 Support authentication with KDF Data Object. 2018-04-03 17:17:39 +09:00
NIIBE Yutaka
8ad176921f Fix kdf_calc.py. 2018-04-03 17:17:28 +09:00
NIIBE Yutaka
d71b116be8 Add kdf_calc.py. 2018-04-03 17:17:20 +09:00
NIIBE Yutaka
d9d3f35ac3 Fix previous commit. 2018-03-30 17:46:52 +09:00
NIIBE Yutaka
7cc8d8930e Support single-salt KDF for admin-less mode. 2018-03-30 15:57:34 +09:00
NIIBE Yutaka
6446a5bd89 KDF format validation should be done before removing data object. 2018-03-22 16:03:56 +09:00
NIIBE Yutaka
8b0cb8be65 factory-reset should erase all upgrade public keys. 2018-03-13 14:05:18 +09:00
NIIBE Yutaka
c73bb0548e Fix KDF DO handling. 2018-02-13 07:26:29 +09:00
NIIBE Yutaka
40b1d453dc Fix .gitignore. 2018-01-23 13:47:46 +09:00
NIIBE Yutaka
3b965fafc0 Fix README. 2018-01-23 13:26:41 +09:00
NIIBE Yutaka
35edbdc731 Version 1.2.8. 2018-01-23 10:13:13 +09:00
NIIBE Yutaka
d4c776e308 Fix the procedure to put VID:PID. Apply the procedure to regnual. 2018-01-23 10:11:35 +09:00
NIIBE Yutaka
6c0c510347 Update documentation. 2018-01-23 09:31:03 +09:00
NIIBE Yutaka
704d8a5cf1 Check passphrase length when changing. 2018-01-22 11:55:10 +09:00
NIIBE Yutaka
55781cb7bb Remove keystring with BY_ADMIN when it's becomming admin-less mode. 2018-01-22 11:02:02 +09:00
NIIBE Yutaka
de24655920 VIDPID substitution at the last stage of build. 2018-01-19 22:36:01 +09:00
NIIBE Yutaka
7bfe0f5427 Add binary-edit.sh. 2018-01-19 22:22:29 +09:00
NIIBE Yutaka
ec058537ed Update Chopstx to 1.8. 2018-01-19 22:15:21 +09:00
NIIBE Yutaka
abeb1015ec Update neug.c. 2018-01-18 19:42:40 +09:00
NIIBE Yutaka
c5f20dc355 Update Chopstx and follow the changes. 2018-01-18 15:14:34 +09:00
NIIBE Yutaka
4ff0b3c5f8 tests: Fix for card readers. 2018-01-09 09:39:42 +09:00
NIIBE Yutaka
4e517778d0 Update Chopstx to 1.7. 2017-12-19 10:24:28 +09:00
NIIBE Yutaka
c81544fffd Fix long-standing bug of admin-less mode. GnuPG should be fixed. 2017-11-26 21:20:46 +09:00
78 changed files with 3144 additions and 891 deletions

4
.gitignore vendored
View File

@@ -1,16 +1,20 @@
*.lst
*.o
*.pyc
regnual/regnual-no-vidpid.elf
src/.dep
src/config.mk
src/config.h
src/gnuk.ld
src/stdaln-sys.ld
src/board.h
src/build/*
src/*.inc
src/put-vid-pid-ver.sh
regnual/regnual.bin
regnual/regnual.hex
regnual/regnual.elf
doc/_build
tests/.cache
tests/__pycache__
tests/.pytest_cache

View File

@@ -65,3 +65,12 @@ NIIBE Yutaka:
src/usb_lld.h
*
and others.
Peter Lebbing:
Modified:
src/config.h.in
src/configure
src/main.c
src/Makefile
Wrote:
src/stdaln-sys.ld.in

414
ChangeLog
View File

@@ -1,3 +1,417 @@
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>
* VERSION: 1.2.9.
* tests: Add test cases for admin-less mode.
* src/openpgp.c (cmd_change_password): Care admin-less mode.
2018-04-04 NIIBE Yutaka <gniibe@fsij.org>
* tests: Add more tests, key generation and KDF support.
* src/openpgp.c (cmd_reset_user_password): Check length of
new passphrase.
* src/openpgp-do.c (proc_resetting_code): Support removal.
(gpg_do_kdf_check): Fix for the case of resetting PW3.
* tests/test_004_reset_pw3.py: New.
2018-04-03 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Clear all auth state.
* tool/upgrade_by_passwd.py (main): Fix for byte compare.
* tool/gnuk_remove_keys_libusb.py (main): Likewise.
2018-04-02 NIIBE Yutaka <gniibe@fsij.org>
* tool/gnuk_token.py (parse_kdf_data): New.
* tool/kdf_calc.py: New.
* tool/gnuk_remove_keys_libusb.py (main): Support KDF auth.
* tool/upgrade_by_passwd.py (main): Likewise.
2018-03-30 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Support single-salt KDF.
(gpg_do_get_initial_pw_setting): Likewise.
(gpg_do_kdf_check): Likewise.
2018-03-22 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Do format validation earlier.
2018-03-13 NIIBE Yutaka <gniibe@fsij.org>
* src/flash.c [FLASH_UPGRADE_SUPPORT] (flash_terminate): Erase
the page for upgrade public keys.
2018-02-12 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Return 0 when NULL.
2018-01-23 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.8.
* src/Makefile (build/gnuk-vidpid.elf): Supply FILE here.
* src/configure (output_vendor_product_serial_strings): For
generating put-vid-pid-ver.sh, don't set FILE.
* regnual/regnual.c (regnual_device_desc): Make this array as a
template.
* regnual/Makefile (regnual.elf): Substitute VID:PID.
2018-01-22 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (USER_PASSWD_MINLEN): New.
(cmd_change_password): Check passphrase length.
2018-01-22 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_change_password): Remove access to private
key with BY_ADMIN when it's becoming admin-less mode.
2018-01-19 NIIBE Yutaka <gniibe@fsij.org>
* src/binary-edit.sh: Copied from NeuG 1.0.8. Exclude FILE.
* src/configure (output_vid_pid_version): Generate a shell script.
* src/Makefile (build/gnuk-vidpid.elf): New target.
* src/usb_desc.c (device_desc): Make this array as a template.
* chopstx: Update to 1.8.
2018-01-18 NIIBE Yutaka <gniibe@fsij.org>
* src/neug.c: Update from NeuG.
2018-01-09 NIIBE Yutaka <gniibe@fsij.org>
* tests/card_reader.py (CardReader.ccid_power_on): Fix for
other card readers for Gemalto's.
2017-12-19 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.7.
2017-11-26 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_change_password): Bug fix for admin-less
mode.
2017-11-26 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.7.

View File

@@ -2,4 +2,5 @@
0000:0000 0200 Gnuk Emulation Free Software Initiative of Japan
234b:0000 0200 Gnuk Token Free Software Initiative of Japan
20a0:4211 0200 Nitrokey Start Nitrokey
1209:2440 0200 Gnuk Token GnuPG e.V.
##########<TAB> ##<TAB> ##########<TAB> #################

157
NEWS
View File

@@ -1,5 +1,155 @@
Gnuk NEWS - User visible changes
* 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
Released 2018-04-05, by NIIBE Yutaka
** A test suite fix: Clear PW3
Until 1.2.8, after running the test suite under "tests", PW3 keystring
remained, which affects use of admin-less mode. New test case is
added to clear PW3.
** tool/upgrade_by_passwd.py supports KDF-DO auth
With KDF-DO, firmware upgrade didn't work. Now, it's supported.
** Add "single-salt" support for KDF-DO
With KDF-DO, "admin-less" mode didn't work well. With new feature of
"single-salt" support, we can use "admin-less" mode with KDF-DO.
** factory-reset deletes all upgrade public keys
By card-edit/factory-reset by GnuPG, it deletes all upgrade public
keys, now.
* Major changes in Gnuk 1.2.8
Released 2018-01-23, by NIIBE Yutaka
** No inclusion of VID:PID in gnuk.elf
Distribution of binary image with VID:PID would violate vendor ID
agreement to USB Forum. Now, we have new file named gnuk-vidpid.elf
for flashing. The file gnuk.elf can be used to generate
gnuk-vidpid.elf and we can check if it is reproducible or not.
** Passphrase length check
Now, Gnuk checks length of passphrase if it's too short when
changing passphrase.
** Remove unused DEK with BY_ADMIN
For admin-less mode, DEK by OPENPGP_CARD_INITIAL_PW3 remained on flash
ROM. This could be considered a backdoor, if some other person had or
kept access to the flash ROM, cheating a user. Now, the DEK is
cleared by zero when the token is set to admin-less mode.
** Upgrade of Chopstx
We use Chopstx 1.8.
* Major changes in Gnuk 1.2.7
Released 2017-11-26, by NIIBE Yutaka
@@ -803,6 +953,7 @@ Gnuk Token could run with GPG4WIN on MS Windows. GPG4WIN runs with
** This is initial release. Only it supports digital signing.
Local Variables:
mode: outline
End:
# Local Variables:
# mode: outline
# End:

112
README
View File

@@ -1,36 +1,34 @@
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 1.2.7
2017-11-26
Version 1.2.16
2020-09-10
Niibe Yutaka
Free Software Initiative of Japan
Release Notes
=============
This is the release of Gnuk, version 1.2.7, which has major
This is the release of Gnuk, version 1.2.16, which has major
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
overriding key import, but importing keys (or generating keys) results
password reset. Also, you need to import private keys before changing
your password. Please update your documentation for Gnuk Token, so
that the instruction of importing keys won't cause any confusion.
It has supports of EdDSA, ECDSA (with NIST P256 and secp256k1), and
ECDH (with X25519, NIST P256 and secp256k1), but this ECC feature is
somehow experimental, and it requires modern GnuPG 2.2 with libgcrypt
1.7.0 or later.
It has supports of Ed25519 and X25519 (ECDH on Curve25519). It also
has experimental support of ECDSA (on NIST P256 and secp256k1) and
ECDH (on NIST P256 and secp256k1).
It also supports RSA-4096, but users should know that it takes more
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
because the device doesn't have enough memory.
In this release, experimental KDF-DO support is added. To use the
feature, you need to build/install experimental branch of GnuPG by
yourself:
It supports new KDF-DO feature. Please note that this is
experimental. To use the feature, you need to use newer GnuPG (2.2.6
or later). You need to prepare the KDF-DO on your token by the
card-edit/kdf-setup command.
https://dev.gnupg.org/source/gnupg/history/gniibe%252Fscd-kdf-support/
And manually prepare the KDF-DO on your token.
With FST-01SZ, experimental ack button support is available for test.
What's Gnuk?
@@ -38,7 +36,7 @@ What's Gnuk?
Gnuk is an implementation of USB cryptographic token for GNU Privacy
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
been nervous of storing secret key(s) on usual secondary storage.
@@ -55,7 +53,7 @@ FAQ
===
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.yubico.com/
A0: Good points of Gnuk are:
@@ -76,18 +74,16 @@ A1: Gnuk version 1.0 only supports RSA-2048.
Q2: How long does it take for digital signing?
A2: It takes a second and a half or so for RSA-2048.
It takes more than 8 secondd for RSA-4096.
It takes more than 8 seconds for RSA-4096.
Q3: What's your recommendation for target board?
A3: Orthodox choice is Olimex STM32-H103.
FST-01 (Flying Stone Tiny 01) is available for sale, and it is a
kind of the best choice, hopefully.
If you have a skill of electronics, STM32 Nucleo F103 is the best
choice for experiment.
FST-01SZ (Flying Stone Tiny 01 SZ) is available for sale, and it
is a kind of the best choice, hopefully. If you have a skill of
electronics, STM32 Nucleo F103 is the best choice for experiment.
Q4: What's version of GnuPG are you using?
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.18 in
unstable.
A4: In Debian GNU/Linux system, I use GnuPG modern 2.2.23.
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
@@ -148,14 +144,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?
Ad: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
writer program. STM32 Nucleo F103 comes with the valiant of
ST-Link/V2. However, the firmware of ST-Link/V2 is proprietary.
Now, I develop BBG-SWD, SWD debugger by BeagleBone Green.
ST-Link/V2. Note that the firmware of ST-Link/V2 is proprietary.
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
===============
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
* Changing Login name, URL, Name, Sex, Language, etc.
@@ -181,15 +183,6 @@ Original features of Gnuk, tested manually lightly:
* Card holder certificate (write by UPDATE BINARY)
* 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
=======
@@ -201,16 +194,6 @@ DfuSe is for experiment only, because it is impossible for DfuSe to
disable read from flash. For real use, please consider killing DfuSe
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
============================
@@ -221,8 +204,8 @@ If your bash is not installed as /bin/bash, you need to run configure
script prepending 'bash' before './configure'.
Some tools are written in Python. If your Python is not installed as
/usr/bin/python, please prepend 'python' for your command invocation.
Python 2.7 and PyUSB 0.4.3 is assumed.
/usr/bin/python, please prepend 'python' or 'python3' for your command
invocation. I use Python 3.8 and PyUSB 1.0.2.
Source code
@@ -259,7 +242,7 @@ External source code
Gnuk is distributed with external source code.
* chopstx/ -- Chopstx 1.5
* chopstx/ -- Chopstx 1.18
We use Chopstx as the kernel for Gnuk.
@@ -381,10 +364,10 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
On Debian we can install the packages of gcc-arm-none-eabi,
gdb-arm-none-eabi and its friends. I'm using:
binutils-arm-none-eabi 2.28-4+9+b3
gcc-arm-none-eabi 15:6.3.1+svn253039-1
gdb-arm-none-eabi 7.12-6+9+b2
libnewlib-arm-none-eabi 2.4.0.20160527-3
binutils-arm-none-eabi 2.31.1-12+11
gcc-arm-none-eabi 15:7-2018-q2-6
gdb-multiarch 8.2.1-1
libnewlib-arm-none-eabi 3.1.0.20181231-1
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
GNU Toolchain for 'arm-none-eabi' target.
@@ -408,6 +391,12 @@ Then, type:
Then, we will have "gnuk.elf" under src/build directory.
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
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
==============
@@ -436,10 +425,12 @@ OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
-c "program build/gnuk.elf verify reset exit"
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
to flash:
@@ -478,7 +469,7 @@ protect, killing DfuSe and accessing by JTAG debugger is recommended.
This is completely optional.
For this procedure, you need python and pyscard (python-pyscard
package in Debian) or PyUSB 0.4.3 (python-usb package in Debian).
package in Debian) or PyUSB (python-usb package in Debian).
(1) [pyscard] Stop scdaemon
[PyUSB] Stop the pcsc daemon.
@@ -490,7 +481,7 @@ Exception" by "Sharing violation".
In case of PyUSB tool, you need to stop pcscd.
# /etc/init.d/pcscd stop
# systemctl stop pcscd
(2) [Optional] Write fixed serial number
@@ -534,8 +525,8 @@ Type following command to see Gnuk runs:
$ gpg --card-status
Besides, there is a functionality test under test/ directory. See
test/README.
Besides, there is a functionality test under tests/ directory. See
tests/README.
Personalize the Token, import keys, and change the password
@@ -596,14 +587,14 @@ See doc/note/firmware-update.
Git Repositories
================
Please use: https://anonscm.debian.org/cgit/gnuk/gnuk/
Please use: https://salsa.debian.org/gnuk-team/gnuk/
You can get it by:
$ git clone git://anonscm.debian.org/gnuk/gnuk/gnuk.git
$ git clone https://salsa.debian.org/gnuk-team/gnuk/gnuk.git
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:
@@ -621,9 +612,8 @@ Please see the FST-01 support pages:
Please consider to join Gnuk-users mailing list:
https://lists.alioth.debian.org/mailman/listinfo/gnuk-users
https://lists.gnupg.org/mailman/listinfo/gnuk-users
The mailing list will be moved to lists.debian.org.
Your Contributions

2
THANKS
View File

@@ -17,6 +17,7 @@ Bertrand Jacquin bertrand@jacquin.bzh
Clint Adams clint@softwarefreedom.org
Daniel Kahn Gillmor dkg@fifthhorseman.net
Elliott Mitchell
Fabio Utzig utzig@apache.org
Hironobu SUZUKI hironobu@h2np.net
Jan Suhr jan@suhr.info
Jeremy Drake jeremydrake+gnuk@eacceleration.com
@@ -34,6 +35,7 @@ Nico Rikken nico@nicorikken.eu
NOKUBI Takatsugu knok@daionet.gr.jp
Paul Fertser
Paul Bakker polarssl_maintainer@polarssl.org
Peter Lebbing peter@digitalbrains.com
Santiago Ruano Rincón santiago@debian.org
Shane Coughlan scoughlan@openinventionnetwork.com
Stanislas Bach sbach@0g.re

View File

@@ -1 +1 @@
release/1.2.7
release/1.2.16

Submodule chopstx updated: 9e527b0532...cc49f4ef23

View File

@@ -40,11 +40,11 @@ We are using "-O3 -Os" for compiler option.
Building Gnuk
-------------
Change directory to ``src``:
Change directory to ``src``: ::
$ cd gnuk-VERSION/src
Then, run ``configure``:
Then, run ``configure``: ::
$ ./configure --vidpid=<VID:PID>
@@ -52,8 +52,14 @@ Here, you need to specify USB vendor ID and product ID. For FSIJ's,
it's: --vidpid=234b:0000 . Please read the section 'USB vendor ID and
product ID' in README.
Type:
Type: ::
$ make
Then, we will have "gnuk.elf" under src/build directory.
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
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.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"

View File

@@ -54,7 +54,7 @@ setting). It should have lines something like: ::
# Gnuk Token by FSIJ
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"
I have those lines in /etc/udev/rules.d/69-gnuk.rules.
@@ -73,16 +73,21 @@ and make: ::
$ make
Please take care of configure options. The default target in 1.0.x
series is Olimex STM32 H103 (not FST-01). The default target in 1.1.8
series is Olimex STM32 H103 (not FST-01). The default target in 1.2.x
is FST-01.
Then you get build/gnuk.elf.
Then you get build/gnuk.elf and build/gnuk.bin.
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
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) means that you are
using FSIJ's USB ID (for reGNUal in this case). Please note that FSIJ
only allows use of its USB ID for specific situations. Please read
README of Gnuk about that.
Invoking configure with FSIJ's USB ID (234b:0000) and generating
gnuk.elf means that you are using FSIJ's USB ID (for reGNUal in this
case). Please note that FSIJ only allows use of its USB ID for
specific situations. Please read README of Gnuk about that.
Bulding reGNUal
@@ -122,8 +127,8 @@ How to run the script: ::
Then, the script on your host PC invoke the steps described above, and
you will get new version of Gnuk installed.
You can also specify -p option to enter your password (other than
factory setting).
You can also specify -f option to skip entering your password (it
assumes the factory setting).
If you already have configured another upgrade key installed, you can
specify different slot by -k ``<slot_no>`` option. SLOT_NO can be 0

View File

@@ -30,9 +30,9 @@ command.
Or, you can use ``gpgconf`` command. Type::
$ gpgconf --reload scdameon
$ gpgconf --reload scdaemon
will do the samething.
will do the same thing.
Let GPG-AGENT/SCDAEMON learn

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).
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"
Usually, udev daemon automatically handles for the changes of configuration

View File

@@ -1,6 +1,6 @@
# Makefile for reGNUal
PROJECT = regnual
PROJECT = regnual-no-vidpid
OBJS = regnual.o usb-stm32f103.o reset.o
@@ -41,13 +41,18 @@ regnual.hex: regnual.elf
$(OBJCOPY) -Obinary regnual.elf regnual.bin
$(OBJCOPY) -Oihex regnual.elf regnual.hex
regnual.elf: regnual-no-vidpid.elf
cp -p regnual-no-vidpid.elf regnual.elf
env FILE="regnual.elf" PATH="../src:$$PATH" bash put-vid-pid-ver.sh
usb-stm32f103.o: ../chopstx/mcu/usb-stm32f103.c
$(CC) $(CFLAGS) -c -o usb-stm32f103.o ../chopstx/mcu/usb-stm32f103.c
regnual.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS)
regnual-no-vidpid.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(LDFLAGS) -o regnual-no-vidpid.elf $(OBJS)
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

View File

@@ -1,7 +1,7 @@
/*
* regnual.c -- Firmware installation for STM32F103 Flash ROM
*
* Copyright (C) 2012, 2013, 2015, 2016, 2017
* Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -57,7 +57,9 @@ static const uint8_t regnual_device_desc[] = {
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */
#include "../src/usb-vid-pid-ver.c.inc"
0x00, 0x00, /* idVendor (will be replaced) */
0x00, 0x00, /* idProduct (will be replaced) */
0x00, 0x00, /* bcdDevice (will be replaced) */
1, /* Index of string descriptor describing manufacturer */
2, /* Index of string descriptor describing product */
3, /* Index of string descriptor describing the device's serial number */

View File

@@ -53,6 +53,10 @@ ifeq ($(CHIP),stm32f103)
CSRC += mcu-stm32f103.c
endif
ifneq ($(USE_DFU),)
OBJS_ADD += build/stdaln-sys-bin.o
endif
###################################
CC = $(CROSS)gcc
LD = $(CROSS)gcc
@@ -72,11 +76,27 @@ sys.c: board.h
build/bignum.o: OPT = -O3 -g
distclean: clean
-rm -f gnuk.ld config.h board.h config.mk \
usb-strings.c.inc usb-vid-pid-ver.c.inc
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 $@
ifneq ($(EMULATION),)
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
-rm -f gnuk.ld stdaln-sys.ld config.h board.h config.mk \
usb-strings.c.inc put-vid-pid-ver.sh
ifeq ($(EMULATION),)
build/gnuk.elf: build/gnuk-no-vidpid.elf binary-edit.sh put-vid-pid-ver.sh
cp -p build/gnuk-no-vidpid.elf build/gnuk.elf
env FILE="build/gnuk.elf" bash put-vid-pid-ver.sh
$(OBJCOPY) -O ihex build/gnuk.elf build/gnuk.hex
$(OBJCOPY) -O binary build/gnuk.elf build/gnuk.bin
else
# By specifying DESTDIR on invocation of "make", you can install
# 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)
{
int pw_len;
int r1, r2;
int r;
uint8_t keystring[KEYSTRING_MD_SIZE];
const uint8_t *salt;
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);
if (access == AC_PSO_CDS_AUTHORIZED)
{
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
r2 = 0;
}
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
else
{
int r1, r2;
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, 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
|| (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)))
if (r < 0)
{
failure:
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)
{
int pw_len;
int r1, r2;
int r;
uint8_t keystring[KEYSTRING_MD_SIZE];
const uint8_t *salt;
int salt_len;
@@ -179,12 +189,11 @@ verify_admin_00 (const uint8_t *pw, int buf_len, int pw_len_known,
if (save_ks)
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring);
r2 = 0;
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring);
if (r1 < 0 || r2 < 0)
if (r < 0)
return -1;
else if (r1 == 0 && r2 == 0)
else if (r == 0)
if ((ks[0] & PW_LEN_KEYSTRING_BIT) == 0
|| memcmp (KS_GET_KEYSTRING (ks), keystring, KEYSTRING_MD_SIZE) != 0)
return -1;

76
src/binary-edit.sh Normal file
View File

@@ -0,0 +1,76 @@
# This is a Bash script to be included.
# Idx Name Size VMA LMA File off Algn
# =================
# 2 .text 00004a40 080010f0 080010f0 000110f0 2**4
# 08006550 l O .text 00000012 device_desc
# =================
# VMA =0x080010f0
# FOFF=0x000110f0
# ADDR=0x08005ad0
# file_off_ADDR = ADDR - VMA + FOFF
# = 0x08005ad0 - 0x080010f0 + 0x000110f0 = 0x00015ad0
function calc_addr () {
local line_sym="" VMA FOFF ADDR
arm-none-eabi-objdump -h -t -j .text $FILE | \
egrep -e '(^ +[0-9] +\.text +|device_desc)' | \
while read -r F0 F1 F2 F3 F4 F5 F6; do
if [ -z "$line_sym" ]; then
VMA=$F3
FOFF=$F5
line_sym="next is a line for the symbol"
else
ADDR=$F0
echo "$((0x$ADDR - 0x$VMA + 0x$FOFF))"
fi
done
}
declare -a OFFSETS
OFFSETS=($(calc_addr))
file_off_ADDR=${OFFSETS[0]}
file_off_fraucheky_ADDR=${OFFSETS[1]}
echo "Offset is $file_off_ADDR"
if [ -n "$file_off_fraucheky_ADDR" ]; then
echo "Offset is $file_off_fraucheky_ADDR"
fi
function replace_file_byte_at () {
printf "\x$1" | dd of=$FILE bs=1 seek=$2 conv=notrunc >& /dev/null
}
#
# vid_lsb: 8
# vid_msb: 9
# pid_lsb: 10
# pid_msb: 11
# bcd_device_lsb: 12
# bcd_device_msb: 13
#
function replace_vid_lsb () {
replace_file_byte_at $1 $((addr + 8))
}
function replace_vid_msb () {
replace_file_byte_at $1 $((addr + 9))
}
function replace_pid_lsb () {
replace_file_byte_at $1 $((addr + 10))
}
function replace_pid_msb () {
replace_file_byte_at $1 $((addr + 11))
}
function replace_bcd_device_lsb () {
replace_file_byte_at $1 $((addr + 12))
}
function replace_bcd_device_msb () {
replace_file_byte_at $1 $((addr + 13))
}

View File

@@ -1,7 +1,8 @@
/*
* 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>
*
* 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
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];
random_bytes_free (rand);
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);
}
}
#endif

View File

@@ -3,9 +3,12 @@
#define ENABLE_VIRTUAL_COM_PORT 1
#endif
@DFU_DEFINE@
@ORIGIN_DEFINE@
@ORIGIN_REAL_DEFINE@
@PINPAD_DEFINE@
@PINPAD_MORE_DEFINE@
@CERTDO_DEFINE@
@HID_CARD_CHANGE_DEFINE@
@SERIALNO_STR_LEN_DEFINE@
@LIFE_CYCLE_MANAGEMENT_DEFINE@
@ACKBTN_DEFINE@
@SERIALNO_STR_LEN_DEFINE@

88
src/configure vendored
View File

@@ -6,7 +6,7 @@ nl=$'\n'
#
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
# Free Software Initiative of Japan
#
# This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -44,6 +44,7 @@ pinpad=no
certdo=no
hid_card_change=no
factory_reset=no
ackbtn_support=yes
flash_override=""
# For emulation
prefix=/usr/local
@@ -135,6 +136,7 @@ Configuration:
supported targets are:
FST_01
FST_01G
FST_01SZ
OLIMEX_STM32_H103
MAPLE_MINI
ST_DONGLE
@@ -167,6 +169,8 @@ BOARD_HEADER_FILE=board-$(echo $target | tr '_[:upper:]' '-[:lower:]').h
echo "Header file is: $BOARD_HEADER_FILE"
ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h
# Frequency
MHZ=72
# Flash page size in byte
FLASH_PAGE_SIZE=1024
# Flash memory size in KiB
@@ -196,6 +200,12 @@ STBEE)
if test "$with_dfu" = "default"; then
with_dfu=yes;
fi ;;
BLUE_PILL_G)
MHZ=96
;;
FST_01SZ)
MHZ=96
;;
*)
;;
esac
@@ -208,6 +218,7 @@ if test "$target" = "GNU_LINUX"; then
mcu="none"
def_emulation="-DGNU_LINUX_EMULATION"
def_memory_size="-DMEMORY_SIZE=1024"
def_mhz=""
enable_hexoutput=""
libs="-lpthread"
else
@@ -218,6 +229,7 @@ else
mcu="cortex-m3"
def_emulation=""
def_memory_size="-DMEMORY_SIZE=$MEMORY_SIZE"
def_mhz="-DMHZ=$MHZ"
enable_hexoutput=yes
libs=""
fi
@@ -248,6 +260,8 @@ else
echo "Debug option disabled"
fi
ORIGIN_REAL=0x08000000
ORIGIN_REAL_DEFINE="#define ORIGIN_REAL $ORIGIN_REAL"
# --with-dfu option
if test "$with_dfu" = "yes"; then
if test "$target" = "FST_01" -o "$target" = "FST_01G" \
@@ -256,15 +270,23 @@ if test "$with_dfu" = "yes"; then
exit 1
fi
echo "Configured for DFU"
ORIGIN=0x08003000
FLASH_SIZE=$((FLASH_SIZE - 12))
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
FLASH_SIZE=$((FLASH_SIZE - 12))
fi
DFU_DEFINE="#define DFU_SUPPORT 1"
else
with_dfu=no
echo "Configured for bare system (no-DFU)"
ORIGIN=0x08000000
ORIGIN=${ORIGIN_REAL}
DFU_DEFINE="#undef DFU_SUPPORT"
fi
ORIGIN_DEFINE="#define ORIGIN $ORIGIN"
# --enable-pinpad option
if test "$pinpad" = "no"; then
@@ -306,6 +328,15 @@ else
echo "Life cycle management is NOT supported"
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
### !!! Replace following string of "FSIJ" to yours !!! ####
SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
@@ -327,8 +358,32 @@ else
fi
output_vid_pid_version () {
echo "$VIDPID" | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\\${nl} 0x\4, 0x\3, /* idProduct */%p"
echo "$VERSION" | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
echo "$VIDPID" | \
sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$%\1\t\2\t\3\t\4%p" | \
while read -r FIRST SECOND THIRD FOURTH; do
if test $FIRST != 00; then
echo replace_vid_msb $FIRST
fi
if test $SECOND != 00; then
echo replace_vid_lsb $SECOND
fi
if test $THIRD != 00; then
echo replace_pid_msb $THIRD
fi
if test $FOURTH != 00; then
echo replace_pid_lsb $FOURTH
fi
done
echo "$VERSION" | \
sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$%\1\t\2%p" | \
while read -r FIRST SECOND; do
if test $FIRST != 00; then
echo replace_bcd_device_msb $FIRST
fi
if test $SECOND != 00; then
echo replace_bcd_device_lsb $SECOND
fi
done
}
output_vendor_product_serial_strings () {
@@ -382,10 +437,16 @@ output_vendor_product_serial_strings () {
fi
}
(echo "#! /bin/bash"
echo
echo 'source "binary-edit.sh"') > put-vid-pid-ver.sh
if !(IFS=" "
while read -r VIDPID VERSION PRODUCT VENDOR; do
if test "$vidpid" = "$VIDPID"; then
output_vid_pid_version > usb-vid-pid-ver.c.inc
echo >> put-vid-pid-ver.sh
echo 'addr=$file_off_ADDR' >> put-vid-pid-ver.sh
output_vid_pid_version >> put-vid-pid-ver.sh
output_vendor_product_serial_strings gnuk_ >usb-strings.c.inc
exit 0
fi
@@ -412,13 +473,19 @@ fi
echo "EMULATION=$emulation";
echo "CROSS=$cross";
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 "LIBS=$libs";
echo "$DEBUG_MAKE_OPTION";
echo "$PINPAD_MAKE_OPTION";
echo "ENABLE_FRAUCHEKY=$enable_fraucheky";
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
echo "prefix=$prefix"
echo "exec_prefix=$exec_prefix"
@@ -439,13 +506,18 @@ else
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
< gnuk.ld.in > gnuk.ld
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/" \
-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_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
-e "s/@ACKBTN_DEFINE@/$ACKBTN_DEFINE/" \
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
< config.h.in > config.h
exit 0

View File

@@ -1,7 +1,7 @@
/*
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -71,7 +71,7 @@ static const uint8_t *data_pool;
static uint8_t *last_p;
/* The first halfword is generation for the data page (little endian) */
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
0x00, 0x00, 0xff, 0xff
};
@@ -157,6 +157,12 @@ flash_terminate (void)
{
int i;
#ifdef FLASH_UPGRADE_SUPPORT
const uint8_t *p;
p = gpg_get_firmware_update_key (0);
flash_erase_page ((uintptr_t)p);
#endif
for (i = 0; i < 3; i++)
flash_erase_page ((uintptr_t)flash_key_getpage (i));
flash_erase_page ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START);

View File

@@ -24,17 +24,18 @@ extern struct apdu apdu;
void ccid_card_change_signal (int how);
/* CCID thread */
#define EV_RX_DATA_READY 1 /* USB Rx data available */
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */
#define EV_TX_FINISHED 4 /* CCID Tx finished */
#define EV_CARD_CHANGE 8
#define EV_CARD_CHANGE 1
#define EV_TX_FINISHED 2 /* CCID Tx finished */
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
#define EV_RX_DATA_READY 16 /* USB Rx data available */
/* OpenPGPcard thread */
#define EV_PINPAD_INPUT_DONE 1
#define EV_EXIT 2
#define EV_MODIFY_CMD_AVAILABLE 1
#define EV_VERIFY_CMD_AVAILABLE 2
#define EV_CMD_AVAILABLE 4
#define EV_VERIFY_CMD_AVAILABLE 8
#define EV_MODIFY_CMD_AVAILABLE 16
#define EV_EXIT 8
#define EV_PINPAD_INPUT_DONE 16
/* 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 */
@@ -53,17 +54,17 @@ enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
/* Busy1, Busy2, Busy3, Busy5 */
CCID_STATE_EXECUTE, /* Busy4 */
CCID_STATE_RECEIVE, /* APDU Received Partially */
CCID_STATE_SEND, /* APDU Sent Partially */
CCID_STATE_EXITED, /* ICC Thread Terminated */
CCID_STATE_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 */
};
extern enum ccid_state *const ccid_state_p;
enum ccid_state ccid_get_ccid_state (void);
extern volatile uint8_t auth_status;
#define AC_NONE_AUTHORIZED 0x00
@@ -123,8 +124,8 @@ const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
enum kind_of_key {
GPG_KEY_FOR_SIGNING = 0,
GPG_KEY_FOR_DECRYPTION,
GPG_KEY_FOR_AUTHENTICATION,
GPG_KEY_FOR_DECRYPTION = 1,
GPG_KEY_FOR_AUTHENTICATION = 2,
};
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,
const uint8_t **r_p);
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));
@@ -378,7 +380,17 @@ extern uint8_t admin_authorized;
#define NR_KEY_ALGO_ATTR_DEC 0xf2
#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). */
/*
@@ -434,6 +446,7 @@ extern const uint8_t gnuk_string_serial[];
#define LED_GNUK_EXEC 32
#define LED_START_COMMAND 64
#define LED_FINISH_COMMAND 128
#define LED_WAIT_FOR_BUTTON 256
#define LED_OFF LED_FINISH_COMMAND
void led_blink (int spec);
@@ -461,6 +474,7 @@ int pinpad_getline (int msg_code, uint32_t timeout_usec);
#endif
extern uint8_t _regnual_start, __heap_end__[];
uint8_t * sram_address (uint32_t offset);

View File

@@ -1,7 +1,7 @@
/*
* 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
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -40,8 +40,6 @@
#include <stdlib.h>
#define main emulated_main
#else
#include "mcu/cortex-m.h"
#include "mcu/stm32.h"
#include "mcu/stm32f103.h"
#endif
@@ -53,6 +51,28 @@
#define LED_TIMEOUT_ONE (100*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
uint8_t *flash_addr_key_storage_start;
@@ -70,7 +90,7 @@ device_initialize_once (void)
* This is the first time invocation.
* 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;
for (i = 0; i < 4; i++)
@@ -85,6 +105,55 @@ device_initialize_once (void)
nibble += (nibble >= 10 ? ('A' - 10) : '0');
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
@@ -148,7 +217,7 @@ emit_led (uint32_t on_time, uint32_t off_time)
static 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;
if (ccid_state == CCID_STATE_START)
@@ -172,8 +241,7 @@ display_status_code (void)
{
usec = LED_TIMEOUT_INTERVAL;
chopstx_poll (&usec, 1, led_event_poll);
emit_led (ccid_state == CCID_STATE_RECEIVE?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
}
}
}
@@ -240,6 +308,7 @@ main (int argc, const char *argv[])
uintptr_t entry;
#endif
chopstx_t ccid_thd;
int wait_for_ack = 0;
chopstx_conf_idle (1);
@@ -356,7 +425,11 @@ main (int argc, const char *argv[])
{
eventmask_t m;
m = eventflag_wait (&led_event);
if (wait_for_ack)
m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL);
else
m = eventflag_wait (&led_event);
switch (m)
{
case LED_ONESHOT:
@@ -377,8 +450,11 @@ main (int argc, const char *argv[])
break;
case LED_GNUK_EXEC:
goto exec;
case LED_WAIT_FOR_BUTTON:
wait_for_ack ^= 1;
/* fall through */
default:
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_ZERO);
break;
}
}
@@ -397,26 +473,10 @@ main (int argc, const char *argv[])
SCB->VTOR = (uintptr_t)&_regnual_start;
entry = calculate_regnual_entry_address (&_regnual_start);
#ifdef DFU_SUPPORT
#define FLASH_SYS_START_ADDR 0x08000000
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
{
extern uint8_t _sys;
uintptr_t addr;
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
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);
/* Use SYS at ORIGIN_REAL instead of the one at ORIGIN */
handler *new_vector = (handler *)ORIGIN_REAL;
void (*func) (void (*)(void)) = (void (*)(void (*)(void))) new_vector[9];
/* Leave Gnuk to exec reGNUal */
(*func) ((void (*)(void))entry);

View File

@@ -23,7 +23,6 @@
*/
#include <stdint.h>
#include "mcu/stm32.h"
#include "mcu/stm32f103.h"
uint8_t *

View File

@@ -1,7 +1,7 @@
/*
* 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>
*
* 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;
bn256 tmp[1];
bn256 dummy[1];
cond = (bn256_add (X, A, B) == 0);
cond &= bn256_sub (tmp, X, P256K1);
if (cond)
/* No-carry AND borrow */
memcpy (tmp, tmp, sizeof (bn256));
else
memcpy (X, tmp, sizeof (bn256));
memcpy (cond?dummy:X, tmp, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
}
/**
@@ -89,13 +87,12 @@ modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
bn256 dummy[1];
borrow = bn256_sub (X, A, B);
bn256_add (tmp, X, P256K1);
if (borrow)
memcpy (X, tmp, sizeof (bn256));
else
memcpy (tmp, tmp, sizeof (bn256));
memcpy (borrow?X:dummy, tmp, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
}
/**

View File

@@ -1,7 +1,7 @@
/*
* modp256r1.c -- modulo arithmetic for p256r1
*
* Copyright (C) 2011, 2013, 2014, 2016
* Copyright (C) 2011, 2013, 2014, 2016, 2020
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -66,14 +66,12 @@ modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t cond;
bn256 tmp[1];
bn256 dummy[1];
cond = (bn256_add (X, A, B) == 0);
cond &= bn256_sub (tmp, X, P256R1);
if (cond)
/* No-carry AND borrow */
memcpy (tmp, tmp, sizeof (bn256));
else
memcpy (X, tmp, sizeof (bn256));
memcpy (cond?dummy:X, tmp, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
}
/**
@@ -84,13 +82,12 @@ modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
bn256 dummy[1];
borrow = bn256_sub (X, A, B);
bn256_add (tmp, X, P256R1);
if (borrow)
memcpy (X, tmp, sizeof (bn256));
else
memcpy (tmp, tmp, sizeof (bn256));
memcpy (borrow?X:dummy, tmp, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
}
/**
@@ -100,6 +97,7 @@ void
modp256r1_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1], tmp0[1];
bn256 dummy[1];
uint32_t borrow;
#define S1 X
@@ -121,10 +119,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
S1->word[1] = A->word[1];
S1->word[0] = A->word[0];
borrow = bn256_sub (tmp0, S1, P256R1);
if (borrow)
memcpy (tmp0, tmp0, sizeof (bn256));
else
memcpy (S1, tmp0, sizeof (bn256));
memcpy (borrow?dummy:S1, tmp0, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
/* X = S1 */
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[0] = A->word[9];
borrow = bn256_sub (tmp0, S5, P256R1);
if (borrow)
memcpy (tmp0, tmp0, sizeof (bn256));
else
memcpy (S5, tmp0, sizeof (bn256));
memcpy (borrow?dummy:S5, tmp0, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
/* 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[0] = A->word[11];
borrow = bn256_sub (tmp0, S6, P256R1);
if (borrow)
memcpy (tmp0, tmp0, sizeof (bn256));
else
memcpy (S6, tmp0, sizeof (bn256));
memcpy (borrow?dummy:S6, tmp0, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
/* 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[0] = A->word[12];
borrow = bn256_sub (tmp0, S7, P256R1);
if (borrow)
memcpy (tmp0, tmp0, sizeof (bn256));
else
memcpy (S7, tmp0, sizeof (bn256));
memcpy (borrow?dummy:S7, tmp0, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
/* X -= S7 */
modp256r1_sub (X, X, S7);

View File

@@ -1,7 +1,7 @@
/*
* neug.c - true random number generation
*
* Copyright (C) 2011, 2012, 2013, 2016, 2017
* Copyright (C) 2011, 2012, 2013, 2016, 2017, 2018
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -30,7 +30,6 @@
#include "sys.h"
#include "neug.h"
#ifndef GNU_LINUX_EMULATION
#include "mcu/stm32.h"
#include "mcu/stm32f103.h"
#endif
#include "adc.h"
@@ -116,6 +115,11 @@ rbit (uint32_t v)
v = ( v >> 16 ) | ( v << 16);
return v;
}
void
crc32_rv_stop (void)
{
}
#else
void
crc32_rv_reset (void)

View File

@@ -1,7 +1,8 @@
/*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
* 2020
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -135,6 +136,14 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
0x01, 0x00,
};
#ifdef ACKBTN_SUPPORT
/* General Feature Management */
static const uint8_t feature_mngmnt[] __attribute__ ((aligned (1))) = {
3,
0x81, 0x01, 0x20,
};
#endif
/* Algorithm Attributes */
#define OPENPGP_ALGO_RSA 0x01
#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_AUT 0x00d8
#define GPG_DO_KDF 0x00f9
#define GPG_DO_ALG_INFO 0x00fa
#define GPG_DO_KEY_IMPORT 0x3fff
#define GPG_DO_LANGUAGE 0x5f2d
#define GPG_DO_SEX 0x5f35
@@ -524,7 +534,7 @@ copy_tag (uint16_t tag)
#define SIZE_FP 20
#define SIZE_KGTIME 4
static int
static void
do_fp_all (uint16_t tag, int with_tag)
{
const uint8_t *data;
@@ -555,10 +565,9 @@ do_fp_all (uint16_t tag, int with_tag)
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
return 1;
}
static int
static void
do_cafp_all (uint16_t tag, int with_tag)
{
const uint8_t *data;
@@ -589,10 +598,9 @@ do_cafp_all (uint16_t tag, int with_tag)
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
return 1;
}
static int
static void
do_kgtime_all (uint16_t tag, int with_tag)
{
const uint8_t *data;
@@ -623,7 +631,6 @@ do_kgtime_all (uint16_t tag, int with_tag)
else
memset (res_p, 0, SIZE_KGTIME);
res_p += SIZE_KGTIME;
return 1;
}
const uint8_t openpgpcard_aid[] = {
@@ -635,7 +642,7 @@ const uint8_t openpgpcard_aid[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
};
static int
static void
do_openpgpcard_aid (uint16_t tag, int with_tag)
{
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)
{
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);
res_p += 8;
@@ -671,11 +678,9 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
*res_p++ = 0;
*res_p++ = 0;
return 1;
}
static int
static void
do_ds_count (uint16_t tag, int 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 >> 8) & 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
@@ -807,7 +842,66 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
}
}
#define SIZE_OF_KDF_DO 110
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_MAX 110
#define OPENPGP_KDF_ITERSALTED_S2K 3
#define OPENPGP_SHA256 8
@@ -826,32 +920,55 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
|| do_ptr[NR_DO_PRVKEY_AUT])
return 0;
/* The valid data format is:
Deleting:
nothing
Minimum (for admin-less):
81 01 03 = KDF_ITERSALTED_S2K
82 01 08 = SHA256
83 04 4-byte... = count
84 08 8-byte... = salt
87 20 32-byte user hash
88 20 32-byte admin hash
Full:
81 01 03 = KDF_ITERSALTED_S2K
82 01 08 = SHA256
83 04 4-byte... = count
84 08 8-byte... = salt user
85 08 8-byte... = salt reset-code
86 08 8-byte... = salt admin
87 20 32-byte user hash
88 20 32-byte admin hash
*/
if (!(len == 0
|| (len == SIZE_OF_KDF_DO_MIN &&
(data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
&& data[12] == 0x84 && data[22] == 0x87 && data[56] == 0x88))
|| (len == SIZE_OF_KDF_DO_MAX &&
(data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
&& data[12] == 0x84 && data[22] == 0x85 && data[32] == 0x86
&& data[42] == 0x87 && data[76] == 0x88))))
return 0;
if (*do_data_p)
flash_do_release (*do_data_p);
/* Clear all keystrings and auth states */
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
gpg_do_write_simple (NR_DO_KEYSTRING_PW3, NULL, 0);
ac_reset_admin ();
ac_reset_pso_cds ();
ac_reset_other ();
if (len == 0)
{
*do_data_p = NULL;
return 1;
}
else if (len != SIZE_OF_KDF_DO ||
!(data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
&& data[12] == 0x84 && data[22] == 0x85 && data[32] == 0x86
&& data[42] == 0x87 && data[76] == 0x88))
/* Format validation failed. The valid format is:
81 01 03 = KDF_ITERSALTED_S2K
82 01 08 = SHA256
83 04 4-byte... = count
84 08 8-byte... = salt user
85 08 8-byte... = salt reset-code
86 08 8-byte... = salt admin
87 20 32-byte user hash
88 20 32-byte admin hash
*/
return 0;
else
{
*do_data_p = flash_do_write (NR_DO_KDF, data, SIZE_OF_KDF_DO);
*do_data_p = flash_do_write (NR_DO_KDF, data, len);
if (*do_data_p)
return 1;
else
@@ -860,7 +977,11 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
}
else
{
copy_do_1 (tag, do_ptr[NR_DO_KDF], with_tag);
if (do_ptr[NR_DO_KDF])
copy_do_1 (tag, do_ptr[NR_DO_KDF], with_tag);
else
return 0;
return 1;
}
}
@@ -868,10 +989,22 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
int
gpg_do_kdf_check (int len, int how_many)
{
const uint8_t *kdf_spec = gpg_do_read_simple (NR_DO_KDF);
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
if (kdf_spec && (kdf_spec[43] * how_many) != len)
return 0;
if (kdf_do)
{
const uint8_t *kdf_spec = kdf_do+1;
int kdf_do_len = kdf_do[0];
int hash_len;
if (kdf_do_len == SIZE_OF_KDF_DO_MIN)
hash_len = kdf_spec[23];
else
hash_len = kdf_spec[43];
if ((hash_len * how_many) != len && hash_len != len)
return 0;
}
return 1;
}
@@ -879,15 +1012,29 @@ gpg_do_kdf_check (int len, int how_many)
void
gpg_do_get_initial_pw_setting (int is_pw3, int *r_len, const uint8_t **r_p)
{
const uint8_t *kdf_spec = gpg_do_read_simple (NR_DO_KDF);
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
if (kdf_spec)
if (kdf_do)
{
int len = kdf_do[0];
const uint8_t *kdf_spec = kdf_do+1;
*r_len = 32;
if (is_pw3)
*r_p = kdf_spec + 78;
if (len == SIZE_OF_KDF_DO_MIN)
{
if (is_pw3)
*r_p = kdf_spec + 58;
else
*r_p = kdf_spec + 24;
}
else
*r_p = kdf_spec + 44;
{
if (is_pw3)
*r_p = kdf_spec + 78;
else
*r_p = kdf_spec + 44;
}
}
else
{
@@ -917,34 +1064,45 @@ proc_resetting_code (const uint8_t *data, int len)
DEBUG_INFO ("Resetting Code!\r\n");
if (gpg_do_kdf_check (len, 1) == 0)
return 0;
if (len == 0)
{ /* Removal of resetting code. */
enum kind_of_key kk0;
newpw_len = len;
newpw = data;
new_ks0[0] = newpw_len;
random_get_salt (salt);
s2k (salt, SALT_SIZE, newpw, newpw_len, new_ks);
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
if (r <= -2)
{
DEBUG_INFO ("memory error.\r\n");
return 0;
}
else if (r < 0)
{
DEBUG_INFO ("security error.\r\n");
return 0;
}
else if (r == 0)
{
DEBUG_INFO ("error (no prvkey).\r\n");
return 0;
for (kk0 = 0; kk0 <= GPG_KEY_FOR_AUTHENTICATION; kk0++)
gpg_do_chks_prvkey (kk0, BY_RESETCODE, NULL, 0, NULL);
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
}
else
{
DEBUG_INFO ("done.\r\n");
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KS_META_SIZE);
if (gpg_do_kdf_check (len, 1) == 0)
return 0;
newpw_len = len;
newpw = data;
new_ks0[0] = newpw_len;
random_get_salt (salt);
s2k (salt, SALT_SIZE, newpw, newpw_len, new_ks);
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
if (r <= -2)
{
DEBUG_INFO ("memory error.\r\n");
return 0;
}
else if (r < 0)
{
DEBUG_INFO ("security error.\r\n");
return 0;
}
else if (r == 0)
{
DEBUG_INFO ("error (no prvkey).\r\n");
return 0;
}
else
{
DEBUG_INFO ("done.\r\n");
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KS_META_SIZE);
}
}
gpg_pw_reset_err_counter (PW_ERR_RC);
@@ -1549,18 +1707,32 @@ static const uint16_t cmp_ch_data[] = {
};
static const uint16_t cmp_app_data[] = {
#ifdef ACKBTN_SUPPORT
4,
#else
3,
#endif
GPG_DO_AID,
GPG_DO_HIST_BYTES,
GPG_DO_DISCRETIONARY,
#ifdef ACKBTN_SUPPORT
GPG_DO_FEATURE_MNGMNT,
#endif
};
static const uint16_t cmp_discretionary[] = {
#ifdef ACKBTN_SUPPORT
11,
#else
8,
#endif
GPG_DO_EXTCAP,
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
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 };
@@ -1590,6 +1762,7 @@ gpg_do_table[] = {
/* Pseudo DO READ: calculated, not changeable by user */
{ 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_ALG_INFO, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_alg_info },
/* Pseudo DO READ/WRITE: calculated */
{ GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_pw_status },
@@ -1599,11 +1772,19 @@ gpg_do_table[] = {
rw_algorithm_attr },
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
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,
rw_kdf },
/* Fixed data */
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
#ifdef ACKBTN_SUPPORT
{ GPG_DO_FEATURE_MNGMNT, DO_FIXED, AC_ALWAYS, AC_NEVER, feature_mngmnt },
#endif
/* Compound data: Read access only */
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
@@ -1642,6 +1823,11 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
digital_signature_counter = 0;
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. */
if (do_start == NULL)
@@ -1700,6 +1886,13 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
algo_attr_aut_p = p - 1;
p++;
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:
p++;
if (second_byte <= PW_ERR_PW3)
@@ -1799,6 +1992,13 @@ gpg_data_copy (const uint8_t *p_start)
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;
for (i = 0; i < NR_DO__LAST__; i++)
if (do_ptr[i] != NULL)
@@ -1912,9 +2112,10 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
}
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:
{

View File

@@ -1,7 +1,8 @@
/*
* openpgp.c -- OpenPGP card protocol support
*
* 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
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -37,6 +38,7 @@
static struct eventflag *openpgp_comm;
#define USER_PASSWD_MINLEN 6
#define ADMIN_PASSWD_MINLEN 8
#define CLS(a) a.cmd_apdu_head[0]
@@ -144,7 +146,7 @@ get_pinpad_input (int msg_code)
#endif
static void
cmd_verify (void)
cmd_verify (struct eventflag *ccid_comm)
{
int len;
uint8_t p1 = P1 (apdu);
@@ -152,6 +154,7 @@ cmd_verify (void)
int r;
const uint8_t *pw;
(void)ccid_comm;
DEBUG_INFO (" - VERIFY\r\n");
DEBUG_BYTE (p2);
@@ -170,7 +173,8 @@ cmd_verify (void)
r = ac_check_status (AC_ADMIN_AUTHORIZED);
if (r)
GPG_SUCCESS (); /* If authentication done already, return success. */
/* If authentication done already, return success. */
GPG_SUCCESS ();
else
{ /* If not, return retry counter, encoded. */
r = gpg_pw_get_retry_counter (p2);
@@ -273,7 +277,7 @@ gpg_change_keystring (int who_old, const uint8_t *old_ks,
}
static void
cmd_change_password (void)
cmd_change_password (struct eventflag *ccid_comm)
{
uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_SIZE];
@@ -293,6 +297,7 @@ cmd_change_password (void)
int salt_len;
const uint8_t *ks_pw3;
(void)ccid_comm;
DEBUG_INFO ("Change PW\r\n");
DEBUG_BYTE (who);
@@ -347,8 +352,9 @@ cmd_change_password (void)
newpw_len = len - pw_len;
ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
/* Check length of password for admin-less mode. */
if (ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
/* Check length of 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 ();
@@ -363,8 +369,24 @@ cmd_change_password (void)
if (ks_pw3 == NULL)
{
salt = NULL;
salt_len = 0;
if (admin_authorized == BY_USER)
{
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
if (ks_pw1 == NULL)
{
GPG_SECURITY_FAILURE ();
return;
}
salt = KS_GET_SALT (ks_pw1);
salt_len = SALT_SIZE;
}
else
{
salt = NULL;
salt_len = 0;
}
}
else
{
@@ -388,6 +410,7 @@ cmd_change_password (void)
{
newpw = pw + pw_len;
newpw_len = len - pw_len;
if (newpw_len == 0 && admin_authorized == BY_ADMIN)
{
const uint8_t *initial_pw;
@@ -397,6 +420,12 @@ cmd_change_password (void)
newsalt_len = 0;
pw3_null = 1;
}
else if (newpw_len < ADMIN_PASSWD_MINLEN)
{
DEBUG_INFO ("new password length is too short.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
who_old = admin_authorized;
}
@@ -426,11 +455,26 @@ cmd_change_password (void)
}
else if (r > 0 && who == BY_USER)
{
/* When it was already admin-less mode, admin_authorized is
* BY_USER. If no PW3 keystring, it's becoming admin-less mode,
* now. For these two cases, we need to reset admin
* authorization status. */
if (admin_authorized == BY_USER)
ac_reset_admin ();
else if (ks_pw3 == NULL)
{
enum kind_of_key kk0;
/* Remove keystrings for BY_ADMIN. */
for (kk0 = 0; kk0 <= GPG_KEY_FOR_AUTHENTICATION; kk0++)
gpg_do_chks_prvkey (kk0, BY_ADMIN, NULL, 0, NULL);
ac_reset_admin ();
}
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KS_META_SIZE);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
GPG_SUCCESS ();
}
@@ -506,7 +550,7 @@ s2k (const unsigned char *salt, size_t slen,
static void
cmd_reset_user_password (void)
cmd_reset_user_password (struct eventflag *ccid_comm)
{
uint8_t p1 = P1 (apdu);
int len;
@@ -517,9 +561,11 @@ cmd_reset_user_password (void)
uint8_t new_ks0[KEYSTRING_SIZE];
uint8_t *new_ks = KS_GET_KEYSTRING (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;
int salt_len;
(void)ccid_comm;
DEBUG_INFO ("Reset PW1\r\n");
DEBUG_BYTE (p1);
@@ -556,6 +602,16 @@ cmd_reset_user_password (void)
salt_len = SALT_SIZE;
newpw = pw + pw_len;
newpw_len = len - pw_len;
/* 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);
s2k (salt, salt_len, pw, pw_len, old_ks);
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
@@ -609,6 +665,16 @@ cmd_reset_user_password (void)
newpw_len = len;
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);
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
@@ -643,12 +709,13 @@ cmd_reset_user_password (void)
}
static void
cmd_put_data (void)
cmd_put_data (struct eventflag *ccid_comm)
{
uint8_t *data;
uint16_t tag;
int len;
(void)ccid_comm;
DEBUG_INFO (" - PUT DATA\r\n");
tag = ((P1 (apdu)<<8) | P2 (apdu));
@@ -658,8 +725,9 @@ cmd_put_data (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_BYTE (P1 (apdu));
@@ -678,10 +746,10 @@ cmd_pgp_gakp (void)
const uint8_t *
gpg_get_firmware_update_key (uint8_t keyno)
{
extern uint8_t _updatekey_store;
extern uint8_t _updatekey_store[1024];
const uint8_t *p;
p = &_updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
p = _updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
return p;
}
#endif
@@ -693,12 +761,13 @@ gpg_get_firmware_update_key (uint8_t keyno)
#endif
static void
cmd_read_binary (void)
cmd_read_binary (struct eventflag *ccid_comm)
{
int is_short_EF = (P1 (apdu) & 0x80) != 0;
uint8_t file_id;
uint16_t offset;
(void)ccid_comm;
DEBUG_INFO (" - Read binary\r\n");
if (is_short_EF)
@@ -769,8 +838,9 @@ cmd_read_binary (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 */
{
DEBUG_INFO (" - select DF by name\r\n");
@@ -839,10 +909,11 @@ cmd_select_file (void)
}
static void
cmd_get_data (void)
cmd_get_data (struct eventflag *ccid_comm)
{
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
(void)ccid_comm;
DEBUG_INFO (" - Get Data\r\n");
gpg_do_get_data (tag, 0);
@@ -857,7 +928,7 @@ cmd_get_data (void)
#define ECC_CIPHER_DO_HEADER_SIZE 7
static void
cmd_pso (void)
cmd_pso (struct eventflag *ccid_comm)
{
int len = apdu.cmd_apdu_data_len;
int r = -1;
@@ -884,6 +955,11 @@ cmd_pso (void)
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)
{
/* Check size of digestInfo */
@@ -929,13 +1005,6 @@ cmd_pso (void)
{
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);
result_len = EDDSA_SIGNATURE_LENGTH;
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
@@ -975,6 +1044,13 @@ cmd_pso (void)
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)
{
/* Skip padding 0x00 */
@@ -1051,7 +1127,7 @@ cmd_pso (void)
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
static void
cmd_internal_authenticate (void)
cmd_internal_authenticate (struct eventflag *ccid_comm)
{
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
@@ -1081,6 +1157,13 @@ cmd_internal_authenticate (void)
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 (len > MAX_RSA_DIGEST_INFO_LEN)
@@ -1128,13 +1211,6 @@ cmd_internal_authenticate (void)
{
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);
result_len = EDDSA_SIGNATURE_LENGTH;
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
@@ -1257,10 +1333,11 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
#if defined(CERTDO_SUPPORT)
static void
cmd_update_binary (void)
cmd_update_binary (struct eventflag *ccid_comm)
{
int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - UPDATE BINARY\r\n");
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("UPDATE BINARY done.\r\n");
@@ -1269,10 +1346,11 @@ cmd_update_binary (void)
static void
cmd_write_binary (void)
cmd_write_binary (struct eventflag *ccid_comm)
{
int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - WRITE BINARY\r\n");
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("WRITE BINARY done.\r\n");
@@ -1281,7 +1359,7 @@ cmd_write_binary (void)
#ifdef FLASH_UPGRADE_SUPPORT
static void
cmd_external_authenticate (void)
cmd_external_authenticate (struct eventflag *ccid_comm)
{
const uint8_t *pubkey;
const uint8_t *signature = apdu.cmd_apdu_data;
@@ -1289,6 +1367,7 @@ cmd_external_authenticate (void)
uint8_t keyno = P2 (apdu);
int r;
(void)ccid_comm;
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
if (keyno >= 4)
@@ -1324,10 +1403,11 @@ cmd_external_authenticate (void)
#endif
static void
cmd_get_challenge (void)
cmd_get_challenge (struct eventflag *ccid_comm)
{
int len = apdu.expected_res_size;
(void)ccid_comm;
DEBUG_INFO (" - GET CHALLENGE\r\n");
if (len > CHALLENGE_LEN)
@@ -1342,6 +1422,13 @@ cmd_get_challenge (void)
if (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 ();
memcpy (res_APDU, challenge, len);
res_APDU_size = len;
@@ -1352,8 +1439,9 @@ cmd_get_challenge (void)
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
static void
cmd_activate_file (void)
cmd_activate_file (struct eventflag *ccid_comm)
{
(void)ccid_comm;
if (file_selection != FILE_CARD_TERMINATED)
{
GPG_NO_RECORD ();
@@ -1366,13 +1454,13 @@ cmd_activate_file (void)
}
static void
cmd_terminate_df (void)
cmd_terminate_df (struct eventflag *ccid_comm)
{
const uint8_t *ks_pw3;
uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu);
(void)ccid_comm;
if (file_selection != FILE_DF_OPENPGP)
{
GPG_NO_RECORD ();
@@ -1416,7 +1504,7 @@ cmd_terminate_df (void)
struct command
{
uint8_t command;
void (*cmd_handler) (void);
void (*cmd_handler) (struct eventflag *ccid_comm);
};
const struct command cmds[] = {
@@ -1450,7 +1538,7 @@ const struct command cmds[] = {
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
static void
process_command_apdu (void)
process_command_apdu (struct eventflag *ccid_comm)
{
int i;
uint8_t cmd = INS (apdu);
@@ -1474,7 +1562,7 @@ process_command_apdu (void)
else
{
chopstx_setcancelstate (1);
cmds[i].cmd_handler ();
cmds[i].cmd_handler (ccid_comm);
chopstx_setcancelstate (0);
}
}
@@ -1588,7 +1676,7 @@ openpgp_card_thread (void *arg)
break;
led_blink (LED_START_COMMAND);
process_command_apdu ();
process_command_apdu (ccid_comm);
led_blink (LED_FINISH_COMMAND);
done:
eventflag_signal (ccid_comm, EV_EXEC_FINISHED);

View File

@@ -986,6 +986,7 @@ tim_main (void *arg)
{
chopstx_intr_wait (&interrupt);
cir_timer_interrupt ();
chopstx_intr_done (&interrupt);
}
return NULL;
@@ -1006,6 +1007,7 @@ ext_main (void *arg)
{
chopstx_intr_wait (&interrupt);
cir_ext_interrupt ();
chopstx_intr_done (&interrupt);
}
return NULL;

View File

@@ -3,7 +3,7 @@
#define SIZE_2 4096
#define SIZE_3 (5 * 4096)
#else
#define SIZE_0 0x0150 /* Main */
#define SIZE_0 0x0160 /* Main */
#define SIZE_1 0x01a0 /* CCID */
#define SIZE_2 0x0180 /* RNG */
#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
*
* 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
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -29,6 +30,10 @@
#include "config.h"
#ifdef ACKBTN_SUPPORT
#include <contrib/ackbtn.h>
#endif
#ifdef DEBUG
#include "usb-cdc.h"
#include "debug.h"
@@ -182,9 +187,11 @@ struct ccid_header {
/* Data structure handled by CCID layer */
struct ccid {
enum ccid_state ccid_state;
uint8_t state;
uint8_t err;
uint32_t ccid_state : 4;
uint32_t state : 4;
uint32_t err : 1;
uint32_t tx_busy : 1;
uint32_t timeout_cnt: 3;
uint8_t *p;
size_t len;
@@ -241,6 +248,7 @@ struct ccid {
static void ccid_reset (struct ccid *c)
{
c->err = 0;
c->tx_busy = 0;
c->state = APDU_STATE_WAIT_COMMAND;
c->p = c->a->cmd_apdu_data;
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)
{
c->ccid_state = CCID_STATE_START;
c->err = 0;
c->tx_busy = 0;
c->state = APDU_STATE_WAIT_COMMAND;
c->p = a->cmd_apdu_data;
c->len = MAX_CMD_APDU_DATA_SIZE;
c->err = 0;
memset (&c->ccid_header, 0, sizeof (struct ccid_header));
c->sw1sw2[0] = 0x90;
c->sw1sw2[1] = 0x00;
@@ -765,6 +774,7 @@ usb_tx_done (uint8_t ep_num, uint16_t len)
#endif
}
/*
* ATR (Answer To Reset) string
*
@@ -820,6 +830,7 @@ static void ccid_error (struct ccid *c, int offset)
#else
usb_lld_write (c->epi->ep_num, ccid_reply, CCID_MSG_HEADER_SIZE);
#endif
c->tx_busy = 1;
}
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);
#endif
DEBUG_INFO ("ON\r\n");
c->tx_busy = 1;
return CCID_STATE_WAIT;
}
@@ -934,6 +945,7 @@ ccid_send_status (struct ccid *c)
#ifdef DEBUG_MORE
DEBUG_INFO ("St\r\n");
#endif
c->tx_busy = 1;
}
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 */
ccid_send_status (c);
DEBUG_INFO ("OFF\r\n");
c->tx_busy = 1;
return CCID_STATE_START;
}
@@ -982,12 +995,16 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
#endif
if (len == 0)
{
c->epi->buf = NULL;
c->epi->tx_done = 1;
#ifdef GNU_LINUX_EMULATION
usb_lld_tx_enable_buf (c->epi->ep_num, endp1_tx_buf,
CCID_MSG_HEADER_SIZE);
#else
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE);
#endif
c->tx_busy = 1;
return;
}
@@ -1065,6 +1082,7 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
#ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n");
#endif
c->tx_busy = 1;
}
static void
@@ -1076,7 +1094,8 @@ ccid_send_data_block (struct ccid *c)
static void
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
@@ -1115,6 +1134,7 @@ ccid_send_data_block_0x9000 (struct ccid *c)
#ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n");
#endif
c->tx_busy = 1;
}
/*
@@ -1211,6 +1231,7 @@ ccid_send_data_block_gr (struct ccid *c, size_t chunk_len)
#ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n");
#endif
c->tx_busy = 1;
}
@@ -1259,6 +1280,7 @@ ccid_send_params (struct ccid *c)
#ifdef DEBUG_MORE
DEBUG_INFO ("PARAMS\r\n");
#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 = &c->p[5];
c->state = APDU_STATE_COMMAND_RECEIVED;
eventflag_signal (&c->openpgp_comm, EV_VERIFY_CMD_AVAILABLE);
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 = &ccid_buffer[5];
c->state = APDU_STATE_COMMAND_RECEIVED;
eventflag_signal (&c->openpgp_comm, EV_MODIFY_CMD_AVAILABLE);
next_state = CCID_STATE_EXECUTE;
}
@@ -1461,6 +1485,8 @@ ccid_handle_data (struct ccid *c)
}
break;
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)
next_state = ccid_power_off (c);
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
@@ -1489,6 +1515,8 @@ ccid_handle_timeout (struct ccid *c)
switch (c->ccid_state)
{
case CCID_STATE_EXECUTE:
case CCID_STATE_ACK_REQUIRED_0:
case CCID_STATE_ACK_REQUIRED_1:
ccid_send_data_block_time_extension (c);
break;
default:
@@ -1500,7 +1528,13 @@ ccid_handle_timeout (struct ccid *c)
}
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
ccid_card_change_signal (int how)
@@ -1545,7 +1579,7 @@ ccid_notify_slot_change (struct ccid *c)
#define USB_CCID_TIMEOUT (1950*1000)
#define GPG_THREAD_TERMINATED 0xffff
#define GPG_ACK_TIMEOUT 0x6600
extern uint32_t bDeviceState;
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_fini (void);
#ifdef ACKBTN_SUPPORT
static chopstx_intr_t ack_intr;
#endif
static chopstx_intr_t usb_intr;
/*
* Return 0 for normal USB event
@@ -1575,6 +1613,7 @@ usb_event_handle (struct usb_dev *dev)
e = usb_lld_event_handler (dev);
ep_num = USB_EVENT_ENDP (e);
chopstx_intr_done (&usb_intr);
/* Transfer to endpoint (not control endpoint) */
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 struct chx_poll_head *const ccid_poll[] = {
(struct chx_poll_head *const)&interrupt,
(struct chx_poll_head *const)&ccid_event_poll_desc
(struct chx_poll_head *const)&usb_intr,
(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 *))
@@ -1689,6 +1730,7 @@ ccid_thread (void *arg)
struct usb_dev dev;
struct ccid *c = &ccid;
uint32_t *timeout_p;
int ackbtn_active = 0;
(void)arg;
@@ -1696,9 +1738,12 @@ ccid_thread (void *arg)
eventflag_init (&ccid.openpgp_comm);
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 */
#ifdef ACKBTN_SUPPORT
ackbtn_init (&ack_intr);
#endif
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
reset:
@@ -1707,6 +1752,13 @@ ccid_thread (void *arg)
struct ep_out *epo = &endpoint_out;
struct apdu *a = &apdu;
if (ackbtn_active)
{
ackbtn_active = 0;
ackbtn_disable ();
led_blink (LED_WAIT_FOR_BUTTON);
}
epi_init (epi, ENDP1, c);
epo_init (epo, ENDP1, c);
apdu_init (a);
@@ -1724,14 +1776,21 @@ ccid_thread (void *arg)
{
eventmask_t m;
if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
if (!c->tx_busy && bDeviceState == USB_DEVICE_STATE_CONFIGURED)
timeout_p = &timeout;
else
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)
continue;
@@ -1751,7 +1810,26 @@ ccid_thread (void *arg)
goto reset;
}
timeout = USB_CCID_TIMEOUT;
#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;
c->timeout_cnt++;
}
m = eventflag_get (&c->ccid_comm);
if (m == EV_CARD_CHANGE)
@@ -1774,10 +1852,17 @@ ccid_thread (void *arg)
ccid_notify_slot_change (c);
}
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)
if (c->ccid_state == CCID_STATE_EXECUTE)
{
#ifdef ACKBTN_SUPPORT
exec_done:
#endif
if (c->a->sw == GPG_THREAD_TERMINATED)
{
c->sw1sw2[0] = 0x90;
@@ -1807,21 +1892,35 @@ ccid_thread (void *arg)
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
{
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)
{
if (c->state == APDU_STATE_RESULT)
{
c->state = APDU_STATE_WAIT_COMMAND;
c->p = c->a->cmd_apdu_data;
c->len = MAX_CMD_APDU_DATA_SIZE;
c->err = 0;
c->a->cmd_apdu_data_len = 0;
c->a->expected_res_size = 0;
}
ccid_reset (c);
else
c->tx_busy = 0;
if (c->state == APDU_STATE_WAIT_COMMAND
|| c->state == APDU_STATE_COMMAND_CHAINING
@@ -1829,7 +1928,20 @@ ccid_thread (void *arg)
ccid_prepare_receive (c);
}
else /* Timeout */
c->ccid_state = ccid_handle_timeout (c);
{
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);
}
}
if (c->application)
@@ -1841,7 +1953,7 @@ ccid_thread (void *arg)
/* Loading reGNUal. */
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
{
chopstx_intr_wait (&interrupt);
chopstx_intr_wait (&usb_intr);
usb_event_handle (&dev);
}

View File

@@ -1,7 +1,7 @@
/*
* 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
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -202,8 +202,6 @@ gnuk_setup_endpoints_for_interface (struct usb_dev *dev,
void
usb_device_reset (struct usb_dev *dev)
{
int i;
usb_lld_reset (dev, USB_INITIAL_FEATURE);
/* Initialize Endpoint 0 */
@@ -214,10 +212,6 @@ usb_device_reset (struct usb_dev *dev)
64);
#endif
/* Stop the interface */
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (dev, i, 1);
bDeviceState = USB_DEVICE_STATE_DEFAULT;
}
@@ -287,7 +281,7 @@ usb_setup (struct usb_dev *dev)
if (arg->request == USB_FSIJ_GNUK_DOWNLOAD)
{
#ifdef FLASH_UPGRADE_SUPPORT
if (*ccid_state_p != CCID_STATE_EXITED)
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return -1;
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)
{
#ifdef FLASH_UPGRADE_SUPPORT
if (*ccid_state_p != CCID_STATE_EXITED)
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return -1;
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 (*ccid_state_p != CCID_STATE_EXITED)
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return;
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;

View File

@@ -70,7 +70,9 @@ uint8_t device_desc[] = {
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */
#include "usb-vid-pid-ver.c.inc"
0x00, 0x00, /* idVendor (will be replaced) */
0x00, 0x00, /* idProduct (will be replaced) */
0x00, 0x00, /* bcdDevice (will be replaced) */
1, /* Index of string descriptor describing manufacturer */
2, /* Index of string descriptor describing product */
3, /* Index of string descriptor describing the device's serial number */

View File

@@ -6,7 +6,7 @@ Gnuk Token is supported as well.
You need to install:
$ sudo apt-get install python3-pytest python3-usb
$ sudo apt install python3-pytest python3-usb python3-cffi
Please run test by typing:

4
tests/card_const.py Normal file
View File

@@ -0,0 +1,4 @@
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
KEY_ATTRIBUTES_RSA4K=b"\x01\x10\x00\x00\x20\x00"
KEY_ATTRIBUTES_RSA2K=b"\x01\x08\x00\x00\x20\x00"

View File

@@ -1,7 +1,7 @@
"""
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>
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, \
endpoint_type, endpoint_direction, \
ENDPOINT_TYPE_BULK, ENDPOINT_OUT, ENDPOINT_IN
from binascii import hexlify
# USB class, subclass, protocol
CCID_CLASS = 0x0B
@@ -168,7 +169,7 @@ class CardReader(object):
return status
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.increment_seq()
status, chain, data = self.ccid_get_result()
@@ -179,8 +180,8 @@ class CardReader(object):
# TPDU reader configuration
self.ns = 0
self.nr = 0
# For Gemalto USB GemPC Pinpad SmartCard Reader
if self.__dev.idVendor == 0x08E6 and self.__dev.idProduct == 0x3478:
# For Gemalto's SmartCard Reader(s)
if self.__dev.idVendor == 0x08E6:
# Set PPS
pps = b"\xFF\x11\x18\xF6"
status, chain, ret_pps = self.ccid_send_data_block(pps)
@@ -237,16 +238,21 @@ class CardReader(object):
def send_tpdu(self, info=None, more=0, response_time_ext=0,
edc_error=0, no_error=0):
rsv = 0
if info:
data = compose_i_block(self.ns, info, more)
elif response_time_ext:
# compose S-block
data = b"\x00\xE3\x00\xE3"
# compose S-block response
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:
data = compose_r_block(self.nr, edc_error=1)
elif no_error:
data = compose_r_block(self.nr)
msg = ccid_compose(0x6f, self.__seq, data=data)
msg = ccid_compose(0x6f, self.__seq, rsv=rsv, data=data)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
@@ -277,7 +283,7 @@ class CardReader(object):
res = b""
while True:
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):
self.nr = self.nr ^ 1
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

@@ -1,7 +1,7 @@
"""
test_remove_keys_card.py - test removing keys on card
card_test_remove_keys.py - test removing keys on card
Copyright (C) 2016 g10 Code GmbH
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.
@@ -22,23 +22,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# Remove a key material on card by changing algorithm attributes of the key
KEY_ATTRIBUTES_RSA4K=b"\x01\x10\x00\x00\x20\x00"
KEY_ATTRIBUTES_RSA2K=b"\x01\x08\x00\x00\x20\x00"
from card_const import *
def test_rsa_import_key_1(card):
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
assert r
class Test_Remove_Keys(object):
def test_rsa_import_key_2(card):
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
assert r
def test_rsa_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_import_key_3(card):
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)
assert r
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()
yield card
del card
reader.ccid_power_off()

View File

@@ -0,0 +1,21 @@
PW1_TEST0=b"another user pass phrase"
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
PW1_TEST2=b"new user pass phrase"
PW1_TEST3=b"next user pass phrase"
PW1_TEST4=b"another user pass phrase"
PW3_TEST0=b"admin pass phrase"
PW3_TEST1=b"another admin pass phrase"
RESETCODE_TEST=b"example reset code 000"
PLAIN_TEXT0=b"This is a test message."
PLAIN_TEXT1=b"RSA decryption is as easy as pie."
PLAIN_TEXT2=b"This is another test message.\nMultiple lines.\n"
KDF_FULL=b"\x81\x01\x03\x82\x01\x08\x83\x04\x00\xC8\x00\x00\x84\x08\xC5\x1F\xB7\xF9\xEE\xF3\xD3\xE8\x85\x08\x75\x1A\x2A\x70\xC0\x7C\xB1\x81\x86\x08\xE6\xB2\x4E\x0C\xEE\x92\xAB\x93\x87\x20\xA2\x08\x89\x16\x09\xD3\xE4\x3D\x48\xAC\x5B\xAA\xBD\xE9\xF1\xB8\xD2\xFC\xD8\x3C\x5F\x35\xCB\xEB\xDA\xFB\x75\x92\x88\xC6\x8B\x2D\x88\x20\xF1\x34\x00\xD2\x5F\x28\x57\xE6\x66\xAA\x9E\xBB\xE0\x7C\x57\x4B\x84\x8B\xD6\x52\x14\xE7\x31\x99\x1A\x3D\x2D\xAA\x3F\x8A\x7F\x03"
KDF_FULL_HASH_PW1=b"\xA2\x08\x89\x16\x09\xD3\xE4\x3D\x48\xAC\x5B\xAA\xBD\xE9\xF1\xB8\xD2\xFC\xD8\x3C\x5F\x35\xCB\xEB\xDA\xFB\x75\x92\x88\xC6\x8B\x2D"
KDF_FULL_HASH_PW3=b"\xF1\x34\x00\xD2\x5F\x28\x57\xE6\x66\xAA\x9E\xBB\xE0\x7C\x57\x4B\x84\x8B\xD6\x52\x14\xE7\x31\x99\x1A\x3D\x2D\xAA\x3F\x8A\x7F\x03"
KDF_SINGLE=b"\x81\x01\x03\x82\x01\x08\x83\x04\x00\xC8\x00\x00\x84\x08\x69\x9E\xDA\xAD\x5A\x72\x5F\x4C\x87\x20\x12\xDB\x16\x9A\x9D\x1A\x56\xCA\x2B\x9E\x96\x7F\xC4\xDA\xB8\xAE\x70\x41\x51\x8E\x3C\xEF\x49\x7E\xC2\x56\x60\x32\x2F\x4C\x03\x07\x88\x20\x1C\x93\x99\xC3\x6D\x49\x92\x27\x54\x39\x76\x7E\xA7\xB4\xEE\xE5\x16\xDA\x92\xC0\x0E\xF4\x74\xBD\x01\x28\x0F\x0C\x30\x45\x4B\xBB"
KDF_SINGLE_HASH_PW1=b"\x12\xDB\x16\x9A\x9D\x1A\x56\xCA\x2B\x9E\x96\x7F\xC4\xDA\xB8\xAE\x70\x41\x51\x8E\x3C\xEF\x49\x7E\xC2\x56\x60\x32\x2F\x4C\x03\x07"
KDF_SINGLE_HASH_PW3=b"\x1C\x93\x99\xC3\x6D\x49\x92\x27\x54\x39\x76\x7E\xA7\xB4\xEE\xE5\x16\xDA\x92\xC0\x0E\xF4\x74\xBD\x01\x28\x0F\x0C\x30\x45\x4B\xBB"

1
tests/kdf_calc.py Symbolic link
View File

@@ -0,0 +1 @@
../tool/kdf_calc.py

View File

@@ -1,7 +1,7 @@
"""
openpgp_card.py - a library for OpenPGP card
Copyright (C) 2011, 2012, 2013, 2015, 2016
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018, 2019
Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -21,7 +21,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/>.
"""
from struct import pack
from struct import pack, unpack
from kdf_calc import kdf_calc
def iso7816_compose(ins, p1, p2, data, cls=0x00, le=None):
data_len = len(data)
@@ -54,6 +55,84 @@ class OpenPGP_Card(object):
"""
self.__reader = reader
self.__kdf_iters = None
self.__kdf_salt_user = None
self.__kdf_salt_reset = None
self.__kdf_salt_admin = None
self.is_gnuk = (reader.get_string(2) == "Gnuk Token")
def configure_with_kdf(self):
kdf_data = self.cmd_get_data(0x00, 0xf9)
if kdf_data != b"":
algo, subalgo, iters, salt_user, salt_reset, salt_admin, hash_user, hash_admin = parse_kdf_data(kdf_data)
self.__kdf_iters = iters
self.__kdf_salt_user = salt_user
self.__kdf_salt_reset = salt_reset
self.__kdf_salt_admin = salt_admin
else:
self.__kdf_iters = None
self.__kdf_salt_user = None
self.__kdf_salt_reset = None
self.__kdf_salt_admin = None
# Higher layer VERIFY possibly using KDF Data Object
def verify(self, who, passwd):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if who == 3 and self.__kdf_salt_admin:
salt = self.__kdf_salt_admin
pw_hash = kdf_calc(passwd, salt, self.__kdf_iters)
return self.cmd_verify(who, pw_hash)
else:
return self.cmd_verify(who, passwd)
# Higher layer CHANGE_PASSWD possibly using KDF Data Object
def change_passwd(self, who, passwd_old, passwd_new):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if who == 3 and self.__kdf_salt_admin:
salt = self.__kdf_salt_admin
hash_old = kdf_calc(passwd_old, salt, self.__kdf_iters)
if passwd_new:
hash_new = kdf_calc(passwd_new, salt, self.__kdf_iters)
else:
hash_new = b""
return self.cmd_change_reference_data(who, hash_old + hash_new)
else:
if not passwd_new:
passwd_new = b""
return self.cmd_change_reference_data(who, passwd_old + passwd_new)
# Higher layer SETUP_RESET_CODE possibly using KDF Data Object
def setup_reset_code(self, resetcode):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if self.__kdf_salt_reset:
salt = self.__kdf_salt_user
reset_hash = kdf_calc(resetcode, salt, self.__kdf_iters)
return self.cmd_put_data(0x00, 0xd3, reset_hash)
else:
return self.cmd_put_data(0x00, 0xd3, resetcode)
# Higher layer reset passwd possibly using KDF Data Object
def reset_passwd_by_resetcode(self, resetcode, pw1):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if self.__kdf_salt_reset:
salt = self.__kdf_salt_user
reset_hash = kdf_calc(resetcode, salt, self.__kdf_iters)
pw1_hash = kdf_calc(pw1, self.__kdf_salt_user, self.__kdf_iters)
return self.cmd_reset_retry_counter(0, 0x81, reset_hash + pw1_hash)
else:
return self.cmd_reset_retry_counter(0, 0x81, resetcode + pw1)
# Higher layer reset passwd possibly using KDF Data Object
def reset_passwd_by_admin(self, pw1):
if self.__kdf_iters:
pw1_hash = kdf_calc(pw1, self.__kdf_salt_user, self.__kdf_iters)
return self.cmd_reset_retry_counter(2, 0x81, pw1_hash)
else:
return self.cmd_reset_retry_counter(2, 0x81, pw1)
def cmd_get_response(self, expected_len):
result = b""
@@ -260,16 +339,20 @@ class OpenPGP_Card(object):
data = b'\xb8\x00'
else:
data = b'\xa4\x00'
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
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)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
if len(sw) < 2:
raise ValueError(sw)
if sw[0] == 0x90 and sw[1] == 0x00:
return b""
elif sw[0] != 0x61:
if sw[-2] == 0x61:
pk = self.cmd_get_response(sw[1])
elif sw[-2] == 0x90 and sw[-1] == 0x00:
pk = sw
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
pk = self.cmd_get_response(sw[1])
return (pk[9:9+256], pk[9+256+2:9+256+2+3])
return (pk[9:9+256], pk[9+256+2:-2])
def cmd_get_public_key(self, keyno):
if keyno == 1:
@@ -280,10 +363,9 @@ class OpenPGP_Card(object):
data = b'\xa4\x00'
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x47, 0x81, 0, data, le=512)
r = self.__reader.send_cmd(cmd_data)
else:
cmd_data = iso7816_compose(0x47, 0x81, 0, data)
r = self.__reader.send_cmd(cmd_data)
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
@@ -336,3 +418,48 @@ class OpenPGP_Card(object):
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def parse_kdf_data(kdf_data):
if len(kdf_data) == 90:
single_salt = True
elif len(kdf_data) == 110:
single_salt = False
else:
raise ValueError("length does not much", kdf_data)
if kdf_data[0:2] != b'\x81\x01':
raise ValueError("data does not much")
algo = kdf_data[2]
if kdf_data[3:5] != b'\x82\x01':
raise ValueError("data does not much")
subalgo = kdf_data[5]
if kdf_data[6:8] != b'\x83\x04':
raise ValueError("data does not much")
iters = unpack(">I", kdf_data[8:12])[0]
if kdf_data[12:14] != b'\x84\x08':
raise ValueError("data does not much")
salt = kdf_data[14:22]
if single_salt:
salt_reset = None
salt_admin = None
if kdf_data[22:24] != b'\x87\x20':
raise ValueError("data does not much")
hash_user = kdf_data[24:56]
if kdf_data[56:58] != b'\x88\x20':
raise ValueError("data does not much")
hash_admin = kdf_data[58:90]
else:
if kdf_data[22:24] != b'\x85\x08':
raise ValueError("data does not much")
salt_reset = kdf_data[24:32]
if kdf_data[32:34] != b'\x86\x08':
raise ValueError("data does not much")
salt_admin = kdf_data[34:42]
if kdf_data[42:44] != b'\x87\x20':
raise ValueError("data does not much")
hash_user = kdf_data[44:76]
if kdf_data[76:78] != b'\x88\x20':
raise ValueError("data does not much")
hash_admin = kdf_data[78:110]
return ( algo, subalgo, iters, salt, salt_reset, salt_admin,
hash_user, hash_admin )

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

@@ -1,7 +1,7 @@
"""
test_empty_card.py - test empty card
Copyright (C) 2016 g10 Code GmbH
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.
@@ -24,13 +24,11 @@ from binascii import hexlify
from re import match, DOTALL
from struct import pack
from util import *
from card_const import *
import pytest
EMPTY_60=bytes(60)
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
def test_login(card):
login = get_data_object(card, 0x5e)
assert check_null(login)
@@ -52,12 +50,21 @@ def test_sex(card):
def test_name_lang_sex(card):
name = b""
lang = b""
lang_de = b"de"
sex = b"9"
sex_alt = b"0"
expected = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
+ 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)
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):
app_data = get_data_object(card, 0x6e)
@@ -142,7 +149,8 @@ def test_historical_bytes(card):
h = get_data_object(card, 0x5f52)
assert h == b'\x001\xc5s\xc0\x01@\x05\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x00\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00'
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):
a = get_data_object(card, 0xc0)

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
"""
test_005_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 skip_gnuk_only_tests import *
from card_test_personalize_admin_less import *
from card_test_personalize_reset import *
from card_test_remove_keys import *
from card_test_reset_pw3 import *

24
tests/test_009_keygen.py Normal file
View File

@@ -0,0 +1,24 @@
"""
test_005_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 card_test_keygen import *
from card_test_remove_keys import *

View File

@@ -0,0 +1,29 @@
"""
test_007_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 skip_gnuk_only_tests import *
from card_test_kdf_full import *
from card_test_personalize_card import *
from card_test_personalize_reset import *
from card_test_remove_keys import *
from card_test_reset_pw3 import *

View File

@@ -0,0 +1,29 @@
"""
test_012_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 skip_gnuk_only_tests import *
from card_test_kdf_single import *
from card_test_personalize_card import *
from card_test_personalize_reset import *
from card_test_remove_keys import *
from card_test_reset_pw3 import *

View File

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

View File

@@ -0,0 +1,40 @@
"""
test_017_kdf_none.py - test KDF data object
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 skip_gnuk_only_tests import *
from card_const import *
from constants_for_test import *
def test_verify_pw3(card):
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
assert v
def test_kdf_put_none(card):
r = card.cmd_put_data(0x00, 0xf9, b"")
if r:
card.configure_with_kdf()
assert r
def test_verify_pw3_1(card):
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
assert v

View File

@@ -1,290 +0,0 @@
"""
test_personalize_card.py - test personalizing card
Copyright (C) 2016 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from struct import pack
from re import match, DOTALL
from util import *
import rsa_keys
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
PW1_TEST0=b"another user pass phrase"
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
PW1_TEST2=b"new user pass phrase"
PW1_TEST3=b"next user pass phrase"
PW1_TEST4=b"another user pass phrase"
PW3_TEST0=b"admin pass phrase"
PW3_TEST1=b"another admin pass phrase"
RESETCODE_TEST=b"example reset code 000"
def test_setup_pw3_0(card):
r = card.cmd_change_reference_data(3, FACTORY_PASSPHRASE_PW3 + PW3_TEST0)
assert r
def test_verify_pw3_0(card):
v = card.cmd_verify(3, PW3_TEST0)
assert v
def test_login_put(card):
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
assert r
def test_name_put(card):
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
assert r
def test_lang_put(card):
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
assert r
def test_sex_put(card):
r = card.cmd_put_data(0x5f, 0x35, b"1")
assert r
def test_url_put(card):
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
assert r
def test_pw1_status_put(card):
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
assert r
def test_login(card):
login = get_data_object(card, 0x5e)
assert login == b"gpg_user"
def test_name_lang_sex(card):
name = b"GnuPG User"
lang = b"ja"
sex = b"1"
expected = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
+ b'\x5f\x35' + pack('B', len(sex)) + sex
name_lang_sex = get_data_object(card, 0x65)
assert name_lang_sex == expected
def test_url(card):
url = get_data_object(card, 0x5f50)
assert url == b"https://www.fsij.org/gnuk/"
def test_pw1_status(card):
s = get_data_object(card, 0xc4)
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
def test_rsa_import_key_1(card):
t = rsa_keys.build_privkey_template(1, 0)
r = card.cmd_put_data_odd(0x3f, 0xff, t)
assert r
def test_rsa_import_key_2(card):
t = rsa_keys.build_privkey_template(2, 1)
r = card.cmd_put_data_odd(0x3f, 0xff, t)
assert r
def test_rsa_import_key_3(card):
t = rsa_keys.build_privkey_template(3, 2)
r = card.cmd_put_data_odd(0x3f, 0xff, t)
assert r
def test_fingerprint_1_put(card):
fpr1 = rsa_keys.fpr[0]
r = card.cmd_put_data(0x00, 0xc7, fpr1)
assert r
def test_fingerprint_2_put(card):
fpr2 = rsa_keys.fpr[1]
r = card.cmd_put_data(0x00, 0xc8, fpr2)
assert r
def test_fingerprint_3_put(card):
fpr3 = rsa_keys.fpr[2]
r = card.cmd_put_data(0x00, 0xc9, fpr3)
assert r
def test_timestamp_1_put(card):
timestamp1 = rsa_keys.timestamp[0]
r = card.cmd_put_data(0x00, 0xce, timestamp1)
assert r
def test_timestamp_2_put(card):
timestamp2 = rsa_keys.timestamp[1]
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
assert r
def test_timestamp_3_put(card):
timestamp3 = rsa_keys.timestamp[2]
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
assert r
def test_ds_counter_0(card):
c = get_data_object(card, 0x7a)
assert c == b'\x93\x03\x00\x00\x00'
def test_pw1_status(card):
s = get_data_object(card, 0xc4)
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
def test_app_data(card):
app_data = get_data_object(card, 0x6e)
hist_len = app_data[20]
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
app_data[18:18+2] == b"\x5f\x52"
def test_public_key_1(card):
pk = card.cmd_get_public_key(1)
assert rsa_keys.key[0][0] == pk[9:9+256]
def test_public_key_2(card):
pk = card.cmd_get_public_key(2)
assert rsa_keys.key[1][0] == pk[9:9+256]
def test_public_key_3(card):
pk = card.cmd_get_public_key(3)
assert rsa_keys.key[2][0] == pk[9:9+256]
def test_setup_pw1_0(card):
r = card.cmd_change_reference_data(1, FACTORY_PASSPHRASE_PW1 + PW1_TEST0)
assert r
def test_verify_pw1_0(card):
v = card.cmd_verify(1, PW1_TEST0)
assert v
def test_verify_pw1_0_2(card):
v = card.cmd_verify(2, PW1_TEST0)
assert v
def test_setup_pw1_1(card):
r = card.cmd_change_reference_data(1, PW1_TEST0 + PW1_TEST1)
assert r
def test_verify_pw1_1(card):
v = card.cmd_verify(1, PW1_TEST1)
assert v
def test_verify_pw1_1_2(card):
v = card.cmd_verify(2, PW1_TEST1)
assert v
def test_setup_reset_code(card):
r = card.cmd_put_data(0x00, 0xd3, RESETCODE_TEST)
assert r
def test_reset_code(card):
r = card.cmd_reset_retry_counter(0, 0x81, RESETCODE_TEST + PW1_TEST2)
assert r
def test_verify_pw1_2(card):
v = card.cmd_verify(1, PW1_TEST2)
assert v
def test_verify_pw1_2_2(card):
v = card.cmd_verify(2, PW1_TEST2)
assert v
def test_setup_pw3_1(card):
r = card.cmd_change_reference_data(3, PW3_TEST0 + PW3_TEST1)
assert r
def test_verify_pw3_1(card):
v = card.cmd_verify(3, PW3_TEST1)
assert v
def test_reset_userpass_admin(card):
r = card.cmd_reset_retry_counter(2, 0x81, PW1_TEST3)
assert r
def test_verify_pw1_3(card):
v = card.cmd_verify(1, PW1_TEST3)
assert v
def test_verify_pw1_3_2(card):
v = card.cmd_verify(2, PW1_TEST3)
assert v
def test_setup_pw1_4(card):
r = card.cmd_change_reference_data(1, PW1_TEST3 + PW1_TEST4)
assert r
def test_verify_pw1_4(card):
v = card.cmd_verify(1, PW1_TEST4)
assert v
def test_verify_pw1_4_2(card):
v = card.cmd_verify(2, PW1_TEST4)
assert v
def test_setup_pw3_2(card):
r = card.cmd_change_reference_data(3, PW3_TEST1 + PW3_TEST0)
assert r
def test_verify_pw3_2(card):
v = card.cmd_verify(3, PW3_TEST0)
assert v
PLAIN_TEXT0=b"This is a test message."
PLAIN_TEXT1=b"RSA decryption is as easy as pie."
PLAIN_TEXT2=b"This is another test message.\nMultiple lines.\n"
def test_sign_0(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
sig = rsa_keys.compute_signature(0, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_sign_1(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
sig = rsa_keys.compute_signature(0, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_ds_counter_1(card):
c = get_data_object(card, 0x7a)
assert c == b'\x93\x03\x00\x00\x02'
def test_sign_auth_0(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
r = card.cmd_internal_authenticate(digestinfo)
sig = rsa_keys.compute_signature(2, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_sign_auth_1(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
r = card.cmd_internal_authenticate(digestinfo)
sig = rsa_keys.compute_signature(2, digestinfo)
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
assert r == sig_bytes
def test_decrypt_0(card):
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
r = card.cmd_pso(0x80, 0x86, ciphertext)
assert r == PLAIN_TEXT0
def test_decrypt_1(card):
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
r = card.cmd_pso(0x80, 0x86, ciphertext)
assert r == PLAIN_TEXT1

View File

@@ -1,91 +0,0 @@
"""
test_personalize_reset_card.py - test resetting personalization of card
Copyright (C) 2016 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from struct import pack
from re import match, DOTALL
from util import *
import rsa_keys
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
PW1_TEST0=b"another user pass phrase"
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
PW1_TEST2=b"new user pass phrase"
PW1_TEST3=b"next user pass phrase"
PW1_TEST4=b"another user pass phrase"
PW3_TEST0=b"admin pass phrase"
PW3_TEST1=b"another admin pass phrase"
RESETCODE_TEST=b"example reset code 000"
def test_login_put(card):
r = card.cmd_put_data(0x00, 0x5e, b"")
assert r
def test_name_put(card):
r = card.cmd_put_data(0x00, 0x5b, b"")
assert r
def test_lang_put(card):
r = card.cmd_put_data(0x5f, 0x2d, b"")
assert r
def test_sex_put(card):
try:
# Gnuk
r = card.cmd_put_data(0x5f, 0x35, b"")
except ValueError:
# OpenPGP card which doesn't allow b""
r = card.cmd_put_data(0x5f, 0x35, b"9")
assert r
def test_url_put(card):
r = card.cmd_put_data(0x5f, 0x50, b"")
assert r
def test_pw1_status_put(card):
r = card.cmd_put_data(0x00, 0xc4, b"\x00")
assert r
def test_setup_pw3_0(card):
r = card.cmd_change_reference_data(3, PW3_TEST0 + FACTORY_PASSPHRASE_PW3)
assert r
def test_verify_pw3_0(card):
v = card.cmd_verify(3, FACTORY_PASSPHRASE_PW3)
assert v
def test_setup_pw1_0(card):
r = card.cmd_change_reference_data(1, PW1_TEST4 + FACTORY_PASSPHRASE_PW1)
assert r
def test_verify_pw1_0(card):
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
assert v
def test_verify_pw1_0_2(card):
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
assert v
def test_setup_reset_code(card):
r = card.cmd_put_data(0x00, 0xd3, b"")
assert r

View File

@@ -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
s = sexp(pubkey_info_str)
if s[0] != 'public-key':
print s
print(s)
exit(1)
rsa = s[1]
if rsa[0] != 'rsa':
print rsa
print(rsa)
exit(1)
n_x = rsa[1]
if n_x[0] != 'n':
print n_x
print(n_x)
exit(1)
n_byte_str = n_x[1]
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
e_x = rsa[2]
if e_x[0] != 'e':
print e_x
print(e_x)
exit(1)
e = e_x[1]
if not timestamp:

View File

@@ -8,21 +8,21 @@ def print_nG(n):
nGy_str = "%064x" % nG.y()
print256(nGx_str)
print256(nGy_str)
print
print()
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[24:32], s[16:24], s[8:16], s[0:8]))
print
print()
for i in range(1,16):
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
print "%064x" % n
n = (i & 1) + (i & 2) * 0x8000000000000000 + (i & 4) * 0x40000000000000000000000000000000 + (i & 8) * 0x200000000000000000000000000000000000000000000000
print("%064x" % n)
print_nG(n)
for i in range(1,16):
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
n = n * 0x100000000L
print "%064x" % n
n = (i & 1) + (i & 2) * 0x8000000000000000 + (i & 4) * 0x40000000000000000000000000000000 + (i & 8) * 0x200000000000000000000000000000000000000000000000
n = n * 0x100000000
print("%064x" % n)
print_nG(n)

View File

@@ -104,9 +104,9 @@ class DFU_STM32(object):
interface: usb.Interface object representing the interface and altenate setting.
"""
if interface.interfaceClass != DFU_CLASS:
raise ValueError, "Wrong interface class"
raise ValueError("Wrong interface class")
if interface.interfaceSubClass != DFU_SUBCLASS:
raise ValueError, "Wrong interface sub class"
raise ValueError("Wrong interface sub class")
self.__protocol = interface.interfaceProtocol
self.__devhandle = device.open()
self.__devhandle.setConfiguration(configuration)
@@ -170,7 +170,7 @@ class DFU_STM32(object):
while s[4] == STATE_DFU_DOWNLOAD_BUSY:
time.sleep(0.1)
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):
bytes = get_four_bytes (address)
@@ -181,7 +181,7 @@ class DFU_STM32(object):
time.sleep(0.1)
s = self.ll_get_status()
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
raise ValueError, "Set Address Pointer failed"
raise ValueError("Set Address Pointer failed")
def dfuse_erase(self, address):
bytes = get_four_bytes (address)
@@ -191,7 +191,7 @@ class DFU_STM32(object):
time.sleep(0.1)
s = self.ll_get_status()
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
raise ValueError, "Erase failed"
raise ValueError("Erase failed")
def dfuse_write_memory(self, block):
blocknum = self.__blocknum
@@ -202,7 +202,7 @@ class DFU_STM32(object):
time.sleep(0.1)
s = self.ll_get_status()
if s[4] != STATE_DFU_DOWNLOAD_IDLE:
raise ValueError, "Write memory failed"
raise ValueError("Write memory failed")
def download(self, ih):
# First, erase pages
@@ -280,7 +280,7 @@ class DFU_STM32(object):
elif s[4] == STATE_DFU_MANIFEST_WAIT_RESET:
self.__devhandle.reset()
elif s[4] != STATE_DFU_IDLE:
raise ValueError, "write failed (%d)." % s[4]
raise ValueError("write failed (%d)." % s[4])
else:
self.ll_clear_status()
self.ll_clear_status()
@@ -315,7 +315,7 @@ class DFU_STM32(object):
j = 0
for c in data[0:(addr + 1024 - start_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
data = data[(addr + 1024 - start_addr):]
addr += 1024
@@ -330,7 +330,7 @@ class DFU_STM32(object):
j = 0
for c in data[i*1024:(i+1)*1024]:
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
if i & 0x03 == 0x03:
sys.stdout.write("#")
@@ -367,25 +367,25 @@ def get_device():
(alt.interfaceProtocol == DFU_STM32PROTOCOL_0 or \
alt.interfaceProtocol == DFU_STM32PROTOCOL_2):
return dev, config, alt
raise ValueError, "Device not found"
raise ValueError("Device not found")
def main(filename):
dev, config, intf = get_device()
print "Device:", dev.filename
print "Configuration", config.value
print "Interface", intf.interfaceNumber
print("Device:", dev.filename)
print("Configuration", config.value)
print("Interface", intf.interfaceNumber)
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()
if s[4] == STATE_DFU_ERROR:
dfu.ll_clear_status()
s = dfu.ll_get_status()
print s
print(s)
if s[4] == STATE_DFU_IDLE:
exit
transfer_size = 1024
if s[0] != DFU_STATUS_OK:
print s
print(s)
exit
ih = intel_hex(filename)
dfu.download(ih)

View File

@@ -27,22 +27,22 @@ from dfuse import *
dev, config, intf = get_device()
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()
dfu.ll_clear_status()
s = dfu.ll_get_status()
print s
print(s)
dfu.dfuse_set_address_pointer(int(sys.argv[1], 16))
s = dfu.ll_get_status()
dfu.ll_clear_status()
s = dfu.ll_get_status()
dfu.ll_clear_status()
s = dfu.ll_get_status()
print s
print(s)
block = dfu.dfuse_read_memory()
count = 0
for d in block:
print "%02x" % d,
print("%02x" % d)
if count & 0x0f == 0x0f:
print
count += 1

View File

@@ -20,7 +20,7 @@ def get_gpg_public_key(keygrip):
pos_last = key.index(")(1:e3:")
key = key[pos:pos_last]
if len(key) != 256:
raise ValueError, binascii.hexlify(key)
raise ValueError(binascii.hexlify(key))
return key
if __name__ == '__main__':

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().tostring()
except Exception as e:
print(count)
raise e
print(hexlify(challenge))
count = count + 1
if not looping:
break

View File

@@ -3,7 +3,7 @@
"""
gnuk_remove_keys_libusb.py - a tool to remove keys in Gnuk Token
Copyright (C) 2012 Free Software Initiative of Japan
Copyright (C) 2012, 2018 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,7 +24,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys, os
from gnuk_token import *
from gnuk_token import gnuk_devices, gnuk_token, parse_kdf_data
from kdf_calc import kdf_calc
# Assume only single CCID device is attached to computer and it's Gnuk Token
@@ -42,13 +43,28 @@ def main(passwd):
break
except:
pass
if not gnuk:
raise ValueError("No ICC present")
if gnuk.icc_get_status() == 2:
raise ValueError("No ICC present")
elif gnuk.icc_get_status() == 1:
gnuk.icc_power_on()
gnuk.cmd_select_openpgp()
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8'))
gnuk.cmd_select_openpgp()
# Compute passwd data
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tostring()
if kdf_data == b"":
passwd_data = passwd.encode('UTF-8')
else:
algo, subalgo, iters, salt_user, salt_reset, salt_admin, \
hash_user, hash_admin = parse_kdf_data(kdf_data)
if salt_admin:
salt = salt_admin
else:
salt = salt_user
passwd_data = kdf_calc(passwd, salt, iters)
# And authenticate with the passwd data
gnuk.cmd_verify(BY_ADMIN, passwd_data)
# Do remove keys and related data objects
gnuk.cmd_put_data_remove(0x00, 0xc7) # FP_SIG
gnuk.cmd_put_data_remove(0x00, 0xce) # KGTIME_SIG
gnuk.cmd_put_data_key_import_remove(1)

View File

@@ -1,7 +1,7 @@
"""
gnuk_token.py - a library for Gnuk Token
Copyright (C) 2011, 2012, 2013, 2015, 2017
Copyright (C) 2011, 2012, 2013, 2015, 2017, 2018
Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -30,6 +30,7 @@ from array import array
USB_PRODUCT_LIST=[
{ 'vendor' : 0x234b, 'product' : 0x0000 }, # FSIJ Gnuk Token
{ 'vendor' : 0x20a0, 'product' : 0x4211 }, # Nitrokey Start
{ 'vendor' : 0x1209, 'product' : 0x2440 }, # GnuPG e.V.
]
# USB class, subclass, protocol
@@ -74,6 +75,7 @@ class gnuk_token(object):
raise ValueError("Wrong interface sub class")
self.__devhandle = device.open()
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting
@@ -635,3 +637,48 @@ def UNSIGNED(n):
def crc32(bytestr):
crc = binascii.crc32(bytestr)
return UNSIGNED(crc)
def parse_kdf_data(kdf_data):
if len(kdf_data) == 90:
single_salt = True
elif len(kdf_data) == 110:
single_salt = False
else:
raise ValueError("length does not much", kdf_data)
if kdf_data[0:2] != b'\x81\x01':
raise ValueError("data does not much")
algo = kdf_data[2]
if kdf_data[3:5] != b'\x82\x01':
raise ValueError("data does not much")
subalgo = kdf_data[5]
if kdf_data[6:8] != b'\x83\x04':
raise ValueError("data does not much")
iters = unpack(">I", kdf_data[8:12])[0]
if kdf_data[12:14] != b'\x84\x08':
raise ValueError("data does not much")
salt = kdf_data[14:22]
if single_salt:
salt_reset = None
salt_admin = None
if kdf_data[22:24] != b'\x87\x20':
raise ValueError("data does not much")
hash_user = kdf_data[24:56]
if kdf_data[56:58] != b'\x88\x20':
raise ValueError("data does not much")
hash_admin = kdf_data[58:90]
else:
if kdf_data[22:24] != b'\x85\x08':
raise ValueError("data does not much")
salt_reset = kdf_data[24:32]
if kdf_data[32:34] != b'\x86\x08':
raise ValueError("data does not much")
salt_admin = kdf_data[34:42]
if kdf_data[42:44] != b'\x87\x20':
raise ValueError("data does not much")
hash_user = kdf_data[44:76]
if kdf_data[76:78] != b'\x88\x20':
raise ValueError("data does not much")
hash_admin = kdf_data[78:110]
return ( algo, subalgo, iters, salt, salt_reset, salt_admin,
hash_user, hash_admin )

51
tool/kdf_calc.py Normal file
View File

@@ -0,0 +1,51 @@
"""
kdf_calc.py - a library for calculating hash by KDF
Copyright (C) 2018 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from cffi import FFI
DEF_gcry_kdf_derive="""
typedef unsigned int gpg_error_t;
gpg_error_t gcry_kdf_derive (const void *passphrase, size_t passphraselen,
int algo, int subalgo, const void *salt,
size_t saltlen, unsigned long iterations,
size_t keysize, void *keybuffer);
"""
GCRY_KDF_ITERSALTED_S2K = 19
GCRY_MD_SHA256 = 8
def kdf_calc(pw_string, salt_byte, iterations):
ffi = FFI()
ffi.cdef(DEF_gcry_kdf_derive)
libgcrypt = ffi.dlopen("libgcrypt.so.20")
if isinstance(pw_string, str):
pw_byte = pw_string.encode('UTF-8')
else:
pw_byte = pw_string
pw=ffi.new("char []", pw_byte)
salt = ffi.new("char []", salt_byte)
kb = ffi.new("char []", 32)
r = libgcrypt.gcry_kdf_derive(pw, len(pw_string), GCRY_KDF_ITERSALTED_S2K,
GCRY_MD_SHA256, salt, 8, iterations, 32, kb)
if r != 0:
raise ValueError("libgcrypt error", r)
return ffi.unpack(kb, 32)

View File

@@ -28,7 +28,7 @@ from sexp import sexp
# Assume it's only OPENPGP.3 key and it's 2048-bit
def debug(string):
print "DEBUG: %s" % string
print("DEBUG: %s" % string)
sys.stdout.flush()
def get_keygrip_list(keyinfo_result):

View File

@@ -82,7 +82,7 @@ class Card(object):
elif code == FEATURE_MODIFY_PIN_DIRECT:
self.modify_ioctl = ioctl
if self.verify_ioctl == -1:
raise ValueError, "Not supported"
raise ValueError("Not supported")
def cmd_select_openpgp(self):
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
@@ -90,7 +90,7 @@ class Card(object):
if sw1 == 0x61: # More data
response, sw1, sw2 = self.connection.transmit([0x00, 0xc0, 0, 0, sw2])
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):
if self.another_byte:
@@ -135,11 +135,11 @@ class Card(object):
sw1 = data[0]
sw2 = data[1]
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):
if self.modify_ioctl == -1:
raise ValueError, "Not supported"
raise ValueError("Not supported")
pin_modify = [ 0x00, # bTimerOut
0x00, # bTimerOut2
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
@@ -171,7 +171,7 @@ class Card(object):
sw1 = data[0]
sw2 = data[1]
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):
if who == BY_ADMIN:
@@ -180,7 +180,7 @@ class Card(object):
apdu = [0x00, 0x2c, 0x00, 0x81, len(data) ] + data # BY_USER with resetcode
response, sw1, sw2 = self.connection.transmit(apdu)
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)
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
response, sw1, sw2 = self.connection.transmit(apdu)
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)
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()
ident = card.connection.getReader()
print "Reader/Token:", ident
print "ATR:", toHexString( card.connection.getATR() )
print("Reader/Token:", ident)
print("ATR:", toHexString( card.connection.getATR() ))
if ident == COVADIS_VEGA_ALPHA:
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()
if method == "verify":
if who == BY_USER:
print "Please input User's PIN"
print("Please input User's PIN")
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(who)
elif method == "change":
if change_by_two_steps:
if who == BY_USER:
print "Please input User's PIN"
print("Please input User's PIN")
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(who)
if who == BY_USER:
print "Please input New User's PIN twice"
print("Please input New User's PIN twice")
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)
else:
if who == BY_USER:
print "Please input User's PIN"
print "and New User's PIN twice"
print("Please input User's PIN")
print("and New User's PIN twice")
else:
print "Please input Admin's PIN"
print "and New Admin's PIN twice"
print("Please input Admin's PIN")
print("and New Admin's PIN twice")
card.cmd_change_reference_data_pinpad(who, False)
elif method == "unblock":
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: "))
card.cmd_reset_retry_counter(who,resetcode+newpin)
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(BY_ADMIN)
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
card.cmd_reset_retry_counter(who,newpin)
else:
if who == BY_USER:
print "Please input reset code"
print "and New User's PIN twice"
print("Please input reset code")
print("and New User's PIN twice")
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
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)
elif method == "put":
if change_by_two_steps:
# 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)
resetcode=s2l(getpass("Please input New Reset Code from keyboard: "))
card.cmd_put_resetcode(resetcode)
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
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()
else:
raise ValueError, method
raise ValueError(method)
card.connection.disconnect()
print "OK."
print("OK.")
return 0
def print_usage():
print "pinpad-test: testing pinentry of PC/SC card reader"
print " help:"
print "\t--help:\t\tthis message"
print " method:\t\t\t\t\t\t\t[verify]"
print "\t--verify:\tverify PIN"
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--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)"
print "\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)"
print "\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)"
print "\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)"
print " options:"
print "\t--fixed N:\tUse fixed length input"
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--pinmin:\tspecify minimum length of PIN\t\t[6]"
print "\t--pinmax:\tspecify maximum length of PIN\t\t[15]"
print "EXAMPLES:"
print " $ pinpad-test # verify user's PIN "
print " $ pinpad-test --admin # verify admin's PIN "
print " $ pinpad-test --change # change user'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 --admin # change admin's PIN by two steps"
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 --put # setup resetcode "
print("pinpad-test: testing pinentry of PC/SC card reader")
print(" help:")
print("\t--help:\t\tthis message")
print(" method:\t\t\t\t\t\t\t[verify]")
print("\t--verify:\tverify PIN")
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--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)")
print("\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)")
print("\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)")
print("\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)")
print(" options:")
print("\t--fixed N:\tUse fixed length input")
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--pinmin:\tspecify minimum length of PIN\t\t[6]")
print("\t--pinmax:\tspecify maximum length of PIN\t\t[15]")
print("EXAMPLES:")
print(" $ pinpad-test # verify user's PIN ")
print(" $ pinpad-test --admin # verify admin's PIN ")
print(" $ pinpad-test --change # change user'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 --admin # change admin's PIN by two steps")
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 --put # setup resetcode ")
if __name__ == '__main__':
who = BY_USER
@@ -374,7 +374,7 @@ if __name__ == '__main__':
print_usage()
exit(0)
else:
raise ValueError, option
raise ValueError(option)
main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed)
# Failure

View File

@@ -4,7 +4,8 @@
upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token
which is just shipped from factory
Copyright (C) 2012, 2013, 2015 Free Software Initiative of Japan
Copyright (C) 2012, 2013, 2015, 2018
Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -23,9 +24,13 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from gnuk_token import *
from gnuk_token import get_gnuk_device, gnuk_devices_by_vidpid, \
gnuk_token, regnual, SHA256_OID_PREFIX, crc32, parse_kdf_data
from kdf_calc import kdf_calc
import sys, binascii, time, os
import rsa
from struct import pack
DEFAULT_PW3 = "12345678"
BY_ADMIN = 3
@@ -45,7 +50,23 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
gnuk = get_gnuk_device()
gnuk.cmd_select_openpgp()
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8'))
# Compute passwd data
try:
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tostring()
except:
kdf_data = b""
if kdf_data == b"":
passwd_data = passwd.encode('UTF-8')
else:
algo, subalgo, iters, salt_user, salt_reset, salt_admin, \
hash_user, hash_admin = parse_kdf_data(kdf_data)
if salt_admin:
salt = salt_admin
else:
salt = salt_user
passwd_data = kdf_calc(passwd, salt, iters)
# And authenticate with the passwd data
gnuk.cmd_verify(BY_ADMIN, passwd_data)
gnuk.cmd_write_binary(1+keyno, rsa_raw_pubkey, False)
gnuk.cmd_select_openpgp()
@@ -71,7 +92,7 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
reg = None
print("Waiting for device to appear:")
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)
for dev in gnuk_devices_by_vidpid():
try: