Compare commits

...

63 Commits

Author SHA1 Message Date
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
58 changed files with 1705 additions and 278 deletions

200
ChangeLog
View File

@@ -1,3 +1,203 @@
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> 2018-01-23 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.8. * VERSION: 1.2.8.

64
NEWS
View File

@@ -1,5 +1,62 @@
Gnuk NEWS - User visible changes Gnuk NEWS - User visible changes
* 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 * Major changes in Gnuk 1.2.8
Released 2018-01-23, by NIIBE Yutaka Released 2018-01-23, by NIIBE Yutaka
@@ -830,6 +887,7 @@ Gnuk Token could run with GPG4WIN on MS Windows. GPG4WIN runs with
** This is initial release. Only it supports digital signing. ** This is initial release. Only it supports digital signing.
Local Variables:
mode: outline # Local Variables:
End: # mode: outline
# End:

61
README
View File

@@ -1,14 +1,14 @@
Gnuk - An Implementation of USB Cryptographic Token for GnuPG Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 1.2.8 Version 1.2.12
2018-01-23 2018-11-25
Niibe Yutaka Niibe Yutaka
Free Software Initiative of Japan Free Software Initiative of Japan
Release Notes Release Notes
============= =============
This is the release of Gnuk, version 1.2.8, which has major This is the release of Gnuk, version 1.2.12, which has major
incompatible changes to Gnuk 1.0.x. Specifically, it now supports incompatible changes to Gnuk 1.0.x. Specifically, it now supports
overriding key import, but importing keys (or generating keys) results overriding key import, but importing keys (or generating keys) results
password reset. Also, you need to import private keys before changing password reset. Also, you need to import private keys before changing
@@ -24,10 +24,12 @@ It also supports RSA-4096, but users should know that it takes more
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails, than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
because the device doesn't have enough memory. because the device doesn't have enough memory.
It supports new KDF-DO feature. To use the feature, you need to use It supports new KDF-DO feature. Please note that this is
newer GnuPG (forthcoming 2.2.5 or later). And you need to manually experimental. To use the feature, you need to use newer GnuPG (2.2.6
prepare the KDF-DO on your token. Please note that this is or later). You need to prepare the KDF-DO on your token by the
experimental. Better way to prepare KDF-DO will be expected. card-edit/kdf-setup command.
With FST-01SZ, experimental ack button support is available for test.
What's Gnuk? What's Gnuk?
@@ -35,7 +37,7 @@ What's Gnuk?
Gnuk is an implementation of USB cryptographic token for GNU Privacy Gnuk is an implementation of USB cryptographic token for GNU Privacy
Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on
STM32F103 processor. STM32F103 processor (and its compatible).
I wish that Gnuk will be a developer's soother who uses GnuPG. I have I wish that Gnuk will be a developer's soother who uses GnuPG. I have
been nervous of storing secret key(s) on usual secondary storage. been nervous of storing secret key(s) on usual secondary storage.
@@ -83,8 +85,7 @@ A3: Orthodox choice is Olimex STM32-H103.
choice for experiment. choice for experiment.
Q4: What's version of GnuPG are you using? Q4: What's version of GnuPG are you using?
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.18 in A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.18.
unstable.
Q5: What's version of pcscd and libccid are you using? Q5: What's version of pcscd and libccid are you using?
A5: I don't use them, pcscd and libccid are optional, you can use Gnuk A5: I don't use them, pcscd and libccid are optional, you can use Gnuk
@@ -178,15 +179,6 @@ Original features of Gnuk, tested manually lightly:
* Card holder certificate (write by UPDATE BINARY) * Card holder certificate (write by UPDATE BINARY)
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal * Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
It is known not-working well:
* It is known that the specific combination of libccid 1.4.1
(or newer) with libusb 1.0.8 (or older) had a minor problem.
It is rare but it is possible for USB communication to be
failed, because of a bug in libusb implementation. Use
libusbx 1.0.9 or newer, or don't use PC/SC, but use internal
CCID driver of GnuPG.
Targets Targets
======= =======
@@ -219,7 +211,8 @@ script prepending 'bash' before './configure'.
Some tools are written in Python. If your Python is not installed as Some tools are written in Python. If your Python is not installed as
/usr/bin/python, please prepend 'python' for your command invocation. /usr/bin/python, please prepend 'python' for your command invocation.
Python 2.7 and PyUSB 0.4.3 is assumed. Python 2.7 and PyUSB 0.4.3 is assumed. I also use Python 3.5 and
PyUSB 1.0.0.
Source code Source code
@@ -256,7 +249,7 @@ External source code
Gnuk is distributed with external source code. Gnuk is distributed with external source code.
* chopstx/ -- Chopstx 1.8 * chopstx/ -- Chopstx 1.12
We use Chopstx as the kernel for Gnuk. We use Chopstx as the kernel for Gnuk.
@@ -378,10 +371,10 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
On Debian we can install the packages of gcc-arm-none-eabi, On Debian we can install the packages of gcc-arm-none-eabi,
gdb-arm-none-eabi and its friends. I'm using: gdb-arm-none-eabi and its friends. I'm using:
binutils-arm-none-eabi 2.28-4+9+b3 binutils-arm-none-eabi 2.31.1-2+10
gcc-arm-none-eabi 15:6.3.1+svn253039-1 gcc-arm-none-eabi 15:7-2018-q2-4
gdb-arm-none-eabi 7.12-6+9+b2 gdb-arm-none-eabi 7.12-6+9+b2
libnewlib-arm-none-eabi 2.4.0.20160527-3 libnewlib-arm-none-eabi 3.0.0.20180802-2
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
GNU Toolchain for 'arm-none-eabi' target. GNU Toolchain for 'arm-none-eabi' target.
@@ -405,9 +398,11 @@ Then, type:
Then, we will have "gnuk.elf" under src/build directory. Then, we will have "gnuk.elf" under src/build directory.
Next, we can get the final image by running following command. If you are not the authorized vendor, please never distribute this
file of "gnuk.elf", which includes VID:PID in the image. If you would
$ make build/gnuk-vidpid.elf like to distribute the image (for example, to check if it's
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
VID:PID.
How to install How to install
@@ -417,11 +412,11 @@ Olimex STM32-H103 board
----------------------- -----------------------
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD
and write "gnuk-vidpid.elf" to Flash ROM: and write "gnuk.elf" to Flash ROM:
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \ $ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \
-f board/olimex_stm32_h103.cfg \ -f board/olimex_stm32_h103.cfg \
-c "program build/gnuk-vidpid.elf verify reset exit" -c "program build/gnuk.elf verify reset exit"
Command invocation is assumed in src/ directory. Command invocation is assumed in src/ directory.
@@ -434,7 +429,7 @@ If you are using Flying Stone Tiny 01, you need a SWD writer.
OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like: OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \ $ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
-c "program build/gnuk-vidpid.elf verify reset exit" -c "program build/gnuk.elf verify reset exit"
@@ -445,7 +440,7 @@ Reset the board with "USER" switch pushed. Type following to write
to flash: to flash:
# cd ../tool # cd ../tool
# ./dfuse.py ../src/build/gnuk-vidpid.hex # ./dfuse.py ../src/build/gnuk.hex
Then, reset the board. Then, reset the board.
@@ -535,8 +530,8 @@ Type following command to see Gnuk runs:
$ gpg --card-status $ gpg --card-status
Besides, there is a functionality test under test/ directory. See Besides, there is a functionality test under tests/ directory. See
test/README. tests/README.
Personalize the Token, import keys, and change the password Personalize the Token, import keys, and change the password

1
THANKS
View File

@@ -17,6 +17,7 @@ Bertrand Jacquin bertrand@jacquin.bzh
Clint Adams clint@softwarefreedom.org Clint Adams clint@softwarefreedom.org
Daniel Kahn Gillmor dkg@fifthhorseman.net Daniel Kahn Gillmor dkg@fifthhorseman.net
Elliott Mitchell Elliott Mitchell
Fabio Utzig utzig@apache.org
Hironobu SUZUKI hironobu@h2np.net Hironobu SUZUKI hironobu@h2np.net
Jan Suhr jan@suhr.info Jan Suhr jan@suhr.info
Jeremy Drake jeremydrake+gnuk@eacceleration.com Jeremy Drake jeremydrake+gnuk@eacceleration.com

View File

@@ -1 +1 @@
release/1.2.8 release/1.2.12

Submodule chopstx updated: aa63ac79bc...39683dbc5f

View File

@@ -58,6 +58,8 @@ Type: ::
Then, we will have "gnuk.elf" under src/build directory. Then, we will have "gnuk.elf" under src/build directory.
Next, we can get the final image by running following command. :: If you are not the authorized vendor, please never distribute this
file of "gnuk.elf", which includes VID:PID in the image. If you would
$ make build/gnuk-vidpid.elf like to distribute the image (for example, to check if it's
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
VID:PID.

View File

@@ -16,7 +16,7 @@ In addition to settings of Gnuk, I create a file
# For updating firmware, permission settings are needed. # For updating firmware, permission settings are needed.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \ SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd" ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
@@ -65,7 +65,7 @@ Invoking firmware update
We specify reGNUal binary and Gnuk binary. We specify reGNUal binary and Gnuk binary.
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk-vidpid.bin $ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk.bin
Two or more tokens Two or more tokens

View File

@@ -54,7 +54,7 @@ setting). It should have lines something like: ::
# Gnuk Token by FSIJ # Gnuk Token by FSIJ
SUBSYSTEMS=="usb", ACTION=="add", \ SUBSYSTEMS=="usb", ACTION=="add", \
ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \ ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg" ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
I have those lines in /etc/udev/rules.d/69-gnuk.rules. I have those lines in /etc/udev/rules.d/69-gnuk.rules.
@@ -78,14 +78,15 @@ is FST-01.
Then you get build/gnuk.elf. Then you get build/gnuk.elf.
Next, we can get the final image by running following command. If you are not the authorized vendor, please never distribute this
file of "gnuk.elf", which includes VID:PID in the image. If you would
$ make build/gnuk-vidpid.elf like to distribute the image (for example, to check if it's
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
VID:PID.
Invoking configure with FSIJ's USB ID (234b:0000) and generating Invoking configure with FSIJ's USB ID (234b:0000) and generating
gnuk-vidpid.elf means that you are using FSIJ's USB ID (for reGNUal in gnuk.elf means that you are using FSIJ's USB ID (for reGNUal in this
this case). Please note that FSIJ only allows use of its USB ID for case). Please note that FSIJ only allows use of its USB ID for
specific situations. Please read README of Gnuk about that. specific situations. Please read README of Gnuk about that.
@@ -121,7 +122,7 @@ your environment for Gnuk Token.
How to run the script: :: How to run the script: ::
$ cd tool $ cd tool
$ ./upgrade_by_passwd.py ../regnual/regnual.bin ../src/build/gnuk-vidpid.bin $ ./upgrade_by_passwd.py ../regnual/regnual.bin ../src/build/gnuk.bin
Then, the script on your host PC invoke the steps described above, and Then, the script on your host PC invoke the steps described above, and
you will get new version of Gnuk installed. you will get new version of Gnuk installed.

View File

@@ -30,9 +30,9 @@ command.
Or, you can use ``gpgconf`` command. Type:: 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 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). there will be no udev rules (there is a bug report #543217 for this issue).
In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules:: In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules::
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \ SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg" ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
Usually, udev daemon automatically handles for the changes of configuration Usually, udev daemon automatically handles for the changes of configuration

View File

@@ -77,11 +77,11 @@ distclean: clean
usb-strings.c.inc usb-vid-pid-ver.c.inc usb-strings.c.inc usb-vid-pid-ver.c.inc
ifeq ($(EMULATION),) ifeq ($(EMULATION),)
build/gnuk-vidpid.elf: build/gnuk.elf binary-edit.sh put-vid-pid-ver.sh build/gnuk.elf: build/gnuk-no-vidpid.elf binary-edit.sh put-vid-pid-ver.sh
cp -p build/gnuk.elf build/gnuk-vidpid.elf cp -p build/gnuk-no-vidpid.elf build/gnuk.elf
env FILE="build/gnuk-vidpid.elf" bash put-vid-pid-ver.sh env FILE="build/gnuk.elf" bash put-vid-pid-ver.sh
$(OBJCOPY) -O ihex build/gnuk-vidpid.elf build/gnuk-vidpid.hex $(OBJCOPY) -O ihex build/gnuk.elf build/gnuk.hex
$(OBJCOPY) -O binary build/gnuk-vidpid.elf build/gnuk-vidpid.bin $(OBJCOPY) -O binary build/gnuk.elf build/gnuk.bin
else else
# By specifying DESTDIR on invocation of "make", you can install # By specifying DESTDIR on invocation of "make", you can install
# program to different ROOT. # program to different ROOT.

View File

@@ -7,5 +7,6 @@
@PINPAD_MORE_DEFINE@ @PINPAD_MORE_DEFINE@
@CERTDO_DEFINE@ @CERTDO_DEFINE@
@HID_CARD_CHANGE_DEFINE@ @HID_CARD_CHANGE_DEFINE@
@SERIALNO_STR_LEN_DEFINE@
@LIFE_CYCLE_MANAGEMENT_DEFINE@ @LIFE_CYCLE_MANAGEMENT_DEFINE@
@ACKBTN_DEFINE@
@SERIALNO_STR_LEN_DEFINE@

27
src/configure vendored
View File

@@ -44,6 +44,7 @@ pinpad=no
certdo=no certdo=no
hid_card_change=no hid_card_change=no
factory_reset=no factory_reset=no
ackbtn_support=yes
flash_override="" flash_override=""
# For emulation # For emulation
prefix=/usr/local prefix=/usr/local
@@ -135,6 +136,7 @@ Configuration:
supported targets are: supported targets are:
FST_01 FST_01
FST_01G FST_01G
FST_01SZ
OLIMEX_STM32_H103 OLIMEX_STM32_H103
MAPLE_MINI MAPLE_MINI
ST_DONGLE ST_DONGLE
@@ -167,6 +169,8 @@ BOARD_HEADER_FILE=board-$(echo $target | tr '_[:upper:]' '-[:lower:]').h
echo "Header file is: $BOARD_HEADER_FILE" echo "Header file is: $BOARD_HEADER_FILE"
ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h
# Frequency
MHZ=72
# Flash page size in byte # Flash page size in byte
FLASH_PAGE_SIZE=1024 FLASH_PAGE_SIZE=1024
# Flash memory size in KiB # Flash memory size in KiB
@@ -196,6 +200,12 @@ STBEE)
if test "$with_dfu" = "default"; then if test "$with_dfu" = "default"; then
with_dfu=yes; with_dfu=yes;
fi ;; fi ;;
BLUE_PILL_G)
MHZ=96
;;
FST_01SZ)
MHZ=96
;;
*) *)
;; ;;
esac esac
@@ -208,6 +218,7 @@ if test "$target" = "GNU_LINUX"; then
mcu="none" mcu="none"
def_emulation="-DGNU_LINUX_EMULATION" def_emulation="-DGNU_LINUX_EMULATION"
def_memory_size="-DMEMORY_SIZE=1024" def_memory_size="-DMEMORY_SIZE=1024"
def_mhz=""
enable_hexoutput="" enable_hexoutput=""
libs="-lpthread" libs="-lpthread"
else else
@@ -218,6 +229,7 @@ else
mcu="cortex-m3" mcu="cortex-m3"
def_emulation="" def_emulation=""
def_memory_size="-DMEMORY_SIZE=$MEMORY_SIZE" def_memory_size="-DMEMORY_SIZE=$MEMORY_SIZE"
def_mhz="-DMHZ=$MHZ"
enable_hexoutput=yes enable_hexoutput=yes
libs="" libs=""
fi fi
@@ -306,6 +318,15 @@ else
echo "Life cycle management is NOT supported" echo "Life cycle management is NOT supported"
fi fi
# Acknowledge button support
if test "$ackbtn_support" = "yes"; then
ACKBTN_DEFINE="#define ACKBTN_SUPPORT 1"
echo "Acknowledge button is supported"
else
ACKBTN_DEFINE="#undef ACKBTN_SUPPORT"
echo "Acknowledge button is not supported"
fi
### !!! Replace following string of "FSIJ" to yours !!! #### ### !!! Replace following string of "FSIJ" to yours !!! ####
SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-" SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
@@ -442,13 +463,16 @@ fi
echo "EMULATION=$emulation"; echo "EMULATION=$emulation";
echo "CROSS=$cross"; echo "CROSS=$cross";
echo "MCU=$mcu"; echo "MCU=$mcu";
echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size"; echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size $def_mhz";
echo "LDSCRIPT=$ldscript"; echo "LDSCRIPT=$ldscript";
echo "LIBS=$libs"; echo "LIBS=$libs";
echo "$DEBUG_MAKE_OPTION"; echo "$DEBUG_MAKE_OPTION";
echo "$PINPAD_MAKE_OPTION"; echo "$PINPAD_MAKE_OPTION";
echo "ENABLE_FRAUCHEKY=$enable_fraucheky"; echo "ENABLE_FRAUCHEKY=$enable_fraucheky";
echo "ENABLE_OUTPUT_HEX=$enable_hexoutput" echo "ENABLE_OUTPUT_HEX=$enable_hexoutput"
if test "$ackbtn_support" = "yes"; then
echo "USE_ACKBTN=yes"
fi
if test "$emulation" = "yes"; then if test "$emulation" = "yes"; then
echo "prefix=$prefix" echo "prefix=$prefix"
echo "exec_prefix=$exec_prefix" echo "exec_prefix=$exec_prefix"
@@ -476,6 +500,7 @@ sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \ -e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \ -e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \ -e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
-e "s/@ACKBTN_DEFINE@/$ACKBTN_DEFINE/" \
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \ -e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
< config.h.in > config.h < config.h.in > config.h
exit 0 exit 0

