Compare commits

...

78 Commits

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

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

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

2
.gitignore vendored
View File

@@ -6,6 +6,7 @@ src/.dep
src/config.mk
src/config.h
src/gnuk.ld
src/stdaln-sys.ld
src/board.h
src/build/*
src/*.inc
@@ -16,3 +17,4 @@ regnual/regnual.elf
doc/_build
tests/.cache
tests/__pycache__
tests/.pytest_cache

View File

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

256
ChangeLog
View File

@@ -1,3 +1,259 @@
2020-01-24 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.15.
2020-01-11 Bertrand Jacquin <bertrand@jacquin.bzh>
* tool/add_openpgp_authkey_from_gpgssh.py: Switch to Python3.
* tool/calc_precompute_table_ecc.py: Likewise.
* tool/dfuse.py: Likewise.
* tool/dump_mem.py: Likewise.
* tool/get_raw_public_key.py: Likewise.
* tool/pageant_proxy_to_gpg.py: Likewise.
2019-12-30 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.18.
2019-06-18 NIIBE Yutaka <gniibe@fsij.org>
* src/bn.c (bn256_random): More portable.
2019-04-03 NIIBE Yutaka <gniibe@fsij.org>
* tests: Factor out tests into classes.
2019-03-04 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.14.
* chopstx: Update to 1.14.
* tool/gnuk_token.py: Add 1209:2440.
2019-02-24 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Clean up the ack button state
at reset (by SET_INTERFACE).
* tool/gnuk_token.py (gnuk_token.__init__): Add back
setAltInterface to issue SET_INTERFACE control transfer.
2019-02-22 NIIBE Yutaka <gniibe@fsij.org>
* tool/gnuk_get_random.py: New.
* src/openpgp.c (cmd_external_authenticate): move
ACKBTN_SUPPORT to...
(cmd_get_challenge): ... here.
* src/gnuk.h (EV_*): Change the values.
* src/usb-ccid.c (GPG_ACK_TIMEOUT): New.
(ccid_thread): Implement timout for the user interaction.
2019-02-21 NIIBE Yutaka <gniibe@fsij.org>
* GNUK_USB_DEVICE_ID: Add 1209:2440.
2018-12-26 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.13.
2018-12-22 Peter Lebbing <peter@digitalbrains.com>
* src/main.c (device_initialize_once): Fill the stack address and
reset vector of Gnuk application (was the one of old SYS).
Reset the board after updating the first five pages of flash.
2018-12-21 Peter Lebbing <peter@digitalbrains.com>
* src/main.c [DFU_SUPPORT] (flash_write_any): New.
(device_initialize_once): Overwrite DFU bootloader by SYS.
(main): Use SYS at ORIGIN_REAL.
* src/stdaln-sys.ld.in: New.
* src/Makefile [USE_DFU] (OBJS_ADD): Add standalone SYS object.
Add rules for stdaln-sys-bin.o and src/stdaln-sys.ld.
* src/configure: Generate stdaln-sys.ld.
[MAPLE_MINI]: Tweak ORIGIN and FLASH_SIZE.
(ORIGIN_DEFINE, ORIGIN_REAL_DEFINE): New macros.
(USE_DFU): New make variable.
* src/config.h.in (ORIGIN_DEFINE, ORIGIN_REAL_DEFINE): New.
2018-12-20 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.13.
2018-12-07 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (EV_EXEC_ACK_REQUIRED): Have precedence
than EV_EXEC_FINISHED.
2018-12-06 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Priority of handling
EV_TX_FINISHED is most important. Don't handle
Ack button event when c->tx_busy = 1.
2018-12-05 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_external_authenticate): Support
ACK button for firmware update.
2018-12-04 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (gpg_data_copy): Fix for NR_DO_UIF_SIG.
2018-11-25 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.12.
2018-11-21 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Fix a race condition sending
result APDU by ack button, time out, sending time extension block
again while tx_busy=1.
2018-11-17 NIIBE Yutaka <gniibe@fsij.org>
* src/main.c (device_initialize_once): Depends on MHZ to
distinguish GD32F103.
* src/openpgp-do.c (do_openpgpcard_aid): Ditto.
2018-11-12 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.11.
* chopstx: Update to 1.12.
* src/configure (ackbtn_support): Always yes.
* src/usb-ccid.c: Fix comma separator.
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
* tool/kdf_calc.py (kdf_calc): Use libgcrypt.so.20.
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_pso, cmd_internal_authenticate): Use
ccid_comm.
* src/usb-ccid.c (struct ccid): New field tx_busy.
(ccid_error, ccid_power_on, ccid_send_status, ccid_power_off)
(ccid_send_data_block_internal, ccid_send_data_block_0x9000)
(ccid_send_data_block_gr, ccid_send_params): Set c->tx_busy.
(ccid_state_p): Remove.
(ccid_get_ccid_state): New.
(ccid_thread): Only handle EV_TX_FINISHED event when c->tx_busy.
* src/usb_ctrl.c (usb_setup, usb_ctrl_write_finish): Use
ccid_get_ccid_state.
* src/main.c (display_status_code): Likewise.
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_handle_data): Set c->state for pinpad input.
(ccid_send_data_block_internal): Fix the case of len == 0.
* src/main.c (display_status_code): There is
no case where ccid_state == CCID_STATE_RECEIVE.
* src/gnuk.h (CCID_STATE_RECEIVE): Remove.
(CCID_STATE_SEND): Remove.
2018-10-12 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Notify host about ack button.
2018-10-02 NIIBE Yutaka <gniibe@fsij.org>
* src/stack-def.h (SIZE_0): Increase.
* chopstx: Update to 1.11.
2018-10-01 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (EV_EXEC_ACK_REQUIRED): New.
(EV_EXEC_FINISHED_ACK): Remove.
(CCID_STATE_CONFIRM_ACK): Remove.
(CCID_STATE_ACK_REQUIRED_0, CCID_STATE_ACK_REQUIRED_1): New.
* src/openpgp.c (cmd_pso): Send EV_EXEC_ACK_REQUIRED, if needed.
(cmd_internal_authenticate): Likewise.
(process_command_apdu): No return value.
(openpgp_card_thread): Always send EV_EXEC_FINISHED.
* src/usb-ccid.c (ccid_send_data_block_time_extension): Follow the
change of state.
(ccid_handle_data, ccid_handle_timeout): Likewise.
(ccid_thread): Handle EV_EXEC_ACK_REQUIRED.
Change for LED blink.
* src/main.c (main): LED blink during waiting ACK.
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (NR_DO_UIF_SIG, NR_DO_UIF_DEC, NR_DO_UIF_AUT): New.
* src/openpgp-do.c (rw_uif) [ACKBTN_SUPPORT]: New.
(GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT): New.
(feature_mngmnt) [ACKBTN_SUPPORT]: New.
(cmp_app_data, cmp_discretionary): Add ACKBTN_SUPPORT.
(gpg_do_table): Add for GPG_DO_UIF_SIG, GPG_DO_UIF_DEC,
GPG_DO_UIF_AUT, and GPG_DO_FEATURE_MNGMNT.
(gpg_do_get_uif) [ACKBTN_SUPPORT]: New.
(gpg_data_scan): Handle uif_flags.
* src/openpgp.c (process_command_apdu) [ACKBTN_SUPPORT]: Add user
interaction handling.
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (LED_WAIT_FOR_BUTTON): New.
* src/main.c (main): Blink rapidly when asking ACK.
* src/usb-ccid.c (ccid_thread): Use LED_WAIT_FOR_BUTTON.
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
* src/config.h.in: Add @ACKBTN_DEFINE@.
* src/configure: Add ACKBTN_SUPPORT.
* src/gnuk.h (EV_EXEC_FINISHED_ACK): New.
(CCID_STATE_CONFIRM_ACK): New.
* src/openpgp.c (process_command_apdu): Change for cmd_pso, and
cmd_internal_authenticate.
* src/usb-ccid.c (ccid_send_data_block_time_extension): Report
time extension differently when waiting ack button.
(ccid_handle_data): Support case of CCID_STATE_CONFIRM_ACK.
(ccid_handle_timeout): Likewise.
(ack_intr) [ACKBTN_SUPPORT]: New.
(ccid_thread) [ACKBTN_SUPPORT]: Add ack button handling.
2018-09-26 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update.
* src/usb-ccid.c (usb_event_handle): Fix for chopstx_intr_done.
* src/pin-cir.c (tim_main, ext_main): Likewise.
* src/configure (FST_01SZ): Set MHZ=96.
2018-07-04 Szczepan Zalega <szczepan@nitrokey.com>
* tool/upgrade_by_passwd.py: Catch exception, when no KDF data is
found.
Output 'second' for 1 second.
2018-05-10 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.10.
* src/Makefile (build/gnuk.elf): New target.
(build/gnuk-vidpid.elf): Remove.
* chopstx: Update to 1.9.
2018-04-26 NIIBE Yutaka <gniibe@fsij.org>
* src/usb_ctrl.c (usb_device_reset): Don't stop the endpoints.
* src/configure (MHZ, def_mhz): New.
2018-04-05 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.9.

View File

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

91
NEWS
View File

@@ -1,5 +1,89 @@
Gnuk NEWS - User visible changes
* Major changes in Gnuk 1.2.15
Released 2020-01-24, by NIIBE Yutaka
** Switch to Python3
Scripts under tool/ are switched to Python3.
Thanks to Bertrand Jacquin.
** Upgrade of Chopstx
We use Chopstx 1.18.
** Tests also support OpenPGPcard
Now, a test suite under "tests" may be used to OpenPGPcard.
* Major changes in Gnuk 1.2.14
Released 2019-03-05, by NIIBE Yutaka
** Timeout for ACK button support
When a user doesn't acknowledge (> 15 seconds), the operation
timeouts, and authentication state is cleared.
** Upgrade of Chopstx
We use Chopstx 1.14.
* Major changes in Gnuk 1.2.13
Released 2018-12-26, by NIIBE Yutaka
** DFU support and its firmware upgrade fix
DFU support was not well maintained, and firmware upgrade was not
possible for boards with DFU. Now, at least for Maple Mini, it is
tested. Note that using Gnuk with DFU on a board is only for an
experiment, because DFU can access the content of flash ROM. DFU
should be killed by upgrading to normal Gnuk, so that you can have
your private keys.
** Fix for UIF Data Object
When flash ROM is full and coping to new page, UIF DO was not properly
copied. This bug resulted losing the flag for user interaction. Now,
it's properly copied, keeping the setting of the feature.
** Upgrade of Chopstx
We use Chopstx 1.13.
* Major changes in Gnuk 1.2.12
Released 2018-11-25, by NIIBE Yutaka
** FST-01SZ fixes
Fixes for Ack button support and serial number.
* Major changes in Gnuk 1.2.11
Released 2018-11-12, by NIIBE Yutaka
** Experimental ACK button support with FST-01SZ
While OpenPGP card specification verison 3 has description for the
"user interaction" button and data objects, there were no
implementation. To evaluate the feature, experimental support is
added.
** Upgrade of Chopstx
We use Chopstx 1.12, which comes with ACK button driver and supports
FST-01SZ.
* Major changes in Gnuk 1.2.10
Released 2018-05-10, by NIIBE Yutaka
** No inclusion of VID:PID in gnuk-no-vidpid.elf
Now, we have new file named gnuk-no-vidpid.elf with no VID:PID. The
file gnuk.elf has the VID:PID, like version 1.2.7 or older.
** Upgrade of Chopstx
We use Chopstx 1.9, which supports GD32F103.
* Major changes in Gnuk 1.2.9
Released 2018-04-05, by NIIBE Yutaka
@@ -851,6 +935,7 @@ Gnuk Token could run with GPG4WIN on MS Windows. GPG4WIN runs with
** This is initial release. Only it supports digital signing.
Local Variables:
mode: outline
End:
# Local Variables:
# mode: outline
# End:

72
README
View File

@@ -1,14 +1,14 @@
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 1.2.9
2018-04-05
Version 1.2.15
2020-01-24
Niibe Yutaka
Free Software Initiative of Japan
Release Notes
=============
This is the release of Gnuk, version 1.2.9, which has major
This is the release of Gnuk, version 1.2.15, which has major
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
overriding key import, but importing keys (or generating keys) results
password reset. Also, you need to import private keys before changing
@@ -25,9 +25,11 @@ than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
because the device doesn't have enough memory.
It supports new KDF-DO feature. Please note that this is
experimental. To use the feature, you need to use newer GnuPG
(forthcoming 2.2.6 or later). You need to prepare the KDF-DO on your
token by the card-edit/kdf-setup command.
experimental. To use the feature, you need to use newer GnuPG (2.2.6
or later). You need to prepare the KDF-DO on your token by the
card-edit/kdf-setup command.
With FST-01SZ, experimental ack button support is available for test.
What's Gnuk?
@@ -35,7 +37,7 @@ What's Gnuk?
Gnuk is an implementation of USB cryptographic token for GNU Privacy
Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on
STM32F103 processor.
STM32F103 processor (and its compatible).
I wish that Gnuk will be a developer's soother who uses GnuPG. I have
been nervous of storing secret key(s) on usual secondary storage.
@@ -73,7 +75,7 @@ A1: Gnuk version 1.0 only supports RSA-2048.
Q2: How long does it take for digital signing?
A2: It takes a second and a half or so for RSA-2048.
It takes more than 8 secondd for RSA-4096.
It takes more than 8 seconds for RSA-4096.
Q3: What's your recommendation for target board?
A3: Orthodox choice is Olimex STM32-H103.
@@ -83,8 +85,7 @@ A3: Orthodox choice is Olimex STM32-H103.
choice for experiment.
Q4: What's version of GnuPG are you using?
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.18 in
unstable.
A4: In Debian GNU/Linux system, I use GnuPG modern 2.2.12.
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
@@ -178,15 +179,6 @@ Original features of Gnuk, tested manually lightly:
* Card holder certificate (write by UPDATE BINARY)
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
It is known not-working well:
* It is known that the specific combination of libccid 1.4.1
(or newer) with libusb 1.0.8 (or older) had a minor problem.
It is rare but it is possible for USB communication to be
failed, because of a bug in libusb implementation. Use
libusbx 1.0.9 or newer, or don't use PC/SC, but use internal
CCID driver of GnuPG.
Targets
=======
@@ -219,7 +211,7 @@ script prepending 'bash' before './configure'.
Some tools are written in Python. If your Python is not installed as
/usr/bin/python, please prepend 'python' for your command invocation.
Python 2.7 and PyUSB 0.4.3 is assumed.
I use Python 3.7 and PyUSB 1.0.0.
Source code
@@ -256,7 +248,7 @@ External source code
Gnuk is distributed with external source code.
* chopstx/ -- Chopstx 1.8
* chopstx/ -- Chopstx 1.18
We use Chopstx as the kernel for Gnuk.
@@ -378,10 +370,10 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
On Debian we can install the packages of gcc-arm-none-eabi,
gdb-arm-none-eabi and its friends. I'm using:
binutils-arm-none-eabi 2.28-4+9+b3
gcc-arm-none-eabi 15:6.3.1+svn253039-1
gdb-arm-none-eabi 7.12-6+9+b2
libnewlib-arm-none-eabi 2.4.0.20160527-3
binutils-arm-none-eabi 2.31.1-12+11
gcc-arm-none-eabi 15:7-2018-q2-6
gdb-multiarch 8.2.1-1
libnewlib-arm-none-eabi 3.1.0.20181231-1
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
GNU Toolchain for 'arm-none-eabi' target.
@@ -405,9 +397,11 @@ Then, type:
Then, we will have "gnuk.elf" under src/build directory.
Next, we can get the final image by running following command.
$ make build/gnuk-vidpid.elf
If you are not the authorized vendor, please never distribute this
file of "gnuk.elf", which includes VID:PID in the image. If you would
like to distribute the image (for example, to check if it's
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
VID:PID.
How to install
@@ -417,11 +411,11 @@ Olimex STM32-H103 board
-----------------------
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 \
-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.
@@ -434,18 +428,20 @@ If you are using Flying Stone Tiny 01, you need a SWD writer.
OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
-c "program build/gnuk-vidpid.elf verify reset exit"
-c "program build/gnuk.elf verify reset exit"
STBee
-----
Note that this is only for your experiment; Your private key materials
on the board can be accessed by DfuSe.
Reset the board with "USER" switch pushed. Type following to write
to flash:
# cd ../tool
# ./dfuse.py ../src/build/gnuk-vidpid.hex
# ./dfuse.py ../src/build/gnuk.hex
Then, reset the board.
@@ -479,7 +475,7 @@ protect, killing DfuSe and accessing by JTAG debugger is recommended.
This is completely optional.
For this procedure, you need python and pyscard (python-pyscard
package in Debian) or PyUSB 0.4.3 (python-usb package in Debian).
package in Debian) or PyUSB (python-usb package in Debian).
(1) [pyscard] Stop scdaemon
[PyUSB] Stop the pcsc daemon.
@@ -491,7 +487,7 @@ Exception" by "Sharing violation".
In case of PyUSB tool, you need to stop pcscd.
# /etc/init.d/pcscd stop
# systemctl stop pcscd
(2) [Optional] Write fixed serial number
@@ -535,8 +531,8 @@ Type following command to see Gnuk runs:
$ gpg --card-status
Besides, there is a functionality test under test/ directory. See
test/README.
Besides, there is a functionality test under tests/ directory. See
tests/README.
Personalize the Token, import keys, and change the password
@@ -604,7 +600,7 @@ You can get it by:
$ git clone https://salsa.debian.org/gnuk-team/gnuk/gnuk.git
It's also available at: www.gniibe.org
You can browse at: https://git.gniibe.org/gitweb?p=gnuk/gnuk.git;a=summary
You can browse at: https://git.gniibe.org/cgit/gnuk/gnuk.git/
I put Chopstx as a submodule of Git. Please do this:

2
THANKS
View File

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

View File

@@ -1 +1 @@
release/1.2.9
release/1.2.15

Submodule chopstx updated: aa63ac79bc...cc49f4ef23

View File

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

View File

@@ -16,7 +16,7 @@ In addition to settings of Gnuk, I create a file
# For updating firmware, permission settings are needed.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
@@ -65,7 +65,7 @@ Invoking firmware update
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

View File

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

View File

@@ -30,7 +30,7 @@ command.
Or, you can use ``gpgconf`` command. Type::
$ gpgconf --reload scdameon
$ gpgconf --reload scdaemon
will do the same thing.

View File

@@ -37,7 +37,7 @@ When we only install "gnupg2" package for 2.0 (with no "gnupg" package),
there will be no udev rules (there is a bug report #543217 for this issue).
In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules::
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
Usually, udev daemon automatically handles for the changes of configuration

View File

@@ -52,6 +52,7 @@ regnual-no-vidpid.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(LDFLAGS) -o regnual-no-vidpid.elf $(OBJS)
clean:
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin *.lst
-rm -f $(OBJS) regnual-no-vidpid.elf regnual.elf regnual.hex regnual.bin \
*.lst
distclean: clean

View File

@@ -53,6 +53,10 @@ ifeq ($(CHIP),stm32f103)
CSRC += mcu-stm32f103.c
endif
ifneq ($(USE_DFU),)
OBJS_ADD += build/stdaln-sys-bin.o
endif
###################################
CC = $(CROSS)gcc
LD = $(CROSS)gcc
@@ -72,16 +76,26 @@ sys.c: board.h
build/bignum.o: OPT = -O3 -g
build/stdaln-sys.elf: build/sys-$(CHIP).o stdaln-sys.ld
@echo
$(LD) -v $< $(MCFLAGS) -nostartfiles -Tstdaln-sys.ld -Wl,--no-warn-mismatch,--gc-sections $(LLIBDIR) -o $@
build/stdaln-sys-bin.o: build/stdaln-sys.elf
@echo
$(OBJCOPY) -O binary -j .sys $< build/stdaln-sys.bin
$(OBJCOPY) -I binary -O default --rename-section .data=.rodata \
build/stdaln-sys.bin $@
distclean: clean
-rm -f gnuk.ld config.h board.h config.mk \
usb-strings.c.inc usb-vid-pid-ver.c.inc
-rm -f gnuk.ld stdaln-sys.ld config.h board.h config.mk \
usb-strings.c.inc put-vid-pid-ver.sh
ifeq ($(EMULATION),)
build/gnuk-vidpid.elf: build/gnuk.elf binary-edit.sh put-vid-pid-ver.sh
cp -p build/gnuk.elf build/gnuk-vidpid.elf
env FILE="build/gnuk-vidpid.elf" bash put-vid-pid-ver.sh
$(OBJCOPY) -O ihex build/gnuk-vidpid.elf build/gnuk-vidpid.hex
$(OBJCOPY) -O binary build/gnuk-vidpid.elf build/gnuk-vidpid.bin
build/gnuk.elf: build/gnuk-no-vidpid.elf binary-edit.sh put-vid-pid-ver.sh
cp -p build/gnuk-no-vidpid.elf build/gnuk.elf
env FILE="build/gnuk.elf" bash put-vid-pid-ver.sh
$(OBJCOPY) -O ihex build/gnuk.elf build/gnuk.hex
$(OBJCOPY) -O binary build/gnuk.elf build/gnuk.bin
else
# By specifying DESTDIR on invocation of "make", you can install
# program to different ROOT.

View File

@@ -1,7 +1,8 @@
/*
* bn.c -- 256-bit (and 512-bit) bignum calculation
*
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Copyright (C) 2011, 2013, 2014, 2019
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -412,17 +413,15 @@ bn256_cmp (const bn256 *A, const bn256 *B)
void
bn256_random (bn256 *X)
{
const uint8_t *rand = random_bytes_get ();
X->word[7] = ((uint32_t *)rand)[7];
X->word[6] = ((uint32_t *)rand)[6];
X->word[5] = ((uint32_t *)rand)[5];
X->word[4] = ((uint32_t *)rand)[4];
X->word[3] = ((uint32_t *)rand)[3];
X->word[2] = ((uint32_t *)rand)[2];
X->word[1] = ((uint32_t *)rand)[1];
X->word[0] = ((uint32_t *)rand)[0];
int i, j;
const uint8_t *rand;
for (i = 0; i < 256/256; i++)
{
rand = random_bytes_get ();
for (j = 0; j < BN256_WORDS; j++)
X->word[i*BN256_WORDS+j] = ((uint32_t *)rand)[j];
random_bytes_free (rand);
}
}
#endif

View File

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

46
src/configure vendored
View File

@@ -44,6 +44,7 @@ pinpad=no
certdo=no
hid_card_change=no
factory_reset=no
ackbtn_support=yes
flash_override=""
# For emulation
prefix=/usr/local
@@ -135,6 +136,7 @@ Configuration:
supported targets are:
FST_01
FST_01G
FST_01SZ
OLIMEX_STM32_H103
MAPLE_MINI
ST_DONGLE
@@ -167,6 +169,8 @@ BOARD_HEADER_FILE=board-$(echo $target | tr '_[:upper:]' '-[:lower:]').h
echo "Header file is: $BOARD_HEADER_FILE"
ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h
# Frequency
MHZ=72
# Flash page size in byte
FLASH_PAGE_SIZE=1024
# Flash memory size in KiB
@@ -196,6 +200,12 @@ STBEE)
if test "$with_dfu" = "default"; then
with_dfu=yes;
fi ;;
BLUE_PILL_G)
MHZ=96
;;
FST_01SZ)
MHZ=96
;;
*)
;;
esac
@@ -208,6 +218,7 @@ if test "$target" = "GNU_LINUX"; then
mcu="none"
def_emulation="-DGNU_LINUX_EMULATION"
def_memory_size="-DMEMORY_SIZE=1024"
def_mhz=""
enable_hexoutput=""
libs="-lpthread"
else
@@ -218,6 +229,7 @@ else
mcu="cortex-m3"
def_emulation=""
def_memory_size="-DMEMORY_SIZE=$MEMORY_SIZE"
def_mhz="-DMHZ=$MHZ"
enable_hexoutput=yes
libs=""
fi
@@ -248,6 +260,8 @@ else
echo "Debug option disabled"
fi
ORIGIN_REAL=0x08000000
ORIGIN_REAL_DEFINE="#define ORIGIN_REAL $ORIGIN_REAL"
# --with-dfu option
if test "$with_dfu" = "yes"; then
if test "$target" = "FST_01" -o "$target" = "FST_01G" \
@@ -256,15 +270,23 @@ if test "$with_dfu" = "yes"; then
exit 1
fi
echo "Configured for DFU"
if test "$target" = "MAPLE_MINI"; then
# Note that the default bootloader is too large, need for instance
# STM32duino for DFU on Maple Mini
ORIGIN=0x08002000
FLASH_SIZE=$((FLASH_SIZE - 8))
else
ORIGIN=0x08003000
FLASH_SIZE=$((FLASH_SIZE - 12))
fi
DFU_DEFINE="#define DFU_SUPPORT 1"
else
with_dfu=no
echo "Configured for bare system (no-DFU)"
ORIGIN=0x08000000
ORIGIN=${ORIGIN_REAL}
DFU_DEFINE="#undef DFU_SUPPORT"
fi
ORIGIN_DEFINE="#define ORIGIN $ORIGIN"
# --enable-pinpad option
if test "$pinpad" = "no"; then
@@ -306,6 +328,15 @@ else
echo "Life cycle management is NOT supported"
fi
# Acknowledge button support
if test "$ackbtn_support" = "yes"; then
ACKBTN_DEFINE="#define ACKBTN_SUPPORT 1"
echo "Acknowledge button is supported"
else
ACKBTN_DEFINE="#undef ACKBTN_SUPPORT"
echo "Acknowledge button is not supported"
fi
### !!! Replace following string of "FSIJ" to yours !!! ####
SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
@@ -442,13 +473,19 @@ fi
echo "EMULATION=$emulation";
echo "CROSS=$cross";
echo "MCU=$mcu";
echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size";
echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size $def_mhz";
echo "LDSCRIPT=$ldscript";
echo "LIBS=$libs";
echo "$DEBUG_MAKE_OPTION";
echo "$PINPAD_MAKE_OPTION";
echo "ENABLE_FRAUCHEKY=$enable_fraucheky";
echo "ENABLE_OUTPUT_HEX=$enable_hexoutput"
if test "$ackbtn_support" = "yes"; then
echo "USE_ACKBTN=yes"
fi
if test "$with_dfu" = "yes"; then
echo "USE_DFU=yes"
fi
if test "$emulation" = "yes"; then
echo "prefix=$prefix"
echo "exec_prefix=$exec_prefix"
@@ -469,13 +506,18 @@ else
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
< gnuk.ld.in > gnuk.ld
fi
sed -e "s/@ORIGIN_REAL@/$ORIGIN_REAL/" -e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
< stdaln-sys.ld.in > stdaln-sys.ld
sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
-e "s/@ORIGIN_DEFINE@/$ORIGIN_DEFINE/" \
-e "s/@ORIGIN_REAL_DEFINE@/$ORIGIN_REAL_DEFINE/" \
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
-e "s/@ACKBTN_DEFINE@/$ACKBTN_DEFINE/" \
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
< config.h.in > config.h
exit 0

View File

@@ -71,7 +71,7 @@ static const uint8_t *data_pool;
static uint8_t *last_p;
/* The first halfword is generation for the data page (little endian) */
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
0x00, 0x00, 0xff, 0xff
};

View File

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

View File

@@ -1,7 +1,7 @@
/*
* main.c - main routine of Gnuk
*
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -51,6 +51,28 @@
#define LED_TIMEOUT_ONE (100*1000)
#define LED_TIMEOUT_STOP (200*1000)
#ifdef DFU_SUPPORT
static int
flash_write_any (uintptr_t dst_addr, const uint8_t *src, size_t len)
{
int status;
while (len)
{
uint16_t hw = *src++;
hw |= (*src++ << 8);
status = flash_program_halfword (dst_addr, hw);
if (status != 0)
return 0; /* error return */
dst_addr += 2;
len -= 2;
}
return 1;
}
#endif
#ifdef GNU_LINUX_EMULATION
uint8_t *flash_addr_key_storage_start;
@@ -68,7 +90,7 @@ device_initialize_once (void)
* This is the first time invocation.
* Setup serial number by unique device ID.
*/
const uint8_t *u = unique_device_id () + 8;
const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
int i;
for (i = 0; i < 4; i++)
@@ -83,6 +105,55 @@ device_initialize_once (void)
nibble += (nibble >= 10 ? ('A' - 10) : '0');
flash_put_data_internal (&p[i*4+2], nibble);
}
#ifdef DFU_SUPPORT
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
/*
* Overwrite DFU bootloader with a copy of SYS linked to ORIGIN_REAL.
* Then protect flash from readout.
*/
{
extern uint8_t _binary_build_stdaln_sys_bin_start;
extern uint8_t _binary_build_stdaln_sys_bin_size;
size_t stdaln_sys_size = (size_t) &_binary_build_stdaln_sys_bin_size;
extern const uint32_t FT0[256], FT1[256], FT2[256];
extern handler vector_table[];
uintptr_t addr;
uint32_t flash_page_size = 1024; /* 1KiB default */
if (((*CHIP_ID_REG)&0x07) == 0x04) /* High density device. */
flash_page_size = 2048; /* It's 2KiB. */
/* Kill DFU */
for (addr = ORIGIN_REAL; addr < ORIGIN;
addr += flash_page_size)
flash_erase_page (addr);
/* Copy SYS */
addr = ORIGIN_REAL;
flash_write_any(addr, &_binary_build_stdaln_sys_bin_start,
stdaln_sys_size);
addr += stdaln_sys_size;
flash_write_any(addr, (const uint8_t *) &FT0, sizeof(FT0));
addr += sizeof(FT0);
flash_write_any(addr, (const uint8_t *) &FT1, sizeof(FT1));
addr += sizeof(FT1);
flash_write_any(addr, (const uint8_t *) &FT2, sizeof(FT2));
addr = ORIGIN_REAL + 0x1000;
if (addr < ORIGIN) {
/* Need to patch top of stack and reset vector there */
handler *new_vector = (handler *) addr;
flash_write((uintptr_t) &new_vector[0], (const uint8_t *)
&vector_table[0], sizeof(handler));
flash_write((uintptr_t) &new_vector[1], (const uint8_t *)
&vector[1], sizeof(handler));
}
flash_protect();
nvic_system_reset();
}
#endif
}
}
#endif
@@ -146,7 +217,7 @@ emit_led (uint32_t on_time, uint32_t off_time)
static void
display_status_code (void)
{
enum ccid_state ccid_state = *ccid_state_p;
enum ccid_state ccid_state = ccid_get_ccid_state ();
uint32_t usec;
if (ccid_state == CCID_STATE_START)
@@ -170,8 +241,7 @@ display_status_code (void)
{
usec = LED_TIMEOUT_INTERVAL;
chopstx_poll (&usec, 1, led_event_poll);
emit_led (ccid_state == CCID_STATE_RECEIVE?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
}
}
}
@@ -238,6 +308,7 @@ main (int argc, const char *argv[])
uintptr_t entry;
#endif
chopstx_t ccid_thd;
int wait_for_ack = 0;
chopstx_conf_idle (1);
@@ -354,7 +425,11 @@ main (int argc, const char *argv[])
{
eventmask_t m;
if (wait_for_ack)
m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL);
else
m = eventflag_wait (&led_event);
switch (m)
{
case LED_ONESHOT:
@@ -375,8 +450,11 @@ main (int argc, const char *argv[])
break;
case LED_GNUK_EXEC:
goto exec;
case LED_WAIT_FOR_BUTTON:
wait_for_ack ^= 1;
/* fall through */
default:
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_ZERO);
break;
}
}
@@ -395,26 +473,10 @@ main (int argc, const char *argv[])
SCB->VTOR = (uintptr_t)&_regnual_start;
entry = calculate_regnual_entry_address (&_regnual_start);
#ifdef DFU_SUPPORT
#define FLASH_SYS_START_ADDR 0x08000000
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
{
extern uint8_t _sys;
uintptr_t addr;
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
/* Use SYS at ORIGIN_REAL instead of the one at ORIGIN */
handler *new_vector = (handler *)ORIGIN_REAL;
void (*func) (void (*)(void)) = (void (*)(void (*)(void))) new_vector[9];
uint32_t flash_page_size = 1024; /* 1KiB default */
if ((*CHIP_ID_REG)&0x07 == 0x04) /* High dencity device. */
flash_page_size = 2048; /* It's 2KiB. */
/* Kill DFU */
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
addr += flash_page_size)
flash_erase_page (addr);
/* copy system service routines */
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
/* Leave Gnuk to exec reGNUal */
(*func) ((void (*)(void))entry);

View File

@@ -135,6 +135,14 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
0x01, 0x00,
};
#ifdef ACKBTN_SUPPORT
/* General Feature Management */
static const uint8_t feature_mngmnt[] __attribute__ ((aligned (1))) = {
3,
0x81, 0x01, 0x20,
};
#endif
/* Algorithm Attributes */
#define OPENPGP_ALGO_RSA 0x01
#define OPENPGP_ALGO_ECDH 0x12
@@ -649,7 +657,7 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
if (vid == 0xffff || vid == 0x0000)
{
const uint8_t *u = unique_device_id () + 8;
const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
memcpy (res_p, openpgpcard_aid, 8);
res_p += 8;
@@ -807,6 +815,64 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
}
}
static uint8_t uif_flags; /* Six bits of flags */
#ifdef ACKBTN_SUPPORT
int
gpg_do_get_uif (enum kind_of_key kk)
{
return ((uif_flags >> (kk * 2)) & 3) != 0;
}
static int
rw_uif (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
{
uint8_t nr;
int v;
if (tag != GPG_DO_UIF_SIG && tag != GPG_DO_UIF_DEC && tag != GPG_DO_UIF_AUT)
return 0; /* Failure */
nr = (tag - GPG_DO_UIF_SIG) + NR_DO_UIF_SIG;
v = (uif_flags >> ((tag - GPG_DO_UIF_SIG) * 2)) & 3;
if (is_write)
{
const uint8_t *p;
if (len != 2 || data[1] != 0x20)
return 0;
if (v == 2)
return 0;
if (data[0] != 0x00 && data[0] != 0x01 && data[0] != 0x02)
return 0;
p = flash_enum_write (nr, data[0]);
if (p == NULL)
return 0;
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
uif_flags |= (data[0] & 3) << ((nr - NR_DO_UIF_SIG) * 2);
return 1;
}
else
{
if (with_tag)
{
copy_tag (tag);
*res_p++ = 2;
}
*res_p++ = v;
*res_p++ = 0x20;
return 1;
}
}
#endif
#define SIZE_OF_KDF_DO_MIN 90
#define SIZE_OF_KDF_DO_MAX 110
#define OPENPGP_KDF_ITERSALTED_S2K 3
@@ -1614,18 +1680,32 @@ static const uint16_t cmp_ch_data[] = {
};
static const uint16_t cmp_app_data[] = {
#ifdef ACKBTN_SUPPORT
4,
#else
3,
#endif
GPG_DO_AID,
GPG_DO_HIST_BYTES,
GPG_DO_DISCRETIONARY,
#ifdef ACKBTN_SUPPORT
GPG_DO_FEATURE_MNGMNT,
#endif
};
static const uint16_t cmp_discretionary[] = {
#ifdef ACKBTN_SUPPORT
11,
#else
8,
#endif
GPG_DO_EXTCAP,
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
GPG_DO_PW_STATUS,
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL,
#ifdef ACKBTN_SUPPORT
GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT
#endif
};
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
@@ -1664,11 +1744,19 @@ gpg_do_table[] = {
rw_algorithm_attr },
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_algorithm_attr },
#ifdef ACKBTN_SUPPORT
{ GPG_DO_UIF_SIG, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
{ GPG_DO_UIF_DEC, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
{ GPG_DO_UIF_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
#endif
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_kdf },
/* Fixed data */
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
#ifdef ACKBTN_SUPPORT
{ GPG_DO_FEATURE_MNGMNT, DO_FIXED, AC_ALWAYS, AC_NEVER, feature_mngmnt },
#endif
/* Compound data: Read access only */
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
@@ -1707,6 +1795,11 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
digital_signature_counter = 0;
uif_flags = 0;
/* Clear all data objects. */
for (i = 0; i < NR_DO__LAST__; i++)
do_ptr[i] = NULL;
/* When the card is terminated no data objects are valid. */
if (do_start == NULL)
@@ -1765,6 +1858,13 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
algo_attr_aut_p = p - 1;
p++;
break;
case NR_DO_UIF_SIG:
case NR_DO_UIF_DEC:
case NR_DO_UIF_AUT:
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
uif_flags |= (second_byte & 3) << ((nr - NR_DO_UIF_SIG) * 2);
p++;
break;
case NR_COUNTER_123:
p++;
if (second_byte <= PW_ERR_PW3)
@@ -1864,6 +1964,13 @@ gpg_data_copy (const uint8_t *p_start)
p += 4;
}
for (i = 0; i < 3; i++)
if ((v = (uif_flags >> (i * 2)) & 3))
{
flash_enum_write_internal (p, NR_DO_UIF_SIG + i, v);
p += 2;
}
data_objects_number_of_bytes = 0;
for (i = 0; i < NR_DO__LAST__; i++)
if (do_ptr[i] != NULL)

View File

@@ -2,6 +2,7 @@
* openpgp.c -- OpenPGP card protocol support
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* 2019
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -145,7 +146,7 @@ get_pinpad_input (int msg_code)
#endif
static void
cmd_verify (void)
cmd_verify (struct eventflag *ccid_comm)
{
int len;
uint8_t p1 = P1 (apdu);
@@ -153,6 +154,7 @@ cmd_verify (void)
int r;
const uint8_t *pw;
(void)ccid_comm;
DEBUG_INFO (" - VERIFY\r\n");
DEBUG_BYTE (p2);
@@ -275,7 +277,7 @@ gpg_change_keystring (int who_old, const uint8_t *old_ks,
}
static void
cmd_change_password (void)
cmd_change_password (struct eventflag *ccid_comm)
{
uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_SIZE];
@@ -295,6 +297,7 @@ cmd_change_password (void)
int salt_len;
const uint8_t *ks_pw3;
(void)ccid_comm;
DEBUG_INFO ("Change PW\r\n");
DEBUG_BYTE (who);
@@ -547,7 +550,7 @@ s2k (const unsigned char *salt, size_t slen,
static void
cmd_reset_user_password (void)
cmd_reset_user_password (struct eventflag *ccid_comm)
{
uint8_t p1 = P1 (apdu);
int len;
@@ -561,6 +564,7 @@ cmd_reset_user_password (void)
const uint8_t *salt;
int salt_len;
(void)ccid_comm;
DEBUG_INFO ("Reset PW1\r\n");
DEBUG_BYTE (p1);
@@ -695,12 +699,13 @@ cmd_reset_user_password (void)
}
static void
cmd_put_data (void)
cmd_put_data (struct eventflag *ccid_comm)
{
uint8_t *data;
uint16_t tag;
int len;
(void)ccid_comm;
DEBUG_INFO (" - PUT DATA\r\n");
tag = ((P1 (apdu)<<8) | P2 (apdu));
@@ -710,8 +715,9 @@ cmd_put_data (void)
}
static void
cmd_pgp_gakp (void)
cmd_pgp_gakp (struct eventflag *ccid_comm)
{
(void)ccid_comm;
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
DEBUG_BYTE (P1 (apdu));
@@ -745,12 +751,13 @@ gpg_get_firmware_update_key (uint8_t keyno)
#endif
static void
cmd_read_binary (void)
cmd_read_binary (struct eventflag *ccid_comm)
{
int is_short_EF = (P1 (apdu) & 0x80) != 0;
uint8_t file_id;
uint16_t offset;
(void)ccid_comm;
DEBUG_INFO (" - Read binary\r\n");
if (is_short_EF)
@@ -821,8 +828,9 @@ cmd_read_binary (void)
}
static void
cmd_select_file (void)
cmd_select_file (struct eventflag *ccid_comm)
{
(void)ccid_comm;
if (P1 (apdu) == 4) /* Selection by DF name */
{
DEBUG_INFO (" - select DF by name\r\n");
@@ -891,10 +899,11 @@ cmd_select_file (void)
}
static void
cmd_get_data (void)
cmd_get_data (struct eventflag *ccid_comm)
{
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
(void)ccid_comm;
DEBUG_INFO (" - Get Data\r\n");
gpg_do_get_data (tag, 0);
@@ -909,7 +918,7 @@ cmd_get_data (void)
#define ECC_CIPHER_DO_HEADER_SIZE 7
static void
cmd_pso (void)
cmd_pso (struct eventflag *ccid_comm)
{
int len = apdu.cmd_apdu_data_len;
int r = -1;
@@ -936,6 +945,11 @@ cmd_pso (void)
return;
}
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
/* Check size of digestInfo */
@@ -1027,6 +1041,13 @@ cmd_pso (void)
return;
}
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#else
(void)ccid_comm;
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
/* Skip padding 0x00 */
@@ -1103,7 +1124,7 @@ cmd_pso (void)
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
static void
cmd_internal_authenticate (void)
cmd_internal_authenticate (struct eventflag *ccid_comm)
{
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
@@ -1133,6 +1154,13 @@ cmd_internal_authenticate (void)
return;
}
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#else
(void)ccid_comm;
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
if (len > MAX_RSA_DIGEST_INFO_LEN)
@@ -1309,10 +1337,11 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
#if defined(CERTDO_SUPPORT)
static void
cmd_update_binary (void)
cmd_update_binary (struct eventflag *ccid_comm)
{
int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - UPDATE BINARY\r\n");
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("UPDATE BINARY done.\r\n");
@@ -1321,10 +1350,11 @@ cmd_update_binary (void)
static void
cmd_write_binary (void)
cmd_write_binary (struct eventflag *ccid_comm)
{
int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - WRITE BINARY\r\n");
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("WRITE BINARY done.\r\n");
@@ -1333,7 +1363,7 @@ cmd_write_binary (void)
#ifdef FLASH_UPGRADE_SUPPORT
static void
cmd_external_authenticate (void)
cmd_external_authenticate (struct eventflag *ccid_comm)
{
const uint8_t *pubkey;
const uint8_t *signature = apdu.cmd_apdu_data;
@@ -1341,6 +1371,7 @@ cmd_external_authenticate (void)
uint8_t keyno = P2 (apdu);
int r;
(void)ccid_comm;
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
if (keyno >= 4)
@@ -1376,10 +1407,11 @@ cmd_external_authenticate (void)
#endif
static void
cmd_get_challenge (void)
cmd_get_challenge (struct eventflag *ccid_comm)
{
int len = apdu.expected_res_size;
(void)ccid_comm;
DEBUG_INFO (" - GET CHALLENGE\r\n");
if (len > CHALLENGE_LEN)
@@ -1394,6 +1426,13 @@ cmd_get_challenge (void)
if (challenge)
random_bytes_free (challenge);
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING)
|| gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION)
|| gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#endif
challenge = random_bytes_get ();
memcpy (res_APDU, challenge, len);
res_APDU_size = len;
@@ -1404,8 +1443,9 @@ cmd_get_challenge (void)
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
static void
cmd_activate_file (void)
cmd_activate_file (struct eventflag *ccid_comm)
{
(void)ccid_comm;
if (file_selection != FILE_CARD_TERMINATED)
{
GPG_NO_RECORD ();
@@ -1418,13 +1458,13 @@ cmd_activate_file (void)
}
static void
cmd_terminate_df (void)
cmd_terminate_df (struct eventflag *ccid_comm)
{
const uint8_t *ks_pw3;
uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu);
(void)ccid_comm;
if (file_selection != FILE_DF_OPENPGP)
{
GPG_NO_RECORD ();
@@ -1468,7 +1508,7 @@ cmd_terminate_df (void)
struct command
{
uint8_t command;
void (*cmd_handler) (void);
void (*cmd_handler) (struct eventflag *ccid_comm);
};
const struct command cmds[] = {
@@ -1502,7 +1542,7 @@ const struct command cmds[] = {
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
static void
process_command_apdu (void)
process_command_apdu (struct eventflag *ccid_comm)
{
int i;
uint8_t cmd = INS (apdu);
@@ -1526,7 +1566,7 @@ process_command_apdu (void)
else
{
chopstx_setcancelstate (1);
cmds[i].cmd_handler ();
cmds[i].cmd_handler (ccid_comm);
chopstx_setcancelstate (0);
}
}
@@ -1640,7 +1680,7 @@ openpgp_card_thread (void *arg)
break;
led_blink (LED_START_COMMAND);
process_command_apdu ();
process_command_apdu (ccid_comm);
led_blink (LED_FINISH_COMMAND);
done:
eventflag_signal (ccid_comm, EV_EXEC_FINISHED);

View File

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

View File

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

39
src/stdaln-sys.ld.in Normal file
View File

@@ -0,0 +1,39 @@
/*
* ST32F103 memory setup.
*/
MEMORY
{
flash0 : org = @ORIGIN_REAL@, len = 4k
ram : org = 0x20000000, len = @MEMORY_SIZE@k
}
__ram_start__ = ORIGIN(ram);
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
SECTIONS
{
. = 0;
.sys : ALIGN(4) SUBALIGN(4)
{
_sys = .;
KEEP(*(.vectors))
. = ALIGN(16);
KEEP(*(.sys.version))
KEEP(*(.sys.board_id))
KEEP(*(.sys.board_name))
build/sys-*.o(.text)
build/sys-*.o(.text.*)
build/sys-*.o(.rodata)
build/sys-*.o(.rodata.*)
. = ALIGN(1024);
} > flash0
.aesft : ALIGN(4) SUBALIGN(4)
{
*(.sys.0)
*(.sys.1)
*(.sys.2)
} > flash0
}

View File

@@ -1,7 +1,8 @@
/*
* usb-ccid.c -- USB CCID protocol handling
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
* 2019
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -29,6 +30,10 @@
#include "config.h"
#ifdef ACKBTN_SUPPORT
#include <contrib/ackbtn.h>
#endif
#ifdef DEBUG
#include "usb-cdc.h"
#include "debug.h"
@@ -182,9 +187,11 @@ struct ccid_header {
/* Data structure handled by CCID layer */
struct ccid {
enum ccid_state ccid_state;
uint8_t state;
uint8_t err;
uint32_t ccid_state : 4;
uint32_t state : 4;
uint32_t err : 1;
uint32_t tx_busy : 1;
uint32_t timeout_cnt: 3;
uint8_t *p;
size_t len;
@@ -241,6 +248,7 @@ struct ccid {
static void ccid_reset (struct ccid *c)
{
c->err = 0;
c->tx_busy = 0;
c->state = APDU_STATE_WAIT_COMMAND;
c->p = c->a->cmd_apdu_data;
c->len = MAX_CMD_APDU_DATA_SIZE;
@@ -252,10 +260,11 @@ static void ccid_init (struct ccid *c, struct ep_in *epi, struct ep_out *epo,
struct apdu *a)
{
c->ccid_state = CCID_STATE_START;
c->err = 0;
c->tx_busy = 0;
c->state = APDU_STATE_WAIT_COMMAND;
c->p = a->cmd_apdu_data;
c->len = MAX_CMD_APDU_DATA_SIZE;
c->err = 0;
memset (&c->ccid_header, 0, sizeof (struct ccid_header));
c->sw1sw2[0] = 0x90;
c->sw1sw2[1] = 0x00;
@@ -765,6 +774,7 @@ usb_tx_done (uint8_t ep_num, uint16_t len)
#endif
}
/*
* ATR (Answer To Reset) string
*
@@ -820,6 +830,7 @@ static void ccid_error (struct ccid *c, int offset)
#else
usb_lld_write (c->epi->ep_num, ccid_reply, CCID_MSG_HEADER_SIZE);
#endif
c->tx_busy = 1;
}
extern void *openpgp_card_thread (void *arg);
@@ -893,7 +904,7 @@ ccid_power_on (struct ccid *c)
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE + size_atr);
#endif
DEBUG_INFO ("ON\r\n");
c->tx_busy = 1;
return CCID_STATE_WAIT;
}
@@ -934,6 +945,7 @@ ccid_send_status (struct ccid *c)
#ifdef DEBUG_MORE
DEBUG_INFO ("St\r\n");
#endif
c->tx_busy = 1;
}
static enum ccid_state
@@ -949,6 +961,7 @@ ccid_power_off (struct ccid *c)
c->ccid_state = CCID_STATE_START; /* This status change should be here */
ccid_send_status (c);
DEBUG_INFO ("OFF\r\n");
c->tx_busy = 1;
return CCID_STATE_START;
}
@@ -982,12 +995,16 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
#endif
if (len == 0)
{
c->epi->buf = NULL;
c->epi->tx_done = 1;
#ifdef GNU_LINUX_EMULATION
usb_lld_tx_enable_buf (c->epi->ep_num, endp1_tx_buf,
CCID_MSG_HEADER_SIZE);
#else
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE);
#endif
c->tx_busy = 1;
return;
}
@@ -1065,6 +1082,7 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
#ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n");
#endif
c->tx_busy = 1;
}
static void
@@ -1076,7 +1094,8 @@ ccid_send_data_block (struct ccid *c)
static void
ccid_send_data_block_time_extension (struct ccid *c)
{
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT, 1);
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT,
c->ccid_state == CCID_STATE_EXECUTE? 1: 0xff);
}
static void
@@ -1115,6 +1134,7 @@ ccid_send_data_block_0x9000 (struct ccid *c)
#ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n");
#endif
c->tx_busy = 1;
}
/*
@@ -1211,6 +1231,7 @@ ccid_send_data_block_gr (struct ccid *c, size_t chunk_len)
#ifdef DEBUG_MORE
DEBUG_INFO ("DATA\r\n");
#endif
c->tx_busy = 1;
}
@@ -1259,6 +1280,7 @@ ccid_send_params (struct ccid *c)
#ifdef DEBUG_MORE
DEBUG_INFO ("PARAMS\r\n");
#endif
c->tx_busy = 1;
}
@@ -1413,6 +1435,7 @@ ccid_handle_data (struct ccid *c)
c->a->res_apdu_data_len = 0;
c->a->res_apdu_data = &c->p[5];
c->state = APDU_STATE_COMMAND_RECEIVED;
eventflag_signal (&c->openpgp_comm, EV_VERIFY_CMD_AVAILABLE);
next_state = CCID_STATE_EXECUTE;
}
@@ -1447,6 +1470,7 @@ ccid_handle_data (struct ccid *c)
c->a->res_apdu_data_len = 0;
c->a->res_apdu_data = &ccid_buffer[5];
c->state = APDU_STATE_COMMAND_RECEIVED;
eventflag_signal (&c->openpgp_comm, EV_MODIFY_CMD_AVAILABLE);
next_state = CCID_STATE_EXECUTE;
}
@@ -1461,6 +1485,8 @@ ccid_handle_data (struct ccid *c)
}
break;
case CCID_STATE_EXECUTE:
case CCID_STATE_ACK_REQUIRED_0:
case CCID_STATE_ACK_REQUIRED_1:
if (c->ccid_header.msg_type == CCID_POWER_OFF)
next_state = ccid_power_off (c);
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
@@ -1489,6 +1515,8 @@ ccid_handle_timeout (struct ccid *c)
switch (c->ccid_state)
{
case CCID_STATE_EXECUTE:
case CCID_STATE_ACK_REQUIRED_0:
case CCID_STATE_ACK_REQUIRED_1:
ccid_send_data_block_time_extension (c);
break;
default:
@@ -1500,7 +1528,13 @@ ccid_handle_timeout (struct ccid *c)
}
static struct ccid ccid;
enum ccid_state *const ccid_state_p = &ccid.ccid_state;
enum ccid_state
ccid_get_ccid_state (void)
{
return ccid.ccid_state;
}
void
ccid_card_change_signal (int how)
@@ -1545,7 +1579,7 @@ ccid_notify_slot_change (struct ccid *c)
#define USB_CCID_TIMEOUT (1950*1000)
#define GPG_THREAD_TERMINATED 0xffff
#define GPG_ACK_TIMEOUT 0x6600
extern uint32_t bDeviceState;
extern void usb_device_reset (struct usb_dev *dev);
@@ -1561,6 +1595,10 @@ extern int usb_get_descriptor (struct usb_dev *dev);
extern void random_init (void);
extern void random_fini (void);
#ifdef ACKBTN_SUPPORT
static chopstx_intr_t ack_intr;
#endif
static chopstx_intr_t usb_intr;
/*
* Return 0 for normal USB event
@@ -1575,6 +1613,7 @@ usb_event_handle (struct usb_dev *dev)
e = usb_lld_event_handler (dev);
ep_num = USB_EVENT_ENDP (e);
chopstx_intr_done (&usb_intr);
/* Transfer to endpoint (not control endpoint) */
if (ep_num != 0)
@@ -1674,11 +1713,13 @@ usb_event_handle (struct usb_dev *dev)
}
static chopstx_intr_t interrupt;
static chopstx_poll_cond_t ccid_event_poll_desc;
static struct chx_poll_head *const ccid_poll[] = {
(struct chx_poll_head *const)&interrupt,
(struct chx_poll_head *const)&ccid_event_poll_desc
(struct chx_poll_head *const)&usb_intr,
(struct chx_poll_head *const)&ccid_event_poll_desc,
#ifdef ACKBTN_SUPPORT
(struct chx_poll_head *const)&ack_intr
#endif
};
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
@@ -1689,6 +1730,7 @@ ccid_thread (void *arg)
struct usb_dev dev;
struct ccid *c = &ccid;
uint32_t *timeout_p;
int ackbtn_active = 0;
(void)arg;
@@ -1696,9 +1738,12 @@ ccid_thread (void *arg)
eventflag_init (&ccid.openpgp_comm);
usb_lld_init (&dev, USB_INITIAL_FEATURE);
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
usb_event_handle (&dev); /* For old SYS < 3.0 */
#ifdef ACKBTN_SUPPORT
ackbtn_init (&ack_intr);
#endif
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
reset:
@@ -1707,6 +1752,13 @@ ccid_thread (void *arg)
struct ep_out *epo = &endpoint_out;
struct apdu *a = &apdu;
if (ackbtn_active)
{
ackbtn_active = 0;
ackbtn_disable ();
led_blink (LED_WAIT_FOR_BUTTON);
}
epi_init (epi, ENDP1, c);
epo_init (epo, ENDP1, c);
apdu_init (a);
@@ -1724,14 +1776,21 @@ ccid_thread (void *arg)
{
eventmask_t m;
if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
if (!c->tx_busy && bDeviceState == USB_DEVICE_STATE_CONFIGURED)
timeout_p = &timeout;
else
timeout_p = NULL;
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
eventflag_set_mask (&c->ccid_comm, c->tx_busy ? EV_TX_FINISHED : ~0);
if (interrupt.ready)
#ifdef ACKBTN_SUPPORT
chopstx_poll (timeout_p, CCID_POLL_NUM - (c->tx_busy || !ackbtn_active),
ccid_poll);
#else
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
#endif
if (usb_intr.ready)
{
if (usb_event_handle (&dev) == 0)
continue;
@@ -1751,7 +1810,26 @@ ccid_thread (void *arg)
goto reset;
}
#ifdef ACKBTN_SUPPORT
if (!c->tx_busy && ack_intr.ready)
{
ackbtn_active = 0;
ackbtn_disable ();
led_blink (LED_WAIT_FOR_BUTTON);
chopstx_intr_done (&ack_intr);
if (c->ccid_state == CCID_STATE_ACK_REQUIRED_1)
goto exec_done;
c->ccid_state = CCID_STATE_EXECUTE;
continue;
}
#endif
if (timeout == 0)
{
timeout = USB_CCID_TIMEOUT;
c->timeout_cnt++;
}
m = eventflag_get (&c->ccid_comm);
if (m == EV_CARD_CHANGE)
@@ -1774,10 +1852,17 @@ ccid_thread (void *arg)
ccid_notify_slot_change (c);
}
else if (m == EV_RX_DATA_READY)
{
c->ccid_state = ccid_handle_data (c);
timeout = 0;
c->timeout_cnt = 0;
}
else if (m == EV_EXEC_FINISHED)
if (c->ccid_state == CCID_STATE_EXECUTE)
{
#ifdef ACKBTN_SUPPORT
exec_done:
#endif
if (c->a->sw == GPG_THREAD_TERMINATED)
{
c->sw1sw2[0] = 0x90;
@@ -1807,21 +1892,35 @@ ccid_thread (void *arg)
c->ccid_state = CCID_STATE_WAIT;
}
}
#ifdef ACKBTN_SUPPORT
else if (c->ccid_state == CCID_STATE_ACK_REQUIRED_0)
c->ccid_state = CCID_STATE_ACK_REQUIRED_1;
#endif
else
{
DEBUG_INFO ("ERR07\r\n");
DEBUG_INFO ("ERR05\r\n");
}
#ifdef ACKBTN_SUPPORT
else if (m == EV_EXEC_ACK_REQUIRED)
if (c->ccid_state == CCID_STATE_EXECUTE)
{
ackbtn_enable ();
ackbtn_active = 1;
led_blink (LED_WAIT_FOR_BUTTON);
c->ccid_state = CCID_STATE_ACK_REQUIRED_0;
ccid_send_data_block_time_extension (c);
}
else
{
DEBUG_INFO ("ERR06\r\n");
}
#endif
else if (m == EV_TX_FINISHED)
{
if (c->state == APDU_STATE_RESULT)
{
c->state = APDU_STATE_WAIT_COMMAND;
c->p = c->a->cmd_apdu_data;
c->len = MAX_CMD_APDU_DATA_SIZE;
c->err = 0;
c->a->cmd_apdu_data_len = 0;
c->a->expected_res_size = 0;
}
ccid_reset (c);
else
c->tx_busy = 0;
if (c->state == APDU_STATE_WAIT_COMMAND
|| c->state == APDU_STATE_COMMAND_CHAINING
@@ -1829,8 +1928,21 @@ ccid_thread (void *arg)
ccid_prepare_receive (c);
}
else /* Timeout */
{
if (c->timeout_cnt == 7
&& c->ccid_state == CCID_STATE_ACK_REQUIRED_1)
{
ackbtn_active = 0;
ackbtn_disable ();
led_blink (LED_WAIT_FOR_BUTTON);
c->a->sw = GPG_ACK_TIMEOUT;
c->a->res_apdu_data_len = 0;
goto exec_done;
}
else
c->ccid_state = ccid_handle_timeout (c);
}
}
if (c->application)
{
@@ -1841,7 +1953,7 @@ ccid_thread (void *arg)
/* Loading reGNUal. */
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
{
chopstx_intr_wait (&interrupt);
chopstx_intr_wait (&usb_intr);
usb_event_handle (&dev);
}

View File

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

View File

@@ -1,7 +1,7 @@
"""
card_reader.py - a library for smartcard reader
Copyright (C) 2016, 2017 Free Software Initiative of Japan
Copyright (C) 2016, 2017, 2019 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -25,6 +25,7 @@ from struct import pack
from usb.util import find_descriptor, claim_interface, get_string, \
endpoint_type, endpoint_direction, \
ENDPOINT_TYPE_BULK, ENDPOINT_OUT, ENDPOINT_IN
from binascii import hexlify
# USB class, subclass, protocol
CCID_CLASS = 0x0B
@@ -168,7 +169,7 @@ class CardReader(object):
return status
def ccid_power_on(self):
msg = ccid_compose(0x62, self.__seq, rsv=1) # Vcc=5V
msg = ccid_compose(0x62, self.__seq, rsv=2) # Vcc=3.3V
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data = self.ccid_get_result()
@@ -237,16 +238,21 @@ class CardReader(object):
def send_tpdu(self, info=None, more=0, response_time_ext=0,
edc_error=0, no_error=0):
rsv = 0
if info:
data = compose_i_block(self.ns, info, more)
elif response_time_ext:
# compose S-block
data = b"\x00\xE3\x00\xE3"
# compose S-block response
pcb = 0xe3
bwi_byte = bytes([response_time_ext])
edc = compute_edc(pcb, bwi_byte)
data = bytes([0, pcb, 1]) + bwi_byte + bytes([edc])
rsv = response_time_ext
elif edc_error:
data = compose_r_block(self.nr, edc_error=1)
elif no_error:
data = compose_r_block(self.nr)
msg = ccid_compose(0x6f, self.__seq, data=data)
msg = ccid_compose(0x6f, self.__seq, rsv=rsv, data=data)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
@@ -277,7 +283,7 @@ class CardReader(object):
res = b""
while True:
if is_s_block_time_ext(blk):
self.send_tpdu(response_time_ext=1)
self.send_tpdu(response_time_ext=blk[3])
elif is_i_block_last(blk):
self.nr = self.nr ^ 1
if is_edc_error(blk):

View File

@@ -0,0 +1,36 @@
"""
card_test_kdf_full.py - test KDF data object
Copyright (C) 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from card_const import *
from constants_for_test import *
class Test_Card_KDF_full(object):
def test_verify_pw3(self, card):
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
assert v
def test_kdf_put_full(self, card):
r = card.cmd_put_data(0x00, 0xf9, KDF_FULL)
if r:
card.configure_with_kdf()
assert r

View File

@@ -0,0 +1,35 @@
"""
card_test_kdf_single.py - test KDF data object
Copyright (C) 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from card_const import *
from constants_for_test import *
class Test_Card_KDF_Single(object):
def test_verify_pw3(self, card):
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
assert v
def test_kdf_put_single(self, card):
r = card.cmd_put_data(0x00, 0xf9, KDF_SINGLE)
if r:
card.configure_with_kdf()
assert r

84
tests/card_test_keygen.py Normal file
View File

@@ -0,0 +1,84 @@
"""
card_test_keygen.py - test key generation
Copyright (C) 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from binascii import hexlify
import rsa_keys
from card_const import *
class Test_Card_Keygen(object):
def test_keygen_1(self, card):
pk = card.cmd_genkey(1)
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
r = card.cmd_put_data(0x00, 0xc7, fpr_date[0])
if r:
r = card.cmd_put_data(0x00, 0xce, fpr_date[1])
assert r
def test_keygen_2(self, card):
pk = card.cmd_genkey(2)
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
r = card.cmd_put_data(0x00, 0xc8, fpr_date[0])
if r:
r = card.cmd_put_data(0x00, 0xcf, fpr_date[1])
assert r
def test_keygen_3(self, card):
pk = card.cmd_genkey(3)
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
r = card.cmd_put_data(0x00, 0xc9, fpr_date[0])
if r:
r = card.cmd_put_data(0x00, 0xd0, fpr_date[1])
assert r
def test_verify_pw1(self, card):
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
assert v
def test_signature_sigkey(self, card):
msg = b"Sign me please"
pk = card.cmd_get_public_key(1)
pk_info = (pk[9:9+256], pk[9+256+2:])
digest = rsa_keys.compute_digestinfo(msg)
sig = int(hexlify(card.cmd_pso(0x9e, 0x9a, digest)),16)
r = rsa_keys.verify_signature(pk_info, digest, sig)
assert r
def test_verify_pw1_2(self, card):
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
assert v
def test_decryption(self, card):
msg = b"encrypt me please"
pk = card.cmd_get_public_key(2)
pk_info = (pk[9:9+256], pk[9+256+2:])
ciphertext = rsa_keys.encrypt_with_pubkey(pk_info, msg)
r = card.cmd_pso(0x80, 0x86, ciphertext)
assert r == msg
def test_signature_authkey(self, card):
msg = b"Sign me please to authenticate"
pk = card.cmd_get_public_key(3)
pk_info = (pk[9:9+256], pk[9+256+2:])
digest = rsa_keys.compute_digestinfo(msg)
sig = int(hexlify(card.cmd_internal_authenticate(digest)),16)
r = rsa_keys.verify_signature(pk_info, digest, sig)
assert r

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,45 @@
"""
card_test_remove_keys.py - test removing keys on card
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
# Remove a key material on card by changing algorithm attributes of the key
from card_const import *
class Test_Remove_Keys(object):
def test_rsa_keyattr_change_1(self, card):
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
assert r
def test_rsa_keyattr_change_2(self, card):
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
assert r
def test_rsa_keyattr_change_3(self, card):
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)
assert r

View File

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

View File

@@ -16,3 +16,4 @@ def card():
card.cmd_select_openpgp()
yield card
del card
reader.ccid_power_off()

View File

@@ -1,7 +1,7 @@
"""
openpgp_card.py - a library for OpenPGP card
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018, 2019
Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -59,6 +59,7 @@ class OpenPGP_Card(object):
self.__kdf_salt_user = None
self.__kdf_salt_reset = None
self.__kdf_salt_admin = None
self.is_gnuk = (reader.get_string(2) == "Gnuk Token")
def configure_with_kdf(self):
kdf_data = self.cmd_get_data(0x00, 0xf9)
@@ -338,16 +339,20 @@ class OpenPGP_Card(object):
data = b'\xb8\x00'
else:
data = b'\xa4\x00'
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x47, 0x80, 0, data, le=512)
else:
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
if len(sw) < 2:
raise ValueError(sw)
if sw[0] == 0x90 and sw[1] == 0x00:
return b""
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
if sw[-2] == 0x61:
pk = self.cmd_get_response(sw[1])
return (pk[9:9+256], pk[9+256+2:9+256+2+3])
elif sw[-2] == 0x90 and sw[-1] == 0x00:
pk = sw
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return (pk[9:9+256], pk[9+256+2:-2])
def cmd_get_public_key(self, keyno):
if keyno == 1:
@@ -358,7 +363,6 @@ class OpenPGP_Card(object):
data = b'\xa4\x00'
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x47, 0x81, 0, data, le=512)
r = self.__reader.send_cmd(cmd_data)
else:
cmd_data = iso7816_compose(0x47, 0x81, 0, data)
r = self.__reader.send_cmd(cmd_data)

View File

@@ -0,0 +1,6 @@
import pytest
@pytest.fixture(scope="module",autouse=True)
def check_gnuk(card):
if not card.is_gnuk:
pytest.skip("Gnuk only feature", allow_module_level=True)

View File

@@ -50,12 +50,16 @@ def test_sex(card):
def test_name_lang_sex(card):
name = b""
lang = b""
lang_de = b"de"
sex = b"9"
expected = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
+ b'\x5f\x35' + pack('B', len(sex)) + sex
expected_de = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang_de)) + lang_de \
+ b'\x5f\x35' + pack('B', len(sex)) + sex
name_lang_sex = get_data_object(card, 0x65)
assert name_lang_sex == b'' or name_lang_sex == expected
assert name_lang_sex == b'' or name_lang_sex == expected or name_lang_sex == expected_de
def test_app_data(card):
app_data = get_data_object(card, 0x6e)
@@ -140,7 +144,8 @@ def test_historical_bytes(card):
h = get_data_object(card, 0x5f52)
assert h == b'\x001\xc5s\xc0\x01@\x05\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x00\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00'
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00' or \
h == b'\x00\x31\xf5\x73\xc0\x01\x60\x05\x90\x00'
def test_extended_capabilities(card):
a = get_data_object(card, 0xc0)

View File

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

View File

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

View File

@@ -1,43 +1 @@
"""
test_remove_keys.py - test removing keys on card
Copyright (C) 2016, 2018 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
# Remove a key material on card by changing algorithm attributes of the key
from card_const import *
def test_rsa_keyattr_change_1(card):
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
assert r
def test_rsa_keyattr_change_2(card):
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
assert r
def test_rsa_keyattr_change_3(card):
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
if r:
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)
assert r
from card_test_remove_keys import *

View File

@@ -1,41 +1 @@
"""
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
from card_test_reset_pw3 import *

View File

@@ -1,7 +1,7 @@
"""
test_005_personalize_admin_less.py - test admin-less mode
Copyright (C) 2016, 2018 g10 Code GmbH
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -20,291 +20,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from struct import pack
from re import match, DOTALL
from util import *
import rsa_keys
from card_const import *
from constants_for_test import *
from skip_gnuk_only_tests 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
from card_test_personalize_admin_less import *
from card_test_personalize_reset import *
from card_test_remove_keys import *
from card_test_reset_pw3 import *

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
"""
test_005_keygen.py - test key generation
Copyright (C) 2018 g10 Code GmbH
Copyright (C) 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -20,64 +20,5 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
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
from card_test_keygen import *
from card_test_remove_keys import *

View File

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

View File

@@ -1,7 +1,7 @@
"""
test_007_kdf_full.py - test KDF data object
Copyright (C) 2018 g10 Code GmbH
Copyright (C) 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -20,15 +20,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from card_const import *
from constants_for_test import *
from skip_gnuk_only_tests 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
from card_test_kdf_full import *
from card_test_personalize_card import *
from card_test_personalize_reset import *
from card_test_remove_keys import *
from card_test_reset_pw3 import *

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
"""
test_012_kdf_single.py - test KDF data object
Copyright (C) 2018 g10 Code GmbH
Copyright (C) 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -20,15 +20,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from card_const import *
from constants_for_test import *
from skip_gnuk_only_tests 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
from card_test_kdf_single import *
from card_test_personalize_card import *
from card_test_personalize_reset import *
from card_test_remove_keys import *
from card_test_reset_pw3 import *

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,6 +20,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from skip_gnuk_only_tests import *
from card_const import *
from constants_for_test import *

View File

@@ -109,15 +109,15 @@ def build_rsakey_from_ssh_key_under_gpg_agent(g, timestamp=None):
# The information is in SEXP format, extract N and E
s = sexp(pubkey_info_str)
if s[0] != 'public-key':
print s
print(s)
exit(1)
rsa = s[1]
if rsa[0] != 'rsa':
print rsa
print(rsa)
exit(1)
n_x = rsa[1]
if n_x[0] != 'n':
print n_x
print(n_x)
exit(1)
n_byte_str = n_x[1]
while n_byte_str[0] == '\x00':
@@ -125,7 +125,7 @@ def build_rsakey_from_ssh_key_under_gpg_agent(g, timestamp=None):
n = n_byte_str
e_x = rsa[2]
if e_x[0] != 'e':
print e_x
print(e_x)
exit(1)
e = e_x[1]
if not timestamp:

View File

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

View File

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

View File

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

View File

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

21
tool/gnuk_get_random.py Executable file
View File

@@ -0,0 +1,21 @@
#! /usr/bin/python3
from gnuk_token import get_gnuk_device, gnuk_token
from binascii import hexlify
import sys
if __name__ == '__main__':
count = 0
gnuk = get_gnuk_device()
gnuk.cmd_select_openpgp()
looping = (len(sys.argv) > 1)
while True:
try:
challenge = gnuk.cmd_get_challenge().tostring()
except Exception as e:
print(count)
raise e
print(hexlify(challenge))
count = count + 1
if not looping:
break

View File

@@ -30,6 +30,7 @@ from array import array
USB_PRODUCT_LIST=[
{ 'vendor' : 0x234b, 'product' : 0x0000 }, # FSIJ Gnuk Token
{ 'vendor' : 0x20a0, 'product' : 0x4211 }, # Nitrokey Start
{ 'vendor' : 0x1209, 'product' : 0x2440 }, # GnuPG e.V.
]
# USB class, subclass, protocol
@@ -74,6 +75,7 @@ class gnuk_token(object):
raise ValueError("Wrong interface sub class")
self.__devhandle = device.open()
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting

View File

@@ -36,7 +36,7 @@ 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")
libgcrypt = ffi.dlopen("libgcrypt.so.20")
if isinstance(pw_string, str):
pw_byte = pw_string.encode('UTF-8')
else:

View File

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

View File

@@ -82,7 +82,7 @@ class Card(object):
elif code == FEATURE_MODIFY_PIN_DIRECT:
self.modify_ioctl = ioctl
if self.verify_ioctl == -1:
raise ValueError, "Not supported"
raise ValueError("Not supported")
def cmd_select_openpgp(self):
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
@@ -90,7 +90,7 @@ class Card(object):
if sw1 == 0x61: # More data
response, sw1, sw2 = self.connection.transmit([0x00, 0xc0, 0, 0, sw2])
elif not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("cmd_select_openpgp %02x %02x" % (sw1, sw2))
raise ValueError("cmd_select_openpgp %02x %02x" % (sw1, sw2))
def possibly_add_dummy_byte(self):
if self.another_byte:
@@ -135,11 +135,11 @@ class Card(object):
sw1 = data[0]
sw2 = data[1]
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("cmd_verify_pinpad %02x %02x" % (sw1, sw2))
raise ValueError("cmd_verify_pinpad %02x %02x" % (sw1, sw2))
def send_modify_pinpad(self, apdu, single_step, command):
if self.modify_ioctl == -1:
raise ValueError, "Not supported"
raise ValueError("Not supported")
pin_modify = [ 0x00, # bTimerOut
0x00, # bTimerOut2
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
@@ -171,7 +171,7 @@ class Card(object):
sw1 = data[0]
sw2 = data[1]
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("%s %02x %02x" % (command, sw1, sw2))
raise ValueError("%s %02x %02x" % (command, sw1, sw2))
def cmd_reset_retry_counter(self, who, data):
if who == BY_ADMIN:
@@ -180,7 +180,7 @@ class Card(object):
apdu = [0x00, 0x2c, 0x00, 0x81, len(data) ] + data # BY_USER with resetcode
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("cmd_reset_retry_counter %02x %02x" % (sw1, sw2))
raise ValueError("cmd_reset_retry_counter %02x %02x" % (sw1, sw2))
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
def cmd_reset_retry_counter_pinpad(self, who):
@@ -195,7 +195,7 @@ class Card(object):
apdu = [0x00, 0xda, 0x00, 0xd3, len(data) ] + data # BY_ADMIN
response, sw1, sw2 = self.connection.transmit(apdu)
if not (sw1 == 0x90 and sw2 == 0x00):
raise ValueError, ("cmd_put_resetcode %02x %02x" % (sw1, sw2))
raise ValueError("cmd_put_resetcode %02x %02x" % (sw1, sw2))
# Note: CCID specification doesn't permit this (only 0x20 and 0x24)
def cmd_put_resetcode_pinpad(self):
@@ -225,8 +225,8 @@ def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed):
card.connection.connect()
ident = card.connection.getReader()
print "Reader/Token:", ident
print "ATR:", toHexString( card.connection.getATR() )
print("Reader/Token:", ident)
print("ATR:", toHexString( card.connection.getATR() ))
if ident == COVADIS_VEGA_ALPHA:
card.cmd_vega_alpha_disable_empty_verify()
@@ -236,29 +236,29 @@ def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed):
card.cmd_select_openpgp()
if method == "verify":
if who == BY_USER:
print "Please input User's PIN"
print("Please input User's PIN")
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(who)
elif method == "change":
if change_by_two_steps:
if who == BY_USER:
print "Please input User's PIN"
print("Please input User's PIN")
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(who)
if who == BY_USER:
print "Please input New User's PIN twice"
print("Please input New User's PIN twice")
else:
print "Please input New Admin's PIN twice"
print("Please input New Admin's PIN twice")
card.cmd_change_reference_data_pinpad(who, True)
else:
if who == BY_USER:
print "Please input User's PIN"
print "and New User's PIN twice"
print("Please input User's PIN")
print("and New User's PIN twice")
else:
print "Please input Admin's PIN"
print "and New Admin's PIN twice"
print("Please input Admin's PIN")
print("and New Admin's PIN twice")
card.cmd_change_reference_data_pinpad(who, False)
elif method == "unblock":
if change_by_two_steps:
@@ -268,66 +268,66 @@ def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed):
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
card.cmd_reset_retry_counter(who,resetcode+newpin)
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(BY_ADMIN)
newpin=s2l(getpass("Please input New User's PIN from keyboard: "))
card.cmd_reset_retry_counter(who,newpin)
else:
if who == BY_USER:
print "Please input reset code"
print "and New User's PIN twice"
print("Please input reset code")
print("and New User's PIN twice")
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(BY_ADMIN)
print "Please input New User's PIN twice"
print("Please input New User's PIN twice")
card.cmd_reset_retry_counter_pinpad(who)
elif method == "put":
if change_by_two_steps:
# It means using keyboard for new PIN
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(BY_ADMIN)
resetcode=s2l(getpass("Please input New Reset Code from keyboard: "))
card.cmd_put_resetcode(resetcode)
else:
print "Please input Admin's PIN"
print("Please input Admin's PIN")
card.cmd_verify_pinpad(BY_ADMIN)
print "Please input New Reset Code twice"
print("Please input New Reset Code twice")
card.cmd_put_resetcode_pinpad()
else:
raise ValueError, method
raise ValueError(method)
card.connection.disconnect()
print "OK."
print("OK.")
return 0
def print_usage():
print "pinpad-test: testing pinentry of PC/SC card reader"
print " help:"
print "\t--help:\t\tthis message"
print " method:\t\t\t\t\t\t\t[verify]"
print "\t--verify:\tverify PIN"
print "\t--change:\tchange PIN (old PIN, new PIN twice)"
print "\t--change2:\tchange PIN by two steps (old PIN, new PIN twice)"
print "\t--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)"
print "\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)"
print "\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)"
print "\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)"
print " options:"
print "\t--fixed N:\tUse fixed length input"
print "\t--admin:\tby administrator\t\t\t[False]"
print "\t--add:\t\tadd a dummy byte at the end of APDU\t[False]"
print "\t--pinmin:\tspecify minimum length of PIN\t\t[6]"
print "\t--pinmax:\tspecify maximum length of PIN\t\t[15]"
print "EXAMPLES:"
print " $ pinpad-test # verify user's PIN "
print " $ pinpad-test --admin # verify admin's PIN "
print " $ pinpad-test --change # change user's PIN "
print " $ pinpad-test --change --admin # change admin's PIN "
print " $ pinpad-test --change2 # change user's PIN by two steps"
print " $ pinpad-test --change2 --admin # change admin's PIN by two steps"
print " $ pinpad-test --unblock # change user's PIN by reset code"
print " $ pinpad-test --unblock --admin # change user's PIN by admin's PIN"
print " $ pinpad-test --put # setup resetcode "
print("pinpad-test: testing pinentry of PC/SC card reader")
print(" help:")
print("\t--help:\t\tthis message")
print(" method:\t\t\t\t\t\t\t[verify]")
print("\t--verify:\tverify PIN")
print("\t--change:\tchange PIN (old PIN, new PIN twice)")
print("\t--change2:\tchange PIN by two steps (old PIN, new PIN twice)")
print("\t--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)")
print("\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)")
print("\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)")
print("\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)")
print(" options:")
print("\t--fixed N:\tUse fixed length input")
print("\t--admin:\tby administrator\t\t\t[False]")
print("\t--add:\t\tadd a dummy byte at the end of APDU\t[False]")
print("\t--pinmin:\tspecify minimum length of PIN\t\t[6]")
print("\t--pinmax:\tspecify maximum length of PIN\t\t[15]")
print("EXAMPLES:")
print(" $ pinpad-test # verify user's PIN ")
print(" $ pinpad-test --admin # verify admin's PIN ")
print(" $ pinpad-test --change # change user's PIN ")
print(" $ pinpad-test --change --admin # change admin's PIN ")
print(" $ pinpad-test --change2 # change user's PIN by two steps")
print(" $ pinpad-test --change2 --admin # change admin's PIN by two steps")
print(" $ pinpad-test --unblock # change user's PIN by reset code")
print(" $ pinpad-test --unblock --admin # change user's PIN by admin's PIN")
print(" $ pinpad-test --put # setup resetcode ")
if __name__ == '__main__':
who = BY_USER
@@ -374,7 +374,7 @@ if __name__ == '__main__':
print_usage()
exit(0)
else:
raise ValueError, option
raise ValueError(option)
main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed)
# Failure

View File

@@ -51,7 +51,10 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
gnuk = get_gnuk_device()
gnuk.cmd_select_openpgp()
# 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:
@@ -89,7 +92,7 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
reg = None
print("Waiting for device to appear:")
while reg == None:
print(" Wait %d seconds..." % wait_e)
print(" Wait {} second{}...".format(wait_e, 's' if wait_e > 1 else ''))
time.sleep(wait_e)
for dev in gnuk_devices_by_vidpid():
try: