Compare commits
76 Commits
release/1.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24adc09406 | ||
|
|
bf9fc628b3 | ||
|
|
d76534dd3a | ||
|
|
d9c5dcf206 | ||
|
|
26448d58ee | ||
|
|
9cfeb817bd | ||
|
|
b6534dceba | ||
|
|
b47bd693ba | ||
|
|
1a7d3a698f | ||
|
|
f7b03f7fb5 | ||
|
|
44971541fe | ||
|
|
53ed5e0a42 | ||
|
|
63eccda0a1 | ||
|
|
f430c90715 | ||
|
|
1f18ec1d63 | ||
|
|
ec7423f493 | ||
|
|
e50dda28d1 | ||
|
|
8ad176921f | ||
|
|
d71b116be8 | ||
|
|
d9d3f35ac3 | ||
|
|
7cc8d8930e | ||
|
|
6446a5bd89 | ||
|
|
8b0cb8be65 | ||
|
|
c73bb0548e | ||
|
|
40b1d453dc | ||
|
|
3b965fafc0 | ||
|
|
35edbdc731 | ||
|
|
d4c776e308 | ||
|
|
6c0c510347 | ||
|
|
704d8a5cf1 | ||
|
|
55781cb7bb | ||
|
|
de24655920 | ||
|
|
7bfe0f5427 | ||
|
|
ec058537ed | ||
|
|
abeb1015ec | ||
|
|
c5f20dc355 | ||
|
|
4ff0b3c5f8 | ||
|
|
4e517778d0 | ||
|
|
c81544fffd | ||
|
|
ad42010272 | ||
|
|
8ce91267be | ||
|
|
b5c2ace2ae | ||
|
|
4cbc661fb7 | ||
|
|
543f28574e | ||
|
|
fe94e1885b | ||
|
|
ce82b347f9 | ||
|
|
d54712c04c | ||
|
|
9c63c874d0 | ||
|
|
bb9b31166f | ||
|
|
e417846408 | ||
|
|
21a481060c | ||
|
|
d4c9d6653b | ||
|
|
f00306627b | ||
|
|
f4b36b7503 | ||
|
|
e85527d302 | ||
|
|
bd58997dc9 | ||
|
|
9d5834d47b | ||
|
|
36ecf67694 | ||
|
|
c9b1e511ba | ||
|
|
01b5aa5984 | ||
|
|
b735c02ec2 | ||
|
|
2ecb104ae4 | ||
|
|
6b4f3c9934 | ||
|
|
660aaeb04b | ||
|
|
1022534c02 | ||
|
|
46cc64cf03 | ||
|
|
effc65381a | ||
|
|
6cbf5a4822 | ||
|
|
8ff3865890 | ||
|
|
43009f39e8 | ||
|
|
56fb5002bf | ||
|
|
3bb5097031 | ||
|
|
8319f4a14b | ||
|
|
f7cf0a3461 | ||
|
|
5ac52d3f2f | ||
|
|
209d459d09 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
*.lst
|
||||
*.o
|
||||
*.pyc
|
||||
regnual/regnual-no-vidpid.elf
|
||||
src/.dep
|
||||
src/config.mk
|
||||
src/config.h
|
||||
@@ -8,6 +9,7 @@ src/gnuk.ld
|
||||
src/board.h
|
||||
src/build/*
|
||||
src/*.inc
|
||||
src/put-vid-pid-ver.sh
|
||||
regnual/regnual.bin
|
||||
regnual/regnual.hex
|
||||
regnual/regnual.elf
|
||||
|
||||
7
AUTHORS
7
AUTHORS
@@ -1,3 +1,10 @@
|
||||
Aurelien Jarno:
|
||||
Modified:
|
||||
src/Makefile
|
||||
src/configure
|
||||
src/main.c
|
||||
src/stack-def.h
|
||||
|
||||
Anthony Romano:
|
||||
Modified:
|
||||
src/call-rsa.c
|
||||
|
||||
261
ChangeLog
261
ChangeLog
@@ -1,3 +1,264 @@
|
||||
2018-04-05 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.2.9.
|
||||
|
||||
* tests: Add test cases for admin-less mode.
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Care admin-less mode.
|
||||
|
||||
2018-04-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tests: Add more tests, key generation and KDF support.
|
||||
|
||||
* src/openpgp.c (cmd_reset_user_password): Check length of
|
||||
new passphrase.
|
||||
|
||||
* src/openpgp-do.c (proc_resetting_code): Support removal.
|
||||
(gpg_do_kdf_check): Fix for the case of resetting PW3.
|
||||
|
||||
* tests/test_004_reset_pw3.py: New.
|
||||
|
||||
2018-04-03 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (rw_kdf): Clear all auth state.
|
||||
|
||||
* tool/upgrade_by_passwd.py (main): Fix for byte compare.
|
||||
* tool/gnuk_remove_keys_libusb.py (main): Likewise.
|
||||
|
||||
2018-04-02 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_token.py (parse_kdf_data): New.
|
||||
* tool/kdf_calc.py: New.
|
||||
|
||||
* tool/gnuk_remove_keys_libusb.py (main): Support KDF auth.
|
||||
* tool/upgrade_by_passwd.py (main): Likewise.
|
||||
|
||||
2018-03-30 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (rw_kdf): Support single-salt KDF.
|
||||
(gpg_do_get_initial_pw_setting): Likewise.
|
||||
(gpg_do_kdf_check): Likewise.
|
||||
|
||||
2018-03-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (rw_kdf): Do format validation earlier.
|
||||
|
||||
2018-03-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/flash.c [FLASH_UPGRADE_SUPPORT] (flash_terminate): Erase
|
||||
the page for upgrade public keys.
|
||||
|
||||
2018-02-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (rw_kdf): Return 0 when NULL.
|
||||
|
||||
2018-01-23 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.2.8.
|
||||
|
||||
* src/Makefile (build/gnuk-vidpid.elf): Supply FILE here.
|
||||
* src/configure (output_vendor_product_serial_strings): For
|
||||
generating put-vid-pid-ver.sh, don't set FILE.
|
||||
|
||||
* regnual/regnual.c (regnual_device_desc): Make this array as a
|
||||
template.
|
||||
* regnual/Makefile (regnual.elf): Substitute VID:PID.
|
||||
|
||||
2018-01-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (USER_PASSWD_MINLEN): New.
|
||||
(cmd_change_password): Check passphrase length.
|
||||
|
||||
2018-01-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Remove access to private
|
||||
key with BY_ADMIN when it's becoming admin-less mode.
|
||||
|
||||
2018-01-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/binary-edit.sh: Copied from NeuG 1.0.8. Exclude FILE.
|
||||
* src/configure (output_vid_pid_version): Generate a shell script.
|
||||
* src/Makefile (build/gnuk-vidpid.elf): New target.
|
||||
* src/usb_desc.c (device_desc): Make this array as a template.
|
||||
|
||||
* chopstx: Update to 1.8.
|
||||
|
||||
2018-01-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/neug.c: Update from NeuG.
|
||||
|
||||
2018-01-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tests/card_reader.py (CardReader.ccid_power_on): Fix for
|
||||
other card readers for Gemalto's.
|
||||
|
||||
2017-12-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx: Update to 1.7.
|
||||
|
||||
2017-11-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Bug fix for admin-less
|
||||
mode.
|
||||
|
||||
2017-11-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.2.7.
|
||||
|
||||
2017-11-24 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* regnual/regnual.c (calc_crc32): Enable CRC module fix.
|
||||
|
||||
* chopstx: Update to 1.6.
|
||||
|
||||
2017-11-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/stack-def.h (SIZE_0): Decrease.
|
||||
|
||||
* src/main.c (emit_led, display_status_code, main): Use
|
||||
chopstx_poll instead of eventflag_wait_timeout.
|
||||
|
||||
2017-11-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/stack-def.h (SIZE_0): Increase.
|
||||
|
||||
* src/main.c (emit_led, display_status_code, main): Use
|
||||
eventflag_wait_timeout instead of chopstx_usec_wait.
|
||||
|
||||
2017-11-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* regnual/regnual.c (calc_crc32): Enable CRC module.
|
||||
|
||||
* src/neug.c (crc32_rv_stop): New.
|
||||
(neug_fini): Call crc32_rv_stop.
|
||||
|
||||
* src/main.c (main): Call chopstx_conf_idle.
|
||||
|
||||
* src/usb-ccid.c (usb_event_handle): Use 2 for call of
|
||||
chopstx_conf_idle on suspend. Call random_fini on suspend
|
||||
to stop ADC module. Call random_init on wakeup.
|
||||
Sleep a bit to switch main thread.
|
||||
|
||||
2017-11-16 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/gnuk.h (LED_OFF): New.
|
||||
|
||||
* src/usb-ccid.c (usb_event_handle): LED off on sleep.
|
||||
(ccid_thread): Use constant pointer for chopstx_poll.
|
||||
(poll_event_intr): Remove.
|
||||
|
||||
2017-11-15 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb-ccid.c (usb_event_handle): Allow sleep on suspend.
|
||||
|
||||
* src/usb_ctrl.c (usb_device_reset): Fix device state.
|
||||
|
||||
2017-11-14 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb-ccid.c (ccid_usb_reset): Remove
|
||||
(usb_event_handle): Return value change to notify
|
||||
caller about needs for going out of the loop.
|
||||
Support USB suspend/resume.
|
||||
(ccid_thread): Supporting USB suspend, sleep forever with
|
||||
timeout_p = NULL.
|
||||
|
||||
* src/main.c (main): Add USB_DEVICE_STATE_ prefix.
|
||||
* src/usb_ctrl.c: Likewise.
|
||||
(usb_device_reset): Don't call ccid_usb_reset.
|
||||
(usb_set_configuration, usb_set_interface): Likewise.
|
||||
|
||||
* src/usb_desc.c (device_desc): bcdUSB = 2.0, supporting
|
||||
suspend/resume.
|
||||
|
||||
2017-11-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb_ctrl.c: Use new const USB_DEVICE_STATE_*
|
||||
* src/main.c (main): Likewise.
|
||||
* src/usb-ccid.c: Likewise.
|
||||
(INTR_REQ_USB): Remove. Use the definition
|
||||
in usb-lld.h.
|
||||
|
||||
2017-11-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (gpg_do_kdf_check): New.
|
||||
(proc_resetting_code): Use gpg_do_kdf_check.
|
||||
* src/openpgp.c (cmd_verify, cmd_change_password)
|
||||
(cmd_reset_user_password): Likewise.
|
||||
|
||||
2017-11-07 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (proc_resetting_code): Error when
|
||||
it's not pass-hash.
|
||||
|
||||
* src/openpgp.c (cmd_verify, cmd_change_password)
|
||||
(cmd_reset_user_password): Avoid authentication error
|
||||
by old GnuPG which doesn't support KDF.
|
||||
|
||||
2017-11-06 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tests/test_empty_card.py (test_extended_capabilities): Support
|
||||
KDF-DO.
|
||||
* test/features/802_get_data_static.feature: Likewise.
|
||||
* test/features/402_get_data_static.feature: Likewise.
|
||||
* test/features/002_get_data_static.feature: Likewise.
|
||||
|
||||
2017-11-02 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (rw_kdf): Only writable when no keys.
|
||||
(gpg_do_get_initial_pw_setting): New.
|
||||
(gpg_do_write_prvkey): Use gpg_do_get_initial_pw_setting.
|
||||
(gpg_do_keygen): Likewise.
|
||||
(extended_capabilities): Enable KDF-DO available bit.
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Use
|
||||
gpg_do_get_initial_pw_setting.
|
||||
* src/ac.c (verify_user_0, verify_admin_0): Likewise.
|
||||
|
||||
2017-11-01 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (GPG_DO_KDF): New.
|
||||
(GPG_DO_FEATURE_MNGMNT): New.
|
||||
(do_tag_to_nr): Support GPG_DO_KDF.
|
||||
(GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT): New.
|
||||
(rw_kdf): New.
|
||||
(gpg_do_table): Add an entry for GPG_DO_KDF.
|
||||
|
||||
* src/gnuk.h (NR_DO_KDF): New.
|
||||
|
||||
2017-10-31 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp-do.c (gpg_do_keygen): Bug fix for memory alignment.
|
||||
|
||||
2017-10-24 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tests/card_reader.py (CardReader.ccid_power_on): Setting
|
||||
PPS only for Gemalto GemPC reader.
|
||||
|
||||
2017-10-18 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
* src/gnuk.ld.in: Fix keystore_pool size.
|
||||
|
||||
2017-10-12 Aurelien Jarno <aurelien@aurel32.net>
|
||||
|
||||
* polarssl/include/polarssl/bn_mul.h (MULADDC_HUIT_DEAD): Rename
|
||||
from MULADDC_HUIT.
|
||||
[__ARM_FEATURE_DSP] (MULADDC_1024_CORE, MULADDC_1024_LOOP)
|
||||
(MULADDC_INIT, MULADDC_CORE, MULADDC_HUIT, MULADDC_STOP): New.
|
||||
|
||||
* polarssl/library/bignum.c (mpi_montsqr): Check on
|
||||
POLARSSL_HAVE_ASM and __arm__.
|
||||
[__ARM_FEATURE_DSP] (mpi_montsqr): New.
|
||||
(MAX_WSIZE): New.
|
||||
(mpi_exp_mod): Use MAX_WSIZE.
|
||||
|
||||
* src/Makefile (DEFS): Remove BIGNUM_C_IMPLEMENTATION.
|
||||
|
||||
* src/main.c (HEAP_SIZE): Rename from MEMORY_SIZE.
|
||||
(HEAP_END, HEAP_ALIGNMENT, HEAP_ALIGN): Likewise.
|
||||
|
||||
* src/stack-def.h (SIZE_3): Depend on MEMORY_SIZE.
|
||||
* src/configure: Emit DEFS with MEMORY_SIZE.
|
||||
|
||||
2017-10-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.2.6.
|
||||
|
||||
69
NEWS
69
NEWS
@@ -1,5 +1,74 @@
|
||||
Gnuk NEWS - User visible changes
|
||||
|
||||
* Major changes in Gnuk 1.2.9
|
||||
|
||||
Released 2018-04-05, by NIIBE Yutaka
|
||||
|
||||
** A test suite fix: Clear PW3
|
||||
Until 1.2.8, after running the test suite under "tests", PW3 keystring
|
||||
remained, which affects use of admin-less mode. New test case is
|
||||
added to clear PW3.
|
||||
|
||||
** tool/upgrade_by_passwd.py supports KDF-DO auth
|
||||
With KDF-DO, firmware upgrade didn't work. Now, it's supported.
|
||||
|
||||
** Add "single-salt" support for KDF-DO
|
||||
With KDF-DO, "admin-less" mode didn't work well. With new feature of
|
||||
"single-salt" support, we can use "admin-less" mode with KDF-DO.
|
||||
|
||||
** factory-reset deletes all upgrade public keys
|
||||
By card-edit/factory-reset by GnuPG, it deletes all upgrade public
|
||||
keys, now.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.8
|
||||
|
||||
Released 2018-01-23, by NIIBE Yutaka
|
||||
|
||||
** No inclusion of VID:PID in gnuk.elf
|
||||
|
||||
Distribution of binary image with VID:PID would violate vendor ID
|
||||
agreement to USB Forum. Now, we have new file named gnuk-vidpid.elf
|
||||
for flashing. The file gnuk.elf can be used to generate
|
||||
gnuk-vidpid.elf and we can check if it is reproducible or not.
|
||||
|
||||
** Passphrase length check
|
||||
|
||||
Now, Gnuk checks length of passphrase if it's too short when
|
||||
changing passphrase.
|
||||
|
||||
** Remove unused DEK with BY_ADMIN
|
||||
|
||||
For admin-less mode, DEK by OPENPGP_CARD_INITIAL_PW3 remained on flash
|
||||
ROM. This could be considered a backdoor, if some other person had or
|
||||
kept access to the flash ROM, cheating a user. Now, the DEK is
|
||||
cleared by zero when the token is set to admin-less mode.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.8.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.7
|
||||
|
||||
Released 2017-11-26, by NIIBE Yutaka
|
||||
|
||||
** reGNUal
|
||||
reGNUal enables CRC module by itself.
|
||||
|
||||
** Flash update change
|
||||
CRC module is disabled when Gnuk stops. It's reGNUal which needs to
|
||||
enable CRC module.
|
||||
|
||||
** Support of USB suspend
|
||||
USB suspend and wakeup event are now handled.
|
||||
|
||||
** KDF-DO support and KDF by host
|
||||
KDF-DO is now available. Host can use this feature.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.6.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.6
|
||||
|
||||
Released 2017-10-11, by NIIBE Yutaka
|
||||
|
||||
53
README
53
README
@@ -1,14 +1,14 @@
|
||||
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
|
||||
|
||||
Version 1.2.6
|
||||
2017-10-11
|
||||
Version 1.2.9
|
||||
2018-04-05
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
This is the release of Gnuk, version 1.2.6, which has major
|
||||
This is the release of Gnuk, version 1.2.9, 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
|
||||
@@ -24,11 +24,10 @@ It also supports RSA-4096, but users should know that it takes more
|
||||
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
|
||||
because the device doesn't have enough memory.
|
||||
|
||||
With this release, you can test how Gnuk Token works on GNU/Linux,
|
||||
without real hardware, by USBIP emulation (--target=GNU_LINUX).
|
||||
Please note that this emulation is intended only for testing. When
|
||||
Gnuk does crypto computation on host, it is vulnerable by side channel
|
||||
attacks.
|
||||
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.
|
||||
|
||||
|
||||
What's Gnuk?
|
||||
@@ -223,8 +222,8 @@ Some tools are written in Python. If your Python is not installed as
|
||||
Python 2.7 and PyUSB 0.4.3 is assumed.
|
||||
|
||||
|
||||
Souce code
|
||||
==========
|
||||
Source code
|
||||
===========
|
||||
|
||||
Gnuk source code is under src/ directory.
|
||||
|
||||
@@ -257,7 +256,7 @@ External source code
|
||||
|
||||
Gnuk is distributed with external source code.
|
||||
|
||||
* chopstx/ -- Chopstx 1.5
|
||||
* chopstx/ -- Chopstx 1.8
|
||||
|
||||
We use Chopstx as the kernel for Gnuk.
|
||||
|
||||
@@ -306,6 +305,15 @@ Gnuk is distributed with external source code.
|
||||
POLARSSL_SELF_TEST, and POLARSSL_PADLOCK_C, and only define
|
||||
POLARSSL_GENPRIME when defined KEYGEN_SUPPORT.
|
||||
|
||||
And polarssl/library/bignum.c is modified to work on 64-bit machine.
|
||||
|
||||
Aurelien Jarno also modified:
|
||||
|
||||
polarssl/include/polarssl/bn_mul.h
|
||||
polarssl/library/bignum.c
|
||||
|
||||
See ChangeLog (and/or history of git) for detail.
|
||||
|
||||
|
||||
USB vendor ID and product ID (USB device ID)
|
||||
============================================
|
||||
@@ -371,9 +379,9 @@ 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:5.4.1+svn241155-1
|
||||
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-2
|
||||
libnewlib-arm-none-eabi 2.4.0.20160527-3
|
||||
|
||||
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
|
||||
GNU Toolchain for 'arm-none-eabi' target.
|
||||
@@ -397,6 +405,10 @@ 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
|
||||
|
||||
|
||||
How to install
|
||||
==============
|
||||
@@ -405,11 +417,11 @@ Olimex STM32-H103 board
|
||||
-----------------------
|
||||
|
||||
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD
|
||||
and write "gnuk.elf" to Flash ROM:
|
||||
and write "gnuk-vidpid.elf" to Flash ROM:
|
||||
|
||||
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \
|
||||
-f board/olimex_stm32_h103.cfg \
|
||||
-c "program build/gnuk.elf verify reset exit"
|
||||
-c "program build/gnuk-vidpid.elf verify reset exit"
|
||||
|
||||
Command invocation is assumed in src/ directory.
|
||||
|
||||
@@ -422,7 +434,7 @@ If you are using Flying Stone Tiny 01, you need a SWD writer.
|
||||
OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
|
||||
|
||||
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
|
||||
-c "program build/gnuk.elf verify reset exit"
|
||||
-c "program build/gnuk-vidpid.elf verify reset exit"
|
||||
|
||||
|
||||
|
||||
@@ -433,7 +445,7 @@ Reset the board with "USER" switch pushed. Type following to write
|
||||
to flash:
|
||||
|
||||
# cd ../tool
|
||||
# ./dfuse.py ../src/build/gnuk.hex
|
||||
# ./dfuse.py ../src/build/gnuk-vidpid.hex
|
||||
|
||||
Then, reset the board.
|
||||
|
||||
@@ -585,11 +597,11 @@ See doc/note/firmware-update.
|
||||
Git Repositories
|
||||
================
|
||||
|
||||
Please use: https://anonscm.debian.org/cgit/gnuk/gnuk/
|
||||
Please use: https://salsa.debian.org/gnuk-team/gnuk/
|
||||
|
||||
You can get it by:
|
||||
|
||||
$ git clone git://anonscm.debian.org/gnuk/gnuk/gnuk.git
|
||||
$ git clone https://salsa.debian.org/gnuk-team/gnuk/gnuk.git
|
||||
|
||||
It's also available at: www.gniibe.org
|
||||
You can browse at: https://git.gniibe.org/gitweb?p=gnuk/gnuk.git;a=summary
|
||||
@@ -610,9 +622,8 @@ Please see the FST-01 support pages:
|
||||
|
||||
Please consider to join Gnuk-users mailing list:
|
||||
|
||||
https://lists.alioth.debian.org/mailman/listinfo/gnuk-users
|
||||
https://lists.gnupg.org/mailman/listinfo/gnuk-users
|
||||
|
||||
The mailing list will be moved to lists.debian.org.
|
||||
|
||||
|
||||
Your Contributions
|
||||
|
||||
1
THANKS
1
THANKS
@@ -7,6 +7,7 @@ Gnuk was originally written by NIIBE Yutaka. People contributed by
|
||||
encouraging the development, testing the implementation, suggesting
|
||||
improvements, or fixing bugs. Here is a list of those people.
|
||||
|
||||
Aurelien Jarno aurelien@aurel32.net
|
||||
Achim Pietig achim@pietig.com
|
||||
Aidan Thornton
|
||||
Anibal Monsalve Salazar anibal@debian.org
|
||||
|
||||
2
chopstx
2
chopstx
Submodule chopstx updated: 96d2a81331...aa63ac79bc
@@ -40,11 +40,11 @@ We are using "-O3 -Os" for compiler option.
|
||||
Building Gnuk
|
||||
-------------
|
||||
|
||||
Change directory to ``src``:
|
||||
Change directory to ``src``: ::
|
||||
|
||||
$ cd gnuk-VERSION/src
|
||||
|
||||
Then, run ``configure``:
|
||||
Then, run ``configure``: ::
|
||||
|
||||
$ ./configure --vidpid=<VID:PID>
|
||||
|
||||
@@ -52,8 +52,12 @@ Here, you need to specify USB vendor ID and product ID. For FSIJ's,
|
||||
it's: --vidpid=234b:0000 . Please read the section 'USB vendor ID and
|
||||
product ID' in README.
|
||||
|
||||
Type:
|
||||
Type: ::
|
||||
|
||||
$ make
|
||||
|
||||
Then, we will have "gnuk.elf" under src/build directory.
|
||||
|
||||
Next, we can get the final image by running following command. ::
|
||||
|
||||
$ make build/gnuk-vidpid.elf
|
||||
|
||||
@@ -65,7 +65,7 @@ Invoking firmware update
|
||||
|
||||
We specify reGNUal binary and Gnuk binary.
|
||||
|
||||
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk.bin
|
||||
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk-vidpid.bin
|
||||
|
||||
|
||||
Two or more tokens
|
||||
|
||||
@@ -73,16 +73,20 @@ and make: ::
|
||||
$ make
|
||||
|
||||
Please take care of configure options. The default target in 1.0.x
|
||||
series is Olimex STM32 H103 (not FST-01). The default target in 1.1.8
|
||||
series is Olimex STM32 H103 (not FST-01). The default target in 1.2.x
|
||||
is FST-01.
|
||||
|
||||
Then you get build/gnuk.elf.
|
||||
|
||||
Then you get build/gnuk.elf and build/gnuk.bin.
|
||||
Next, we can get the final image by running following command.
|
||||
|
||||
Invoking configure with FSIJ's USB ID (234b:0000) means that you are
|
||||
using FSIJ's USB ID (for reGNUal in this case). Please note that FSIJ
|
||||
only allows use of its USB ID for specific situations. Please read
|
||||
README of Gnuk about that.
|
||||
$ make build/gnuk-vidpid.elf
|
||||
|
||||
|
||||
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
|
||||
specific situations. Please read README of Gnuk about that.
|
||||
|
||||
|
||||
Bulding reGNUal
|
||||
@@ -117,13 +121,13 @@ your environment for Gnuk Token.
|
||||
How to run the script: ::
|
||||
|
||||
$ cd tool
|
||||
$ ./upgrade_by_passwd.py ../regnual/regnual.bin ../src/build/gnuk.bin
|
||||
$ ./upgrade_by_passwd.py ../regnual/regnual.bin ../src/build/gnuk-vidpid.bin
|
||||
|
||||
Then, the script on your host PC invoke the steps described above, and
|
||||
you will get new version of Gnuk installed.
|
||||
|
||||
You can also specify -p option to enter your password (other than
|
||||
factory setting).
|
||||
You can also specify -f option to skip entering your password (it
|
||||
assumes the factory setting).
|
||||
|
||||
If you already have configured another upgrade key installed, you can
|
||||
specify different slot by -k ``<slot_no>`` option. SLOT_NO can be 0
|
||||
|
||||
@@ -495,6 +495,67 @@
|
||||
#endif /* TriCore */
|
||||
|
||||
#if defined(__arm__)
|
||||
#if defined(__ARM_FEATURE_DSP)
|
||||
/* The ARM DSP instructions are available on Cortex M4, M7 and
|
||||
Cortex A CPUs */
|
||||
|
||||
#define MULADDC_1024_CORE \
|
||||
"ldmia %[s]!, { r7, r8, r9, r10 } \n\t" \
|
||||
"ldmia %[d], { r3, r4, r5, r6 } \n\t" \
|
||||
"umaal r3, %2, %[b], r7 \n\t" \
|
||||
"umaal r4, %2, %[b], r8 \n\t" \
|
||||
"umaal r5, %2, %[b], r9 \n\t" \
|
||||
"umaal r6, %2, %[b], r10 \n\t" \
|
||||
"stmia %[d]!, {r3, r4, r5, r6} \n\t"
|
||||
|
||||
#define MULADDC_1024_LOOP \
|
||||
asm( "tst %[i], #0xfe0 \n\t" \
|
||||
"beq 0f \n" \
|
||||
"1: sub %[i], %[i], #32 \n\t" \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
"tst %[i], #0xfe0 \n\t" \
|
||||
"bne 1b \n" \
|
||||
"0:" \
|
||||
: [s] "=r" (s), [d] "=r" (d), [c] "=r" (c), [i] "=r" (i) \
|
||||
: [b] "r" (b), "[s]" (s), "[d]" (d), "[c]" (c), "[i]" (i) \
|
||||
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "memory", "cc" );
|
||||
|
||||
#define MULADDC_INIT \
|
||||
asm(
|
||||
|
||||
#define MULADDC_CORE \
|
||||
"ldr r0, [%0], #4 \n\t" \
|
||||
"ldr r1, [%1] \n\t" \
|
||||
"umaal r1, %2, %3, r0 \n\t" \
|
||||
"str r1, [%1], #4 \n\t"
|
||||
|
||||
#define MULADDC_HUIT \
|
||||
"ldmia %0!, {r0, r1, r2, r3} \n\t" \
|
||||
"ldmia %1, {r4, r5, r6, r7} \n\t" \
|
||||
"umaal r4, %2, %3, r0 \n\t" \
|
||||
"umaal r5, %2, %3, r1 \n\t" \
|
||||
"umaal r6, %2, %3, r2 \n\t" \
|
||||
"umaal r7, %2, %3, r3 \n\t" \
|
||||
"stmia %1!, {r4, r5, r6, r7} \n\t" \
|
||||
"ldmia %0!, {r0, r1, r2, r3} \n\t" \
|
||||
"ldmia %1, {r4, r5, r6, r7} \n\t" \
|
||||
"umaal r4, %2, %3, r0 \n\t" \
|
||||
"umaal r5, %2, %3, r1 \n\t" \
|
||||
"umaal r6, %2, %3, r2 \n\t" \
|
||||
"umaal r7, %2, %3, r3 \n\t" \
|
||||
"stmia %1!, {r4, r5, r6, r7} \n\t"
|
||||
|
||||
#define MULADDC_STOP \
|
||||
: "=r" (s), "=r" (d), "=r" (c) \
|
||||
: "r" (b), "0" (s), "1" (d), "2" (c) \
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5", \
|
||||
"r6", "r7", "memory");
|
||||
|
||||
#else /* __ARM_FEATURE_DSP */
|
||||
|
||||
#define MULADDC_1024_CORE \
|
||||
"ldmia %[s]!, { r8, r9, r10 } \n\t" \
|
||||
"ldmia %[d], { r5, r6, r7 } \n\t" \
|
||||
@@ -556,7 +617,7 @@
|
||||
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "memory", "cc" );
|
||||
|
||||
/* Just for reference (dead code) */
|
||||
#define MULADDC_HUIT \
|
||||
#define MULADDC_HUIT_DEAD \
|
||||
"ldmia %0!, { r4, r5 } \n\t" \
|
||||
"ldmia %1, { r8, r9 } \n\t" \
|
||||
"umull r6, r7, %3, r4 \n\t" \
|
||||
@@ -620,6 +681,7 @@
|
||||
: "r" (b), "0" (s), "1" (d), "2" (c) \
|
||||
: "r4", "r5", "r6", "r7", "memory", "cc" );
|
||||
|
||||
#endif /* __ARM_FEATURE_DSP */
|
||||
#endif /* ARMv3 */
|
||||
|
||||
#if defined(__alpha__)
|
||||
@@ -811,8 +873,8 @@
|
||||
#else
|
||||
#define MULADDC_INIT \
|
||||
{ \
|
||||
t_int s0, s1, b0, b1; \
|
||||
t_int r0, r1, rx, ry; \
|
||||
t_uint s0, s1, b0, b1; \
|
||||
t_uint r0, r1, rx, ry; \
|
||||
b0 = ( b << biH ) >> biH; \
|
||||
b1 = ( b >> biH );
|
||||
|
||||
|
||||
@@ -1524,12 +1524,7 @@ static void mpi_montred( size_t n, const t_uint *np, t_uint mm, t_uint *d )
|
||||
*/
|
||||
static void mpi_montsqr( size_t n, const t_uint *np, t_uint mm, t_uint *d )
|
||||
{
|
||||
#ifdef BIGNUM_C_IMPLEMENTATION
|
||||
t_uint a_input[n];
|
||||
|
||||
memcpy (a_input, &d[n], sizeof (a_input));
|
||||
mpi_montmul (n, np, mm, d, a_input);
|
||||
#else
|
||||
#if defined(POLARSSL_HAVE_ASM) && defined(__arm__)
|
||||
size_t i;
|
||||
register t_uint c = 0;
|
||||
|
||||
@@ -1542,6 +1537,51 @@ static void mpi_montsqr( size_t n, const t_uint *np, t_uint mm, t_uint *d )
|
||||
x_i = *xj;
|
||||
*xj++ = c;
|
||||
|
||||
#if defined(__ARM_FEATURE_DSP)
|
||||
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */
|
||||
"mov %[c], #0\n\t"
|
||||
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */
|
||||
"mov r4, %[c]\n\t"
|
||||
"umlal r5, r4, %[x_i], %[x_i]\n\t"
|
||||
"str r5, [%[wij]], #4\n\t"
|
||||
"cmp %[xj], %[x_max1]\n\t"
|
||||
"bhi 0f\n\t"
|
||||
"mov r9, %[c]\n\t" /* R9 := 0, the constant ZERO from here. */
|
||||
"beq 1f\n"
|
||||
"2:\n\t"
|
||||
"ldmia %[xj]!, { r7, r8 }\n\t"
|
||||
"ldmia %[wij], { r5, r6 }\n\t"
|
||||
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
|
||||
"umaal r5, r4, %[x_i], r7\n\t"
|
||||
"umlal r5, %[c], %[x_i], r7\n\t"
|
||||
"umaal r4, %[c], r9, r9\n\t"
|
||||
/* (C,R4,R6) := (C,R4) + w_i_j + 2*x_i*x_j; */
|
||||
"umaal r6, r4, %[x_i], r8\n\t"
|
||||
"umlal r6, %[c], %[x_i], r8\n\t"
|
||||
"umaal r4, %[c], r9, r9\n\t"
|
||||
/**/
|
||||
"stmia %[wij]!, { r5, r6 }\n\t"
|
||||
"cmp %[xj], %[x_max1]\n\t"
|
||||
"bcc 2b\n\t"
|
||||
"bne 0f\n"
|
||||
"1:\n\t"
|
||||
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
|
||||
"ldr r5, [%[wij]]\n\t"
|
||||
"ldr r6, [%[xj]], #4\n\t"
|
||||
"umaal r5, r4, %[x_i], r6\n\t"
|
||||
"umlal r5, %[c], %[x_i], r6\n\t"
|
||||
"umaal r4, %[c], r9, r9\n\t"
|
||||
"str r5, [%[wij]], #4\n"
|
||||
"0:\n\t"
|
||||
"ldr r5, [%[wij]]\n\t"
|
||||
"adds r4, r4, r5\n\t"
|
||||
"adc %[c], %[c], #0\n\t"
|
||||
"str r4, [%[wij]]"
|
||||
: [c] "=&r" (c), [wij] "=r" (wij), [xj] "=r" (xj)
|
||||
: [x_i] "r" (x_i), [x_max1] "r" (&d[n*2-1]),
|
||||
"[wij]" (wij), "[xj]" (xj)
|
||||
: "r4", "r5", "r6", "r7", "r8", "r9", "memory", "cc");
|
||||
#else
|
||||
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */
|
||||
"mov %[c], #0\n\t"
|
||||
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */
|
||||
@@ -1603,6 +1643,7 @@ static void mpi_montsqr( size_t n, const t_uint *np, t_uint mm, t_uint *d )
|
||||
: [x_i] "r" (x_i), [x_max1] "r" (&d[n*2-1]),
|
||||
"[wij]" (wij), "[xj]" (xj)
|
||||
: "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc");
|
||||
#endif
|
||||
|
||||
c += mpi_mul_hlp( n, np, &d[i], d[i] * mm );
|
||||
}
|
||||
@@ -1614,17 +1655,29 @@ static void mpi_montsqr( size_t n, const t_uint *np, t_uint mm, t_uint *d )
|
||||
mpi_sub_hlp( n, np, d );
|
||||
else
|
||||
mpi_sub_hlp( n, d - n, d - n);
|
||||
#else
|
||||
t_uint a_input[n];
|
||||
|
||||
memcpy (a_input, &d[n], sizeof (a_input));
|
||||
mpi_montmul (n, np, mm, d, a_input);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
|
||||
*/
|
||||
#if MEMORY_SIZE >= 32
|
||||
#define MAX_WSIZE 6
|
||||
#elif MEMORY_SIZE >= 24
|
||||
#define MAX_WSIZE 5
|
||||
#else
|
||||
#define MAX_WSIZE 4
|
||||
#endif
|
||||
int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
|
||||
{
|
||||
int ret;
|
||||
size_t i = mpi_msb( E );
|
||||
size_t wsize = ( i > 1024 ) ? 4 : /* Because of not enough memory. */
|
||||
size_t wsize = ( i > 1024 ) ? MAX_WSIZE :
|
||||
( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
|
||||
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
|
||||
size_t wbits, one = 1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Makefile for reGNUal
|
||||
|
||||
PROJECT = regnual
|
||||
PROJECT = regnual-no-vidpid
|
||||
|
||||
OBJS = regnual.o usb-stm32f103.o reset.o
|
||||
|
||||
@@ -41,11 +41,15 @@ regnual.hex: regnual.elf
|
||||
$(OBJCOPY) -Obinary regnual.elf regnual.bin
|
||||
$(OBJCOPY) -Oihex regnual.elf regnual.hex
|
||||
|
||||
regnual.elf: regnual-no-vidpid.elf
|
||||
cp -p regnual-no-vidpid.elf regnual.elf
|
||||
env FILE="regnual.elf" PATH="../src:$$PATH" bash put-vid-pid-ver.sh
|
||||
|
||||
usb-stm32f103.o: ../chopstx/mcu/usb-stm32f103.c
|
||||
$(CC) $(CFLAGS) -c -o usb-stm32f103.o ../chopstx/mcu/usb-stm32f103.c
|
||||
|
||||
regnual.elf: $(OBJS) $(LDSCRIPT)
|
||||
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS)
|
||||
regnual-no-vidpid.elf: $(OBJS) $(LDSCRIPT)
|
||||
$(CC) $(LDFLAGS) -o regnual-no-vidpid.elf $(OBJS)
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin *.lst
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* regnual.c -- Firmware installation for STM32F103 Flash ROM
|
||||
*
|
||||
* Copyright (C) 2012, 2013, 2015, 2016, 2017
|
||||
* Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -57,7 +57,9 @@ static const uint8_t regnual_device_desc[] = {
|
||||
0x00, /* bDeviceSubClass */
|
||||
0x00, /* bDeviceProtocol */
|
||||
0x40, /* bMaxPacketSize0 */
|
||||
#include "../src/usb-vid-pid-ver.c.inc"
|
||||
0x00, 0x00, /* idVendor (will be replaced) */
|
||||
0x00, 0x00, /* idProduct (will be replaced) */
|
||||
0x00, 0x00, /* bcdDevice (will be replaced) */
|
||||
1, /* Index of string descriptor describing manufacturer */
|
||||
2, /* Index of string descriptor describing product */
|
||||
3, /* Index of string descriptor describing the device's serial number */
|
||||
@@ -147,19 +149,33 @@ static uint32_t fetch (int i)
|
||||
}
|
||||
|
||||
struct CRC {
|
||||
__IO uint32_t DR;
|
||||
__IO uint8_t IDR;
|
||||
volatile uint32_t DR;
|
||||
volatile uint8_t IDR;
|
||||
uint8_t RESERVED0;
|
||||
uint16_t RESERVED1;
|
||||
__IO uint32_t CR;
|
||||
volatile uint32_t CR;
|
||||
};
|
||||
static struct CRC *const CRC = (struct CRC *)0x40023000;
|
||||
|
||||
struct RCC {
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t CIR;
|
||||
volatile uint32_t APB2RSTR;
|
||||
volatile uint32_t APB1RSTR;
|
||||
volatile uint32_t AHBENR;
|
||||
/* ... */
|
||||
};
|
||||
static struct RCC *const RCC = (struct RCC *)0x40021000;
|
||||
#define RCC_AHBENR_CRCEN 0x00000040
|
||||
|
||||
|
||||
#define CRC_CR_RESET 0x01
|
||||
static uint32_t calc_crc32 (void)
|
||||
{
|
||||
struct CRC *CRC = (struct CRC *)0x40023000;
|
||||
int i;
|
||||
|
||||
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
||||
CRC->CR = CRC_CR_RESET;
|
||||
|
||||
for (i = 0; i < 256/4; i++)
|
||||
|
||||
@@ -9,5 +9,3 @@ typedef unsigned int uintptr_t;
|
||||
#define FALSE 0
|
||||
|
||||
#define NULL 0
|
||||
|
||||
#define __IO volatile
|
||||
|
||||
10
src/Makefile
10
src/Makefile
@@ -34,7 +34,7 @@ USE_EVENTFLAG = yes
|
||||
ifeq ($(EMULATION),)
|
||||
DEFS += -DFLASH_UPGRADE_SUPPORT
|
||||
else
|
||||
DEFS += -DBN256_C_IMPLEMENTATION -DBIGNUM_C_IMPLEMENTATION
|
||||
DEFS += -DBN256_C_IMPLEMENTATION
|
||||
endif
|
||||
|
||||
ifneq ($(ENABLE_DEBUG),)
|
||||
@@ -76,7 +76,13 @@ distclean: clean
|
||||
-rm -f gnuk.ld config.h board.h config.mk \
|
||||
usb-strings.c.inc usb-vid-pid-ver.c.inc
|
||||
|
||||
ifneq ($(EMULATION),)
|
||||
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
|
||||
else
|
||||
# By specifying DESTDIR on invocation of "make", you can install
|
||||
# program to different ROOT.
|
||||
|
||||
|
||||
17
src/ac.c
17
src/ac.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ac.c -- Check access condition
|
||||
*
|
||||
* Copyright (C) 2010, 2012, 2013 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2012, 2013, 2017 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -73,12 +73,14 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
|
||||
if (ks_pw1 == NULL)
|
||||
{
|
||||
pw_len = strlen (OPENPGP_CARD_INITIAL_PW1);
|
||||
const uint8_t *initial_pw;
|
||||
|
||||
salt = NULL;
|
||||
salt_len = 0;
|
||||
gpg_do_get_initial_pw_setting (0, &pw_len, &initial_pw);
|
||||
if ((pw_len_known >= 0 && pw_len_known != pw_len)
|
||||
|| buf_len < pw_len
|
||||
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW1, pw_len))
|
||||
|| memcmp (pw, initial_pw, pw_len))
|
||||
goto failure;
|
||||
}
|
||||
else
|
||||
@@ -220,6 +222,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t *initial_pw;
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
|
||||
if (ks_pw1 != NULL)
|
||||
@@ -237,13 +240,13 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For the case of empty PW3 (with empty PW1), pass phrase
|
||||
* should be OPENPGP_CARD_INITIAL_PW3
|
||||
* For the case of empty PW3 (with empty PW1), passphrase is
|
||||
* OPENPGP_CARD_INITIAL_PW3, or defined by KDF DO.
|
||||
*/
|
||||
pw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
|
||||
gpg_do_get_initial_pw_setting (1, &pw_len, &initial_pw);
|
||||
if ((pw_len_known >=0 && pw_len_known != pw_len)
|
||||
|| buf_len < pw_len
|
||||
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW3, pw_len))
|
||||
|| memcmp (pw, initial_pw, pw_len))
|
||||
goto failure;
|
||||
|
||||
admin_authorized = BY_ADMIN;
|
||||
|
||||
76
src/binary-edit.sh
Normal file
76
src/binary-edit.sh
Normal file
@@ -0,0 +1,76 @@
|
||||
# This is a Bash script to be included.
|
||||
|
||||
# Idx Name Size VMA LMA File off Algn
|
||||
# =================
|
||||
# 2 .text 00004a40 080010f0 080010f0 000110f0 2**4
|
||||
# 08006550 l O .text 00000012 device_desc
|
||||
# =================
|
||||
# VMA =0x080010f0
|
||||
# FOFF=0x000110f0
|
||||
# ADDR=0x08005ad0
|
||||
# file_off_ADDR = ADDR - VMA + FOFF
|
||||
# = 0x08005ad0 - 0x080010f0 + 0x000110f0 = 0x00015ad0
|
||||
|
||||
function calc_addr () {
|
||||
local line_sym="" VMA FOFF ADDR
|
||||
|
||||
arm-none-eabi-objdump -h -t -j .text $FILE | \
|
||||
egrep -e '(^ +[0-9] +\.text +|device_desc)' | \
|
||||
while read -r F0 F1 F2 F3 F4 F5 F6; do
|
||||
if [ -z "$line_sym" ]; then
|
||||
VMA=$F3
|
||||
FOFF=$F5
|
||||
line_sym="next is a line for the symbol"
|
||||
else
|
||||
ADDR=$F0
|
||||
echo "$((0x$ADDR - 0x$VMA + 0x$FOFF))"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
declare -a OFFSETS
|
||||
OFFSETS=($(calc_addr))
|
||||
file_off_ADDR=${OFFSETS[0]}
|
||||
file_off_fraucheky_ADDR=${OFFSETS[1]}
|
||||
|
||||
echo "Offset is $file_off_ADDR"
|
||||
if [ -n "$file_off_fraucheky_ADDR" ]; then
|
||||
echo "Offset is $file_off_fraucheky_ADDR"
|
||||
fi
|
||||
|
||||
function replace_file_byte_at () {
|
||||
printf "\x$1" | dd of=$FILE bs=1 seek=$2 conv=notrunc >& /dev/null
|
||||
}
|
||||
|
||||
#
|
||||
# vid_lsb: 8
|
||||
# vid_msb: 9
|
||||
# pid_lsb: 10
|
||||
# pid_msb: 11
|
||||
# bcd_device_lsb: 12
|
||||
# bcd_device_msb: 13
|
||||
#
|
||||
|
||||
function replace_vid_lsb () {
|
||||
replace_file_byte_at $1 $((addr + 8))
|
||||
}
|
||||
|
||||
function replace_vid_msb () {
|
||||
replace_file_byte_at $1 $((addr + 9))
|
||||
}
|
||||
|
||||
function replace_pid_lsb () {
|
||||
replace_file_byte_at $1 $((addr + 10))
|
||||
}
|
||||
|
||||
function replace_pid_msb () {
|
||||
replace_file_byte_at $1 $((addr + 11))
|
||||
}
|
||||
|
||||
function replace_bcd_device_lsb () {
|
||||
replace_file_byte_at $1 $((addr + 12))
|
||||
}
|
||||
|
||||
function replace_bcd_device_msb () {
|
||||
replace_file_byte_at $1 $((addr + 13))
|
||||
}
|
||||
42
src/configure
vendored
42
src/configure
vendored
@@ -6,7 +6,7 @@ nl=$'\n'
|
||||
#
|
||||
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
|
||||
#
|
||||
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||
# Free Software Initiative of Japan
|
||||
#
|
||||
# This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -207,6 +207,7 @@ if test "$target" = "GNU_LINUX"; then
|
||||
cross=""
|
||||
mcu="none"
|
||||
def_emulation="-DGNU_LINUX_EMULATION"
|
||||
def_memory_size="-DMEMORY_SIZE=1024"
|
||||
enable_hexoutput=""
|
||||
libs="-lpthread"
|
||||
else
|
||||
@@ -216,6 +217,7 @@ else
|
||||
cross="arm-none-eabi-"
|
||||
mcu="cortex-m3"
|
||||
def_emulation=""
|
||||
def_memory_size="-DMEMORY_SIZE=$MEMORY_SIZE"
|
||||
enable_hexoutput=yes
|
||||
libs=""
|
||||
fi
|
||||
@@ -325,8 +327,32 @@ else
|
||||
fi
|
||||
|
||||
output_vid_pid_version () {
|
||||
echo "$VIDPID" | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\\${nl} 0x\4, 0x\3, /* idProduct */%p"
|
||||
echo "$VERSION" | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
|
||||
echo "$VIDPID" | \
|
||||
sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$%\1\t\2\t\3\t\4%p" | \
|
||||
while read -r FIRST SECOND THIRD FOURTH; do
|
||||
if test $FIRST != 00; then
|
||||
echo replace_vid_msb $FIRST
|
||||
fi
|
||||
if test $SECOND != 00; then
|
||||
echo replace_vid_lsb $SECOND
|
||||
fi
|
||||
if test $THIRD != 00; then
|
||||
echo replace_pid_msb $THIRD
|
||||
fi
|
||||
if test $FOURTH != 00; then
|
||||
echo replace_pid_lsb $FOURTH
|
||||
fi
|
||||
done
|
||||
echo "$VERSION" | \
|
||||
sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$%\1\t\2%p" | \
|
||||
while read -r FIRST SECOND; do
|
||||
if test $FIRST != 00; then
|
||||
echo replace_bcd_device_msb $FIRST
|
||||
fi
|
||||
if test $SECOND != 00; then
|
||||
echo replace_bcd_device_lsb $SECOND
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
output_vendor_product_serial_strings () {
|
||||
@@ -380,10 +406,16 @@ output_vendor_product_serial_strings () {
|
||||
fi
|
||||
}
|
||||
|
||||
(echo "#! /bin/bash"
|
||||
echo
|
||||
echo 'source "binary-edit.sh"') > put-vid-pid-ver.sh
|
||||
|
||||
if !(IFS=" "
|
||||
while read -r VIDPID VERSION PRODUCT VENDOR; do
|
||||
if test "$vidpid" = "$VIDPID"; then
|
||||
output_vid_pid_version > usb-vid-pid-ver.c.inc
|
||||
echo >> put-vid-pid-ver.sh
|
||||
echo 'addr=$file_off_ADDR' >> put-vid-pid-ver.sh
|
||||
output_vid_pid_version >> put-vid-pid-ver.sh
|
||||
output_vendor_product_serial_strings gnuk_ >usb-strings.c.inc
|
||||
exit 0
|
||||
fi
|
||||
@@ -410,7 +442,7 @@ fi
|
||||
echo "EMULATION=$emulation";
|
||||
echo "CROSS=$cross";
|
||||
echo "MCU=$mcu";
|
||||
echo "DEFS=$use_sys3 $flash_override $def_emulation";
|
||||
echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size";
|
||||
echo "LDSCRIPT=$ldscript";
|
||||
echo "LIBS=$libs";
|
||||
echo "$DEBUG_MAKE_OPTION";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -157,6 +157,12 @@ flash_terminate (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef FLASH_UPGRADE_SUPPORT
|
||||
const uint8_t *p;
|
||||
|
||||
p = gpg_get_firmware_update_key (0);
|
||||
flash_erase_page ((uintptr_t)p);
|
||||
#endif
|
||||
for (i = 0; i < 3; i++)
|
||||
flash_erase_page ((uintptr_t)flash_key_getpage (i));
|
||||
flash_erase_page ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START);
|
||||
|
||||
12
src/gnuk.h
12
src/gnuk.h
@@ -22,15 +22,12 @@ extern struct apdu apdu;
|
||||
#define CARD_CHANGE_REMOVE 1
|
||||
#define CARD_CHANGE_TOGGLE 2
|
||||
void ccid_card_change_signal (int how);
|
||||
void ccid_usb_reset (int);
|
||||
|
||||
/* 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_USB_SET_INTERFACE 16
|
||||
#define EV_USB_DEVICE_RESET 32
|
||||
#define EV_CARD_CHANGE 8
|
||||
|
||||
/* OpenPGPcard thread */
|
||||
#define EV_PINPAD_INPUT_DONE 1
|
||||
@@ -296,6 +293,9 @@ int ecdh_decrypt_curve25519 (const uint8_t *input, uint8_t *output,
|
||||
const uint8_t *gpg_do_read_simple (uint8_t);
|
||||
void gpg_do_write_simple (uint8_t, const uint8_t *, int);
|
||||
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);
|
||||
|
||||
|
||||
void fatal (uint8_t code) __attribute__ ((noreturn));
|
||||
@@ -334,7 +334,8 @@ extern uint8_t admin_authorized;
|
||||
#define NR_DO_KEYSTRING_PW1 0x11
|
||||
#define NR_DO_KEYSTRING_RC 0x12
|
||||
#define NR_DO_KEYSTRING_PW3 0x13
|
||||
#define NR_DO__LAST__ 20 /* == 0x14 */
|
||||
#define NR_DO_KDF 0x14
|
||||
#define NR_DO__LAST__ 21 /* == 0x15 */
|
||||
/* 14-bit counter for DS: Recorded in flash memory by 1-halfword (2-byte). */
|
||||
/*
|
||||
* Representation of 14-bit counter:
|
||||
@@ -433,6 +434,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_OFF LED_FINISH_COMMAND
|
||||
void led_blink (int spec);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
|
||||
@@ -135,11 +135,11 @@ SECTIONS
|
||||
{
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
_keystore_pool = .;
|
||||
. += 512;
|
||||
. += 1024;
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
. += 512;
|
||||
. += 1024;
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
. += 512;
|
||||
. += 1024;
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
_updatekey_store = .;
|
||||
. += 1024;
|
||||
|
||||
51
src/main.c
51
src/main.c
@@ -90,6 +90,10 @@ device_initialize_once (void)
|
||||
|
||||
static volatile uint8_t fatal_code;
|
||||
static struct eventflag led_event;
|
||||
static chopstx_poll_cond_t led_event_poll_desc;
|
||||
static struct chx_poll_head *const led_event_poll[] = {
|
||||
(struct chx_poll_head *)&led_event_poll_desc
|
||||
};
|
||||
|
||||
static void display_fatal_code (void)
|
||||
{
|
||||
@@ -130,17 +134,20 @@ static void display_fatal_code (void)
|
||||
|
||||
static uint8_t led_inverted;
|
||||
|
||||
static void emit_led (int on_time, int off_time)
|
||||
static void
|
||||
emit_led (uint32_t on_time, uint32_t off_time)
|
||||
{
|
||||
set_led (!led_inverted);
|
||||
chopstx_usec_wait (on_time);
|
||||
chopstx_poll (&on_time, 1, led_event_poll);
|
||||
set_led (led_inverted);
|
||||
chopstx_usec_wait (off_time);
|
||||
chopstx_poll (&off_time, 1, led_event_poll);
|
||||
}
|
||||
|
||||
static void display_status_code (void)
|
||||
static void
|
||||
display_status_code (void)
|
||||
{
|
||||
enum ccid_state ccid_state = *ccid_state_p;
|
||||
uint32_t usec;
|
||||
|
||||
if (ccid_state == CCID_STATE_START)
|
||||
emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
|
||||
@@ -155,10 +162,14 @@ static void display_status_code (void)
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_INTERVAL);
|
||||
|
||||
if (ccid_state == CCID_STATE_WAIT)
|
||||
chopstx_usec_wait (LED_TIMEOUT_STOP * 2);
|
||||
{
|
||||
usec = LED_TIMEOUT_STOP * 2;
|
||||
chopstx_poll (&usec, 1, led_event_poll);
|
||||
}
|
||||
else
|
||||
{
|
||||
chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
|
||||
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);
|
||||
}
|
||||
@@ -228,6 +239,8 @@ main (int argc, const char *argv[])
|
||||
#endif
|
||||
chopstx_t ccid_thd;
|
||||
|
||||
chopstx_conf_idle (1);
|
||||
|
||||
gnuk_malloc_init ();
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
@@ -329,12 +342,14 @@ main (int argc, const char *argv[])
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (bDeviceState != UNCONNECTED)
|
||||
if (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
|
||||
break;
|
||||
|
||||
chopstx_usec_wait (250*1000);
|
||||
}
|
||||
|
||||
eventflag_prepare_poll (&led_event, &led_event_poll_desc);
|
||||
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
@@ -443,23 +458,23 @@ fatal (uint8_t code)
|
||||
*/
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#define MEMORY_SIZE (32*1024)
|
||||
uint8_t __heap_base__[MEMORY_SIZE];
|
||||
#define HEAP_SIZE (32*1024)
|
||||
uint8_t __heap_base__[HEAP_SIZE];
|
||||
|
||||
#define HEAP_START __heap_base__
|
||||
#define MEMORY_END (__heap_base__ + MEMORY_SIZE)
|
||||
#define MEMORY_ALIGNMENT 32
|
||||
#define HEAP_END (__heap_base__ + HEAP_SIZE)
|
||||
#define HEAP_ALIGNMENT 32
|
||||
#else
|
||||
extern uint8_t __heap_base__[];
|
||||
extern uint8_t __heap_end__[];
|
||||
|
||||
#define HEAP_START __heap_base__
|
||||
#define MEMORY_END (__heap_end__)
|
||||
#define MEMORY_ALIGNMENT 16
|
||||
#define MEMORY_SIZE ((uintptr_t)__heap_end__ - (uintptr_t)__heap_base__)
|
||||
#define HEAP_END (__heap_end__)
|
||||
#define HEAP_ALIGNMENT 16
|
||||
#define HEAP_SIZE ((uintptr_t)__heap_end__ - (uintptr_t)__heap_base__)
|
||||
#endif
|
||||
|
||||
#define MEMORY_ALIGN(n) (((n) + MEMORY_ALIGNMENT - 1) & ~(MEMORY_ALIGNMENT - 1))
|
||||
#define HEAP_ALIGN(n) (((n) + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT - 1))
|
||||
|
||||
static uint8_t *heap_p;
|
||||
static chopstx_mutex_t malloc_mtx;
|
||||
@@ -472,7 +487,7 @@ struct mem_head {
|
||||
};
|
||||
|
||||
#define MEM_HEAD_IS_CORRUPT(x) \
|
||||
((x)->size != MEMORY_ALIGN((x)->size) || (x)->size > MEMORY_SIZE)
|
||||
((x)->size != HEAP_ALIGN((x)->size) || (x)->size > HEAP_SIZE)
|
||||
#define MEM_HEAD_CHECK(x) if (MEM_HEAD_IS_CORRUPT(x)) fatal (FATAL_HEAP)
|
||||
|
||||
static struct mem_head *free_list;
|
||||
@@ -490,7 +505,7 @@ sbrk (size_t size)
|
||||
{
|
||||
void *p = (void *)heap_p;
|
||||
|
||||
if ((size_t)(MEMORY_END - heap_p) < size)
|
||||
if ((size_t)(HEAP_END - heap_p) < size)
|
||||
return NULL;
|
||||
|
||||
heap_p += size;
|
||||
@@ -515,7 +530,7 @@ gnuk_malloc (size_t size)
|
||||
struct mem_head *m;
|
||||
struct mem_head *m0;
|
||||
|
||||
size = MEMORY_ALIGN (size + sizeof (uintptr_t));
|
||||
size = HEAP_ALIGN (size + sizeof (uintptr_t));
|
||||
|
||||
chopstx_mutex_lock (&malloc_mtx);
|
||||
DEBUG_INFO ("malloc: ");
|
||||
|
||||
14
src/neug.c
14
src/neug.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* neug.c - true random number generation
|
||||
*
|
||||
* Copyright (C) 2011, 2012, 2013, 2016, 2017
|
||||
* Copyright (C) 2011, 2012, 2013, 2016, 2017, 2018
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -115,6 +115,11 @@ rbit (uint32_t v)
|
||||
v = ( v >> 16 ) | ( v << 16);
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
crc32_rv_stop (void)
|
||||
{
|
||||
}
|
||||
#else
|
||||
void
|
||||
crc32_rv_reset (void)
|
||||
@@ -143,6 +148,12 @@ rbit (uint32_t v)
|
||||
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
crc32_rv_stop (void)
|
||||
{
|
||||
RCC->AHBENR &= ~RCC_AHBENR_CRCEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
static chopstx_mutex_t mode_mtx;
|
||||
@@ -894,6 +905,7 @@ neug_fini (void)
|
||||
rng_should_terminate = 1;
|
||||
neug_get (1);
|
||||
chopstx_join (rng_thread, NULL);
|
||||
crc32_rv_stop ();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
246
src/openpgp-do.c
246
src/openpgp-do.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -112,13 +112,15 @@ const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
|
||||
/* Extended Capabilities */
|
||||
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
|
||||
10,
|
||||
0x74, /*
|
||||
0x75, /*
|
||||
* No Secure Messaging supported
|
||||
* GET CHALLENGE supported
|
||||
* Key import supported
|
||||
* PW status byte can be put
|
||||
* No private_use_DO
|
||||
* Algorithm attrs are changable
|
||||
* No DEC with AES
|
||||
* KDF-DO available
|
||||
*/
|
||||
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
|
||||
0x00, CHALLENGE_LEN, /* Max size of GET CHALLENGE */
|
||||
@@ -452,12 +454,17 @@ static const struct do_table_entry *get_do_entry (uint16_t tag);
|
||||
#define GPG_DO_KGTIME_DEC 0x00cf
|
||||
#define GPG_DO_KGTIME_AUT 0x00d0
|
||||
#define GPG_DO_RESETTING_CODE 0x00d3
|
||||
#define GPG_DO_UIF_SIG 0x00d6
|
||||
#define GPG_DO_UIF_DEC 0x00d7
|
||||
#define GPG_DO_UIF_AUT 0x00d8
|
||||
#define GPG_DO_KDF 0x00f9
|
||||
#define GPG_DO_KEY_IMPORT 0x3fff
|
||||
#define GPG_DO_LANGUAGE 0x5f2d
|
||||
#define GPG_DO_SEX 0x5f35
|
||||
#define GPG_DO_URL 0x5f50
|
||||
#define GPG_DO_HIST_BYTES 0x5f52
|
||||
#define GPG_DO_CH_CERTIFICATE 0x7f21
|
||||
#define GPG_DO_FEATURE_MNGMNT 0x7f74
|
||||
|
||||
static const uint8_t *do_ptr[NR_DO__LAST__];
|
||||
|
||||
@@ -494,6 +501,8 @@ do_tag_to_nr (uint16_t tag)
|
||||
return NR_DO_NAME;
|
||||
case GPG_DO_LANGUAGE:
|
||||
return NR_DO_LANGUAGE;
|
||||
case GPG_DO_KDF:
|
||||
return NR_DO_KDF;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@@ -798,6 +807,157 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
|
||||
}
|
||||
}
|
||||
|
||||
#define SIZE_OF_KDF_DO_MIN 90
|
||||
#define SIZE_OF_KDF_DO_MAX 110
|
||||
#define OPENPGP_KDF_ITERSALTED_S2K 3
|
||||
#define OPENPGP_SHA256 8
|
||||
|
||||
static int
|
||||
rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
|
||||
{
|
||||
if (tag != GPG_DO_KDF)
|
||||
return 0; /* Failure */
|
||||
|
||||
if (is_write)
|
||||
{
|
||||
const uint8_t **do_data_p = (const uint8_t **)&do_ptr[NR_DO_KDF];
|
||||
|
||||
/* KDF DO can be changed only when no keys are registered. */
|
||||
if (do_ptr[NR_DO_PRVKEY_SIG] || do_ptr[NR_DO_PRVKEY_DEC]
|
||||
|| do_ptr[NR_DO_PRVKEY_AUT])
|
||||
return 0;
|
||||
|
||||
/* The valid data format is:
|
||||
Deleting:
|
||||
nothing
|
||||
Minimum (for admin-less):
|
||||
81 01 03 = KDF_ITERSALTED_S2K
|
||||
82 01 08 = SHA256
|
||||
83 04 4-byte... = count
|
||||
84 08 8-byte... = salt
|
||||
87 20 32-byte user hash
|
||||
88 20 32-byte admin hash
|
||||
Full:
|
||||
81 01 03 = KDF_ITERSALTED_S2K
|
||||
82 01 08 = SHA256
|
||||
83 04 4-byte... = count
|
||||
84 08 8-byte... = salt user
|
||||
85 08 8-byte... = salt reset-code
|
||||
86 08 8-byte... = salt admin
|
||||
87 20 32-byte user hash
|
||||
88 20 32-byte admin hash
|
||||
*/
|
||||
if (!(len == 0
|
||||
|| (len == SIZE_OF_KDF_DO_MIN &&
|
||||
(data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
|
||||
&& data[12] == 0x84 && data[22] == 0x87 && data[56] == 0x88))
|
||||
|| (len == SIZE_OF_KDF_DO_MAX &&
|
||||
(data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
|
||||
&& data[12] == 0x84 && data[22] == 0x85 && data[32] == 0x86
|
||||
&& data[42] == 0x87 && data[76] == 0x88))))
|
||||
return 0;
|
||||
|
||||
if (*do_data_p)
|
||||
flash_do_release (*do_data_p);
|
||||
|
||||
/* Clear all keystrings and auth states */
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW3, NULL, 0);
|
||||
ac_reset_admin ();
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
*do_data_p = NULL;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*do_data_p = flash_do_write (NR_DO_KDF, data, len);
|
||||
if (*do_data_p)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (do_ptr[NR_DO_KDF])
|
||||
copy_do_1 (tag, do_ptr[NR_DO_KDF], with_tag);
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gpg_do_kdf_check (int len, int how_many)
|
||||
{
|
||||
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
|
||||
|
||||
if (kdf_do)
|
||||
{
|
||||
const uint8_t *kdf_spec = kdf_do+1;
|
||||
int kdf_do_len = kdf_do[0];
|
||||
int hash_len;
|
||||
|
||||
if (kdf_do_len == SIZE_OF_KDF_DO_MIN)
|
||||
hash_len = kdf_spec[23];
|
||||
else
|
||||
hash_len = kdf_spec[43];
|
||||
|
||||
if ((hash_len * how_many) != len && hash_len != len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
gpg_do_get_initial_pw_setting (int is_pw3, int *r_len, const uint8_t **r_p)
|
||||
{
|
||||
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
|
||||
|
||||
if (kdf_do)
|
||||
{
|
||||
int len = kdf_do[0];
|
||||
const uint8_t *kdf_spec = kdf_do+1;
|
||||
|
||||
*r_len = 32;
|
||||
|
||||
if (len == SIZE_OF_KDF_DO_MIN)
|
||||
{
|
||||
if (is_pw3)
|
||||
*r_p = kdf_spec + 58;
|
||||
else
|
||||
*r_p = kdf_spec + 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_pw3)
|
||||
*r_p = kdf_spec + 78;
|
||||
else
|
||||
*r_p = kdf_spec + 44;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_pw3)
|
||||
{
|
||||
*r_len = strlen (OPENPGP_CARD_INITIAL_PW3);
|
||||
*r_p = (const uint8_t *)OPENPGP_CARD_INITIAL_PW3;
|
||||
}
|
||||
else
|
||||
{
|
||||
*r_len = strlen (OPENPGP_CARD_INITIAL_PW1);
|
||||
*r_p = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
proc_resetting_code (const uint8_t *data, int len)
|
||||
{
|
||||
@@ -811,31 +971,45 @@ proc_resetting_code (const uint8_t *data, int len)
|
||||
|
||||
DEBUG_INFO ("Resetting Code!\r\n");
|
||||
|
||||
newpw_len = len;
|
||||
newpw = data;
|
||||
new_ks0[0] = newpw_len;
|
||||
random_get_salt (salt);
|
||||
s2k (salt, SALT_SIZE, newpw, newpw_len, new_ks);
|
||||
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
|
||||
if (r <= -2)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
return 0;
|
||||
}
|
||||
else if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("security error.\r\n");
|
||||
return 0;
|
||||
}
|
||||
else if (r == 0)
|
||||
{
|
||||
DEBUG_INFO ("error (no prvkey).\r\n");
|
||||
return 0;
|
||||
if (len == 0)
|
||||
{ /* Removal of resetting code. */
|
||||
enum kind_of_key kk0;
|
||||
|
||||
for (kk0 = 0; kk0 <= GPG_KEY_FOR_AUTHENTICATION; kk0++)
|
||||
gpg_do_chks_prvkey (kk0, BY_RESETCODE, NULL, 0, NULL);
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KS_META_SIZE);
|
||||
if (gpg_do_kdf_check (len, 1) == 0)
|
||||
return 0;
|
||||
|
||||
newpw_len = len;
|
||||
newpw = data;
|
||||
new_ks0[0] = newpw_len;
|
||||
random_get_salt (salt);
|
||||
s2k (salt, SALT_SIZE, newpw, newpw_len, new_ks);
|
||||
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
|
||||
if (r <= -2)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
return 0;
|
||||
}
|
||||
else if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("security error.\r\n");
|
||||
return 0;
|
||||
}
|
||||
else if (r == 0)
|
||||
{
|
||||
DEBUG_INFO ("error (no prvkey).\r\n");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KS_META_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
gpg_pw_reset_err_counter (PW_ERR_RC);
|
||||
@@ -1090,6 +1264,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
|
||||
int pubkey_len;
|
||||
uint8_t ks[KEYSTRING_MD_SIZE];
|
||||
enum kind_of_key kk0;
|
||||
int pw_len;
|
||||
const uint8_t *initial_pw;
|
||||
|
||||
DEBUG_INFO ("Key import\r\n");
|
||||
DEBUG_SHORT (prvkey_len);
|
||||
@@ -1147,8 +1323,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
|
||||
memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
s2k (NULL, 0, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1,
|
||||
strlen (OPENPGP_CARD_INITIAL_PW1), ks);
|
||||
gpg_do_get_initial_pw_setting (0, &pw_len, &initial_pw);
|
||||
s2k (NULL, 0, initial_pw, pw_len, ks);
|
||||
|
||||
/* Handle existing keys and keystring DOs. */
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
|
||||
@@ -1488,6 +1664,8 @@ gpg_do_table[] = {
|
||||
rw_algorithm_attr },
|
||||
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||
rw_algorithm_attr },
|
||||
{ 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 },
|
||||
@@ -2067,10 +2245,10 @@ gpg_do_keygen (uint8_t *buf)
|
||||
const uint8_t *prv;
|
||||
const uint8_t *rnd;
|
||||
int r = 0;
|
||||
#define p_q buf
|
||||
#define d buf
|
||||
#define d1 (&buf[64])
|
||||
#define pubkey (&buf[256])
|
||||
#define p_q (&buf[3])
|
||||
#define d (&buf[3])
|
||||
#define d1 (&buf[3+64])
|
||||
#define pubkey (&buf[3+256])
|
||||
|
||||
DEBUG_INFO ("Keygen\r\n");
|
||||
DEBUG_BYTE (kk_byte);
|
||||
@@ -2088,7 +2266,7 @@ gpg_do_keygen (uint8_t *buf)
|
||||
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
|
||||
{
|
||||
const uint8_t *p;
|
||||
int i, r;
|
||||
int i;
|
||||
|
||||
rnd = NULL;
|
||||
do
|
||||
@@ -2173,14 +2351,16 @@ gpg_do_keygen (uint8_t *buf)
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
{
|
||||
const uint8_t *pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
|
||||
int pw_len;
|
||||
const uint8_t *initial_pw;
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
|
||||
/* GnuPG expects it's ready for signing. */
|
||||
/* Don't call ac_reset_pso_cds here, but load the private key */
|
||||
|
||||
gpg_reset_digital_signature_counter ();
|
||||
s2k (NULL, 0, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
|
||||
gpg_do_get_initial_pw_setting (0, &pw_len, &initial_pw);
|
||||
s2k (NULL, 0, initial_pw, pw_len, keystring);
|
||||
gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* openpgp.c -- OpenPGP card protocol support
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
static struct eventflag *openpgp_comm;
|
||||
|
||||
#define USER_PASSWD_MINLEN 6
|
||||
#define ADMIN_PASSWD_MINLEN 8
|
||||
|
||||
#define CLS(a) a.cmd_apdu_head[0]
|
||||
@@ -170,7 +171,8 @@ cmd_verify (void)
|
||||
r = ac_check_status (AC_ADMIN_AUTHORIZED);
|
||||
|
||||
if (r)
|
||||
GPG_SUCCESS (); /* If authentication done already, return success. */
|
||||
/* If authentication done already, return success. */
|
||||
GPG_SUCCESS ();
|
||||
else
|
||||
{ /* If not, return retry counter, encoded. */
|
||||
r = gpg_pw_get_retry_counter (p2);
|
||||
@@ -192,6 +194,12 @@ cmd_verify (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpg_do_kdf_check (len, 1) == 0)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is real authentication. */
|
||||
if (p2 == 0x81)
|
||||
r = verify_pso_cds (pw, len);
|
||||
@@ -299,6 +307,12 @@ cmd_change_password (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpg_do_kdf_check (len, 2) == 0)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (who == BY_USER) /* PW1 */
|
||||
{
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
@@ -335,8 +349,9 @@ cmd_change_password (void)
|
||||
newpw_len = len - pw_len;
|
||||
ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
||||
|
||||
/* Check length of password for admin-less mode. */
|
||||
if (ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|
||||
/* Check length of password */
|
||||
if ((ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|
||||
|| newpw_len < USER_PASSWD_MINLEN)
|
||||
{
|
||||
DEBUG_INFO ("new password length is too short.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
@@ -351,8 +366,24 @@ cmd_change_password (void)
|
||||
|
||||
if (ks_pw3 == NULL)
|
||||
{
|
||||
salt = NULL;
|
||||
salt_len = 0;
|
||||
if (admin_authorized == BY_USER)
|
||||
{
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
|
||||
if (ks_pw1 == NULL)
|
||||
{
|
||||
GPG_SECURITY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
salt = KS_GET_SALT (ks_pw1);
|
||||
salt_len = SALT_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
salt = NULL;
|
||||
salt_len = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -376,13 +407,22 @@ cmd_change_password (void)
|
||||
{
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = len - pw_len;
|
||||
|
||||
if (newpw_len == 0 && admin_authorized == BY_ADMIN)
|
||||
{
|
||||
newpw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
|
||||
memcpy (newpw, OPENPGP_CARD_INITIAL_PW3, newpw_len);
|
||||
const uint8_t *initial_pw;
|
||||
|
||||
gpg_do_get_initial_pw_setting (1, &newpw_len, &initial_pw);
|
||||
memcpy (newpw, initial_pw, newpw_len);
|
||||
newsalt_len = 0;
|
||||
pw3_null = 1;
|
||||
}
|
||||
else if (newpw_len < ADMIN_PASSWD_MINLEN)
|
||||
{
|
||||
DEBUG_INFO ("new password length is too short.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
who_old = admin_authorized;
|
||||
}
|
||||
@@ -412,11 +452,26 @@ cmd_change_password (void)
|
||||
}
|
||||
else if (r > 0 && who == BY_USER)
|
||||
{
|
||||
/* When it was already admin-less mode, admin_authorized is
|
||||
* BY_USER. If no PW3 keystring, it's becoming admin-less mode,
|
||||
* now. For these two cases, we need to reset admin
|
||||
* authorization status. */
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
else if (ks_pw3 == NULL)
|
||||
{
|
||||
enum kind_of_key kk0;
|
||||
|
||||
/* Remove keystrings for BY_ADMIN. */
|
||||
for (kk0 = 0; kk0 <= GPG_KEY_FOR_AUTHENTICATION; kk0++)
|
||||
gpg_do_chks_prvkey (kk0, BY_ADMIN, NULL, 0, NULL);
|
||||
|
||||
ac_reset_admin ();
|
||||
}
|
||||
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KS_META_SIZE);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -516,6 +571,13 @@ cmd_reset_user_password (void)
|
||||
{
|
||||
const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
|
||||
uint8_t old_ks[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
||||
|
||||
if (gpg_do_kdf_check (len, 2) == 0)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpg_pw_locked (PW_ERR_RC))
|
||||
{
|
||||
@@ -536,6 +598,16 @@ cmd_reset_user_password (void)
|
||||
salt_len = SALT_SIZE;
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = len - pw_len;
|
||||
|
||||
/* Check length of new password */
|
||||
if ((ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|
||||
|| newpw_len < USER_PASSWD_MINLEN)
|
||||
{
|
||||
DEBUG_INFO ("new password length is too short.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
random_get_salt (new_salt);
|
||||
s2k (salt, salt_len, pw, pw_len, old_ks);
|
||||
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
|
||||
@@ -581,6 +653,12 @@ cmd_reset_user_password (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpg_do_kdf_check (len, 1) == 0)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
newpw_len = len;
|
||||
newpw = pw;
|
||||
random_get_salt (new_salt);
|
||||
|
||||
@@ -40,14 +40,14 @@ cir_ext_disable (void)
|
||||
int rcvd = (EXTI->PR & EXTI_PR) != 0;
|
||||
|
||||
EXTI->IMR &= ~EXTI_IMR;
|
||||
EXTI->PR = EXTI_PR;
|
||||
EXTI->PR |= EXTI_PR;
|
||||
return rcvd;
|
||||
}
|
||||
|
||||
static void
|
||||
cir_ext_enable (void)
|
||||
{
|
||||
EXTI->PR = EXTI_PR;
|
||||
EXTI->PR |= EXTI_PR;
|
||||
EXTI->IMR |= EXTI_IMR;
|
||||
}
|
||||
|
||||
@@ -1033,8 +1033,8 @@ cir_init (void)
|
||||
|
||||
/* EXTIx <= Py */
|
||||
AFIO->EXTICR[AFIO_EXTICR_INDEX] = AFIO_EXTICR1_EXTIx_Py;
|
||||
EXTI->IMR = 0;
|
||||
EXTI->FTSR = EXTI_FTSR_TR;
|
||||
EXTI->IMR &= ~EXTI_IMR;
|
||||
EXTI->FTSR |= EXTI_FTSR_TR;
|
||||
|
||||
/* TIM */
|
||||
#ifdef ENABLE_RCC_APB1
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#define SIZE_1 4096
|
||||
#define SIZE_2 4096
|
||||
#define SIZE_3 (4 * 4096)
|
||||
#define SIZE_3 (5 * 4096)
|
||||
#else
|
||||
#define SIZE_0 0x0100 /* Main */
|
||||
#define SIZE_0 0x0150 /* Main */
|
||||
#define SIZE_1 0x01a0 /* CCID */
|
||||
#define SIZE_2 0x0180 /* RNG */
|
||||
#if MEMORY_SIZE >= 32
|
||||
#define SIZE_3 0x4640 /* openpgp-card */
|
||||
#elif MEMORY_SIZE >= 24
|
||||
#define SIZE_3 0x2640 /* openpgp-card */
|
||||
#else
|
||||
#define SIZE_3 0x1640 /* openpgp-card */
|
||||
#endif
|
||||
#define SIZE_4 0x0000 /* --- */
|
||||
#define SIZE_5 0x0200 /* msc */
|
||||
#define SIZE_6 0x00c0 /* timer (cir) */
|
||||
|
||||
231
src/usb-ccid.c
231
src/usb-ccid.c
@@ -1513,14 +1513,6 @@ ccid_card_change_signal (int how)
|
||||
eventflag_signal (&c->ccid_comm, EV_CARD_CHANGE);
|
||||
}
|
||||
|
||||
void
|
||||
ccid_usb_reset (int full)
|
||||
{
|
||||
struct ccid *c = &ccid;
|
||||
|
||||
eventflag_signal (&c->ccid_comm,
|
||||
full ? EV_USB_DEVICE_RESET : EV_USB_SET_INTERFACE);
|
||||
}
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
static uint8_t endp2_tx_buf[2];
|
||||
@@ -1555,13 +1547,6 @@ ccid_notify_slot_change (struct ccid *c)
|
||||
#define GPG_THREAD_TERMINATED 0xffff
|
||||
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#include <signal.h>
|
||||
#define INTR_REQ_USB SIGUSR1
|
||||
#else
|
||||
#define INTR_REQ_USB 20
|
||||
#endif
|
||||
|
||||
extern uint32_t bDeviceState;
|
||||
extern void usb_device_reset (struct usb_dev *dev);
|
||||
extern int usb_setup (struct usb_dev *dev);
|
||||
@@ -1573,7 +1558,16 @@ extern int usb_get_status_interface (struct usb_dev *dev);
|
||||
|
||||
extern int usb_get_descriptor (struct usb_dev *dev);
|
||||
|
||||
static void
|
||||
extern void random_init (void);
|
||||
extern void random_fini (void);
|
||||
|
||||
|
||||
/*
|
||||
* Return 0 for normal USB event
|
||||
* -1 for USB reset
|
||||
* 1 for SET_INTERFACE or SET_CONFIGURATION
|
||||
*/
|
||||
static int
|
||||
usb_event_handle (struct usb_dev *dev)
|
||||
{
|
||||
uint8_t ep_num;
|
||||
@@ -1582,94 +1576,119 @@ usb_event_handle (struct usb_dev *dev)
|
||||
e = usb_lld_event_handler (dev);
|
||||
ep_num = USB_EVENT_ENDP (e);
|
||||
|
||||
/* Transfer to endpoint (not control endpoint) */
|
||||
if (ep_num != 0)
|
||||
{
|
||||
if (USB_EVENT_TXRX (e))
|
||||
usb_tx_done (ep_num, USB_EVENT_LEN (e));
|
||||
else
|
||||
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
switch (USB_EVENT_ID (e))
|
||||
{
|
||||
case USB_EVENT_DEVICE_RESET:
|
||||
usb_device_reset (dev);
|
||||
break;
|
||||
|
||||
case USB_EVENT_DEVICE_ADDRESSED:
|
||||
bDeviceState = ADDRESSED;
|
||||
break;
|
||||
/* Control endpoint */
|
||||
switch (USB_EVENT_ID (e))
|
||||
{
|
||||
case USB_EVENT_DEVICE_RESET:
|
||||
usb_device_reset (dev);
|
||||
return -1;
|
||||
|
||||
case USB_EVENT_GET_DESCRIPTOR:
|
||||
if (usb_get_descriptor (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
case USB_EVENT_DEVICE_ADDRESSED:
|
||||
bDeviceState = USB_DEVICE_STATE_ADDRESSED;
|
||||
break;
|
||||
|
||||
case USB_EVENT_SET_CONFIGURATION:
|
||||
if (usb_set_configuration (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
case USB_EVENT_GET_DESCRIPTOR:
|
||||
if (usb_get_descriptor (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
|
||||
case USB_EVENT_SET_INTERFACE:
|
||||
if (usb_set_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
case USB_EVENT_SET_CONFIGURATION:
|
||||
if (usb_set_configuration (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
else
|
||||
{
|
||||
if (bDeviceState == USB_DEVICE_STATE_ADDRESSED)
|
||||
/* de-Configured */
|
||||
return -1;
|
||||
else
|
||||
/* Configured */
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_EVENT_CTRL_REQUEST:
|
||||
/* Device specific device request. */
|
||||
if (usb_setup (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
case USB_EVENT_SET_INTERFACE:
|
||||
if (usb_set_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
else
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case USB_EVENT_GET_STATUS_INTERFACE:
|
||||
if (usb_get_status_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
case USB_EVENT_CTRL_REQUEST:
|
||||
/* Device specific device request. */
|
||||
if (usb_setup (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
|
||||
case USB_EVENT_GET_INTERFACE:
|
||||
if (usb_get_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
case USB_EVENT_GET_STATUS_INTERFACE:
|
||||
if (usb_get_status_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
|
||||
case USB_EVENT_SET_FEATURE_DEVICE:
|
||||
case USB_EVENT_SET_FEATURE_ENDPOINT:
|
||||
case USB_EVENT_CLEAR_FEATURE_DEVICE:
|
||||
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
|
||||
usb_lld_ctrl_ack (dev);
|
||||
break;
|
||||
case USB_EVENT_GET_INTERFACE:
|
||||
if (usb_get_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
break;
|
||||
|
||||
case USB_EVENT_CTRL_WRITE_FINISH:
|
||||
/* Control WRITE transfer finished. */
|
||||
usb_ctrl_write_finish (dev);
|
||||
break;
|
||||
case USB_EVENT_SET_FEATURE_DEVICE:
|
||||
case USB_EVENT_SET_FEATURE_ENDPOINT:
|
||||
case USB_EVENT_CLEAR_FEATURE_DEVICE:
|
||||
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
|
||||
usb_lld_ctrl_ack (dev);
|
||||
break;
|
||||
|
||||
case USB_EVENT_OK:
|
||||
case USB_EVENT_DEVICE_SUSPEND:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case USB_EVENT_CTRL_WRITE_FINISH:
|
||||
/* Control WRITE transfer finished. */
|
||||
usb_ctrl_write_finish (dev);
|
||||
break;
|
||||
|
||||
case USB_EVENT_DEVICE_SUSPEND:
|
||||
led_blink (LED_OFF);
|
||||
chopstx_usec_wait (10); /* Make sure LED off */
|
||||
random_fini ();
|
||||
chopstx_conf_idle (2);
|
||||
bDeviceState |= USB_DEVICE_STATE_SUSPEND;
|
||||
break;
|
||||
|
||||
case USB_EVENT_DEVICE_WAKEUP:
|
||||
chopstx_conf_idle (1);
|
||||
random_init ();
|
||||
bDeviceState &= ~USB_DEVICE_STATE_SUSPEND;
|
||||
break;
|
||||
|
||||
case USB_EVENT_OK:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
poll_event_intr (uint32_t *timeout, struct eventflag *ev, chopstx_intr_t *intr)
|
||||
{
|
||||
chopstx_poll_cond_t poll_desc;
|
||||
struct chx_poll_head *pd_array[2] = {
|
||||
(struct chx_poll_head *)intr,
|
||||
(struct chx_poll_head *)&poll_desc
|
||||
};
|
||||
|
||||
eventflag_prepare_poll (ev, &poll_desc);
|
||||
chopstx_poll (timeout, 2, pd_array);
|
||||
}
|
||||
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
|
||||
};
|
||||
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
|
||||
|
||||
void *
|
||||
ccid_thread (void *arg)
|
||||
{
|
||||
chopstx_intr_t interrupt;
|
||||
uint32_t timeout;
|
||||
struct usb_dev dev;
|
||||
struct ccid *c = &ccid;
|
||||
uint32_t *timeout_p;
|
||||
|
||||
(void)arg;
|
||||
|
||||
@@ -1680,7 +1699,9 @@ ccid_thread (void *arg)
|
||||
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
|
||||
usb_event_handle (&dev); /* For old SYS < 3.0 */
|
||||
|
||||
device_reset:
|
||||
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
|
||||
|
||||
reset:
|
||||
{
|
||||
struct ep_in *epi = &endpoint_in;
|
||||
struct ep_out *epo = &endpoint_out;
|
||||
@@ -1692,50 +1713,48 @@ ccid_thread (void *arg)
|
||||
ccid_init (c, epi, epo, a);
|
||||
}
|
||||
|
||||
while (bDeviceState != CONFIGURED)
|
||||
timeout = USB_CCID_TIMEOUT;
|
||||
if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
|
||||
{
|
||||
poll_event_intr (NULL, &c->ccid_comm, &interrupt);
|
||||
if (interrupt.ready)
|
||||
usb_event_handle (&dev);
|
||||
|
||||
eventflag_get (&c->ccid_comm);
|
||||
/* Ignore event while not-configured. */
|
||||
ccid_prepare_receive (c);
|
||||
ccid_notify_slot_change (c);
|
||||
}
|
||||
|
||||
interface_reset:
|
||||
timeout = USB_CCID_TIMEOUT;
|
||||
ccid_prepare_receive (c);
|
||||
ccid_notify_slot_change (c);
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
poll_event_intr (&timeout, &c->ccid_comm, &interrupt);
|
||||
if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
|
||||
timeout_p = &timeout;
|
||||
else
|
||||
timeout_p = NULL;
|
||||
|
||||
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
|
||||
|
||||
if (interrupt.ready)
|
||||
{
|
||||
usb_event_handle (&dev);
|
||||
continue;
|
||||
}
|
||||
if (usb_event_handle (&dev) == 0)
|
||||
continue;
|
||||
|
||||
timeout = USB_CCID_TIMEOUT;
|
||||
m = eventflag_get (&c->ccid_comm);
|
||||
|
||||
if (m == EV_USB_DEVICE_RESET)
|
||||
{
|
||||
/* RESET handling:
|
||||
* (1) After DEVICE_RESET, it needs to re-start out of the loop.
|
||||
* (2) After SET_CONFIGURATION or SET_INTERFACE, the
|
||||
* endpoint is reset to RX_NAK. It needs to prepare
|
||||
* receive again.
|
||||
*/
|
||||
if (c->application)
|
||||
{
|
||||
chopstx_cancel (c->application);
|
||||
chopstx_join (c->application, NULL);
|
||||
c->application = 0;
|
||||
}
|
||||
goto device_reset;
|
||||
goto reset;
|
||||
}
|
||||
else if (m == EV_USB_SET_INTERFACE)
|
||||
/* Upon receival of SET_INTERFACE, the endpoint is reset to RX_NAK.
|
||||
* Thus, we need to prepare receive again.
|
||||
*/
|
||||
goto interface_reset;
|
||||
else if (m == EV_CARD_CHANGE)
|
||||
|
||||
timeout = USB_CCID_TIMEOUT;
|
||||
m = eventflag_get (&c->ccid_comm);
|
||||
|
||||
if (m == EV_CARD_CHANGE)
|
||||
{
|
||||
if (c->ccid_state == CCID_STATE_NOCARD)
|
||||
/* Inserted! */
|
||||
@@ -1820,7 +1839,7 @@ ccid_thread (void *arg)
|
||||
}
|
||||
|
||||
/* Loading reGNUal. */
|
||||
while (bDeviceState != UNCONNECTED)
|
||||
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
|
||||
{
|
||||
chopstx_intr_wait (&interrupt);
|
||||
usb_event_handle (&dev);
|
||||
|
||||
@@ -87,7 +87,7 @@ vcom_port_data_setup (struct usb_dev *dev)
|
||||
#include "usb-msc.h"
|
||||
#endif
|
||||
|
||||
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
|
||||
uint32_t bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
||||
|
||||
#define USB_HID_REQ_GET_REPORT 1
|
||||
#define USB_HID_REQ_GET_IDLE 2
|
||||
@@ -218,8 +218,7 @@ usb_device_reset (struct usb_dev *dev)
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (dev, i, 1);
|
||||
|
||||
bDeviceState = ATTACHED;
|
||||
ccid_usb_reset (1);
|
||||
bDeviceState = USB_DEVICE_STATE_DEFAULT;
|
||||
}
|
||||
|
||||
#define USB_CCID_REQ_ABORT 0x01
|
||||
@@ -414,7 +413,7 @@ usb_ctrl_write_finish (struct usb_dev *dev)
|
||||
if (*ccid_state_p != CCID_STATE_EXITED)
|
||||
return;
|
||||
|
||||
bDeviceState = UNCONNECTED;
|
||||
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
||||
usb_lld_prepare_shutdown (); /* No further USB communication */
|
||||
led_blink (LED_GNUK_EXEC); /* Notify the main. */
|
||||
}
|
||||
@@ -476,7 +475,7 @@ usb_set_configuration (struct usb_dev *dev)
|
||||
usb_lld_set_configuration (dev, 1);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (dev, i, 0);
|
||||
bDeviceState = CONFIGURED;
|
||||
bDeviceState = USB_DEVICE_STATE_CONFIGURED;
|
||||
}
|
||||
else if (current_conf != dev->dev_req.value)
|
||||
{
|
||||
@@ -486,8 +485,7 @@ usb_set_configuration (struct usb_dev *dev)
|
||||
usb_lld_set_configuration (dev, 0);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (dev, i, 1);
|
||||
bDeviceState = ADDRESSED;
|
||||
ccid_usb_reset (1);
|
||||
bDeviceState = USB_DEVICE_STATE_ADDRESSED;
|
||||
}
|
||||
|
||||
/* Do nothing when current_conf == value */
|
||||
@@ -509,7 +507,6 @@ usb_set_interface (struct usb_dev *dev)
|
||||
else
|
||||
{
|
||||
gnuk_setup_endpoints_for_interface (dev, interface, 0);
|
||||
ccid_usb_reset (0);
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,12 +65,14 @@ static const
|
||||
uint8_t device_desc[] = {
|
||||
18, /* bLength */
|
||||
DEVICE_DESCRIPTOR, /* bDescriptorType */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0x00, 0x02, /* bcdUSB = 2.0 */
|
||||
0x00, /* bDeviceClass: 0 means deferred to interface */
|
||||
0x00, /* bDeviceSubClass */
|
||||
0x00, /* bDeviceProtocol */
|
||||
0x40, /* bMaxPacketSize0 */
|
||||
#include "usb-vid-pid-ver.c.inc"
|
||||
0x00, 0x00, /* idVendor (will be replaced) */
|
||||
0x00, 0x00, /* idProduct (will be replaced) */
|
||||
0x00, 0x00, /* bcdDevice (will be replaced) */
|
||||
1, /* Index of string descriptor describing manufacturer */
|
||||
2, /* Index of string descriptor describing product */
|
||||
3, /* Index of string descriptor describing the device's serial number */
|
||||
|
||||
@@ -8,7 +8,7 @@ Feature: command GET DATA
|
||||
|
||||
Scenario: data object extended capabilities
|
||||
When requesting extended capabilities: c0
|
||||
Then data should match: [\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
Then data should match: [\x70\x74\x75]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
|
||||
Scenario: data object algorithm attributes 1
|
||||
When requesting algorithm attributes 1: c1
|
||||
|
||||
@@ -8,7 +8,7 @@ Feature: command GET DATA
|
||||
|
||||
Scenario: data object extended capabilities
|
||||
When requesting extended capabilities: c0
|
||||
Then data should match: [\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
Then data should match: [\x70\x74\x75]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
|
||||
Scenario: data object algorithm attributes 1
|
||||
When requesting algorithm attributes 1: c1
|
||||
|
||||
@@ -8,7 +8,7 @@ Feature: command GET DATA
|
||||
|
||||
Scenario: data object extended capabilities
|
||||
When requesting extended capabilities: c0
|
||||
Then data should match: [\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
Then data should match: [\x70\x74\x75]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
|
||||
|
||||
Scenario: data object algorithm attributes 1
|
||||
When requesting algorithm attributes 1: c1
|
||||
|
||||
@@ -6,7 +6,7 @@ Gnuk Token is supported as well.
|
||||
|
||||
You need to install:
|
||||
|
||||
$ sudo apt-get install python3-pytest python3-usb
|
||||
$ sudo apt install python3-pytest python3-usb python3-cffi
|
||||
|
||||
Please run test by typing:
|
||||
|
||||
|
||||
4
tests/card_const.py
Normal file
4
tests/card_const.py
Normal file
@@ -0,0 +1,4 @@
|
||||
FACTORY_PASSPHRASE_PW1=b"123456"
|
||||
FACTORY_PASSPHRASE_PW3=b"12345678"
|
||||
KEY_ATTRIBUTES_RSA4K=b"\x01\x10\x00\x00\x20\x00"
|
||||
KEY_ATTRIBUTES_RSA2K=b"\x01\x08\x00\x00\x20\x00"
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
card_reader.py - a library for smartcard reader
|
||||
|
||||
Copyright (C) 2016 Free Software Initiative of Japan
|
||||
Copyright (C) 2016, 2017 Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -179,9 +179,11 @@ class CardReader(object):
|
||||
# TPDU reader configuration
|
||||
self.ns = 0
|
||||
self.nr = 0
|
||||
# Set PPS
|
||||
pps = b"\xFF\x11\x18\xF6"
|
||||
status, chain, ret_pps = self.ccid_send_data_block(pps)
|
||||
# For Gemalto's SmartCard Reader(s)
|
||||
if self.__dev.idVendor == 0x08E6:
|
||||
# Set PPS
|
||||
pps = b"\xFF\x11\x18\xF6"
|
||||
status, chain, ret_pps = self.ccid_send_data_block(pps)
|
||||
# Set parameters
|
||||
param = b"\x18\x10\xFF\x75\x00\xFE\x00"
|
||||
# ^--- This shoud be adapted by ATR string, see update_param_by_atr
|
||||
|
||||
21
tests/constants_for_test.py
Normal file
21
tests/constants_for_test.py
Normal file
@@ -0,0 +1,21 @@
|
||||
PW1_TEST0=b"another user pass phrase"
|
||||
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
|
||||
PW1_TEST2=b"new user pass phrase"
|
||||
PW1_TEST3=b"next user pass phrase"
|
||||
PW1_TEST4=b"another user pass phrase"
|
||||
PW3_TEST0=b"admin pass phrase"
|
||||
PW3_TEST1=b"another admin pass phrase"
|
||||
|
||||
RESETCODE_TEST=b"example reset code 000"
|
||||
|
||||
PLAIN_TEXT0=b"This is a test message."
|
||||
PLAIN_TEXT1=b"RSA decryption is as easy as pie."
|
||||
PLAIN_TEXT2=b"This is another test message.\nMultiple lines.\n"
|
||||
|
||||
KDF_FULL=b"\x81\x01\x03\x82\x01\x08\x83\x04\x00\xC8\x00\x00\x84\x08\xC5\x1F\xB7\xF9\xEE\xF3\xD3\xE8\x85\x08\x75\x1A\x2A\x70\xC0\x7C\xB1\x81\x86\x08\xE6\xB2\x4E\x0C\xEE\x92\xAB\x93\x87\x20\xA2\x08\x89\x16\x09\xD3\xE4\x3D\x48\xAC\x5B\xAA\xBD\xE9\xF1\xB8\xD2\xFC\xD8\x3C\x5F\x35\xCB\xEB\xDA\xFB\x75\x92\x88\xC6\x8B\x2D\x88\x20\xF1\x34\x00\xD2\x5F\x28\x57\xE6\x66\xAA\x9E\xBB\xE0\x7C\x57\x4B\x84\x8B\xD6\x52\x14\xE7\x31\x99\x1A\x3D\x2D\xAA\x3F\x8A\x7F\x03"
|
||||
KDF_FULL_HASH_PW1=b"\xA2\x08\x89\x16\x09\xD3\xE4\x3D\x48\xAC\x5B\xAA\xBD\xE9\xF1\xB8\xD2\xFC\xD8\x3C\x5F\x35\xCB\xEB\xDA\xFB\x75\x92\x88\xC6\x8B\x2D"
|
||||
KDF_FULL_HASH_PW3=b"\xF1\x34\x00\xD2\x5F\x28\x57\xE6\x66\xAA\x9E\xBB\xE0\x7C\x57\x4B\x84\x8B\xD6\x52\x14\xE7\x31\x99\x1A\x3D\x2D\xAA\x3F\x8A\x7F\x03"
|
||||
|
||||
KDF_SINGLE=b"\x81\x01\x03\x82\x01\x08\x83\x04\x00\xC8\x00\x00\x84\x08\x69\x9E\xDA\xAD\x5A\x72\x5F\x4C\x87\x20\x12\xDB\x16\x9A\x9D\x1A\x56\xCA\x2B\x9E\x96\x7F\xC4\xDA\xB8\xAE\x70\x41\x51\x8E\x3C\xEF\x49\x7E\xC2\x56\x60\x32\x2F\x4C\x03\x07\x88\x20\x1C\x93\x99\xC3\x6D\x49\x92\x27\x54\x39\x76\x7E\xA7\xB4\xEE\xE5\x16\xDA\x92\xC0\x0E\xF4\x74\xBD\x01\x28\x0F\x0C\x30\x45\x4B\xBB"
|
||||
KDF_SINGLE_HASH_PW1=b"\x12\xDB\x16\x9A\x9D\x1A\x56\xCA\x2B\x9E\x96\x7F\xC4\xDA\xB8\xAE\x70\x41\x51\x8E\x3C\xEF\x49\x7E\xC2\x56\x60\x32\x2F\x4C\x03\x07"
|
||||
KDF_SINGLE_HASH_PW3=b"\x1C\x93\x99\xC3\x6D\x49\x92\x27\x54\x39\x76\x7E\xA7\xB4\xEE\xE5\x16\xDA\x92\xC0\x0E\xF4\x74\xBD\x01\x28\x0F\x0C\x30\x45\x4B\xBB"
|
||||
1
tests/kdf_calc.py
Symbolic link
1
tests/kdf_calc.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../tool/kdf_calc.py
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
openpgp_card.py - a library for OpenPGP card
|
||||
|
||||
Copyright (C) 2011, 2012, 2013, 2015, 2016
|
||||
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018
|
||||
Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
@@ -21,7 +21,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from struct import pack
|
||||
from struct import pack, unpack
|
||||
from kdf_calc import kdf_calc
|
||||
|
||||
def iso7816_compose(ins, p1, p2, data, cls=0x00, le=None):
|
||||
data_len = len(data)
|
||||
@@ -54,6 +55,83 @@ class OpenPGP_Card(object):
|
||||
"""
|
||||
|
||||
self.__reader = reader
|
||||
self.__kdf_iters = None
|
||||
self.__kdf_salt_user = None
|
||||
self.__kdf_salt_reset = None
|
||||
self.__kdf_salt_admin = None
|
||||
|
||||
def configure_with_kdf(self):
|
||||
kdf_data = self.cmd_get_data(0x00, 0xf9)
|
||||
if kdf_data != b"":
|
||||
algo, subalgo, iters, salt_user, salt_reset, salt_admin, hash_user, hash_admin = parse_kdf_data(kdf_data)
|
||||
self.__kdf_iters = iters
|
||||
self.__kdf_salt_user = salt_user
|
||||
self.__kdf_salt_reset = salt_reset
|
||||
self.__kdf_salt_admin = salt_admin
|
||||
else:
|
||||
self.__kdf_iters = None
|
||||
self.__kdf_salt_user = None
|
||||
self.__kdf_salt_reset = None
|
||||
self.__kdf_salt_admin = None
|
||||
|
||||
# Higher layer VERIFY possibly using KDF Data Object
|
||||
def verify(self, who, passwd):
|
||||
if self.__kdf_iters:
|
||||
salt = self.__kdf_salt_user
|
||||
if who == 3 and self.__kdf_salt_admin:
|
||||
salt = self.__kdf_salt_admin
|
||||
pw_hash = kdf_calc(passwd, salt, self.__kdf_iters)
|
||||
return self.cmd_verify(who, pw_hash)
|
||||
else:
|
||||
return self.cmd_verify(who, passwd)
|
||||
|
||||
# Higher layer CHANGE_PASSWD possibly using KDF Data Object
|
||||
def change_passwd(self, who, passwd_old, passwd_new):
|
||||
if self.__kdf_iters:
|
||||
salt = self.__kdf_salt_user
|
||||
if who == 3 and self.__kdf_salt_admin:
|
||||
salt = self.__kdf_salt_admin
|
||||
hash_old = kdf_calc(passwd_old, salt, self.__kdf_iters)
|
||||
if passwd_new:
|
||||
hash_new = kdf_calc(passwd_new, salt, self.__kdf_iters)
|
||||
else:
|
||||
hash_new = b""
|
||||
return self.cmd_change_reference_data(who, hash_old + hash_new)
|
||||
else:
|
||||
if not passwd_new:
|
||||
passwd_new = b""
|
||||
return self.cmd_change_reference_data(who, passwd_old + passwd_new)
|
||||
|
||||
# Higher layer SETUP_RESET_CODE possibly using KDF Data Object
|
||||
def setup_reset_code(self, resetcode):
|
||||
if self.__kdf_iters:
|
||||
salt = self.__kdf_salt_user
|
||||
if self.__kdf_salt_reset:
|
||||
salt = self.__kdf_salt_user
|
||||
reset_hash = kdf_calc(resetcode, salt, self.__kdf_iters)
|
||||
return self.cmd_put_data(0x00, 0xd3, reset_hash)
|
||||
else:
|
||||
return self.cmd_put_data(0x00, 0xd3, resetcode)
|
||||
|
||||
# Higher layer reset passwd possibly using KDF Data Object
|
||||
def reset_passwd_by_resetcode(self, resetcode, pw1):
|
||||
if self.__kdf_iters:
|
||||
salt = self.__kdf_salt_user
|
||||
if self.__kdf_salt_reset:
|
||||
salt = self.__kdf_salt_user
|
||||
reset_hash = kdf_calc(resetcode, salt, self.__kdf_iters)
|
||||
pw1_hash = kdf_calc(pw1, self.__kdf_salt_user, self.__kdf_iters)
|
||||
return self.cmd_reset_retry_counter(0, 0x81, reset_hash + pw1_hash)
|
||||
else:
|
||||
return self.cmd_reset_retry_counter(0, 0x81, resetcode + pw1)
|
||||
|
||||
# Higher layer reset passwd possibly using KDF Data Object
|
||||
def reset_passwd_by_admin(self, pw1):
|
||||
if self.__kdf_iters:
|
||||
pw1_hash = kdf_calc(pw1, self.__kdf_salt_user, self.__kdf_iters)
|
||||
return self.cmd_reset_retry_counter(2, 0x81, pw1_hash)
|
||||
else:
|
||||
return self.cmd_reset_retry_counter(2, 0x81, pw1)
|
||||
|
||||
def cmd_get_response(self, expected_len):
|
||||
result = b""
|
||||
@@ -336,3 +414,48 @@ class OpenPGP_Card(object):
|
||||
raise ValueError(sw)
|
||||
if not (sw[0] == 0x90 and sw[1] == 0x00):
|
||||
raise ValueError("%02x%02x" % (sw[0], sw[1]))
|
||||
|
||||
def parse_kdf_data(kdf_data):
|
||||
if len(kdf_data) == 90:
|
||||
single_salt = True
|
||||
elif len(kdf_data) == 110:
|
||||
single_salt = False
|
||||
else:
|
||||
raise ValueError("length does not much", kdf_data)
|
||||
|
||||
if kdf_data[0:2] != b'\x81\x01':
|
||||
raise ValueError("data does not much")
|
||||
algo = kdf_data[2]
|
||||
if kdf_data[3:5] != b'\x82\x01':
|
||||
raise ValueError("data does not much")
|
||||
subalgo = kdf_data[5]
|
||||
if kdf_data[6:8] != b'\x83\x04':
|
||||
raise ValueError("data does not much")
|
||||
iters = unpack(">I", kdf_data[8:12])[0]
|
||||
if kdf_data[12:14] != b'\x84\x08':
|
||||
raise ValueError("data does not much")
|
||||
salt = kdf_data[14:22]
|
||||
if single_salt:
|
||||
salt_reset = None
|
||||
salt_admin = None
|
||||
if kdf_data[22:24] != b'\x87\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_user = kdf_data[24:56]
|
||||
if kdf_data[56:58] != b'\x88\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_admin = kdf_data[58:90]
|
||||
else:
|
||||
if kdf_data[22:24] != b'\x85\x08':
|
||||
raise ValueError("data does not much")
|
||||
salt_reset = kdf_data[24:32]
|
||||
if kdf_data[32:34] != b'\x86\x08':
|
||||
raise ValueError("data does not much")
|
||||
salt_admin = kdf_data[34:42]
|
||||
if kdf_data[42:44] != b'\x87\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_user = kdf_data[44:76]
|
||||
if kdf_data[76:78] != b'\x88\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_admin = kdf_data[78:110]
|
||||
return ( algo, subalgo, iters, salt, salt_reset, salt_admin,
|
||||
hash_user, hash_admin )
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_empty_card.py - test empty card
|
||||
|
||||
Copyright (C) 2016 g10 Code GmbH
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -24,13 +24,11 @@ from binascii import hexlify
|
||||
from re import match, DOTALL
|
||||
from struct import pack
|
||||
from util import *
|
||||
from card_const import *
|
||||
import pytest
|
||||
|
||||
EMPTY_60=bytes(60)
|
||||
|
||||
FACTORY_PASSPHRASE_PW1=b"123456"
|
||||
FACTORY_PASSPHRASE_PW3=b"12345678"
|
||||
|
||||
def test_login(card):
|
||||
login = get_data_object(card, 0x5e)
|
||||
assert check_null(login)
|
||||
@@ -146,7 +144,7 @@ def test_historical_bytes(card):
|
||||
|
||||
def test_extended_capabilities(card):
|
||||
a = get_data_object(card, 0xc0)
|
||||
assert a == None or match(b'[\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00', a)
|
||||
assert a == None or match(b'[\x70\x74\x75]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00', a)
|
||||
|
||||
def test_algorithm_attributes_1(card):
|
||||
a = get_data_object(card, 0xc1)
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_personalize_card.py - test personalizing card
|
||||
|
||||
Copyright (C) 2016 g10 Code GmbH
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -24,25 +24,15 @@ from struct import pack
|
||||
from re import match, DOTALL
|
||||
from util import *
|
||||
import rsa_keys
|
||||
|
||||
FACTORY_PASSPHRASE_PW1=b"123456"
|
||||
FACTORY_PASSPHRASE_PW3=b"12345678"
|
||||
PW1_TEST0=b"another user pass phrase"
|
||||
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
|
||||
PW1_TEST2=b"new user pass phrase"
|
||||
PW1_TEST3=b"next user pass phrase"
|
||||
PW1_TEST4=b"another user pass phrase"
|
||||
PW3_TEST0=b"admin pass phrase"
|
||||
PW3_TEST1=b"another admin pass phrase"
|
||||
|
||||
RESETCODE_TEST=b"example reset code 000"
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_setup_pw3_0(card):
|
||||
r = card.cmd_change_reference_data(3, FACTORY_PASSPHRASE_PW3 + PW3_TEST0)
|
||||
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, PW3_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_0(card):
|
||||
v = card.cmd_verify(3, PW3_TEST0)
|
||||
v = card.verify(3, PW3_TEST0)
|
||||
assert v
|
||||
|
||||
def test_login_put(card):
|
||||
@@ -164,89 +154,85 @@ def test_public_key_3(card):
|
||||
assert rsa_keys.key[2][0] == pk[9:9+256]
|
||||
|
||||
def test_setup_pw1_0(card):
|
||||
r = card.cmd_change_reference_data(1, FACTORY_PASSPHRASE_PW1 + PW1_TEST0)
|
||||
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_0(card):
|
||||
v = card.cmd_verify(1, PW1_TEST0)
|
||||
v = card.verify(1, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_0_2(card):
|
||||
v = card.cmd_verify(2, PW1_TEST0)
|
||||
v = card.verify(2, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_1(card):
|
||||
r = card.cmd_change_reference_data(1, PW1_TEST0 + PW1_TEST1)
|
||||
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_1(card):
|
||||
v = card.cmd_verify(1, PW1_TEST1)
|
||||
v = card.verify(1, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_1_2(card):
|
||||
v = card.cmd_verify(2, PW1_TEST1)
|
||||
v = card.verify(2, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_setup_reset_code(card):
|
||||
r = card.cmd_put_data(0x00, 0xd3, RESETCODE_TEST)
|
||||
r = card.setup_reset_code(RESETCODE_TEST)
|
||||
assert r
|
||||
|
||||
def test_reset_code(card):
|
||||
r = card.cmd_reset_retry_counter(0, 0x81, RESETCODE_TEST + PW1_TEST2)
|
||||
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.cmd_verify(1, PW1_TEST2)
|
||||
v = card.verify(1, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_2_2(card):
|
||||
v = card.cmd_verify(2, PW1_TEST2)
|
||||
v = card.verify(2, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_setup_pw3_1(card):
|
||||
r = card.cmd_change_reference_data(3, PW3_TEST0 + PW3_TEST1)
|
||||
r = card.change_passwd(3, PW3_TEST0, PW3_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_1(card):
|
||||
v = card.cmd_verify(3, PW3_TEST1)
|
||||
v = card.verify(3, PW3_TEST1)
|
||||
assert v
|
||||
|
||||
def test_reset_userpass_admin(card):
|
||||
r = card.cmd_reset_retry_counter(2, 0x81, PW1_TEST3)
|
||||
r = card.reset_passwd_by_admin(PW1_TEST3)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_3(card):
|
||||
v = card.cmd_verify(1, PW1_TEST3)
|
||||
v = card.verify(1, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_3_2(card):
|
||||
v = card.cmd_verify(2, PW1_TEST3)
|
||||
v = card.verify(2, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_4(card):
|
||||
r = card.cmd_change_reference_data(1, PW1_TEST3 + PW1_TEST4)
|
||||
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_4(card):
|
||||
v = card.cmd_verify(1, PW1_TEST4)
|
||||
v = card.verify(1, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_4_2(card):
|
||||
v = card.cmd_verify(2, PW1_TEST4)
|
||||
v = card.verify(2, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_setup_pw3_2(card):
|
||||
r = card.cmd_change_reference_data(3, PW3_TEST1 + PW3_TEST0)
|
||||
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_2(card):
|
||||
v = card.cmd_verify(3, PW3_TEST0)
|
||||
v = card.verify(3, PW3_TEST0)
|
||||
assert v
|
||||
|
||||
PLAIN_TEXT0=b"This is a test message."
|
||||
PLAIN_TEXT1=b"RSA decryption is as easy as pie."
|
||||
PLAIN_TEXT2=b"This is another test message.\nMultiple lines.\n"
|
||||
|
||||
def test_sign_0(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_personalize_reset_card.py - test resetting personalization of card
|
||||
test_personalize_reset.py - test resetting personalization of card
|
||||
|
||||
Copyright (C) 2016 g10 Code GmbH
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -24,18 +24,8 @@ from struct import pack
|
||||
from re import match, DOTALL
|
||||
from util import *
|
||||
import rsa_keys
|
||||
|
||||
FACTORY_PASSPHRASE_PW1=b"123456"
|
||||
FACTORY_PASSPHRASE_PW3=b"12345678"
|
||||
PW1_TEST0=b"another user pass phrase"
|
||||
PW1_TEST1=b"PASSPHRASE SHOULD BE LONG"
|
||||
PW1_TEST2=b"new user pass phrase"
|
||||
PW1_TEST3=b"next user pass phrase"
|
||||
PW1_TEST4=b"another user pass phrase"
|
||||
PW3_TEST0=b"admin pass phrase"
|
||||
PW3_TEST1=b"another admin pass phrase"
|
||||
|
||||
RESETCODE_TEST=b"example reset code 000"
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_login_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5e, b"")
|
||||
@@ -67,25 +57,25 @@ def test_pw1_status_put(card):
|
||||
assert r
|
||||
|
||||
def test_setup_pw3_0(card):
|
||||
r = card.cmd_change_reference_data(3, PW3_TEST0 + FACTORY_PASSPHRASE_PW3)
|
||||
r = card.change_passwd(3, PW3_TEST0, FACTORY_PASSPHRASE_PW3)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_0(card):
|
||||
v = card.cmd_verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_0(card):
|
||||
r = card.cmd_change_reference_data(1, PW1_TEST4 + FACTORY_PASSPHRASE_PW1)
|
||||
r = card.change_passwd(1, PW1_TEST4, FACTORY_PASSPHRASE_PW1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_0(card):
|
||||
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_0_2(card):
|
||||
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_setup_reset_code(card):
|
||||
def test_delete_reset_code(card):
|
||||
r = card.cmd_put_data(0x00, 0xd3, b"")
|
||||
assert r
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_remove_keys_card.py - test removing keys on card
|
||||
test_remove_keys.py - test removing keys on card
|
||||
|
||||
Copyright (C) 2016 g10 Code GmbH
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -22,22 +22,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Remove a key material on card by changing algorithm attributes of the key
|
||||
|
||||
KEY_ATTRIBUTES_RSA4K=b"\x01\x10\x00\x00\x20\x00"
|
||||
KEY_ATTRIBUTES_RSA2K=b"\x01\x08\x00\x00\x20\x00"
|
||||
from card_const import *
|
||||
|
||||
def test_rsa_import_key_1(card):
|
||||
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_import_key_2(card):
|
||||
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_import_key_3(card):
|
||||
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)
|
||||
41
tests/test_004_reset_pw3.py
Normal file
41
tests/test_004_reset_pw3.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
test_004_reset_pw3.py - test resetting pw3
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from card_const import *
|
||||
|
||||
# Gnuk specific feature of clear PW3
|
||||
def test_setup_pw3_null(card):
|
||||
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, None)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
# Check PW1 again to see the possiblity of admin-less mode
|
||||
def test_verify_pw1(card):
|
||||
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
310
tests/test_005_personalize_admin_less.py
Normal file
310
tests/test_005_personalize_admin_less.py
Normal file
@@ -0,0 +1,310 @@
|
||||
"""
|
||||
test_005_personalize_admin_less.py - test admin-less mode
|
||||
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from struct import pack
|
||||
from re import match, DOTALL
|
||||
from util import *
|
||||
import rsa_keys
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_verify_pw3_0(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_rsa_import_key_1(card):
|
||||
t = rsa_keys.build_privkey_template(1, 0)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_rsa_import_key_2(card):
|
||||
t = rsa_keys.build_privkey_template(2, 1)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_rsa_import_key_3(card):
|
||||
t = rsa_keys.build_privkey_template(3, 2)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_1_put(card):
|
||||
fpr1 = rsa_keys.fpr[0]
|
||||
r = card.cmd_put_data(0x00, 0xc7, fpr1)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_2_put(card):
|
||||
fpr2 = rsa_keys.fpr[1]
|
||||
r = card.cmd_put_data(0x00, 0xc8, fpr2)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_3_put(card):
|
||||
fpr3 = rsa_keys.fpr[2]
|
||||
r = card.cmd_put_data(0x00, 0xc9, fpr3)
|
||||
assert r
|
||||
|
||||
def test_timestamp_1_put(card):
|
||||
timestamp1 = rsa_keys.timestamp[0]
|
||||
r = card.cmd_put_data(0x00, 0xce, timestamp1)
|
||||
assert r
|
||||
|
||||
def test_timestamp_2_put(card):
|
||||
timestamp2 = rsa_keys.timestamp[1]
|
||||
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
|
||||
assert r
|
||||
|
||||
def test_timestamp_3_put(card):
|
||||
timestamp3 = rsa_keys.timestamp[2]
|
||||
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
|
||||
assert r
|
||||
|
||||
def test_ds_counter_0(card):
|
||||
c = get_data_object(card, 0x7a)
|
||||
assert c == b'\x93\x03\x00\x00\x00'
|
||||
|
||||
def test_pw1_status(card):
|
||||
s = get_data_object(card, 0xc4)
|
||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||
|
||||
def test_app_data(card):
|
||||
app_data = get_data_object(card, 0x6e)
|
||||
hist_len = app_data[20]
|
||||
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
|
||||
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
|
||||
app_data[18:18+2] == b"\x5f\x52"
|
||||
|
||||
def test_public_key_1(card):
|
||||
pk = card.cmd_get_public_key(1)
|
||||
assert rsa_keys.key[0][0] == pk[9:9+256]
|
||||
|
||||
def test_public_key_2(card):
|
||||
pk = card.cmd_get_public_key(2)
|
||||
assert rsa_keys.key[1][0] == pk[9:9+256]
|
||||
|
||||
def test_public_key_3(card):
|
||||
pk = card.cmd_get_public_key(3)
|
||||
assert rsa_keys.key[2][0] == pk[9:9+256]
|
||||
|
||||
# Changing PW1 to admin-less mode
|
||||
|
||||
def test_setup_pw1_0(card):
|
||||
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
||||
assert r
|
||||
|
||||
# Now, it's admin-less mode, auth-status admin cleared
|
||||
|
||||
def test_verify_pw3_fail_1(card):
|
||||
try:
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
except ValueError as e:
|
||||
v = False
|
||||
assert not v
|
||||
|
||||
def test_verify_pw1_0(card):
|
||||
v = card.verify(1, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_0_2(card):
|
||||
v = card.verify(2, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_1(card):
|
||||
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_1(card):
|
||||
v = card.verify(1, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_1_2(card):
|
||||
v = card.verify(2, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw3_admin_less_1(card):
|
||||
v = card.verify(3, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_setup_reset_code(card):
|
||||
r = card.setup_reset_code(RESETCODE_TEST)
|
||||
assert r
|
||||
|
||||
def test_reset_code(card):
|
||||
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
||||
assert r
|
||||
|
||||
# Changing PW1, auth status for admin cleared
|
||||
def test_login_put_fail(card):
|
||||
try:
|
||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||
except ValueError as e:
|
||||
r = e.args[0]
|
||||
assert r == "6982"
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.verify(1, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_2_2(card):
|
||||
v = card.verify(2, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_verify_pw3_fail_2(card):
|
||||
try:
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
except ValueError as e:
|
||||
v = e.args[0]
|
||||
assert v == "6982"
|
||||
|
||||
def test_sign_0(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||
sig = rsa_keys.compute_signature(0, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
# Since forcesig setting, failed
|
||||
def test_sign_1(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||
try:
|
||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||
except ValueError as e:
|
||||
r = e.args[0]
|
||||
assert r == "6982"
|
||||
|
||||
def test_ds_counter_1(card):
|
||||
c = get_data_object(card, 0x7a)
|
||||
assert c == b'\x93\x03\x00\x00\x01'
|
||||
|
||||
def test_sign_auth_0(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||
r = card.cmd_internal_authenticate(digestinfo)
|
||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_sign_auth_1(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||
r = card.cmd_internal_authenticate(digestinfo)
|
||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_decrypt_0(card):
|
||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == PLAIN_TEXT0
|
||||
|
||||
def test_decrypt_1(card):
|
||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == PLAIN_TEXT1
|
||||
|
||||
def test_verify_pw3_admin_less_2(card):
|
||||
v = card.verify(3, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_login_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||
assert r
|
||||
|
||||
def test_name_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
|
||||
assert r
|
||||
|
||||
def test_lang_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
|
||||
assert r
|
||||
|
||||
def test_sex_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x35, b"1")
|
||||
assert r
|
||||
|
||||
def test_url_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
|
||||
assert r
|
||||
|
||||
def test_pw1_status_put(card):
|
||||
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
|
||||
assert r
|
||||
|
||||
def test_login(card):
|
||||
login = get_data_object(card, 0x5e)
|
||||
assert login == b"gpg_user"
|
||||
|
||||
def test_name_lang_sex(card):
|
||||
name = b"GnuPG User"
|
||||
lang = b"ja"
|
||||
sex = b"1"
|
||||
expected = b'\x5b' + pack('B', len(name)) + name \
|
||||
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||
name_lang_sex = get_data_object(card, 0x65)
|
||||
assert name_lang_sex == expected
|
||||
|
||||
def test_url(card):
|
||||
url = get_data_object(card, 0x5f50)
|
||||
assert url == b"https://www.fsij.org/gnuk/"
|
||||
|
||||
def test_pw1_status(card):
|
||||
s = get_data_object(card, 0xc4)
|
||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||
|
||||
# Setting PW3, changed to admin-full mode
|
||||
|
||||
def test_setup_pw3_1(card):
|
||||
r = card.change_passwd(3, PW1_TEST2, PW3_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_1(card):
|
||||
v = card.verify(3, PW3_TEST1)
|
||||
assert v
|
||||
|
||||
def test_reset_userpass_admin(card):
|
||||
r = card.reset_passwd_by_admin(PW1_TEST3)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_3(card):
|
||||
v = card.verify(1, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_3_2(card):
|
||||
v = card.verify(2, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_4(card):
|
||||
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_4(card):
|
||||
v = card.verify(1, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_4_2(card):
|
||||
v = card.verify(2, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_setup_pw3_2(card):
|
||||
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_2(card):
|
||||
v = card.verify(3, PW3_TEST0)
|
||||
assert v
|
||||
1
tests/test_006_personalize_reset.py
Symbolic link
1
tests/test_006_personalize_reset.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_002_personalize_reset.py
|
||||
1
tests/test_007_remove_keys.py
Symbolic link
1
tests/test_007_remove_keys.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_003_remove_keys.py
|
||||
1
tests/test_008_reset_pw3.py
Symbolic link
1
tests/test_008_reset_pw3.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_004_reset_pw3.py
|
||||
83
tests/test_009_keygen.py
Normal file
83
tests/test_009_keygen.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
test_005_keygen.py - test key generation
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from binascii import hexlify
|
||||
import rsa_keys
|
||||
from card_const import *
|
||||
|
||||
def test_keygen_1(card):
|
||||
pk = card.cmd_genkey(1)
|
||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||
r = card.cmd_put_data(0x00, 0xc7, fpr_date[0])
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xce, fpr_date[1])
|
||||
assert r
|
||||
|
||||
def test_keygen_2(card):
|
||||
pk = card.cmd_genkey(2)
|
||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||
r = card.cmd_put_data(0x00, 0xc8, fpr_date[0])
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xcf, fpr_date[1])
|
||||
assert r
|
||||
|
||||
def test_keygen_3(card):
|
||||
pk = card.cmd_genkey(3)
|
||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||
r = card.cmd_put_data(0x00, 0xc9, fpr_date[0])
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xd0, fpr_date[1])
|
||||
assert r
|
||||
|
||||
def test_verify_pw1(card):
|
||||
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_signature_sigkey(card):
|
||||
msg = b"Sign me please"
|
||||
pk = card.cmd_get_public_key(1)
|
||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
||||
digest = rsa_keys.compute_digestinfo(msg)
|
||||
sig = int(hexlify(card.cmd_pso(0x9e, 0x9a, digest)),16)
|
||||
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_decryption(card):
|
||||
msg = b"encrypt me please"
|
||||
pk = card.cmd_get_public_key(2)
|
||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
||||
ciphertext = rsa_keys.encrypt_with_pubkey(pk_info, msg)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == msg
|
||||
|
||||
def test_signature_authkey(card):
|
||||
msg = b"Sign me please to authenticate"
|
||||
pk = card.cmd_get_public_key(3)
|
||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
||||
digest = rsa_keys.compute_digestinfo(msg)
|
||||
sig = int(hexlify(card.cmd_internal_authenticate(digest)),16)
|
||||
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
||||
assert r
|
||||
1
tests/test_010_remove_keys.py
Symbolic link
1
tests/test_010_remove_keys.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_003_remove_keys.py
|
||||
34
tests/test_011_kdf_full.py
Normal file
34
tests/test_011_kdf_full.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
test_007_kdf_full.py - test KDF data object
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_verify_pw3(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_kdf_put_full(card):
|
||||
r = card.cmd_put_data(0x00, 0xf9, KDF_FULL)
|
||||
if r:
|
||||
card.configure_with_kdf()
|
||||
assert r
|
||||
1
tests/test_012_personalize_card.py
Symbolic link
1
tests/test_012_personalize_card.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_001_personalize_card.py
|
||||
1
tests/test_013_personalize_reset.py
Symbolic link
1
tests/test_013_personalize_reset.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_002_personalize_reset.py
|
||||
1
tests/test_014_remove_keys.py
Symbolic link
1
tests/test_014_remove_keys.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_003_remove_keys.py
|
||||
1
tests/test_015_reset_pw3.py
Symbolic link
1
tests/test_015_reset_pw3.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_004_reset_pw3.py
|
||||
34
tests/test_016_kdf_single.py
Normal file
34
tests/test_016_kdf_single.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
test_012_kdf_single.py - test KDF data object
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_verify_pw3(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_kdf_put_single(card):
|
||||
r = card.cmd_put_data(0x00, 0xf9, KDF_SINGLE)
|
||||
if r:
|
||||
card.configure_with_kdf()
|
||||
assert r
|
||||
1
tests/test_017_personalize_card.py
Symbolic link
1
tests/test_017_personalize_card.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_001_personalize_card.py
|
||||
1
tests/test_018_personalize_reset.py
Symbolic link
1
tests/test_018_personalize_reset.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_002_personalize_reset.py
|
||||
1
tests/test_019_remove_keys.py
Symbolic link
1
tests/test_019_remove_keys.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_003_remove_keys.py
|
||||
1
tests/test_020_reset_pw3.py
Symbolic link
1
tests/test_020_reset_pw3.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_004_reset_pw3.py
|
||||
1
tests/test_021_personalize_admin_less.py
Symbolic link
1
tests/test_021_personalize_admin_less.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_005_personalize_admin_less.py
|
||||
1
tests/test_022_personalize_reset.py
Symbolic link
1
tests/test_022_personalize_reset.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_002_personalize_reset.py
|
||||
1
tests/test_023_remove_keys.py
Symbolic link
1
tests/test_023_remove_keys.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_003_remove_keys.py
|
||||
1
tests/test_024_reset_pw3.py
Symbolic link
1
tests/test_024_reset_pw3.py
Symbolic link
@@ -0,0 +1 @@
|
||||
test_004_reset_pw3.py
|
||||
38
tests/test_025_kdf_none.py
Normal file
38
tests/test_025_kdf_none.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""
|
||||
test_017_kdf_none.py - test KDF data object
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_verify_pw3(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_kdf_put_none(card):
|
||||
r = card.cmd_put_data(0x00, 0xf9, b"")
|
||||
if r:
|
||||
card.configure_with_kdf()
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_1(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
@@ -3,7 +3,7 @@
|
||||
"""
|
||||
gnuk_remove_keys_libusb.py - a tool to remove keys in Gnuk Token
|
||||
|
||||
Copyright (C) 2012 Free Software Initiative of Japan
|
||||
Copyright (C) 2012, 2018 Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -24,7 +24,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys, os
|
||||
|
||||
from gnuk_token import *
|
||||
from gnuk_token import gnuk_devices, gnuk_token, parse_kdf_data
|
||||
from kdf_calc import kdf_calc
|
||||
|
||||
# Assume only single CCID device is attached to computer and it's Gnuk Token
|
||||
|
||||
@@ -42,13 +43,28 @@ def main(passwd):
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if not gnuk:
|
||||
raise ValueError("No ICC present")
|
||||
if gnuk.icc_get_status() == 2:
|
||||
raise ValueError("No ICC present")
|
||||
elif gnuk.icc_get_status() == 1:
|
||||
gnuk.icc_power_on()
|
||||
gnuk.cmd_select_openpgp()
|
||||
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8'))
|
||||
gnuk.cmd_select_openpgp()
|
||||
# Compute passwd data
|
||||
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tostring()
|
||||
if kdf_data == b"":
|
||||
passwd_data = passwd.encode('UTF-8')
|
||||
else:
|
||||
algo, subalgo, iters, salt_user, salt_reset, salt_admin, \
|
||||
hash_user, hash_admin = parse_kdf_data(kdf_data)
|
||||
if salt_admin:
|
||||
salt = salt_admin
|
||||
else:
|
||||
salt = salt_user
|
||||
passwd_data = kdf_calc(passwd, salt, iters)
|
||||
# And authenticate with the passwd data
|
||||
gnuk.cmd_verify(BY_ADMIN, passwd_data)
|
||||
# Do remove keys and related data objects
|
||||
gnuk.cmd_put_data_remove(0x00, 0xc7) # FP_SIG
|
||||
gnuk.cmd_put_data_remove(0x00, 0xce) # KGTIME_SIG
|
||||
gnuk.cmd_put_data_key_import_remove(1)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
gnuk_token.py - a library for Gnuk Token
|
||||
|
||||
Copyright (C) 2011, 2012, 2013, 2015, 2017
|
||||
Copyright (C) 2011, 2012, 2013, 2015, 2017, 2018
|
||||
Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
@@ -635,3 +635,48 @@ def UNSIGNED(n):
|
||||
def crc32(bytestr):
|
||||
crc = binascii.crc32(bytestr)
|
||||
return UNSIGNED(crc)
|
||||
|
||||
def parse_kdf_data(kdf_data):
|
||||
if len(kdf_data) == 90:
|
||||
single_salt = True
|
||||
elif len(kdf_data) == 110:
|
||||
single_salt = False
|
||||
else:
|
||||
raise ValueError("length does not much", kdf_data)
|
||||
|
||||
if kdf_data[0:2] != b'\x81\x01':
|
||||
raise ValueError("data does not much")
|
||||
algo = kdf_data[2]
|
||||
if kdf_data[3:5] != b'\x82\x01':
|
||||
raise ValueError("data does not much")
|
||||
subalgo = kdf_data[5]
|
||||
if kdf_data[6:8] != b'\x83\x04':
|
||||
raise ValueError("data does not much")
|
||||
iters = unpack(">I", kdf_data[8:12])[0]
|
||||
if kdf_data[12:14] != b'\x84\x08':
|
||||
raise ValueError("data does not much")
|
||||
salt = kdf_data[14:22]
|
||||
if single_salt:
|
||||
salt_reset = None
|
||||
salt_admin = None
|
||||
if kdf_data[22:24] != b'\x87\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_user = kdf_data[24:56]
|
||||
if kdf_data[56:58] != b'\x88\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_admin = kdf_data[58:90]
|
||||
else:
|
||||
if kdf_data[22:24] != b'\x85\x08':
|
||||
raise ValueError("data does not much")
|
||||
salt_reset = kdf_data[24:32]
|
||||
if kdf_data[32:34] != b'\x86\x08':
|
||||
raise ValueError("data does not much")
|
||||
salt_admin = kdf_data[34:42]
|
||||
if kdf_data[42:44] != b'\x87\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_user = kdf_data[44:76]
|
||||
if kdf_data[76:78] != b'\x88\x20':
|
||||
raise ValueError("data does not much")
|
||||
hash_admin = kdf_data[78:110]
|
||||
return ( algo, subalgo, iters, salt, salt_reset, salt_admin,
|
||||
hash_user, hash_admin )
|
||||
|
||||
51
tool/kdf_calc.py
Normal file
51
tool/kdf_calc.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
kdf_calc.py - a library for calculating hash by KDF
|
||||
|
||||
Copyright (C) 2018 Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from cffi import FFI
|
||||
|
||||
DEF_gcry_kdf_derive="""
|
||||
typedef unsigned int gpg_error_t;
|
||||
gpg_error_t gcry_kdf_derive (const void *passphrase, size_t passphraselen,
|
||||
int algo, int subalgo, const void *salt,
|
||||
size_t saltlen, unsigned long iterations,
|
||||
size_t keysize, void *keybuffer);
|
||||
"""
|
||||
|
||||
GCRY_KDF_ITERSALTED_S2K = 19
|
||||
GCRY_MD_SHA256 = 8
|
||||
|
||||
def kdf_calc(pw_string, salt_byte, iterations):
|
||||
ffi = FFI()
|
||||
ffi.cdef(DEF_gcry_kdf_derive)
|
||||
libgcrypt = ffi.dlopen("libgcrypt.so")
|
||||
if isinstance(pw_string, str):
|
||||
pw_byte = pw_string.encode('UTF-8')
|
||||
else:
|
||||
pw_byte = pw_string
|
||||
pw=ffi.new("char []", pw_byte)
|
||||
salt = ffi.new("char []", salt_byte)
|
||||
kb = ffi.new("char []", 32)
|
||||
r = libgcrypt.gcry_kdf_derive(pw, len(pw_string), GCRY_KDF_ITERSALTED_S2K,
|
||||
GCRY_MD_SHA256, salt, 8, iterations, 32, kb)
|
||||
if r != 0:
|
||||
raise ValueError("libgcrypt error", r)
|
||||
return ffi.unpack(kb, 32)
|
||||
@@ -4,7 +4,8 @@
|
||||
upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token
|
||||
which is just shipped from factory
|
||||
|
||||
Copyright (C) 2012, 2013, 2015 Free Software Initiative of Japan
|
||||
Copyright (C) 2012, 2013, 2015, 2018
|
||||
Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -23,9 +24,13 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from gnuk_token import *
|
||||
from gnuk_token import get_gnuk_device, gnuk_devices_by_vidpid, \
|
||||
gnuk_token, regnual, SHA256_OID_PREFIX, crc32, parse_kdf_data
|
||||
from kdf_calc import kdf_calc
|
||||
|
||||
import sys, binascii, time, os
|
||||
import rsa
|
||||
from struct import pack
|
||||
|
||||
DEFAULT_PW3 = "12345678"
|
||||
BY_ADMIN = 3
|
||||
@@ -45,7 +50,20 @@ def main(wait_e, keyno, passwd, data_regnual, data_upgrade):
|
||||
|
||||
gnuk = get_gnuk_device()
|
||||
gnuk.cmd_select_openpgp()
|
||||
gnuk.cmd_verify(BY_ADMIN, passwd.encode('UTF-8'))
|
||||
# Compute passwd data
|
||||
kdf_data = gnuk.cmd_get_data(0x00, 0xf9).tostring()
|
||||
if kdf_data == b"":
|
||||
passwd_data = passwd.encode('UTF-8')
|
||||
else:
|
||||
algo, subalgo, iters, salt_user, salt_reset, salt_admin, \
|
||||
hash_user, hash_admin = parse_kdf_data(kdf_data)
|
||||
if salt_admin:
|
||||
salt = salt_admin
|
||||
else:
|
||||
salt = salt_user
|
||||
passwd_data = kdf_calc(passwd, salt, iters)
|
||||
# And authenticate with the passwd data
|
||||
gnuk.cmd_verify(BY_ADMIN, passwd_data)
|
||||
gnuk.cmd_write_binary(1+keyno, rsa_raw_pubkey, False)
|
||||
|
||||
gnuk.cmd_select_openpgp()
|
||||
|
||||
Reference in New Issue
Block a user