View File

@@ -1,7 +1,7 @@
/* /*
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM * 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 * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -71,7 +71,7 @@ static const uint8_t *data_pool;
static uint8_t *last_p; static uint8_t *last_p;
/* The first halfword is generation for the data page (little endian) */ /* The first halfword is generation for the data page (little endian) */
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = { const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
0x00, 0x00, 0xff, 0xff 0x00, 0x00, 0xff, 0xff
}; };
@@ -157,6 +157,12 @@ flash_terminate (void)
{ {
int i; 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++) for (i = 0; i < 3; i++)
flash_erase_page ((uintptr_t)flash_key_getpage (i)); flash_erase_page ((uintptr_t)flash_key_getpage (i));
flash_erase_page ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START); flash_erase_page ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START);

View File

@@ -24,10 +24,11 @@ extern struct apdu apdu;
void ccid_card_change_signal (int how); void ccid_card_change_signal (int how);
/* CCID thread */ /* CCID thread */
#define EV_RX_DATA_READY 1 /* USB Rx data available */ #define EV_RX_DATA_READY 1 /* USB Rx data available */
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */ #define EV_EXEC_ACK_REQUIRED 2 /* OpenPGPcard Execution ACK required*/
#define EV_TX_FINISHED 4 /* CCID Tx finished */ #define EV_EXEC_FINISHED 4 /* OpenPGPcard Execution finished */
#define EV_CARD_CHANGE 8 #define EV_TX_FINISHED 8 /* CCID Tx finished */
#define EV_CARD_CHANGE 16
/* OpenPGPcard thread */ /* OpenPGPcard thread */
#define EV_PINPAD_INPUT_DONE 1 #define EV_PINPAD_INPUT_DONE 1
@@ -53,17 +54,17 @@ enum ccid_state {
CCID_STATE_NOCARD, /* No card available */ CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */ CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */ CCID_STATE_WAIT, /* Waiting APDU */
/* Busy1, Busy2, Busy3, Busy5 */
CCID_STATE_EXECUTE, /* Busy4 */
CCID_STATE_RECEIVE, /* APDU Received Partially */
CCID_STATE_SEND, /* APDU Sent Partially */
CCID_STATE_EXITED, /* ICC Thread Terminated */ CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */ CCID_STATE_EXEC_REQUESTED, /* Exec requested */
}; };
extern enum ccid_state *const ccid_state_p; enum ccid_state ccid_get_ccid_state (void);
extern volatile uint8_t auth_status; extern volatile uint8_t auth_status;
#define AC_NONE_AUTHORIZED 0x00 #define AC_NONE_AUTHORIZED 0x00
@@ -123,8 +124,8 @@ const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
enum kind_of_key { enum kind_of_key {
GPG_KEY_FOR_SIGNING = 0, GPG_KEY_FOR_SIGNING = 0,
GPG_KEY_FOR_DECRYPTION, GPG_KEY_FOR_DECRYPTION = 1,
GPG_KEY_FOR_AUTHENTICATION, GPG_KEY_FOR_AUTHENTICATION = 2,
}; };
enum size_of_key { enum size_of_key {
@@ -296,6 +297,7 @@ void gpg_increment_digital_signature_counter (void);
void gpg_do_get_initial_pw_setting (int is_pw3, int *r_len, void gpg_do_get_initial_pw_setting (int is_pw3, int *r_len,
const uint8_t **r_p); const uint8_t **r_p);
int gpg_do_kdf_check (int len, int how_many); int gpg_do_kdf_check (int len, int how_many);
int gpg_do_get_uif (enum kind_of_key kk);
void fatal (uint8_t code) __attribute__ ((noreturn)); void fatal (uint8_t code) __attribute__ ((noreturn));
@@ -378,7 +380,17 @@ extern uint8_t admin_authorized;
#define NR_KEY_ALGO_ATTR_DEC 0xf2 #define NR_KEY_ALGO_ATTR_DEC 0xf2
#define NR_KEY_ALGO_ATTR_AUT 0xf3 #define NR_KEY_ALGO_ATTR_AUT 0xf3
/* /*
* NR_UINT_SOMETHING could be here... Use 0xf[456789abcd] * Representation of User Interaction Flag:
* 0 (UIF disabled): 0xf?00 or No record in flash memory
* 1 (UIF enabled): 0xf?01
* 2 (UIF permanently enabled): 0xf?02
*
*/
#define NR_DO_UIF_SIG 0xf6
#define NR_DO_UIF_DEC 0xf7
#define NR_DO_UIF_AUT 0xf8
/*
* NR_UINT_SOMETHING could be here... Use 0xf[459abcd]
*/ */
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */ /* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
/* /*
@@ -434,6 +446,7 @@ extern const uint8_t gnuk_string_serial[];
#define LED_GNUK_EXEC 32 #define LED_GNUK_EXEC 32
#define LED_START_COMMAND 64 #define LED_START_COMMAND 64
#define LED_FINISH_COMMAND 128 #define LED_FINISH_COMMAND 128
#define LED_WAIT_FOR_BUTTON 256
#define LED_OFF LED_FINISH_COMMAND #define LED_OFF LED_FINISH_COMMAND
void led_blink (int spec); void led_blink (int spec);
@@ -461,6 +474,7 @@ int pinpad_getline (int msg_code, uint32_t timeout_usec);
#endif #endif
extern uint8_t _regnual_start, __heap_end__[]; extern uint8_t _regnual_start, __heap_end__[];
uint8_t * sram_address (uint32_t offset); uint8_t * sram_address (uint32_t offset);

View File

@@ -1,7 +1,7 @@
/* /*
* main.c - main routine of Gnuk * main.c - main routine of Gnuk
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017 * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -68,7 +68,7 @@ device_initialize_once (void)
* This is the first time invocation. * This is the first time invocation.
* Setup serial number by unique device ID. * Setup serial number by unique device ID.
*/ */
const uint8_t *u = unique_device_id () + 8; const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
int i; int i;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@@ -146,7 +146,7 @@ emit_led (uint32_t on_time, uint32_t off_time)
static void static void
display_status_code (void) display_status_code (void)
{ {
enum ccid_state ccid_state = *ccid_state_p; enum ccid_state ccid_state = ccid_get_ccid_state ();
uint32_t usec; uint32_t usec;
if (ccid_state == CCID_STATE_START) if (ccid_state == CCID_STATE_START)
@@ -170,8 +170,7 @@ display_status_code (void)
{ {
usec = LED_TIMEOUT_INTERVAL; usec = LED_TIMEOUT_INTERVAL;
chopstx_poll (&usec, 1, led_event_poll); chopstx_poll (&usec, 1, led_event_poll);
emit_led (ccid_state == CCID_STATE_RECEIVE? emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
} }
} }
} }
@@ -238,6 +237,7 @@ main (int argc, const char *argv[])
uintptr_t entry; uintptr_t entry;
#endif #endif
chopstx_t ccid_thd; chopstx_t ccid_thd;
int wait_for_ack = 0;
chopstx_conf_idle (1); chopstx_conf_idle (1);
@@ -354,7 +354,11 @@ main (int argc, const char *argv[])
{ {
eventmask_t m; 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) switch (m)
{ {
case LED_ONESHOT: case LED_ONESHOT:
@@ -375,8 +379,11 @@ main (int argc, const char *argv[])
break; break;
case LED_GNUK_EXEC: case LED_GNUK_EXEC:
goto exec; goto exec;
case LED_WAIT_FOR_BUTTON:
wait_for_ack ^= 1;
/* fall through */
default: default:
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP); emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_ZERO);
break; break;
} }
} }

View File

@@ -1,7 +1,7 @@
/* /*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling * openpgp-do.c -- OpenPGP card Data Objects (DO) handling
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -135,6 +135,14 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
0x01, 0x00, 0x01, 0x00,
}; };
#ifdef ACKBTN_SUPPORT
/* General Feature Management */
static const uint8_t feature_mngmnt[] __attribute__ ((aligned (1))) = {
3,
0x81, 0x01, 0x20,
};
#endif
/* Algorithm Attributes */ /* Algorithm Attributes */
#define OPENPGP_ALGO_RSA 0x01 #define OPENPGP_ALGO_RSA 0x01
#define OPENPGP_ALGO_ECDH 0x12 #define OPENPGP_ALGO_ECDH 0x12
@@ -649,7 +657,7 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
if (vid == 0xffff || vid == 0x0000) if (vid == 0xffff || vid == 0x0000)
{ {
const uint8_t *u = unique_device_id () + 8; const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
memcpy (res_p, openpgpcard_aid, 8); memcpy (res_p, openpgpcard_aid, 8);
res_p += 8; res_p += 8;
@@ -807,7 +815,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_KDF_ITERSALTED_S2K 3
#define OPENPGP_SHA256 8 #define OPENPGP_SHA256 8
@@ -826,32 +893,55 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
|| do_ptr[NR_DO_PRVKEY_AUT]) || do_ptr[NR_DO_PRVKEY_AUT])
return 0; 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) if (*do_data_p)
flash_do_release (*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) if (len == 0)
{ {
*do_data_p = NULL; *do_data_p = NULL;
return 1; 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 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) if (*do_data_p)
return 1; return 1;
else else
@@ -860,7 +950,11 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
} }
else 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; return 1;
} }
} }
@@ -868,10 +962,22 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
int int
gpg_do_kdf_check (int len, int how_many) 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) if (kdf_do)
return 0; {
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; return 1;
} }
@@ -879,15 +985,29 @@ gpg_do_kdf_check (int len, int how_many)
void void
gpg_do_get_initial_pw_setting (int is_pw3, int *r_len, const uint8_t **r_p) 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; *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 else
*r_p = kdf_spec + 44; {
if (is_pw3)
*r_p = kdf_spec + 78;
else
*r_p = kdf_spec + 44;
}
} }
else else
{ {
@@ -917,34 +1037,45 @@ proc_resetting_code (const uint8_t *data, int len)
DEBUG_INFO ("Resetting Code!\r\n"); DEBUG_INFO ("Resetting Code!\r\n");
if (gpg_do_kdf_check (len, 1) == 0) if (len == 0)
return 0; { /* Removal of resetting code. */
enum kind_of_key kk0;
newpw_len = len; for (kk0 = 0; kk0 <= GPG_KEY_FOR_AUTHENTICATION; kk0++)
newpw = data; gpg_do_chks_prvkey (kk0, BY_RESETCODE, NULL, 0, NULL);
new_ks0[0] = newpw_len; gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
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 else
{ {
DEBUG_INFO ("done.\r\n"); if (gpg_do_kdf_check (len, 1) == 0)
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KS_META_SIZE); 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); gpg_pw_reset_err_counter (PW_ERR_RC);
@@ -1549,18 +1680,32 @@ static const uint16_t cmp_ch_data[] = {
}; };
static const uint16_t cmp_app_data[] = { static const uint16_t cmp_app_data[] = {
#ifdef ACKBTN_SUPPORT
4,
#else
3, 3,
#endif
GPG_DO_AID, GPG_DO_AID,
GPG_DO_HIST_BYTES, GPG_DO_HIST_BYTES,
GPG_DO_DISCRETIONARY, GPG_DO_DISCRETIONARY,
#ifdef ACKBTN_SUPPORT
GPG_DO_FEATURE_MNGMNT,
#endif
}; };
static const uint16_t cmp_discretionary[] = { static const uint16_t cmp_discretionary[] = {
#ifdef ACKBTN_SUPPORT
11,
#else
8, 8,
#endif
GPG_DO_EXTCAP, GPG_DO_EXTCAP,
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT, GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
GPG_DO_PW_STATUS, GPG_DO_PW_STATUS,
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL,
#ifdef ACKBTN_SUPPORT
GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT
#endif
}; };
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT }; static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
@@ -1599,11 +1744,19 @@ gpg_do_table[] = {
rw_algorithm_attr }, rw_algorithm_attr },
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, { GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_algorithm_attr }, rw_algorithm_attr },
#ifdef ACKBTN_SUPPORT
{ GPG_DO_UIF_SIG, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
{ GPG_DO_UIF_DEC, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
{ GPG_DO_UIF_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
#endif
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, { GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_kdf }, rw_kdf },
/* Fixed data */ /* Fixed data */
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes }, { GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities }, { GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
#ifdef ACKBTN_SUPPORT
{ GPG_DO_FEATURE_MNGMNT, DO_FIXED, AC_ALWAYS, AC_NEVER, feature_mngmnt },
#endif
/* Compound data: Read access only */ /* Compound data: Read access only */
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data }, { GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data }, { GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
@@ -1642,6 +1795,11 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
pw_err_counter_p[PW_ERR_PW3] = NULL; pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL; algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
digital_signature_counter = 0; digital_signature_counter = 0;
uif_flags = 0;
/* Clear all data objects. */
for (i = 0; i < NR_DO__LAST__; i++)
do_ptr[i] = NULL;
/* When the card is terminated no data objects are valid. */ /* When the card is terminated no data objects are valid. */
if (do_start == NULL) if (do_start == NULL)
@@ -1700,6 +1858,13 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
algo_attr_aut_p = p - 1; algo_attr_aut_p = p - 1;
p++; p++;
break; break;
case NR_DO_UIF_SIG:
case NR_DO_UIF_DEC:
case NR_DO_UIF_AUT:
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
uif_flags |= (second_byte & 3) << ((nr - NR_DO_UIF_SIG) * 2);
p++;
break;
case NR_COUNTER_123: case NR_COUNTER_123:
p++; p++;
if (second_byte <= PW_ERR_PW3) if (second_byte <= PW_ERR_PW3)
@@ -1799,6 +1964,13 @@ gpg_data_copy (const uint8_t *p_start)
p += 4; p += 4;
} }
for (i = 0; i < 3; i++)
if ((v = (uif_flags & (3 << (i * 2)))))
{
flash_enum_write_internal (p, NR_DO_UIF_SIG + 1, v);
p += 2;
}
data_objects_number_of_bytes = 0; data_objects_number_of_bytes = 0;
for (i = 0; i < NR_DO__LAST__; i++) for (i = 0; i < NR_DO__LAST__; i++)
if (do_ptr[i] != NULL) if (do_ptr[i] != NULL)

View File

@@ -145,7 +145,7 @@ get_pinpad_input (int msg_code)
#endif #endif
static void static void
cmd_verify (void) cmd_verify (struct eventflag *ccid_comm)
{ {
int len; int len;
uint8_t p1 = P1 (apdu); uint8_t p1 = P1 (apdu);
@@ -153,6 +153,7 @@ cmd_verify (void)
int r; int r;
const uint8_t *pw; const uint8_t *pw;
(void)ccid_comm;
DEBUG_INFO (" - VERIFY\r\n"); DEBUG_INFO (" - VERIFY\r\n");
DEBUG_BYTE (p2); DEBUG_BYTE (p2);
@@ -171,7 +172,8 @@ cmd_verify (void)
r = ac_check_status (AC_ADMIN_AUTHORIZED); r = ac_check_status (AC_ADMIN_AUTHORIZED);
if (r) if (r)
GPG_SUCCESS (); /* If authentication done already, return success. */ /* If authentication done already, return success. */
GPG_SUCCESS ();
else else
{ /* If not, return retry counter, encoded. */ { /* If not, return retry counter, encoded. */
r = gpg_pw_get_retry_counter (p2); r = gpg_pw_get_retry_counter (p2);
@@ -274,7 +276,7 @@ gpg_change_keystring (int who_old, const uint8_t *old_ks,
} }
static void static void
cmd_change_password (void) cmd_change_password (struct eventflag *ccid_comm)
{ {
uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_SIZE]; uint8_t new_ks0[KEYSTRING_SIZE];
@@ -294,6 +296,7 @@ cmd_change_password (void)
int salt_len; int salt_len;
const uint8_t *ks_pw3; const uint8_t *ks_pw3;
(void)ccid_comm;
DEBUG_INFO ("Change PW\r\n"); DEBUG_INFO ("Change PW\r\n");
DEBUG_BYTE (who); DEBUG_BYTE (who);
@@ -365,8 +368,24 @@ cmd_change_password (void)
if (ks_pw3 == NULL) if (ks_pw3 == NULL)
{ {
salt = NULL; if (admin_authorized == BY_USER)
salt_len = 0; {
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 else
{ {
@@ -530,7 +549,7 @@ s2k (const unsigned char *salt, size_t slen,
static void static void
cmd_reset_user_password (void) cmd_reset_user_password (struct eventflag *ccid_comm)
{ {
uint8_t p1 = P1 (apdu); uint8_t p1 = P1 (apdu);
int len; int len;
@@ -544,6 +563,7 @@ cmd_reset_user_password (void)
const uint8_t *salt; const uint8_t *salt;
int salt_len; int salt_len;
(void)ccid_comm;
DEBUG_INFO ("Reset PW1\r\n"); DEBUG_INFO ("Reset PW1\r\n");
DEBUG_BYTE (p1); DEBUG_BYTE (p1);
@@ -554,6 +574,7 @@ cmd_reset_user_password (void)
{ {
const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC); const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t old_ks[KEYSTRING_MD_SIZE];
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
if (gpg_do_kdf_check (len, 2) == 0) if (gpg_do_kdf_check (len, 2) == 0)
{ {
@@ -580,6 +601,16 @@ cmd_reset_user_password (void)
salt_len = SALT_SIZE; salt_len = SALT_SIZE;
newpw = pw + pw_len; newpw = pw + pw_len;
newpw_len = len - 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); random_get_salt (new_salt);
s2k (salt, salt_len, pw, pw_len, old_ks); s2k (salt, salt_len, pw, pw_len, old_ks);
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks); s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
@@ -667,12 +698,13 @@ cmd_reset_user_password (void)
} }
static void static void
cmd_put_data (void) cmd_put_data (struct eventflag *ccid_comm)
{ {
uint8_t *data; uint8_t *data;
uint16_t tag; uint16_t tag;
int len; int len;
(void)ccid_comm;
DEBUG_INFO (" - PUT DATA\r\n"); DEBUG_INFO (" - PUT DATA\r\n");
tag = ((P1 (apdu)<<8) | P2 (apdu)); tag = ((P1 (apdu)<<8) | P2 (apdu));
@@ -682,8 +714,9 @@ cmd_put_data (void)
} }
static void static void
cmd_pgp_gakp (void) cmd_pgp_gakp (struct eventflag *ccid_comm)
{ {
(void)ccid_comm;
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n"); DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
DEBUG_BYTE (P1 (apdu)); DEBUG_BYTE (P1 (apdu));
@@ -717,12 +750,13 @@ gpg_get_firmware_update_key (uint8_t keyno)
#endif #endif
static void static void
cmd_read_binary (void) cmd_read_binary (struct eventflag *ccid_comm)
{ {
int is_short_EF = (P1 (apdu) & 0x80) != 0; int is_short_EF = (P1 (apdu) & 0x80) != 0;
uint8_t file_id; uint8_t file_id;
uint16_t offset; uint16_t offset;
(void)ccid_comm;
DEBUG_INFO (" - Read binary\r\n"); DEBUG_INFO (" - Read binary\r\n");
if (is_short_EF) if (is_short_EF)
@@ -793,8 +827,9 @@ cmd_read_binary (void)
} }
static void static void
cmd_select_file (void) cmd_select_file (struct eventflag *ccid_comm)
{ {
(void)ccid_comm;
if (P1 (apdu) == 4) /* Selection by DF name */ if (P1 (apdu) == 4) /* Selection by DF name */
{ {
DEBUG_INFO (" - select DF by name\r\n"); DEBUG_INFO (" - select DF by name\r\n");
@@ -863,10 +898,11 @@ cmd_select_file (void)
} }
static void static void
cmd_get_data (void) cmd_get_data (struct eventflag *ccid_comm)
{ {
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu)); uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
(void)ccid_comm;
DEBUG_INFO (" - Get Data\r\n"); DEBUG_INFO (" - Get Data\r\n");
gpg_do_get_data (tag, 0); gpg_do_get_data (tag, 0);
@@ -881,7 +917,7 @@ cmd_get_data (void)
#define ECC_CIPHER_DO_HEADER_SIZE 7 #define ECC_CIPHER_DO_HEADER_SIZE 7
static void static void
cmd_pso (void) cmd_pso (struct eventflag *ccid_comm)
{ {
int len = apdu.cmd_apdu_data_len; int len = apdu.cmd_apdu_data_len;
int r = -1; int r = -1;
@@ -908,6 +944,11 @@ cmd_pso (void)
return; return;
} }
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K) if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{ {
/* Check size of digestInfo */ /* Check size of digestInfo */
@@ -999,6 +1040,13 @@ cmd_pso (void)
return; return;
} }
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#else
(void)ccid_comm;
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K) if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{ {
/* Skip padding 0x00 */ /* Skip padding 0x00 */
@@ -1075,7 +1123,7 @@ cmd_pso (void)
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */ #define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
static void static void
cmd_internal_authenticate (void) cmd_internal_authenticate (struct eventflag *ccid_comm)
{ {
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION); int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION, int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
@@ -1105,6 +1153,13 @@ cmd_internal_authenticate (void)
return; return;
} }
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#else
(void)ccid_comm;
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K) if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{ {
if (len > MAX_RSA_DIGEST_INFO_LEN) if (len > MAX_RSA_DIGEST_INFO_LEN)
@@ -1281,10 +1336,11 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
#if defined(CERTDO_SUPPORT) #if defined(CERTDO_SUPPORT)
static void static void
cmd_update_binary (void) cmd_update_binary (struct eventflag *ccid_comm)
{ {
int len = apdu.cmd_apdu_data_len; int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - UPDATE BINARY\r\n"); DEBUG_INFO (" - UPDATE BINARY\r\n");
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len); modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("UPDATE BINARY done.\r\n"); DEBUG_INFO ("UPDATE BINARY done.\r\n");
@@ -1293,10 +1349,11 @@ cmd_update_binary (void)
static void static void
cmd_write_binary (void) cmd_write_binary (struct eventflag *ccid_comm)
{ {
int len = apdu.cmd_apdu_data_len; int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - WRITE BINARY\r\n"); DEBUG_INFO (" - WRITE BINARY\r\n");
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len); modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("WRITE BINARY done.\r\n"); DEBUG_INFO ("WRITE BINARY done.\r\n");
@@ -1305,7 +1362,7 @@ cmd_write_binary (void)
#ifdef FLASH_UPGRADE_SUPPORT #ifdef FLASH_UPGRADE_SUPPORT
static void static void
cmd_external_authenticate (void) cmd_external_authenticate (struct eventflag *ccid_comm)
{ {
const uint8_t *pubkey; const uint8_t *pubkey;
const uint8_t *signature = apdu.cmd_apdu_data; const uint8_t *signature = apdu.cmd_apdu_data;
@@ -1313,6 +1370,7 @@ cmd_external_authenticate (void)
uint8_t keyno = P2 (apdu); uint8_t keyno = P2 (apdu);
int r; int r;
(void)ccid_comm;
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n"); DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
if (keyno >= 4) if (keyno >= 4)
@@ -1348,10 +1406,11 @@ cmd_external_authenticate (void)
#endif #endif
static void static void
cmd_get_challenge (void) cmd_get_challenge (struct eventflag *ccid_comm)
{ {
int len = apdu.expected_res_size; int len = apdu.expected_res_size;
(void)ccid_comm;
DEBUG_INFO (" - GET CHALLENGE\r\n"); DEBUG_INFO (" - GET CHALLENGE\r\n");
if (len > CHALLENGE_LEN) if (len > CHALLENGE_LEN)
@@ -1376,8 +1435,9 @@ cmd_get_challenge (void)
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT #ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
static void static void
cmd_activate_file (void) cmd_activate_file (struct eventflag *ccid_comm)
{ {
(void)ccid_comm;
if (file_selection != FILE_CARD_TERMINATED) if (file_selection != FILE_CARD_TERMINATED)
{ {
GPG_NO_RECORD (); GPG_NO_RECORD ();
@@ -1390,13 +1450,13 @@ cmd_activate_file (void)
} }
static void static void
cmd_terminate_df (void) cmd_terminate_df (struct eventflag *ccid_comm)
{ {
const uint8_t *ks_pw3; const uint8_t *ks_pw3;
uint8_t p1 = P1 (apdu); uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu); uint8_t p2 = P2 (apdu);
(void)ccid_comm;
if (file_selection != FILE_DF_OPENPGP) if (file_selection != FILE_DF_OPENPGP)
{ {
GPG_NO_RECORD (); GPG_NO_RECORD ();
@@ -1440,7 +1500,7 @@ cmd_terminate_df (void)
struct command struct command
{ {
uint8_t command; uint8_t command;
void (*cmd_handler) (void); void (*cmd_handler) (struct eventflag *ccid_comm);
}; };
const struct command cmds[] = { const struct command cmds[] = {
@@ -1474,7 +1534,7 @@ const struct command cmds[] = {
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command))) #define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
static void static void
process_command_apdu (void) process_command_apdu (struct eventflag *ccid_comm)
{ {
int i; int i;
uint8_t cmd = INS (apdu); uint8_t cmd = INS (apdu);
@@ -1498,7 +1558,7 @@ process_command_apdu (void)
else else
{ {
chopstx_setcancelstate (1); chopstx_setcancelstate (1);
cmds[i].cmd_handler (); cmds[i].cmd_handler (ccid_comm);
chopstx_setcancelstate (0); chopstx_setcancelstate (0);
} }
} }
@@ -1612,7 +1672,7 @@ openpgp_card_thread (void *arg)
break; break;
led_blink (LED_START_COMMAND); led_blink (LED_START_COMMAND);
process_command_apdu (); process_command_apdu (ccid_comm);
led_blink (LED_FINISH_COMMAND); led_blink (LED_FINISH_COMMAND);
done: done:
eventflag_signal (ccid_comm, EV_EXEC_FINISHED); eventflag_signal (ccid_comm, EV_EXEC_FINISHED);

View File

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

View File

@@ -3,7 +3,7 @@
#define SIZE_2 4096 #define SIZE_2 4096
#define SIZE_3 (5 * 4096) #define SIZE_3 (5 * 4096)
#else #else
#define SIZE_0 0x0150 /* Main */ #define SIZE_0 0x0160 /* Main */
#define SIZE_1 0x01a0 /* CCID */ #define SIZE_1 0x01a0 /* CCID */
#define SIZE_2 0x0180 /* RNG */ #define SIZE_2 0x0180 /* RNG */
#if MEMORY_SIZE >= 32 #if MEMORY_SIZE >= 32

View File

@@ -1,7 +1,7 @@
/* /*
* usb-ccid.c -- USB CCID protocol handling * usb-ccid.c -- USB CCID protocol handling
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -29,6 +29,10 @@
#include "config.h" #include "config.h"
#ifdef ACKBTN_SUPPORT
#include <contrib/ackbtn.h>
#endif
#ifdef DEBUG #ifdef DEBUG
#include "usb-cdc.h" #include "usb-cdc.h"
#include "debug.h" #include "debug.h"
@@ -182,9 +186,10 @@ struct ccid_header {
/* Data structure handled by CCID layer */ /* Data structure handled by CCID layer */
struct ccid { struct ccid {
enum ccid_state ccid_state; uint32_t ccid_state : 4;
uint8_t state; uint32_t state : 4;
uint8_t err; uint32_t err : 1;
uint32_t tx_busy : 1;
uint8_t *p; uint8_t *p;
size_t len; size_t len;
@@ -241,6 +246,7 @@ struct ccid {
static void ccid_reset (struct ccid *c) static void ccid_reset (struct ccid *c)
{ {
c->err = 0; c->err = 0;
c->tx_busy = 0;
c->state = APDU_STATE_WAIT_COMMAND; c->state = APDU_STATE_WAIT_COMMAND;
c->p = c->a->cmd_apdu_data; c->p = c->a->cmd_apdu_data;
c->len = MAX_CMD_APDU_DATA_SIZE; c->len = MAX_CMD_APDU_DATA_SIZE;
@@ -252,10 +258,11 @@ static void ccid_init (struct ccid *c, struct ep_in *epi, struct ep_out *epo,
struct apdu *a) struct apdu *a)
{ {
c->ccid_state = CCID_STATE_START; c->ccid_state = CCID_STATE_START;
c->err = 0;
c->tx_busy = 0;
c->state = APDU_STATE_WAIT_COMMAND; c->state = APDU_STATE_WAIT_COMMAND;
c->p = a->cmd_apdu_data; c->p = a->cmd_apdu_data;
c->len = MAX_CMD_APDU_DATA_SIZE; c->len = MAX_CMD_APDU_DATA_SIZE;
c->err = 0;
memset (&c->ccid_header, 0, sizeof (struct ccid_header)); memset (&c->ccid_header, 0, sizeof (struct ccid_header));
c->sw1sw2[0] = 0x90; c->sw1sw2[0] = 0x90;
c->sw1sw2[1] = 0x00; c->sw1sw2[1] = 0x00;
@@ -765,6 +772,7 @@ usb_tx_done (uint8_t ep_num, uint16_t len)
#endif #endif
} }
/* /*
* ATR (Answer To Reset) string * ATR (Answer To Reset) string
* *
@@ -820,6 +828,7 @@ static void ccid_error (struct ccid *c, int offset)
#else #else
usb_lld_write (c->epi->ep_num, ccid_reply, CCID_MSG_HEADER_SIZE); usb_lld_write (c->epi->ep_num, ccid_reply, CCID_MSG_HEADER_SIZE);
#endif #endif
c->tx_busy = 1;
} }
extern void *openpgp_card_thread (void *arg); extern void *openpgp_card_thread (void *arg);
@@ -893,7 +902,7 @@ ccid_power_on (struct ccid *c)
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE + size_atr); usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE + size_atr);
#endif #endif
DEBUG_INFO ("ON\r\n"); DEBUG_INFO ("ON\r\n");
c->tx_busy = 1;
return CCID_STATE_WAIT; return CCID_STATE_WAIT;
} }
@@ -934,6 +943,7 @@ ccid_send_status (struct ccid *c)
#ifdef DEBUG_MORE #ifdef DEBUG_MORE
DEBUG_INFO ("St\r\n"); DEBUG_INFO ("St\r\n");
#endif #endif
c->tx_busy = 1;
} }
static enum ccid_state static enum ccid_state
@@ -949,6 +959,7 @@ ccid_power_off (struct ccid *c)
c->ccid_state = CCID_STATE_START; /* This status change should be here */ c->ccid_state = CCID_STATE_START; /* This status change should be here */
ccid_send_status (c); ccid_send_status (c);
DEBUG_INFO ("OFF\r\n"); DEBUG_INFO ("OFF\r\n");
c->tx_busy = 1;
return CCID_STATE_START; return CCID_STATE_START;
} }
@@ -982,12 +993,16 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
#endif #endif
if (len == 0) if (len == 0)
{ {
c->epi->buf = NULL;
c->epi->tx_done = 1;
#ifdef GNU_LINUX_EMULATION #ifdef GNU_LINUX_EMULATION
usb_lld_tx_enable_buf (c->epi->ep_num, endp1_tx_buf, usb_lld_tx_enable_buf (c->epi->ep_num, endp1_tx_buf,
CCID_MSG_HEADER_SIZE); CCID_MSG_HEADER_SIZE);
#else #else
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE); usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE);
#endif #endif
c->tx_busy = 1;
return; return;
} }
@@ -1065,6 +1080,7 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
#ifdef DEBUG_MORE #ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n"); DEBUG_INFO ("DATA\r\n");
#endif #endif
c->tx_busy = 1;
} }
static void static void
@@ -1076,7 +1092,8 @@ ccid_send_data_block (struct ccid *c)
static void static void
ccid_send_data_block_time_extension (struct ccid *c) ccid_send_data_block_time_extension (struct ccid *c)
{ {
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT, 1); ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT,
c->ccid_state == CCID_STATE_EXECUTE? 1: 0xff);
} }
static void static void
@@ -1115,6 +1132,7 @@ ccid_send_data_block_0x9000 (struct ccid *c)
#ifdef DEBUG_MORE #ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n"); DEBUG_INFO ("DATA\r\n");
#endif #endif
c->tx_busy = 1;
} }
/* /*
@@ -1211,6 +1229,7 @@ ccid_send_data_block_gr (struct ccid *c, size_t chunk_len)
#ifdef DEBUG_MORE #ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n"); DEBUG_INFO ("DATA\r\n");
#endif #endif
c->tx_busy = 1;
} }
@@ -1259,6 +1278,7 @@ ccid_send_params (struct ccid *c)
#ifdef DEBUG_MORE #ifdef DEBUG_MORE
DEBUG_INFO ("PARAMS\r\n"); DEBUG_INFO ("PARAMS\r\n");
#endif #endif
c->tx_busy = 1;
} }
@@ -1413,6 +1433,7 @@ ccid_handle_data (struct ccid *c)
c->a->res_apdu_data_len = 0; c->a->res_apdu_data_len = 0;
c->a->res_apdu_data = &c->p[5]; c->a->res_apdu_data = &c->p[5];
c->state = APDU_STATE_COMMAND_RECEIVED;
eventflag_signal (&c->openpgp_comm, EV_VERIFY_CMD_AVAILABLE); eventflag_signal (&c->openpgp_comm, EV_VERIFY_CMD_AVAILABLE);
next_state = CCID_STATE_EXECUTE; next_state = CCID_STATE_EXECUTE;
} }
@@ -1447,6 +1468,7 @@ ccid_handle_data (struct ccid *c)
c->a->res_apdu_data_len = 0; c->a->res_apdu_data_len = 0;
c->a->res_apdu_data = &ccid_buffer[5]; c->a->res_apdu_data = &ccid_buffer[5];
c->state = APDU_STATE_COMMAND_RECEIVED;
eventflag_signal (&c->openpgp_comm, EV_MODIFY_CMD_AVAILABLE); eventflag_signal (&c->openpgp_comm, EV_MODIFY_CMD_AVAILABLE);
next_state = CCID_STATE_EXECUTE; next_state = CCID_STATE_EXECUTE;
} }
@@ -1461,6 +1483,8 @@ ccid_handle_data (struct ccid *c)
} }
break; break;
case CCID_STATE_EXECUTE: case CCID_STATE_EXECUTE:
case CCID_STATE_ACK_REQUIRED_0:
case CCID_STATE_ACK_REQUIRED_1:
if (c->ccid_header.msg_type == CCID_POWER_OFF) if (c->ccid_header.msg_type == CCID_POWER_OFF)
next_state = ccid_power_off (c); next_state = ccid_power_off (c);
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS) else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
@@ -1489,6 +1513,8 @@ ccid_handle_timeout (struct ccid *c)
switch (c->ccid_state) switch (c->ccid_state)
{ {
case CCID_STATE_EXECUTE: case CCID_STATE_EXECUTE:
case CCID_STATE_ACK_REQUIRED_0:
case CCID_STATE_ACK_REQUIRED_1:
ccid_send_data_block_time_extension (c); ccid_send_data_block_time_extension (c);
break; break;
default: default:
@@ -1500,7 +1526,13 @@ ccid_handle_timeout (struct ccid *c)
} }
static struct ccid ccid; static struct ccid ccid;
enum ccid_state *const ccid_state_p = &ccid.ccid_state;
enum ccid_state
ccid_get_ccid_state (void)
{
return ccid.ccid_state;
}
void void
ccid_card_change_signal (int how) ccid_card_change_signal (int how)
@@ -1561,6 +1593,10 @@ extern int usb_get_descriptor (struct usb_dev *dev);
extern void random_init (void); extern void random_init (void);
extern void random_fini (void); extern void random_fini (void);
#ifdef ACKBTN_SUPPORT
static chopstx_intr_t ack_intr;
#endif
static chopstx_intr_t usb_intr;
/* /*
* Return 0 for normal USB event * Return 0 for normal USB event
@@ -1575,6 +1611,7 @@ usb_event_handle (struct usb_dev *dev)
e = usb_lld_event_handler (dev); e = usb_lld_event_handler (dev);
ep_num = USB_EVENT_ENDP (e); ep_num = USB_EVENT_ENDP (e);
chopstx_intr_done (&usb_intr);
/* Transfer to endpoint (not control endpoint) */ /* Transfer to endpoint (not control endpoint) */
if (ep_num != 0) if (ep_num != 0)
@@ -1674,11 +1711,13 @@ usb_event_handle (struct usb_dev *dev)
} }
static chopstx_intr_t interrupt;
static chopstx_poll_cond_t ccid_event_poll_desc; static chopstx_poll_cond_t ccid_event_poll_desc;
static struct chx_poll_head *const ccid_poll[] = { static struct chx_poll_head *const ccid_poll[] = {
(struct chx_poll_head *const)&interrupt, (struct chx_poll_head *const)&usb_intr,
(struct chx_poll_head *const)&ccid_event_poll_desc (struct chx_poll_head *const)&ccid_event_poll_desc,
#ifdef ACKBTN_SUPPORT
(struct chx_poll_head *const)&ack_intr
#endif
}; };
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *)) #define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
@@ -1696,9 +1735,12 @@ ccid_thread (void *arg)
eventflag_init (&ccid.openpgp_comm); eventflag_init (&ccid.openpgp_comm);
usb_lld_init (&dev, USB_INITIAL_FEATURE); usb_lld_init (&dev, USB_INITIAL_FEATURE);
chopstx_claim_irq (&interrupt, INTR_REQ_USB); chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
usb_event_handle (&dev); /* For old SYS < 3.0 */ usb_event_handle (&dev); /* For old SYS < 3.0 */
#ifdef ACKBTN_SUPPORT
ackbtn_init (&ack_intr);
#endif
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc); eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
reset: reset:
@@ -1724,14 +1766,20 @@ ccid_thread (void *arg)
{ {
eventmask_t m; eventmask_t m;
if (bDeviceState == USB_DEVICE_STATE_CONFIGURED) if (!c->tx_busy && bDeviceState == USB_DEVICE_STATE_CONFIGURED)
timeout_p = &timeout; timeout_p = &timeout;
else else
timeout_p = NULL; timeout_p = NULL;
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll); eventflag_set_mask (&c->ccid_comm, c->tx_busy ? EV_TX_FINISHED : ~0);
if (interrupt.ready) #ifdef ACKBTN_SUPPORT
chopstx_poll (timeout_p, CCID_POLL_NUM - c->tx_busy, ccid_poll);
#else
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
#endif
if (usb_intr.ready)
{ {
if (usb_event_handle (&dev) == 0) if (usb_event_handle (&dev) == 0)
continue; continue;
@@ -1751,6 +1799,20 @@ ccid_thread (void *arg)
goto reset; goto reset;
} }
#ifdef ACKBTN_SUPPORT
if (ack_intr.ready)
{
ackbtn_disable ();
chopstx_intr_done (&ack_intr);
led_blink (LED_WAIT_FOR_BUTTON);
if (c->ccid_state == CCID_STATE_ACK_REQUIRED_1)
goto exec_done;
c->ccid_state = CCID_STATE_EXECUTE;
continue;
}
#endif
timeout = USB_CCID_TIMEOUT; timeout = USB_CCID_TIMEOUT;
m = eventflag_get (&c->ccid_comm); m = eventflag_get (&c->ccid_comm);
@@ -1778,6 +1840,9 @@ ccid_thread (void *arg)
else if (m == EV_EXEC_FINISHED) else if (m == EV_EXEC_FINISHED)
if (c->ccid_state == CCID_STATE_EXECUTE) if (c->ccid_state == CCID_STATE_EXECUTE)
{ {
#ifdef ACKBTN_SUPPORT
exec_done:
#endif
if (c->a->sw == GPG_THREAD_TERMINATED) if (c->a->sw == GPG_THREAD_TERMINATED)
{ {
c->sw1sw2[0] = 0x90; c->sw1sw2[0] = 0x90;
@@ -1807,21 +1872,34 @@ ccid_thread (void *arg)
c->ccid_state = CCID_STATE_WAIT; c->ccid_state = CCID_STATE_WAIT;
} }
} }
#ifdef ACKBTN_SUPPORT
else if (c->ccid_state == CCID_STATE_ACK_REQUIRED_0)
c->ccid_state = CCID_STATE_ACK_REQUIRED_1;
#endif
else else
{ {
DEBUG_INFO ("ERR07\r\n"); DEBUG_INFO ("ERR05\r\n");
} }
#ifdef ACKBTN_SUPPORT
else if (m == EV_EXEC_ACK_REQUIRED)
if (c->ccid_state == CCID_STATE_EXECUTE)
{
ackbtn_enable ();
led_blink (LED_WAIT_FOR_BUTTON);
c->ccid_state = CCID_STATE_ACK_REQUIRED_0;
ccid_send_data_block_time_extension (c);
}
else
{
DEBUG_INFO ("ERR06\r\n");
}
#endif
else if (m == EV_TX_FINISHED) else if (m == EV_TX_FINISHED)
{ {
if (c->state == APDU_STATE_RESULT) if (c->state == APDU_STATE_RESULT)
{ ccid_reset (c);
c->state = APDU_STATE_WAIT_COMMAND; else
c->p = c->a->cmd_apdu_data; c->tx_busy = 0;
c->len = MAX_CMD_APDU_DATA_SIZE;
c->err = 0;
c->a->cmd_apdu_data_len = 0;
c->a->expected_res_size = 0;
}
if (c->state == APDU_STATE_WAIT_COMMAND if (c->state == APDU_STATE_WAIT_COMMAND
|| c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_COMMAND_CHAINING
@@ -1841,7 +1919,7 @@ ccid_thread (void *arg)
/* Loading reGNUal. */ /* Loading reGNUal. */
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED) while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
{ {
chopstx_intr_wait (&interrupt); chopstx_intr_wait (&usb_intr);
usb_event_handle (&dev); usb_event_handle (&dev);
} }

View File

@@ -1,7 +1,7 @@
/* /*
* usb_ctrl.c - USB control pipe device specific code for Gnuk * usb_ctrl.c - USB control pipe device specific code for Gnuk
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017 * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -202,8 +202,6 @@ gnuk_setup_endpoints_for_interface (struct usb_dev *dev,
void void
usb_device_reset (struct usb_dev *dev) usb_device_reset (struct usb_dev *dev)
{ {
int i;
usb_lld_reset (dev, USB_INITIAL_FEATURE); usb_lld_reset (dev, USB_INITIAL_FEATURE);
/* Initialize Endpoint 0 */ /* Initialize Endpoint 0 */
@@ -214,10 +212,6 @@ usb_device_reset (struct usb_dev *dev)
64); 64);
#endif #endif
/* Stop the interface */
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (dev, i, 1);
bDeviceState = USB_DEVICE_STATE_DEFAULT; bDeviceState = USB_DEVICE_STATE_DEFAULT;
} }
@@ -287,7 +281,7 @@ usb_setup (struct usb_dev *dev)
if (arg->request == USB_FSIJ_GNUK_DOWNLOAD) if (arg->request == USB_FSIJ_GNUK_DOWNLOAD)
{ {
#ifdef FLASH_UPGRADE_SUPPORT #ifdef FLASH_UPGRADE_SUPPORT
if (*ccid_state_p != CCID_STATE_EXITED) if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return -1; return -1;
if (addr < &_regnual_start || addr + arg->len > __heap_end__) if (addr < &_regnual_start || addr + arg->len > __heap_end__)
@@ -305,7 +299,7 @@ usb_setup (struct usb_dev *dev)
else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0) else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0)
{ {
#ifdef FLASH_UPGRADE_SUPPORT #ifdef FLASH_UPGRADE_SUPPORT
if (*ccid_state_p != CCID_STATE_EXITED) if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return -1; return -1;
if (((uintptr_t)addr & 0x03)) if (((uintptr_t)addr & 0x03))
@@ -410,7 +404,7 @@ usb_ctrl_write_finish (struct usb_dev *dev)
{ {
if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC) if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC)
{ {
if (*ccid_state_p != CCID_STATE_EXITED) if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return; return;
bDeviceState = USB_DEVICE_STATE_UNCONNECTED; bDeviceState = USB_DEVICE_STATE_UNCONNECTED;

View File

@@ -6,7 +6,7 @@ Gnuk Token is supported as well.
You need to install: 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: 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

@@ -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 openpgp_card.py - a library for OpenPGP card
Copyright (C) 2011, 2012, 2013, 2015, 2016 Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018
Free Software Initiative of Japan Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org> 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/>. 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): def iso7816_compose(ins, p1, p2, data, cls=0x00, le=None):
data_len = len(data) data_len = len(data)
@@ -54,6 +55,83 @@ class OpenPGP_Card(object):
""" """
self.__reader = reader self.__reader = reader
self.__kdf_iters = None
self.__kdf_salt_user = None
self.__kdf_salt_reset = None
self.__kdf_salt_admin = None
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): def cmd_get_response(self, expected_len):
result = b"" result = b""
@@ -336,3 +414,48 @@ class OpenPGP_Card(object):
raise ValueError(sw) raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00): if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1])) 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

@@ -1,7 +1,7 @@
""" """
test_empty_card.py - test empty card 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> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,13 +24,11 @@ from binascii import hexlify
from re import match, DOTALL from re import match, DOTALL
from struct import pack from struct import pack
from util import * from util import *
from card_const import *
import pytest import pytest
EMPTY_60=bytes(60) EMPTY_60=bytes(60)
FACTORY_PASSPHRASE_PW1=b"123456"
FACTORY_PASSPHRASE_PW3=b"12345678"
def test_login(card): def test_login(card):
login = get_data_object(card, 0x5e) login = get_data_object(card, 0x5e)
assert check_null(login) assert check_null(login)

View File

@@ -1,7 +1,7 @@
""" """
test_personalize_card.py - test personalizing card test_personalize_card.py - test personalizing card
Copyright (C) 2016 g10 Code GmbH Copyright (C) 2016, 2018 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,25 +24,15 @@ from struct import pack
from re import match, DOTALL from re import match, DOTALL
from util import * from util import *
import rsa_keys import rsa_keys
from card_const import *
FACTORY_PASSPHRASE_PW1=b"123456" from constants_for_test import *
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): def test_setup_pw3_0(card):
r = card.cmd_change_reference_data(3, FACTORY_PASSPHRASE_PW3 + PW3_TEST0) r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, PW3_TEST0)
assert r assert r
def test_verify_pw3_0(card): def test_verify_pw3_0(card):
v = card.cmd_verify(3, PW3_TEST0) v = card.verify(3, PW3_TEST0)
assert v assert v
def test_login_put(card): def test_login_put(card):
@@ -164,89 +154,85 @@ def test_public_key_3(card):
assert rsa_keys.key[2][0] == pk[9:9+256] assert rsa_keys.key[2][0] == pk[9:9+256]
def test_setup_pw1_0(card): def test_setup_pw1_0(card):
r = card.cmd_change_reference_data(1, FACTORY_PASSPHRASE_PW1 + PW1_TEST0) r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
assert r assert r
def test_verify_pw1_0(card): def test_verify_pw1_0(card):
v = card.cmd_verify(1, PW1_TEST0) v = card.verify(1, PW1_TEST0)
assert v assert v
def test_verify_pw1_0_2(card): def test_verify_pw1_0_2(card):
v = card.cmd_verify(2, PW1_TEST0) v = card.verify(2, PW1_TEST0)
assert v assert v
def test_setup_pw1_1(card): def test_setup_pw1_1(card):
r = card.cmd_change_reference_data(1, PW1_TEST0 + PW1_TEST1) r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
assert r assert r
def test_verify_pw1_1(card): def test_verify_pw1_1(card):
v = card.cmd_verify(1, PW1_TEST1) v = card.verify(1, PW1_TEST1)
assert v assert v
def test_verify_pw1_1_2(card): def test_verify_pw1_1_2(card):
v = card.cmd_verify(2, PW1_TEST1) v = card.verify(2, PW1_TEST1)
assert v assert v
def test_setup_reset_code(card): def test_setup_reset_code(card):
r = card.cmd_put_data(0x00, 0xd3, RESETCODE_TEST) r = card.setup_reset_code(RESETCODE_TEST)
assert r assert r
def test_reset_code(card): def test_reset_code(card):
r = card.cmd_reset_retry_counter(0, 0x81, RESETCODE_TEST + PW1_TEST2) r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
assert r assert r
def test_verify_pw1_2(card): def test_verify_pw1_2(card):
v = card.cmd_verify(1, PW1_TEST2) v = card.verify(1, PW1_TEST2)
assert v assert v
def test_verify_pw1_2_2(card): def test_verify_pw1_2_2(card):
v = card.cmd_verify(2, PW1_TEST2) v = card.verify(2, PW1_TEST2)
assert v assert v
def test_setup_pw3_1(card): def test_setup_pw3_1(card):
r = card.cmd_change_reference_data(3, PW3_TEST0 + PW3_TEST1) r = card.change_passwd(3, PW3_TEST0, PW3_TEST1)
assert r assert r
def test_verify_pw3_1(card): def test_verify_pw3_1(card):
v = card.cmd_verify(3, PW3_TEST1) v = card.verify(3, PW3_TEST1)
assert v assert v
def test_reset_userpass_admin(card): def test_reset_userpass_admin(card):
r = card.cmd_reset_retry_counter(2, 0x81, PW1_TEST3) r = card.reset_passwd_by_admin(PW1_TEST3)
assert r assert r
def test_verify_pw1_3(card): def test_verify_pw1_3(card):
v = card.cmd_verify(1, PW1_TEST3) v = card.verify(1, PW1_TEST3)
assert v assert v
def test_verify_pw1_3_2(card): def test_verify_pw1_3_2(card):
v = card.cmd_verify(2, PW1_TEST3) v = card.verify(2, PW1_TEST3)
assert v assert v
def test_setup_pw1_4(card): def test_setup_pw1_4(card):
r = card.cmd_change_reference_data(1, PW1_TEST3 + PW1_TEST4) r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
assert r assert r
def test_verify_pw1_4(card): def test_verify_pw1_4(card):
v = card.cmd_verify(1, PW1_TEST4) v = card.verify(1, PW1_TEST4)
assert v assert v
def test_verify_pw1_4_2(card): def test_verify_pw1_4_2(card):
v = card.cmd_verify(2, PW1_TEST4) v = card.verify(2, PW1_TEST4)
assert v assert v
def test_setup_pw3_2(card): def test_setup_pw3_2(card):
r = card.cmd_change_reference_data(3, PW3_TEST1 + PW3_TEST0) r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
assert r assert r
def test_verify_pw3_2(card): def test_verify_pw3_2(card):
v = card.cmd_verify(3, PW3_TEST0) v = card.verify(3, PW3_TEST0)
assert v 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): def test_sign_0(card):
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0) digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
r = card.cmd_pso(0x9e, 0x9a, digestinfo) r = card.cmd_pso(0x9e, 0x9a, digestinfo)

View File

@@ -1,7 +1,7 @@
""" """
test_personalize_reset_card.py - test resetting personalization of card test_personalize_reset.py - test resetting personalization of card
Copyright (C) 2016 g10 Code GmbH Copyright (C) 2016, 2018 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,18 +24,8 @@ from struct import pack
from re import match, DOTALL from re import match, DOTALL
from util import * from util import *
import rsa_keys import rsa_keys
from card_const import *
FACTORY_PASSPHRASE_PW1=b"123456" from constants_for_test import *
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): def test_login_put(card):
r = card.cmd_put_data(0x00, 0x5e, b"") r = card.cmd_put_data(0x00, 0x5e, b"")
@@ -67,25 +57,25 @@ def test_pw1_status_put(card):
assert r assert r
def test_setup_pw3_0(card): def test_setup_pw3_0(card):
r = card.cmd_change_reference_data(3, PW3_TEST0 + FACTORY_PASSPHRASE_PW3) r = card.change_passwd(3, PW3_TEST0, FACTORY_PASSPHRASE_PW3)
assert r assert r
def test_verify_pw3_0(card): def test_verify_pw3_0(card):
v = card.cmd_verify(3, FACTORY_PASSPHRASE_PW3) v = card.verify(3, FACTORY_PASSPHRASE_PW3)
assert v assert v
def test_setup_pw1_0(card): def test_setup_pw1_0(card):
r = card.cmd_change_reference_data(1, PW1_TEST4 + FACTORY_PASSPHRASE_PW1) r = card.change_passwd(1, PW1_TEST4, FACTORY_PASSPHRASE_PW1)
assert r assert r
def test_verify_pw1_0(card): def test_verify_pw1_0(card):
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1) v = card.verify(1, FACTORY_PASSPHRASE_PW1)
assert v assert v
def test_verify_pw1_0_2(card): def test_verify_pw1_0_2(card):
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1) v = card.verify(2, FACTORY_PASSPHRASE_PW1)
assert v assert v
def test_setup_reset_code(card): def test_delete_reset_code(card):
r = card.cmd_put_data(0x00, 0xd3, b"") r = card.cmd_put_data(0x00, 0xd3, b"")
assert r assert r

View File

@@ -1,7 +1,7 @@
""" """
test_remove_keys_card.py - test removing keys on card test_remove_keys.py - test removing keys on card
Copyright (C) 2016 g10 Code GmbH Copyright (C) 2016, 2018 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -22,22 +22,21 @@ 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 # Remove a key material on card by changing algorithm attributes of the key
KEY_ATTRIBUTES_RSA4K=b"\x01\x10\x00\x00\x20\x00" from card_const import *
KEY_ATTRIBUTES_RSA2K=b"\x01\x08\x00\x00\x20\x00"
def test_rsa_import_key_1(card): def test_rsa_keyattr_change_1(card):
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K) r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
if r: if r:
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K) r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
assert r assert r
def test_rsa_import_key_2(card): def test_rsa_keyattr_change_2(card):
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K) r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
if r: if r:
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K) r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
assert r assert r
def test_rsa_import_key_3(card): def test_rsa_keyattr_change_3(card):
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K) r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
if r: if r:
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K) r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)

View File

@@ -0,0 +1,41 @@
"""
test_004_reset_pw3.py - test resetting pw3
Copyright (C) 2018 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from card_const import *
# Gnuk specific feature of clear PW3
def test_setup_pw3_null(card):
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, None)
assert r
def test_verify_pw3(card):
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
assert v
# Check PW1 again to see the possiblity of admin-less mode
def test_verify_pw1(card):
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
assert v
def test_verify_pw1_2(card):
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
assert v

View File

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

View File

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

View File

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

1
tests/test_008_reset_pw3.py Symbolic link
View File

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

83
tests/test_009_keygen.py Normal file
View File

@@ -0,0 +1,83 @@
"""
test_005_keygen.py - test key generation
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 binascii import hexlify
import rsa_keys
from card_const import *
def test_keygen_1(card):
pk = card.cmd_genkey(1)
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
r = card.cmd_put_data(0x00, 0xc7, fpr_date[0])
if r:
r = card.cmd_put_data(0x00, 0xce, fpr_date[1])
assert r
def test_keygen_2(card):
pk = card.cmd_genkey(2)
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
r = card.cmd_put_data(0x00, 0xc8, fpr_date[0])
if r:
r = card.cmd_put_data(0x00, 0xcf, fpr_date[1])
assert r
def test_keygen_3(card):
pk = card.cmd_genkey(3)
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
r = card.cmd_put_data(0x00, 0xc9, fpr_date[0])
if r:
r = card.cmd_put_data(0x00, 0xd0, fpr_date[1])
assert r
def test_verify_pw1(card):
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
assert v
def test_signature_sigkey(card):
msg = b"Sign me please"
pk = card.cmd_get_public_key(1)
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
digest = rsa_keys.compute_digestinfo(msg)
sig = int(hexlify(card.cmd_pso(0x9e, 0x9a, digest)),16)
r = rsa_keys.verify_signature(pk_info, digest, sig)
assert r
def test_verify_pw1_2(card):
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
assert v
def test_decryption(card):
msg = b"encrypt me please"
pk = card.cmd_get_public_key(2)
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
ciphertext = rsa_keys.encrypt_with_pubkey(pk_info, msg)
r = card.cmd_pso(0x80, 0x86, ciphertext)
assert r == msg
def test_signature_authkey(card):
msg = b"Sign me please to authenticate"
pk = card.cmd_get_public_key(3)
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
digest = rsa_keys.compute_digestinfo(msg)
sig = int(hexlify(card.cmd_internal_authenticate(digest)),16)
r = rsa_keys.verify_signature(pk_info, digest, sig)
assert r

View File

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

View File

@@ -0,0 +1,34 @@
"""
test_007_kdf_full.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 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_full(card):
r = card.cmd_put_data(0x00, 0xf9, KDF_FULL)
if r:
card.configure_with_kdf()
assert r

View File

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

View File

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

View File

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

1
tests/test_015_reset_pw3.py Symbolic link
View File

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

View File

@@ -0,0 +1,34 @@
"""
test_012_kdf_single.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 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_single(card):
r = card.cmd_put_data(0x00, 0xf9, KDF_SINGLE)
if r:
card.configure_with_kdf()
assert r

View File

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

View File

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

View File

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

1
tests/test_020_reset_pw3.py Symbolic link
View File

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

View File

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

View File

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

View File

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

1
tests/test_024_reset_pw3.py Symbolic link
View File

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

View File

@@ -0,0 +1,38 @@
"""
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 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

@@ -3,7 +3,7 @@
""" """
gnuk_remove_keys_libusb.py - a tool to remove keys in Gnuk Token gnuk_remove_keys_libusb.py - a tool to remove keys in Gnuk Token
Copyright (C) 2012 Free Software Initiative of Japan Copyright (C) 2012, 2018 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,7 +24,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys, os 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 # Assume only single CCID device is attached to computer and it's Gnuk Token
@@ -42,13 +43,28 @@ def main(passwd):
break break
except: except:
pass pass
if not gnuk:
raise ValueError("No ICC present")
if gnuk.icc_get_status() == 2: if gnuk.icc_get_status() == 2:
raise ValueError("No ICC present") raise ValueError("No ICC present")
elif gnuk.icc_get_status() == 1: elif gnuk.icc_get_status() == 1:
gnuk.icc_power_on() gnuk.icc_power_on()
gnuk.cmd_select_openpgp() gnuk.cmd_select_openpgp()
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8')) # Compute passwd data
gnuk.cmd_select_openpgp() 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, 0xc7) # FP_SIG
gnuk.cmd_put_data_remove(0x00, 0xce) # KGTIME_SIG gnuk.cmd_put_data_remove(0x00, 0xce) # KGTIME_SIG
gnuk.cmd_put_data_key_import_remove(1) gnuk.cmd_put_data_key_import_remove(1)

View File

@@ -1,7 +1,7 @@
""" """
gnuk_token.py - a library for Gnuk Token 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 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -635,3 +635,48 @@ def UNSIGNED(n):
def crc32(bytestr): def crc32(bytestr):
crc = binascii.crc32(bytestr) crc = binascii.crc32(bytestr)
return UNSIGNED(crc) 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

@@ -4,7 +4,8 @@
upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token
which is just shipped from factory which is just shipped from factory
Copyright (C) 2012, 2013, 2015 Free Software Initiative of Japan Copyright (C) 2012, 2013, 2015, 2018
Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org> Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation. This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -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/>. 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 sys, binascii, time, os
import rsa import rsa
from struct import pack
DEFAULT_PW3 = "12345678" DEFAULT_PW3 = "12345678"
BY_ADMIN = 3 BY_ADMIN = 3
@@ -45,7 +50,23 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
gnuk = get_gnuk_device() gnuk = get_gnuk_device()
gnuk.cmd_select_openpgp() gnuk.cmd_select_openpgp()
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_write_binary(1+keyno, rsa_raw_pubkey, False)
gnuk.cmd_select_openpgp() gnuk.cmd_select_openpgp()
@@ -71,7 +92,7 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
reg = None reg = None
print("Waiting for device to appear:") print("Waiting for device to appear:")
while reg == None: while reg == None:
print(" Wait %d seconds..." % wait_e) print(" Wait {} second{}...".format(wait_e, 's' if wait_e > 1 else ''))
time.sleep(wait_e) time.sleep(wait_e)
for dev in gnuk_devices_by_vidpid(): for dev in gnuk_devices_by_vidpid():
try: try: