Compare commits

..

259 Commits

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

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

Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2018-07-13 16:23:58 +09:00
NIIBE Yutaka
b905b4802f Version 1.2.10. 2018-05-10 13:54:21 +09:00
NIIBE Yutaka
40f2c6c49e Version 1.2.10. 2018-05-10 13:53:09 +09:00
NIIBE Yutaka
61a7f9602b gnuk.elf is the target with VID:PID. New target gnuk-no-vidpid.elf. 2018-05-10 12:09:19 +09:00
NIIBE Yutaka
5465fda927 Update Chopstx to 1.9. 2018-05-10 12:04:37 +09:00
NIIBE Yutaka
f7c46a6c55 More usb_device_reset fix. 2018-04-26 21:23:44 +09:00
NIIBE Yutaka
4550458806 Fix USB initialization.
After USB RESET, all endpoints registers are being reset.  So,
there is no need to let each endpoint stall (it's disabled).
Actually, it's wrong to call usb_lld_stall_rx or usb_lld_stall_tx
before usb_lld_setup_endpoint, because other fields of endpoint
register are not specified after RESET.
2018-04-26 21:22:36 +09:00
NIIBE Yutaka
93a2bac94b Support GD32F103. 2018-04-26 17:33:48 +09:00
NIIBE Yutaka
24adc09406 Version 1.2.9. 2018-04-05 14:00:50 +09:00
NIIBE Yutaka
bf9fc628b3 More tests for admin-less mode. 2018-04-05 13:06:13 +09:00
NIIBE Yutaka
d76534dd3a Fix admin-less mode -> admin-full mode change. 2018-04-05 12:13:45 +09:00
NIIBE Yutaka
d9c5dcf206 Update ChangeLog. 2018-04-04 19:33:56 +09:00
NIIBE Yutaka
26448d58ee Update copyright year. 2018-04-04 19:29:35 +09:00
NIIBE Yutaka
9cfeb817bd More check for length of PW1. 2018-04-04 19:28:42 +09:00
NIIBE Yutaka
b6534dceba Fix removal of resetting code. 2018-04-04 18:59:28 +09:00
NIIBE Yutaka
b47bd693ba More tests (3). 2018-04-04 17:42:14 +09:00
NIIBE Yutaka
1a7d3a698f More tests (2). 2018-04-04 16:34:51 +09:00
NIIBE Yutaka
f7b03f7fb5 More tests. 2018-04-04 16:34:07 +09:00
NIIBE Yutaka
44971541fe More test suite improvement. Add experimental KDF DO tests. 2018-04-04 15:44:34 +09:00
NIIBE Yutaka
53ed5e0a42 Test suite improvement. 2018-04-04 15:10:52 +09:00
NIIBE Yutaka
63eccda0a1 Add a test case to reset PW3. 2018-04-04 10:51:32 +09:00
NIIBE Yutaka
f430c90715 Rename tests. 2018-04-04 08:48:40 +09:00
NIIBE Yutaka
1f18ec1d63 Clear all keystrings when KDF DO is written. 2018-04-03 20:24:28 +09:00
NIIBE Yutaka
ec7423f493 Fix tool/. 2018-04-03 17:17:51 +09:00
NIIBE Yutaka
e50dda28d1 Support authentication with KDF Data Object. 2018-04-03 17:17:39 +09:00
NIIBE Yutaka
8ad176921f Fix kdf_calc.py. 2018-04-03 17:17:28 +09:00
NIIBE Yutaka
d71b116be8 Add kdf_calc.py. 2018-04-03 17:17:20 +09:00
NIIBE Yutaka
d9d3f35ac3 Fix previous commit. 2018-03-30 17:46:52 +09:00
NIIBE Yutaka
7cc8d8930e Support single-salt KDF for admin-less mode. 2018-03-30 15:57:34 +09:00
NIIBE Yutaka
6446a5bd89 KDF format validation should be done before removing data object. 2018-03-22 16:03:56 +09:00
NIIBE Yutaka
8b0cb8be65 factory-reset should erase all upgrade public keys. 2018-03-13 14:05:18 +09:00
NIIBE Yutaka
c73bb0548e Fix KDF DO handling. 2018-02-13 07:26:29 +09:00
NIIBE Yutaka
40b1d453dc Fix .gitignore. 2018-01-23 13:47:46 +09:00
NIIBE Yutaka
3b965fafc0 Fix README. 2018-01-23 13:26:41 +09:00
NIIBE Yutaka
35edbdc731 Version 1.2.8. 2018-01-23 10:13:13 +09:00
NIIBE Yutaka
d4c776e308 Fix the procedure to put VID:PID. Apply the procedure to regnual. 2018-01-23 10:11:35 +09:00
NIIBE Yutaka
6c0c510347 Update documentation. 2018-01-23 09:31:03 +09:00
NIIBE Yutaka
704d8a5cf1 Check passphrase length when changing. 2018-01-22 11:55:10 +09:00
NIIBE Yutaka
55781cb7bb Remove keystring with BY_ADMIN when it's becomming admin-less mode. 2018-01-22 11:02:02 +09:00
NIIBE Yutaka
de24655920 VIDPID substitution at the last stage of build. 2018-01-19 22:36:01 +09:00
NIIBE Yutaka
7bfe0f5427 Add binary-edit.sh. 2018-01-19 22:22:29 +09:00
NIIBE Yutaka
ec058537ed Update Chopstx to 1.8. 2018-01-19 22:15:21 +09:00
NIIBE Yutaka
abeb1015ec Update neug.c. 2018-01-18 19:42:40 +09:00
NIIBE Yutaka
c5f20dc355 Update Chopstx and follow the changes. 2018-01-18 15:14:34 +09:00
NIIBE Yutaka
4ff0b3c5f8 tests: Fix for card readers. 2018-01-09 09:39:42 +09:00
NIIBE Yutaka
4e517778d0 Update Chopstx to 1.7. 2017-12-19 10:24:28 +09:00
NIIBE Yutaka
c81544fffd Fix long-standing bug of admin-less mode. GnuPG should be fixed. 2017-11-26 21:20:46 +09:00
NIIBE Yutaka
ad42010272 Version 1.2.7. 2017-11-26 19:38:26 +09:00
NIIBE Yutaka
8ce91267be Fix regnual. 2017-11-26 19:28:03 +09:00
NIIBE Yutaka
b5c2ace2ae NEWS update. 2017-11-25 15:02:51 +09:00
NIIBE Yutaka
4cbc661fb7 Update Chopstx to 1.6. 2017-11-24 20:53:40 +09:00
NIIBE Yutaka
543f28574e Use of eventflag poll change. 2017-11-17 20:10:13 +09:00
NIIBE Yutaka
fe94e1885b LED status loop change.
Using chopstx_poll, it requires more memory on stack.
2017-11-17 17:20:52 +09:00
NIIBE Yutaka
ce82b347f9 Make sure to turn off LED soon. 2017-11-17 16:25:26 +09:00
NIIBE Yutaka
d54712c04c Less power consumption on suspend. 2017-11-17 15:49:56 +09:00
NIIBE Yutaka
9c63c874d0 Fix ReGNUal. 2017-11-17 15:47:59 +09:00
NIIBE Yutaka
bb9b31166f Fix NeuG for CRC module clock setting. 2017-11-17 15:47:22 +09:00
NIIBE Yutaka
e417846408 More change for USB suspend. 2017-11-17 12:29:32 +09:00
NIIBE Yutaka
21a481060c Make sure to turn off LED on suspend. 2017-11-16 13:08:00 +09:00
NIIBE Yutaka
d4c9d6653b Use const pointer for chopstx_poll. 2017-11-16 09:17:33 +09:00
NIIBE Yutaka
f00306627b Fix pin-cir.c for use of EXTI. 2017-11-16 08:40:49 +09:00
NIIBE Yutaka
f4b36b7503 Lower power consumption on suspend. 2017-11-15 10:59:55 +09:00
NIIBE Yutaka
e85527d302 USB suspend/resume change. 2017-11-14 12:59:18 +09:00
NIIBE Yutaka
bd58997dc9 Possibly support other hash in future, for KDF. 2017-11-08 10:28:55 +09:00
NIIBE Yutaka
9d5834d47b Avoid passphrase-error-lock by old GnuPG. 2017-11-07 13:48:08 +09:00
NIIBE Yutaka
36ecf67694 Update tool information in README. 2017-11-06 15:29:02 +09:00
NIIBE Yutaka
c9b1e511ba Fix test and tests. 2017-11-06 10:51:11 +09:00
NIIBE Yutaka
01b5aa5984 Enable KDF-DO available bit. 2017-11-02 13:53:06 +09:00
NIIBE Yutaka
b735c02ec2 Implement use of KDF data object. 2017-11-02 10:59:17 +09:00
NIIBE Yutaka
2ecb104ae4 Implement rw_kdf. 2017-11-02 09:28:43 +09:00
NIIBE Yutaka
6b4f3c9934 Start adding KDF-DO of OpenPGPcard v3. 2017-11-01 16:52:58 +09:00
NIIBE Yutaka
660aaeb04b Bug fix for keygeneration. 2017-10-31 17:10:03 +09:00
NIIBE Yutaka
1022534c02 Fix gpg_do_keygen. 2017-10-30 15:01:17 +09:00
Daniel Kahn Gillmor
46cc64cf03 fix documentation typo 2017-10-25 16:54:41 +09:00
NIIBE Yutaka
effc65381a Don't change PPS for other readers. 2017-10-24 20:39:51 +09:00
Aurelien Jarno
6cbf5a4822 linker script: fix keystore_pool size
Gnuk supports RSA keys up to 4096 bits. This require 1024 bytes of
storage (p and q are 256 bytes, n is 512 bytes). The linker script
should therefore reserve 1024 bytes per key instead of 512.

In practice it's not an issue at all as all supported MCU have a page
size bigger than 1024 bytes and Gnuk use one page per key.
2017-10-19 14:31:12 +09:00
NIIBE Yutaka
8ff3865890 Update ChangeLog, README, AUTHORS, and THANKS. 2017-10-17 15:26:46 +09:00
Aurelien Jarno
43009f39e8 polarssl: use a bigger sliding window when possible 2017-10-17 15:01:17 +09:00
Aurelien Jarno
56fb5002bf malloc: rename MEMORY_ into HEAP_
That way MEMORY_SIZE can be exported in a later patch.
2017-10-17 15:01:13 +09:00
Aurelien Jarno
3bb5097031 polarssl: add ARM DSP optimized mpi_montsqr 2017-10-17 15:01:09 +09:00
Aurelien Jarno
8319f4a14b polarssl: replace BIGNUM_C_IMPLEMENTATION check
Replace the BIGNUM_C_IMPLEMENTATION check by a check on POLARSSL_HAVE_ASM
and __arm__. This way it's possible to use this code on non arm, but
also to run the GNU/Linux emulation on an arm machine, which is useful
for debugging and profiling.
2017-10-17 15:01:06 +09:00
Aurelien Jarno
f7cf0a3461 polarssl: add ARM DSP optimized MULADDC code
The Cortex M4, M7 MCUs and the Cortex A CPUs support the ARM DSP
instructions, and especially the umaal instruction which greatly
speed up MULADDC code.
2017-10-17 15:01:03 +09:00
Aurelien Jarno
5ac52d3f2f polarssl: rename MULADDC_HUIT into MULADDC_HUIT_DEAD
As the comment above said, it's dead code. Renaming it make sure it's
not used by mistake, for example when testing/debugging code.
2017-10-17 15:01:00 +09:00
Aurelien Jarno
209d459d09 polarssl: fix build without POLARSSL_HAVE_ASM
This fixes building polarssl for architectures without assembly code or
when POLARSSL_HAVE_ASM is not defined.

This has been done in upstream commit a755ca1bbe, but somehow the
generic version has been missed in gnuk's version.
2017-10-17 15:00:55 +09:00
NIIBE Yutaka
ad704edc4e Version 1.2.6.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-10-11 16:50:13 +09:00
NIIBE Yutaka
97a1870e6e Fix test/*. 2017-10-11 16:08:17 +09:00
NIIBE Yutaka
f72e132967 Fix configure. 2017-10-11 11:24:12 +09:00
NIIBE Yutaka
a22b695f96 No --vidpid for GNU/Linux. 2017-10-10 21:06:42 +09:00
NIIBE Yutaka
0c901d8052 Support --debug option for GNU/Linux emulation. 2017-10-10 14:36:34 +09:00
NIIBE Yutaka
a1b8e7f40c STM8S Discovery kit is supported again. 2017-10-06 17:19:55 +09:00
NIIBE Yutaka
dccda32b93 Fix for 64KB STM32F103. 2017-10-06 17:04:45 +09:00
NIIBE Yutaka
75049ce949 Fix linker script. 2017-10-06 17:00:00 +09:00
NIIBE Yutaka
be80a3ef2f For emulation, support --vidpid at runtime. 2017-10-06 10:20:54 +09:00
NIIBE Yutaka
94424e85c3 Fix stack size for ARM. 2017-10-05 17:07:06 +09:00
NIIBE Yutaka
43980d1c81 RSA in a single step. 2017-10-05 17:06:50 +09:00
NIIBE Yutaka
183cec8a04 Emulation tool added. 2017-10-05 13:53:48 +09:00
NIIBE Yutaka
7bae61f300 Fix bignum for 64-bit machine. 2017-10-05 13:45:24 +09:00
NIIBE Yutaka
7e4ee2b361 Serial string for GNU/Linux emulation. 2017-10-04 18:54:16 +09:00
NIIBE Yutaka
30fde2a0f0 Fix bignum for 64-bit machine. 2017-10-04 17:08:42 +09:00
NIIBE Yutaka
eee8d046a9 Fix gnuk_malloc for 64-bit. 2017-10-04 12:38:37 +09:00
NIIBE Yutaka
550010f25f Tweak the size of stack of openpgp-card thread. 2017-10-04 10:45:39 +09:00
NIIBE Yutaka
3adbe30c4d RSA key generation in two steps. 2017-10-04 09:44:19 +09:00
NIIBE Yutaka
d9ec8778fc Don't use malloc if not needed. 2017-10-03 16:12:41 +09:00
NIIBE Yutaka
eff0c7077d Don't provide stdlib.h, but provide gnuk-malloc.h. 2017-10-03 16:04:43 +09:00
NIIBE Yutaka
289d3db8c4 generate flash.data. 2017-10-03 13:50:51 +09:00
NIIBE Yutaka
7c5eb7efd2 Fix non-use of stdlib.h. 2017-10-03 13:27:12 +09:00
NIIBE Yutaka
6f1fbdd82d flash memory handling change to support GNU/Linux. 2017-10-03 11:50:48 +09:00
NIIBE Yutaka
cbedf98a52 Not for GNU/Linux. 2017-10-02 16:45:08 +09:00
NIIBE Yutaka
15689b5b86 FLASH_UPGRADE_SUPPORT is not relevant to GNU/Linux. 2017-10-02 16:24:56 +09:00
NIIBE Yutaka
8170b60ee2 Fix for main.c. 2017-10-02 16:08:20 +09:00
NIIBE Yutaka
ca7f4c8758 More USB fix for GNU/Linux. 2017-10-02 15:29:45 +09:00
NIIBE Yutaka
0b4099d6d1 mpi_montsqr fix for GNU/Linux. 2017-10-02 15:27:27 +09:00
NIIBE Yutaka
65fee7eb2a Fix flash.c for GNU/Linux emulation. 2017-09-30 21:03:17 +09:00
NIIBE Yutaka
0c229f5712 Small USB clean up. 2017-09-30 20:51:21 +09:00
NIIBE Yutaka
5948f6ec50 Revert part of simplification. 2017-09-30 20:20:36 +09:00
NIIBE Yutaka
7b1ea00307 More fix for USB. 2017-09-29 21:06:15 +09:00
NIIBE Yutaka
277be86958 Fix USB code for USBIP on GNU/Linux. 2017-09-29 19:23:39 +09:00
NIIBE Yutaka
a6b90ad648 Fix for FLASH_UPGRADE_SUPPORT. 2017-09-29 16:58:59 +09:00
NIIBE Yutaka
547e263d6b Fix for 64-bit machine (emulation). 2017-09-29 14:15:48 +09:00
NIIBE Yutaka
7004453669 Stack definition change. 2017-09-29 13:18:49 +09:00
NIIBE Yutaka
81b18f2db4 More for GNU/Linux emulation. 2017-09-28 16:44:54 +09:00
NIIBE Yutaka
86715dd4fe More fixes. 2017-09-28 15:36:59 +09:00
NIIBE Yutaka
62f27f319c Fix for GNU/Linux. 2017-09-28 15:25:06 +09:00
NIIBE Yutaka
7345f3c241 Rename flash functions. 2017-09-28 15:10:20 +09:00
NIIBE Yutaka
f4b9073b11 stdlib fixes. 2017-09-28 15:09:21 +09:00
NIIBE Yutaka
6678ac28c2 GNU/Linux emulation is done by Chopstx. 2017-09-28 11:04:28 +09:00
NIIBE Yutaka
83414a747a Version 1.2.5. 2017-08-11 22:12:09 +09:00
NIIBE Yutaka
8a615d087b Update .gitignore. 2017-08-11 22:11:49 +09:00
NIIBE Yutaka
967b949967 Tweak process size of gpg. 2017-08-11 22:00:01 +09:00
NIIBE Yutaka
11afbdde14 src/config.mk generation. 2017-08-11 21:06:59 +09:00
NIIBE Yutaka
328766af12 Merge branch 'master' of git.gniibe.org:gnuk/gnuk 2017-08-04 08:33:46 +09:00
NIIBE Yutaka
2b340ee1c5 Fix factory-reset for admin-less mode.
Reported-by: Stanislas Bach <sbach@0g.re>
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-04 08:32:39 +09:00
NIIBE Yutaka
86e6adf47e Fix factory-reset for admin-less mode.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-03 21:35:20 +09:00
Jeremy Drake
eea011fe70 Allow compile-time override of detected flash size.
On the STM32F103C8, as used in the "blue pill" boards, it has been
determined that, despite these only officially having 64KiB flash, it is
possible to actually use 128KiB of flash.

This commit allows for a preprocessor define
STM32F103_OVERRIDE_FLASH_SIZE which, when set, is used as the size of
flash in KiB instead of reading it from the FLASH_SIZE_REG.
2017-08-03 21:20:47 +09:00
Jeremy Drake
e736227de7 Erase CERTDO on terminate.
When both certdo and lifecycle support are enabled, flash_terminate
neglected to erase the certdo pages.  It now does so.
2017-08-02 11:13:02 +09:00
NIIBE Yutaka
22156ea7f9 Fix factory-reset. 2017-08-01 13:30:02 +09:00
Anthony Romano
db45e62ebe configure: sanitize for shellcheck
Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-20 12:25:24 +09:00
Anthony Romano
3270740631 docker: source checking container
Includes shellcheck and scan-build

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-20 12:24:44 +09:00
NIIBE Yutaka
e4e72a29ae Initialize TMP to avoid confusion by static analysis.
--

The computation using TMP is keeping it constant-time only, but
it is better not to confuse static analysis.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-19 11:55:20 +09:00
NIIBE Yutaka
25d3f021c1 Support no git situation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-19 11:25:38 +09:00
NIIBE Yutaka
ae76d66d53 Fix accessing garbage on error path.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Reported-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-19 10:48:16 +09:00
NIIBE Yutaka
10c5010141 Git is assumed for the source with .git.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-18 14:12:20 +09:00
Anthony Romano
d12483c3c9 Support building with docker.
Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:38:46 +09:00
Anthony Romano
67acb670d1 call fatal if mem_head size is corrupted.
Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:31:06 +09:00
Anthony Romano
a44244b27e avoid null dereference when openpgp algo goes from !rsa2k to rsa2k.
Detected with scan-build.

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:27:12 +09:00
Anthony Romano
2622840e27 remove unused calculations from mod_reduce.
Detected with scan-build.

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:19:42 +09:00
Anthony Romano
a51ac8593b call-rsa: free modulus buffers on error paths.
* MPI_CHK jumps to cleanup on ret != 0, so p_q_modulus is never freed if
  rsa_gen_key fails (detected via scan-build).
* modulus_calc never freed its modulus buffer on error.

Signed-off-by: Anthony Romano <anthony.romano@coreos.com>
2017-07-18 13:15:42 +09:00
NIIBE Yutaka
de81caba3e Update Chopstx.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-07-18 12:58:23 +09:00
NIIBE Yutaka
fa69a85826 Version 1.2.4.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-12 17:22:20 +09:00
NIIBE Yutaka
5c3c3e3001 usbip list -r 127.0.0.1 now works.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-12 14:13:53 +09:00
NIIBE Yutaka
6dcb4dd027 Add usb-emu.c.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-02 15:05:15 +09:00
NIIBE Yutaka
fa08f44cac Fix old documentation (note) for firmware update.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-05-01 14:58:15 +09:00
NIIBE Yutaka
4c2294ea6c Portability change.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-28 16:14:30 +09:00
NIIBE Yutaka
86eaa26d32 New: src/mcu-stm32f103.c.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-28 15:49:38 +09:00
NIIBE Yutaka
9e52789203 Fix long standing buf of digital signature counter.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-28 14:54:15 +09:00
NIIBE Yutaka
702bc8cbde Move data objects at the end of flash.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-27 15:23:25 +09:00
NIIBE Yutaka
2cfce76d91 [SECURITY] Flash memory usage change.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-04-27 14:36:32 +09:00
NIIBE Yutaka
207652246a emulation: USB device emulation by USBIP protocol. 2017-04-18 15:45:25 +09:00
NIIBE Yutaka
32779b6f96 Version 1.2.3. 2017-02-02 16:33:30 +09:00
NIIBE Yutaka
55c1015faa Increase CCID thread stack size by 0x20 for newer GCC. 2017-02-02 14:11:11 +09:00
NIIBE Yutaka
0932465f0b Update Chopstx to 1.3. 2017-02-02 13:07:35 +09:00
NIIBE Yutaka
4417799a51 Update README 2017-02-01 17:16:54 +09:00
Szczepan Zalega
b424cecf1e Regnual update tool: do not allow other than binary formats (upgrade_by_passwd)
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2017-02-01 15:40:56 +09:00
NIIBE Yutaka
7ef417ae36 tool: Improve tool/*.py.
--

Szczepan Zalega's idea of using the file GNUK_USB_DEVICE_ID would
good, but not merged yet.  Because it makes difficult to distribute
the scripts.  We need to consider installing tools and the file
like GNUK_USB_DEVICE_ID altogether.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-02-01 12:34:35 +09:00
NIIBE Yutaka
d4469c24ec fix NIST P-256 / secp256k1 key generation. 2016-10-21 15:30:07 +09:00
NIIBE Yutaka
e4333c6580 Version 1.2.2 2016-10-15 20:18:20 +09:00
NIIBE Yutaka
d2261d53e3 fix scripts 2016-10-15 20:14:18 +09:00
NIIBE Yutaka
27bd37781a Fix flash initialization 2016-10-15 19:29:23 +09:00
NIIBE Yutaka
bed43d4049 Add tests/ accessing DO 6E 2016-10-15 19:28:57 +09:00
NIIBE Yutaka
f7d857b527 fix stack usage of CCID 2016-10-15 18:37:22 +09:00
NIIBE Yutaka
350528e1f4 tests/ update for signature counter 2016-10-15 18:35:21 +09:00
NIIBE Yutaka
4de605ed63 Add pubkey tests 2016-10-15 16:55:22 +09:00
NIIBE Yutaka
ffa9bf1f94 support factory_reset. 2016-10-14 08:45:01 +09:00
NIIBE Yutaka
34d0b34144 add factory reset support (not-full yet) 2016-10-13 15:06:19 +09:00
NIIBE Yutaka
5795dc9877 rename status-code.h 2016-10-13 11:03:50 +09:00
NIIBE Yutaka
c8b17a8759 Update to Chopstx 1.2 2016-10-13 10:35:22 +09:00
NIIBE Yutaka
38d70e277b Fix difference between original OpenPGP card 2016-10-13 10:33:02 +09:00
NIIBE Yutaka
b00bab8dbf tests/ update 2016-10-13 10:04:27 +09:00
NIIBE Yutaka
3c91dce8b7 fix tests/ 2016-10-12 19:42:22 +09:00
NIIBE Yutaka
f1773c146b fix test/ 2016-10-12 15:32:51 +09:00
NIIBE Yutaka
979992c046 fix test/ 2016-10-12 14:56:57 +09:00
NIIBE Yutaka
50700e3887 more tests (incomplete) 2016-10-12 10:22:57 +09:00
NIIBE Yutaka
b0ee8b4452 TPDU reader works now 2016-10-07 16:39:20 +09:00
NIIBE Yutaka
a73f8cf4fd implement TPDU card reader 2016-10-05 20:00:22 +09:00
NIIBE Yutaka
c1cc75f5b0 New test suite for OpenPGP card 2016-09-30 16:38:27 +09:00
NIIBE Yutaka
47150b5c98 minor fix for configure 2016-09-30 16:20:19 +09:00
NIIBE Yutaka
f46880d2a8 Add Gnuk logo of PNG 2016-09-02 11:01:55 +09:00
NIIBE Yutaka
23bbc9c755 Fix test setup 2016-08-24 10:39:27 +09:00
NIIBE Yutaka
2b784cb3b9 Upgrade tool/hub_ctrl.py 2016-08-03 21:19:34 +09:00
115 changed files with 6814 additions and 1293 deletions

8
.gitignore vendored
View File

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

26
AUTHORS
View File

@@ -1,3 +1,20 @@
Aurelien Jarno:
Modified:
src/Makefile
src/configure
src/main.c
src/stack-def.h
Anthony Romano:
Modified:
src/call-rsa.c
src/main.c
src/mod.c
Jeremy Drake:
Modified:
regnual/regnual.c
Kaz Kojima: Kaz Kojima:
Added STM32 Primer2 support. Added STM32 Primer2 support.
@@ -48,3 +65,12 @@ NIIBE Yutaka:
src/usb_lld.h src/usb_lld.h
* *
and others. and others.
Peter Lebbing:
Modified:
src/config.h.in
src/configure
src/main.c
src/Makefile
Wrote:
src/stdaln-sys.ld.in

913
ChangeLog
View File

@@ -1,3 +1,916 @@
2020-01-24 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.15.
2020-01-11 Bertrand Jacquin <bertrand@jacquin.bzh>
* tool/add_openpgp_authkey_from_gpgssh.py: Switch to Python3.
* tool/calc_precompute_table_ecc.py: Likewise.
* tool/dfuse.py: Likewise.
* tool/dump_mem.py: Likewise.
* tool/get_raw_public_key.py: Likewise.
* tool/pageant_proxy_to_gpg.py: Likewise.
2019-12-30 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.18.
2019-06-18 NIIBE Yutaka <gniibe@fsij.org>
* src/bn.c (bn256_random): More portable.
2019-04-03 NIIBE Yutaka <gniibe@fsij.org>
* tests: Factor out tests into classes.
2019-03-04 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.14.
* chopstx: Update to 1.14.
* tool/gnuk_token.py: Add 1209:2440.
2019-02-24 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Clean up the ack button state
at reset (by SET_INTERFACE).
* tool/gnuk_token.py (gnuk_token.__init__): Add back
setAltInterface to issue SET_INTERFACE control transfer.
2019-02-22 NIIBE Yutaka <gniibe@fsij.org>
* tool/gnuk_get_random.py: New.
* src/openpgp.c (cmd_external_authenticate): move
ACKBTN_SUPPORT to...
(cmd_get_challenge): ... here.
* src/gnuk.h (EV_*): Change the values.
* src/usb-ccid.c (GPG_ACK_TIMEOUT): New.
(ccid_thread): Implement timout for the user interaction.
2019-02-21 NIIBE Yutaka <gniibe@fsij.org>
* GNUK_USB_DEVICE_ID: Add 1209:2440.
2018-12-26 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.13.
2018-12-22 Peter Lebbing <peter@digitalbrains.com>
* src/main.c (device_initialize_once): Fill the stack address and
reset vector of Gnuk application (was the one of old SYS).
Reset the board after updating the first five pages of flash.
2018-12-21 Peter Lebbing <peter@digitalbrains.com>
* src/main.c [DFU_SUPPORT] (flash_write_any): New.
(device_initialize_once): Overwrite DFU bootloader by SYS.
(main): Use SYS at ORIGIN_REAL.
* src/stdaln-sys.ld.in: New.
* src/Makefile [USE_DFU] (OBJS_ADD): Add standalone SYS object.
Add rules for stdaln-sys-bin.o and src/stdaln-sys.ld.
* src/configure: Generate stdaln-sys.ld.
[MAPLE_MINI]: Tweak ORIGIN and FLASH_SIZE.
(ORIGIN_DEFINE, ORIGIN_REAL_DEFINE): New macros.
(USE_DFU): New make variable.
* src/config.h.in (ORIGIN_DEFINE, ORIGIN_REAL_DEFINE): New.
2018-12-20 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.13.
2018-12-07 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (EV_EXEC_ACK_REQUIRED): Have precedence
than EV_EXEC_FINISHED.
2018-12-06 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Priority of handling
EV_TX_FINISHED is most important. Don't handle
Ack button event when c->tx_busy = 1.
2018-12-05 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_external_authenticate): Support
ACK button for firmware update.
2018-12-04 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (gpg_data_copy): Fix for NR_DO_UIF_SIG.
2018-11-25 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.12.
2018-11-21 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Fix a race condition sending
result APDU by ack button, time out, sending time extension block
again while tx_busy=1.
2018-11-17 NIIBE Yutaka <gniibe@fsij.org>
* src/main.c (device_initialize_once): Depends on MHZ to
distinguish GD32F103.
* src/openpgp-do.c (do_openpgpcard_aid): Ditto.
2018-11-12 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.11.
* chopstx: Update to 1.12.
* src/configure (ackbtn_support): Always yes.
* src/usb-ccid.c: Fix comma separator.
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
* tool/kdf_calc.py (kdf_calc): Use libgcrypt.so.20.
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_pso, cmd_internal_authenticate): Use
ccid_comm.
* src/usb-ccid.c (struct ccid): New field tx_busy.
(ccid_error, ccid_power_on, ccid_send_status, ccid_power_off)
(ccid_send_data_block_internal, ccid_send_data_block_0x9000)
(ccid_send_data_block_gr, ccid_send_params): Set c->tx_busy.
(ccid_state_p): Remove.
(ccid_get_ccid_state): New.
(ccid_thread): Only handle EV_TX_FINISHED event when c->tx_busy.
* src/usb_ctrl.c (usb_setup, usb_ctrl_write_finish): Use
ccid_get_ccid_state.
* src/main.c (display_status_code): Likewise.
2018-11-09 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_handle_data): Set c->state for pinpad input.
(ccid_send_data_block_internal): Fix the case of len == 0.
* src/main.c (display_status_code): There is
no case where ccid_state == CCID_STATE_RECEIVE.
* src/gnuk.h (CCID_STATE_RECEIVE): Remove.
(CCID_STATE_SEND): Remove.
2018-10-12 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_thread): Notify host about ack button.
2018-10-02 NIIBE Yutaka <gniibe@fsij.org>
* src/stack-def.h (SIZE_0): Increase.
* chopstx: Update to 1.11.
2018-10-01 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (EV_EXEC_ACK_REQUIRED): New.
(EV_EXEC_FINISHED_ACK): Remove.
(CCID_STATE_CONFIRM_ACK): Remove.
(CCID_STATE_ACK_REQUIRED_0, CCID_STATE_ACK_REQUIRED_1): New.
* src/openpgp.c (cmd_pso): Send EV_EXEC_ACK_REQUIRED, if needed.
(cmd_internal_authenticate): Likewise.
(process_command_apdu): No return value.
(openpgp_card_thread): Always send EV_EXEC_FINISHED.
* src/usb-ccid.c (ccid_send_data_block_time_extension): Follow the
change of state.
(ccid_handle_data, ccid_handle_timeout): Likewise.
(ccid_thread): Handle EV_EXEC_ACK_REQUIRED.
Change for LED blink.
* src/main.c (main): LED blink during waiting ACK.
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (NR_DO_UIF_SIG, NR_DO_UIF_DEC, NR_DO_UIF_AUT): New.
* src/openpgp-do.c (rw_uif) [ACKBTN_SUPPORT]: New.
(GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT): New.
(feature_mngmnt) [ACKBTN_SUPPORT]: New.
(cmp_app_data, cmp_discretionary): Add ACKBTN_SUPPORT.
(gpg_do_table): Add for GPG_DO_UIF_SIG, GPG_DO_UIF_DEC,
GPG_DO_UIF_AUT, and GPG_DO_FEATURE_MNGMNT.
(gpg_do_get_uif) [ACKBTN_SUPPORT]: New.
(gpg_data_scan): Handle uif_flags.
* src/openpgp.c (process_command_apdu) [ACKBTN_SUPPORT]: Add user
interaction handling.
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.h (LED_WAIT_FOR_BUTTON): New.
* src/main.c (main): Blink rapidly when asking ACK.
* src/usb-ccid.c (ccid_thread): Use LED_WAIT_FOR_BUTTON.
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
* src/config.h.in: Add @ACKBTN_DEFINE@.
* src/configure: Add ACKBTN_SUPPORT.
* src/gnuk.h (EV_EXEC_FINISHED_ACK): New.
(CCID_STATE_CONFIRM_ACK): New.
* src/openpgp.c (process_command_apdu): Change for cmd_pso, and
cmd_internal_authenticate.
* src/usb-ccid.c (ccid_send_data_block_time_extension): Report
time extension differently when waiting ack button.
(ccid_handle_data): Support case of CCID_STATE_CONFIRM_ACK.
(ccid_handle_timeout): Likewise.
(ack_intr) [ACKBTN_SUPPORT]: New.
(ccid_thread) [ACKBTN_SUPPORT]: Add ack button handling.
2018-09-26 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update.
* src/usb-ccid.c (usb_event_handle): Fix for chopstx_intr_done.
* src/pin-cir.c (tim_main, ext_main): Likewise.
* src/configure (FST_01SZ): Set MHZ=96.
2018-07-04 Szczepan Zalega <szczepan@nitrokey.com>
* tool/upgrade_by_passwd.py: Catch exception, when no KDF data is
found.
Output 'second' for 1 second.
2018-05-10 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.10.
* src/Makefile (build/gnuk.elf): New target.
(build/gnuk-vidpid.elf): Remove.
* chopstx: Update to 1.9.
2018-04-26 NIIBE Yutaka <gniibe@fsij.org>
* src/usb_ctrl.c (usb_device_reset): Don't stop the endpoints.
* src/configure (MHZ, def_mhz): New.
2018-04-05 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.9.
* tests: Add test cases for admin-less mode.
* src/openpgp.c (cmd_change_password): Care admin-less mode.
2018-04-04 NIIBE Yutaka <gniibe@fsij.org>
* tests: Add more tests, key generation and KDF support.
* src/openpgp.c (cmd_reset_user_password): Check length of
new passphrase.
* src/openpgp-do.c (proc_resetting_code): Support removal.
(gpg_do_kdf_check): Fix for the case of resetting PW3.
* tests/test_004_reset_pw3.py: New.
2018-04-03 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Clear all auth state.
* tool/upgrade_by_passwd.py (main): Fix for byte compare.
* tool/gnuk_remove_keys_libusb.py (main): Likewise.
2018-04-02 NIIBE Yutaka <gniibe@fsij.org>
* tool/gnuk_token.py (parse_kdf_data): New.
* tool/kdf_calc.py: New.
* tool/gnuk_remove_keys_libusb.py (main): Support KDF auth.
* tool/upgrade_by_passwd.py (main): Likewise.
2018-03-30 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Support single-salt KDF.
(gpg_do_get_initial_pw_setting): Likewise.
(gpg_do_kdf_check): Likewise.
2018-03-22 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Do format validation earlier.
2018-03-13 NIIBE Yutaka <gniibe@fsij.org>
* src/flash.c [FLASH_UPGRADE_SUPPORT] (flash_terminate): Erase
the page for upgrade public keys.
2018-02-12 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (rw_kdf): Return 0 when NULL.
2018-01-23 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.8.
* src/Makefile (build/gnuk-vidpid.elf): Supply FILE here.
* src/configure (output_vendor_product_serial_strings): For
generating put-vid-pid-ver.sh, don't set FILE.
* regnual/regnual.c (regnual_device_desc): Make this array as a
template.
* regnual/Makefile (regnual.elf): Substitute VID:PID.
2018-01-22 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (USER_PASSWD_MINLEN): New.
(cmd_change_password): Check passphrase length.
2018-01-22 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_change_password): Remove access to private
key with BY_ADMIN when it's becoming admin-less mode.
2018-01-19 NIIBE Yutaka <gniibe@fsij.org>
* src/binary-edit.sh: Copied from NeuG 1.0.8. Exclude FILE.
* src/configure (output_vid_pid_version): Generate a shell script.
* src/Makefile (build/gnuk-vidpid.elf): New target.
* src/usb_desc.c (device_desc): Make this array as a template.
* chopstx: Update to 1.8.
2018-01-18 NIIBE Yutaka <gniibe@fsij.org>
* src/neug.c: Update from NeuG.
2018-01-09 NIIBE Yutaka <gniibe@fsij.org>
* tests/card_reader.py (CardReader.ccid_power_on): Fix for
other card readers for Gemalto's.
2017-12-19 NIIBE Yutaka <gniibe@fsij.org>
* chopstx: Update to 1.7.
2017-11-26 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_change_password): Bug fix for admin-less
mode.
2017-11-26 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.7.
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.
* regnual/Makefile (LDSCRIPT): Move after include.
* regnual/types.h: Add uintptr_t.
* test/features/002_get_data_static.feature (data object AID): Fix
for any binary value.
* 402_get_data_static.feature: Likewise.
* 802_get_data_static.feature: Likewise.
2017-10-10 NIIBE Yutaka <gniibe@fsij.org>
* src/main.c (main): Support --debug option.
* chopstx: Update to 1.5.
2017-10-06 NIIBE Yutaka <gniibe@fsij.org>
* src/configure (flash_override): Fix suggested by Jeremy Drake.
(help): STM8S_DISCOVERY is supported again.
2017-10-06 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.ld.in (.stacks): Specify NOLOAD type.
* src/configure: Allow not specifying VIDPID.
* src/main.c [GNU_LINUX_EMULATION] (main): Handle "--vidpid"
option to assign vendor ID and product ID of USB.
* src/usb_desc.c [GNU_LINUX_EMULATION] (device_desc): Export.
* GNUK_USB_DEVICE_ID (0000:0000): New.
2017-10-05 NIIBE Yutaka <gniibe@fsij.org>
* src/stack-def.h (SIZE_1, SIZE_3): Tweak the size.
* src/call-rsa.c (rsa_genkey): Single step.
* src/openpgp-do.c (gpg_do_keygen): Do RSA key generation in single
step, using APDU buffer.
* src/openpgp.c (cmd_pgp_gakp): Supply the APDU as a buffer.
* src/Makefile (install): New target.
* src/configure (prefix. exec_prefix, libexecdir): Add.
* src/main.c [GNU_LINUX_EMULATION] (main): Option handling.
* tool/gnuk-emulation-setup: New.
* polarssl/library/bignum.c (M_LIMBS, limbs_M, MAX_A_LIMBS)
(limbs_MAX_A, mpi_gen_prime): Fix for 64-bit machine.
2017-10-04 NIIBE Yutaka <gniibe@fsij.org>
* src/configure (output_vendor_product_serial_strings): Support
GNU/Linux emulation.
* polarssl/library/bignum.c (mpi_div_mpi): Fix for 64-bit machine.
* src/main.c (gnuk_malloc, gnuk_free): Fix for 64-bit machine.
* src/stack-def.h (SIZE_3): Tweak the size.
* src/openpgp-do.c (gpg_do_keygen): Do RSA key generation in two
steps.
* src/call-rsa.c (rsa_genkey_start, rsa_genkey_finish): New.
(rsa_genkey): Remove.
2017-10-03 NIIBE Yutaka <gniibe@fsij.org>
* src/call-ec.c (ecc_compute_public): No use of malloc.
* src/call-rsa.c (modulus_calc, rsa_genkey): Likewise.
* src/ecc-edwards.c (eddsa_compute_public_25519): Likewise.
* src/ecc-mont.c (ecdh_compute_public_25519): Likewise.
* src/openpgp-do.c (gpg_do_write_prvkey, gpg_do_chks_prvkey)
(proc_key_import, gpg_do_keygen): Likewise.
* polarssl/library/rsa.c: Don't include stdlib.h.
* src/gnuk-malloc.h: Rename from stdlib.h.
* polarssl/library/bignum.c: Include gnuk-malloc.h.
* src/Makefile (build/flash.data): Generate.
* src/main.c (flash_addr_key_storage_start)
(flash_addr_data_storage_start): New.
(main): Determine flash address.
* src/flash.c (FLASH_ADDR_KEY_STORAGE_START)
(FLASH_ADDR_DATA_STORAGE_START): New.
(flash_do_storage_init, flash_terminate, flash_activate)
(flash_key_storage_init, flash_copying_gc, flash_do_release)
(flash_key_getpage): Use new macros.
2017-10-02 NIIBE Yutaka <gniibe@fsij.org>
* src/main.c (device_initialize_once): Not for GNU/Linux.
* src/openpgp.c, src/flash.c: Distinguish FLASH_UPGRADE_SUPPORT.
* src/main.c [GNU_LINUX_EMULATION]: Use emulated_main.
(MEMORY_SIZE, MEMORY_END): Fix for GNU/Linux.
* src/usb-ccid.c (INTR_REQ_USB): Fix for GNU/Linux.
* polarssl/library/bignum.c (mpi_montsqr): Easy C implementation.
2017-09-30 NIIBE Yutaka <gniibe@fsij.org>
* src/flash.c (flash_terminate, flash_activate)
(flash_copying_gc, flash_do_write_internal, flash_do_release)
(flash_key_write, flash_check_all_other_keys_released)
(flash_key_fill_zero_as_released, flash_key_release)
(flash_key_release_page, flash_clear_halfword)
(flash_put_data_internal, flash_put_data, flash_bool_clear)
(flash_bool_write_internal, flash_bool_write)
(flash_enum_write_internal, flash_enum_write)
(flash_cnt123_write_internal, flash_cnt123_increment)
(flash_cnt123_clear, flash_erase_binary, flash_write_binary): Fix
for GNU/Linux.
* src/usb-ccid.c (ccid_tx_done): Rename from EP1_IN_Callback.
(ccid_rx_ready): Rename from EP1_OUT_Callback.
2017-09-29 NIIBE Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (epo_init, epi_init, ccid_thread): Simplify.
(EP1_IN_Callback, ccid_prepare_receive, EP1_OUT_Callback)
(usb_rx_ready, ccid_error, ccid_power_on, ccid_send_status)
(ccid_send_data_block_internal, ccid_send_data_block_0x9000)
(ccid_send_data_block_gr, ccid_send_params)
(ccid_notify_slot_change, _write) [GNU_LINUX_EMULATION]: Use
different usb driver API.
* src/usb_ctrl.c (usb_device_reset): Fix control endpoint init.
(gnuk_setup_endpoints_for_interface): Add DEV
argument.
(usb_device_reset) [GNU_LINUX_EMULATION]: Use usb_lld_setup_endp.
2017-09-29 NIIBE Yutaka <gniibe@fsij.org>
* src/main.c [FLASH_UPGRADE_SUPPORT] (main): Factor out flash ROM
upgrade support.
(calculate_regnual_entry_address): Likewise.
* src/usb_ctrl.c (usb_setup, download_check_crc32): Likewise.
* src/openpgp.c (modify_binary): Fix for 64-bit machine.
* src/openpgp-do.c (encrypt, decrypt): Likewise.
(gpg_data_scan): Likewise.
(gpg_do_chks_prvkey): Fix error return path.
* src/stack-def.h: New.
* src/gnuk.ld.in: Remove stack definitions.
* src/configure: Remove stack size modifications.
* src/main.c (STACK_MAIN, STACK_PROCESS_1): Use stack-def.h.
* src/usb-ccid.c (STACK_PROCESS_3): Likewise.
* src/usb-msc.c (STACK_PROCESS_5): Likewise.
* src/pin-cir.c (STACK_PROCESS_6, STACK_PROCESS_7): Likewise.
* src/usb_ctrl.c (download_check_crc32): Use chrc32_rv_ functions.
* src/mcu-stm32f103.c (rbit, check_crc32): Remove.
* src/neug.c: Update from NeuG.
* src/neug.h: Ditto.
2017-09-28 NIIBE Yutaka <gniibe@fsij.org>
* src/ec_p256k1.c (coefficient_a): Remove.
* polarssl/library/bignum.c (mpi_fill_pseudo_random): Fix for
64-bit machine.
* src/call-rsa.c (rsa_decrypt): Fix for 64-bit machine.
* src/flash.c (flash_do_storage_init): Rename from flash_init.
(flash_key_storage_init): Rename from flash_init_keys.
* src/openpgp.c (gpg_init): Use new function names.
* src/stdlib.h: Update for GNU/Linux emulation.
* src/Makefile: Support GNU/Linux emulation.
* src/configure: Support GNU/Linux emulation.
* emulation: Remove.
2017-08-11 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.5.
* chopstx: Update to 1.4.
* src/gnuk.ld.in (__process3_stack_size__): Tweak the size.
* src/configure: Define STM32F103_OVERRIDE_FLASH_SIZE_KB for
BULE_PILL.
* src/configure: Let generate src/config.mk.
* src/Makefile: Rename from src/Makefile.in.
* regnual/Makefile: Use src/config.mk.
2017-08-03 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_terminate_df): Fix for admin-less mode.
2017-08-03 Jeremy Drake <jeremydrake+gnuk@eacceleration.com>
* regnual/regnual.c (main): Allow compile time
flash size definition by STM32F103_OVERRIDE_FLASH_SIZE_KB.
2017-08-02 Jeremy Drake <jeremydrake+gnuk@eacceleration.com>
* src/flash.c (flash_terminate): Erase Certificate DO, too.
2017-08-01 NIIBE Yutaka <gniibe@fsij.org>
* src/openpgp.c (FILE_CARD_TERMINATED_OPENPGP): Remove.
(cmd_select_file): Don't change file_selection.
2017-07-19 NIIBE Yutaka <gniibe@fsij.org>
* src/mod.c (mod_inv): Clear TMP.
* src/configure (REVISION): Generate even when no git.
* polarssl/library/bignum.c (mpi_exp_mod): Call mpi_grow for X
after the initialization of RR.
2017-07-18 NIIBE Yutaka <gniibe@fsij.org>
* src/configure: Bark when no git available.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* docker: New.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/main.c (MEMORY_SIZE, MEM_HEAD_IS_CORRUPT, MEM_HEAD_CHECK):
New.
(gnuk_malloc, gnuk_free): Add calls to MEM_HEAD_CHECK.
* src/gnuk.h (FATAL_HEAP): New.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/openpgp-do.c (gpg_reset_algo_attr): New.
(rw_algorithm_attr): Use gpg_reset_algo_attr.
Fix null dereference.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/mod.c (mod_reduce): Clean up unused code.
2017-07-18 Anthony Romano <anthony.romano@coreos.com>
* src/call-rsa.c (modulus_calc): Free modulus on error.
(rsa_genkey): Remove bogus check, and call chopstx_cleanup_pop
with 1 to release p_q_modulus on error. Assign NULL to clp.arg
when it's goes with no error.
* src/main.c (gnuk_free): Allow NULL.
2017-07-18 NIIBE Yutaka <gniibe@fsij.org>
* Update chopstx (with USBIP emulation).
2017-05-12 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.4.
2017-04-28 NIIBE Yutaka <gniibe@fsij.org>
* src/mcu-stm32f103.c: New.
(check_crc32, sram_address): New.
* src/usb_ctrl.c (download_check_crc32): Use check_crc32 and
sram_address.
* src/openpgp-do.c (gpg_write_digital_signature_counter): Fix
writing lower 10-bit.
2017-04-27 NIIBE Yutaka <gniibe@fsij.org>
* src/gnuk.ld.in (_data_pool): Move to the end.
* src/flash.c (flash_init): Return address of end of data object.
* src/openpgp.c (gpg_init): Get address of end of data object.
* src/openpgp-do.c (gpg_data_scan): Check the end address.
2017-02-02 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.3.
* src/gnuk.ld.in (__process1_stack_size__): Increase by 0x20.
* chopstx: Update to 1.3.
* src/configure: Add BLUE_PILL in the help message.
2017-02-01 NIIBE Yutaka <gniibe@fsij.org>
* README: Update README. Thanks to Paul Fertser.
2017-01-02 Szczepan Zalega <szczepan@nitrokey.com>
* tool/upgrade_by_passwd.py: Add file extention check.
2017-02-01 NIIBE Yutaka <gniibe@fsij.org>
* tool/upgrade_by_passwd.py (main): More verbose messages
suggested by Szczepan Zalega <szczepan@nitrokey.com>.
* tool/gnuk_token.py (USB_PRODUCT_LIST): New.
(gnuk_devices_by_vidpid): Support searching by USB_PRODUCT_LIST.
Thanks to Szczepan Zalega <szczepan@nitrokey.com>.
* tool/usb_strings.py: Use gnuk_token.py.
2016-10-21 Niibe Yutaka <gniibe@fsij.org>
* src/ecc.c (check_secret): Fix condition.
2016-10-15 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.2.
* tool/gnuk_put_binary_libusb.py (main): Likewise.
* tool/upgrade_by_passwd.py (main): Add call of cmd_select_openpgp
method.
* src/openpgp.c (gpg_init): flash_init_keys shoule be after
gpg_data_scan since flash_init_keys accesses Data Object for
key attributes.
* src/usb-ccid.c (ccid_power_on): Don't waste stack.
2016-10-14 Niibe Yutaka <gniibe@fsij.org>
* src/usb-ccid.c (ccid_power_on) [LIFE_CYCLE_MANAGEMENT_SUPPORT]:
Change LCS value in ATR at run time.
* src/openpgp.c (gpg_init): Handle FILE_CARD_TERMINATED.
(cmd_select_file): Don't return AID.
(cmd_activate_file, cmd_terminate_df): New.
(process_command_apdu): Let return GPG_NO_RECORD() when
not selected.
* src/openpgp-do.c (gpg_do_terminate): New.
(gpg_data_scan): Handle p_start is NULL.
(do_hist_bytes): Remove.
* src/flash.c (flash_data): Change the value from 0x0000.
(flash_init): Support termination state. Fix handling
of the boundary case where gen0 is 0xfffe.
(flash_terminate, flash_activate): New.
(flash_copying_gc): Skip 0xffff for generation number.
2016-10-13 Niibe Yutaka <gniibe@fsij.org>
* src/status-code.h: Rename from openpgp.h.
* chopstx: Update to 1.2.
* tests: New test suite for OpenPGP card with PyTest.
* src/configure (factory_reset): New.
* src/usb-ccid.c (ccid_power_on): Use ATR_head and historical
bytes.
* src/openpgp-do.c (rw_algorithm_attr): Clear fingerprint, timestamp,
and possibly ds_counter.
2016-10-12 Niibe Yutaka <gniibe@fsij.org>
* test/features/steps.py (cmd_reset_retry_counter): Fix.
* tool/gnuk_token.py (gnuk_token.cmd_reset_retry_counter): Fix.
(gnuk_token.cmd_select_openpgp): Fix P2.
2016-09-02 Niibe Yutaka <gniibe@fsij.org>
* src/configure (REVISION): Fix the detection of .git.
It may be a regular file (if it's created by worktree).
2016-08-24 Niibe Yutaka <gniibe@fsij.org>
* test/features/steps.py (ini): Use GLC (the global context),
instead of FTC (the feature context), so that token only is
opened once.
2016-08-03 Niibe Yutaka <gniibe@fsij.org>
* tool/hub_ctrl.py: Port to Python 3.
2016-07-11 NIIBE Yutaka <gniibe@fsij.org> 2016-07-11 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.1. * VERSION: 1.2.1.

View File

@@ -1,4 +1,6 @@
# VID:PID bcdDev Product_STRING Vendor_STRING # VID:PID bcdDev Product_STRING Vendor_STRING
0000:0000 0200 Gnuk Emulation Free Software Initiative of Japan
234b:0000 0200 Gnuk Token Free Software Initiative of Japan 234b:0000 0200 Gnuk Token Free Software Initiative of Japan
20a0:4211 0200 Nitrokey Start Nitrokey 20a0:4211 0200 Nitrokey Start Nitrokey
1209:2440 0200 Gnuk Token GnuPG e.V.
##########<TAB> ##<TAB> ##########<TAB> ################# ##########<TAB> ##<TAB> ##########<TAB> #################

222
NEWS
View File

@@ -1,5 +1,220 @@
Gnuk NEWS - User visible changes Gnuk NEWS - User visible changes
* Major changes in Gnuk 1.2.15
Released 2020-01-24, by NIIBE Yutaka
** Switch to Python3
Scripts under tool/ are switched to Python3.
Thanks to Bertrand Jacquin.
** Upgrade of Chopstx
We use Chopstx 1.18.
** Tests also support OpenPGPcard
Now, a test suite under "tests" may be used to OpenPGPcard.
* Major changes in Gnuk 1.2.14
Released 2019-03-05, by NIIBE Yutaka
** Timeout for ACK button support
When a user doesn't acknowledge (> 15 seconds), the operation
timeouts, and authentication state is cleared.
** Upgrade of Chopstx
We use Chopstx 1.14.
* Major changes in Gnuk 1.2.13
Released 2018-12-26, by NIIBE Yutaka
** DFU support and its firmware upgrade fix
DFU support was not well maintained, and firmware upgrade was not
possible for boards with DFU. Now, at least for Maple Mini, it is
tested. Note that using Gnuk with DFU on a board is only for an
experiment, because DFU can access the content of flash ROM. DFU
should be killed by upgrading to normal Gnuk, so that you can have
your private keys.
** Fix for UIF Data Object
When flash ROM is full and coping to new page, UIF DO was not properly
copied. This bug resulted losing the flag for user interaction. Now,
it's properly copied, keeping the setting of the feature.
** Upgrade of Chopstx
We use Chopstx 1.13.
* Major changes in Gnuk 1.2.12
Released 2018-11-25, by NIIBE Yutaka
** FST-01SZ fixes
Fixes for Ack button support and serial number.
* Major changes in Gnuk 1.2.11
Released 2018-11-12, by NIIBE Yutaka
** Experimental ACK button support with FST-01SZ
While OpenPGP card specification verison 3 has description for the
"user interaction" button and data objects, there were no
implementation. To evaluate the feature, experimental support is
added.
** Upgrade of Chopstx
We use Chopstx 1.12, which comes with ACK button driver and supports
FST-01SZ.
* Major changes in Gnuk 1.2.10
Released 2018-05-10, by NIIBE Yutaka
** No inclusion of VID:PID in gnuk-no-vidpid.elf
Now, we have new file named gnuk-no-vidpid.elf with no VID:PID. The
file gnuk.elf has the VID:PID, like version 1.2.7 or older.
** Upgrade of Chopstx
We use Chopstx 1.9, which supports GD32F103.
* Major changes in Gnuk 1.2.9
Released 2018-04-05, by NIIBE Yutaka
** 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
** Port to GNU/Linux emulation
We can "run" Gnuk Token on GNU/Linux by emulation through USBIP.
** Upgrade of Chopstx
We use Chopstx 1.5.
* Major changes in Gnuk 1.2.5
Released 2017-08-11, by NIIBE Yutaka
** "factory-reset" fix
Gnuk's behavior was implemented by referring the gpg implementation.
It found that gpg implementation was not good from the viewpoint of
the OpenPGP card specification. GnuPG was fixed to match the OpenPGP
card specification already. Thus, Gnuk is now fixed.
** Upgrade of Chopstx
We use Chopstx 1.4.
* Major changes in Gnuk 1.2.4
Released 2017-05-12, by NIIBE Yutaka
** Flash ROM security fix
The partial content of flash ROM might be exposed when scanning of
data object had a problem. Added boundary check and changed layout of
flash ROM.
* Major changes in Gnuk 1.2.3
Released 2017-02-02, by NIIBE Yutaka
** ECC key generation on the device
Bug fixed.
** Upgrade of Chopstx
We use Chopstx 1.3.
* Major changes in Gnuk 1.2.2
Released 2016-10-15, by NIIBE Yutaka
** Change of SELECT FILE behavior
Gnuk used to reply AID upon SELECT FILE command. Now, to be compatible
to original OpenPGP card, it returns nothing but status code of 9000.
** Added feature of Factory Reset as compile time option
Original OpenPGP card has the feature, and Gnuk is now configurable to
support the feature.
** Upgrade of Chopstx
We use Chopstx 1.2.
* Major changes in Gnuk 1.2.1 * Major changes in Gnuk 1.2.1
Released 2016-07-11, by NIIBE Yutaka Released 2016-07-11, by NIIBE Yutaka
@@ -720,6 +935,7 @@ Gnuk Token could run with GPG4WIN on MS Windows. GPG4WIN runs with
** This is initial release. Only it supports digital signing. ** This is initial release. Only it supports digital signing.
Local Variables:
mode: outline # Local Variables:
End: # mode: outline
# End:

154
README
View File

@@ -1,35 +1,43 @@
Gnuk - An Implementation of USB Cryptographic Token for GnuPG Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 1.2.1 Version 1.2.15
2016-07-11 2020-01-24
Niibe Yutaka Niibe Yutaka
Free Software Initiative of Japan Free Software Initiative of Japan
Release Notes Release Notes
============= =============
This is the release of Gnuk, version 1.2.1, which has major This is the release of Gnuk, version 1.2.15, which has major
incompatible changes to Gnuk 1.0.x. Specifically, it now supports incompatible changes to Gnuk 1.0.x. Specifically, it now supports
overriding key import, but importing keys (or generating keys) results overriding key import, but importing keys (or generating keys) results
password reset. Please update your documentation for Gnuk Token, so password reset. Also, you need to import private keys before changing
your password. Please update your documentation for Gnuk Token, so
that the instruction of importing keys won't cause any confusion. that the instruction of importing keys won't cause any confusion.
It has supports of EdDSA, ECDSA (with NIST P256 and secp256k1), and It has supports of EdDSA, ECDSA (with NIST P256 and secp256k1), and
ECDH (with X25519, NIST P256 and secp256k1), but this ECC feature is ECDH (with X25519, NIST P256 and secp256k1), but this ECC feature is
somehow experimental, and it requires modern GnuPG 2.1 with libgcrypt somehow experimental, and it requires modern GnuPG 2.2 with libgcrypt
1.7.0 or later. 1.7.0 or later.
It also supports RSA-4096, but users should know that it takes more It also supports RSA-4096, but users should know that it takes more
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails, than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
because the device doesn't have enough memory. because the device doesn't have enough memory.
It supports new KDF-DO feature. Please note that this is
experimental. To use the feature, you need to use newer GnuPG (2.2.6
or later). You need to prepare the KDF-DO on your token by the
card-edit/kdf-setup command.
With FST-01SZ, experimental ack button support is available for test.
What's Gnuk? What's Gnuk?
============ ============
Gnuk is an implementation of USB cryptographic token for GNU Privacy Gnuk is an implementation of USB cryptographic token for GNU Privacy
Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on
STM32F103 processor. STM32F103 processor (and its compatible).
I wish that Gnuk will be a developer's soother who uses GnuPG. I have I wish that Gnuk will be a developer's soother who uses GnuPG. I have
been nervous of storing secret key(s) on usual secondary storage. been nervous of storing secret key(s) on usual secondary storage.
@@ -47,7 +55,7 @@ FAQ
Q0: How Gnuk USB Token is superior than other solutions (OpenPGP Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
card 2.0, YubiKey, etc.) ? card 2.0, YubiKey, etc.) ?
http://www.g10code.de/p-card.html https://www.g10code.de/p-card.html
https://www.yubico.com/ https://www.yubico.com/
A0: Good points of Gnuk are: A0: Good points of Gnuk are:
* If you have skill of electronics and like DIY, you can build * If you have skill of electronics and like DIY, you can build
@@ -67,7 +75,7 @@ A1: Gnuk version 1.0 only supports RSA-2048.
Q2: How long does it take for digital signing? Q2: How long does it take for digital signing?
A2: It takes a second and a half or so for RSA-2048. A2: It takes a second and a half or so for RSA-2048.
It takes more than 8 secondd for RSA-4096. It takes more than 8 seconds for RSA-4096.
Q3: What's your recommendation for target board? Q3: What's your recommendation for target board?
A3: Orthodox choice is Olimex STM32-H103. A3: Orthodox choice is Olimex STM32-H103.
@@ -77,12 +85,11 @@ A3: Orthodox choice is Olimex STM32-H103.
choice for experiment. choice for experiment.
Q4: What's version of GnuPG are you using? Q4: What's version of GnuPG are you using?
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.13 in A4: In Debian GNU/Linux system, I use GnuPG modern 2.2.12.
experimental.
Q5: What's version of pcscd and libccid are you using? Q5: What's version of pcscd and libccid are you using?
A5: I don't use them, pcscd and libccid are optional, you can use Gnuk A5: I don't use them, pcscd and libccid are optional, you can use Gnuk
without them. Token without them.
I tested pcscd 1.5.5-4 and libccid 1.3.11-2 which were in Debian I tested pcscd 1.5.5-4 and libccid 1.3.11-2 which were in Debian
squeeze. squeeze.
@@ -172,15 +179,6 @@ Original features of Gnuk, tested manually lightly:
* Card holder certificate (write by UPDATE BINARY) * Card holder certificate (write by UPDATE BINARY)
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal * Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
It is known not-working well:
* It is known that the specific combination of libccid 1.4.1
(or newer) with libusb 1.0.8 (or older) had a minor problem.
It is rare but it is possible for USB communication to be
failed, because of a bug in libusb implementation. Use
libusbx 1.0.9 or newer, or don't use PC/SC, but use internal
CCID driver of GnuPG.
Targets Targets
======= =======
@@ -213,18 +211,20 @@ script prepending 'bash' before './configure'.
Some tools are written in Python. If your Python is not installed as Some tools are written in Python. If your Python is not installed as
/usr/bin/python, please prepend 'python' for your command invocation. /usr/bin/python, please prepend 'python' for your command invocation.
Python 2.7 and PyUSB 0.4.3 is assumed. I use Python 3.7 and PyUSB 1.0.0.
Souce code Source code
========== ===========
Gnuk source code is under src/ directory. Gnuk source code is under src/ directory.
Note that SHA-2 hash function implementation, src/sha256.c, is based Note that SHA-2 hash function implementation, src/sha256.c, is based
on the original implementation by Dr. Brian Gladman. See: on the original implementation by Dr. Brian Gladman. See:
http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php http://brg.a2hosted.com//oldsite/cryptography_technology/sha/index.php
(was at:
http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php)
License License
@@ -248,7 +248,7 @@ External source code
Gnuk is distributed with external source code. Gnuk is distributed with external source code.
* chopstx/ -- Chopstx 1.1 * chopstx/ -- Chopstx 1.18
We use Chopstx as the kernel for Gnuk. We use Chopstx as the kernel for Gnuk.
@@ -297,6 +297,15 @@ Gnuk is distributed with external source code.
POLARSSL_SELF_TEST, and POLARSSL_PADLOCK_C, and only define POLARSSL_SELF_TEST, and POLARSSL_PADLOCK_C, and only define
POLARSSL_GENPRIME when defined KEYGEN_SUPPORT. 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) USB vendor ID and product ID (USB device ID)
============================================ ============================================
@@ -361,10 +370,10 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
On Debian we can install the packages of gcc-arm-none-eabi, On Debian we can install the packages of gcc-arm-none-eabi,
gdb-arm-none-eabi and its friends. I'm using: gdb-arm-none-eabi and its friends. I'm using:
binutils-arm-none-eabi 2.26-4+8 binutils-arm-none-eabi 2.31.1-12+11
gcc-arm-none-eabi 15:4.9.3+svn231177-1 gcc-arm-none-eabi 15:7-2018-q2-6
gdb-arm-none-eabi 7.10-1+9 gdb-multiarch 8.2.1-1
libnewlib-arm-none-eabi 2.2.0+git20150830.5a3d536-1 libnewlib-arm-none-eabi 3.1.0.20181231-1
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
GNU Toolchain for 'arm-none-eabi' target. GNU Toolchain for 'arm-none-eabi' target.
@@ -388,6 +397,12 @@ Then, type:
Then, we will have "gnuk.elf" under src/build directory. Then, we will have "gnuk.elf" under src/build directory.
If you are not the authorized vendor, please never distribute this
file of "gnuk.elf", which includes VID:PID in the image. If you would
like to distribute the image (for example, to check if it's
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
VID:PID.
How to install How to install
============== ==============
@@ -395,18 +410,14 @@ How to install
Olimex STM32-H103 board Olimex STM32-H103 board
----------------------- -----------------------
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD: If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD
and write "gnuk.elf" to Flash ROM:
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg -f board/olimex_stm32_h103.cfg $ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \
-f board/olimex_stm32_h103.cfg \
-c "program build/gnuk.elf verify reset exit"
Then, with another terminal, type following to write "gnuk.elf" to Flash ROM: Command invocation is assumed in src/ directory.
$ telnet localhost 4444
> reset halt
> flash write_image erase gnuk.elf
> reset
> exit
$
Flying Stone Tiny 01 Flying Stone Tiny 01
@@ -414,15 +425,18 @@ Flying Stone Tiny 01
If you are using Flying Stone Tiny 01, you need a SWD writer. If you are using Flying Stone Tiny 01, you need a SWD writer.
OpenOCD 0.9 now supports ST-Link/V2. We can use it: OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x_stlink.cfg
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
-c "program build/gnuk.elf verify reset exit"
STBee STBee
----- -----
Note that this is only for your experiment; Your private key materials
on the board can be accessed by DfuSe.
Reset the board with "USER" switch pushed. Type following to write Reset the board with "USER" switch pushed. Type following to write
to flash: to flash:
@@ -435,20 +449,24 @@ Then, reset the board.
How to protect flash ROM How to protect flash ROM
======================== ========================
Invoke your OpenOCD and type: To protect, invoke OpenOCD like (for FST-01):
$ telnet localhost 4444 $ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
> reset halt -c init -c "reset halt" -c "stm32f1x lock 0" -c reset -c exit
> stm32f1x lock 0
> reset
> shutdown
After power-off / power-on sequence, the contents of flash ROM cannot After power-off / power-on sequence, the contents of flash ROM cannot
be accessible from JTAG debugger. be accessible from JTAG debugger.
Unprotecting is:
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
-c init -c "reset halt" -c "stm32f1x unlock 0" -c reset -c exit
Upon unprotection, flash is erased.
Note that it would be still possible for some implementation of DfuSe Note that it would be still possible for some implementation of DfuSe
to access the contents. If you want to protect, killing DfuSe and to access the contents, even if it's protected. If you really want to
accessing by JTAG debugger is recommended. protect, killing DfuSe and accessing by JTAG debugger is recommended.
(Optional) Configure serial number and X.509 certificate (Optional) Configure serial number and X.509 certificate
@@ -457,7 +475,7 @@ accessing by JTAG debugger is recommended.
This is completely optional. This is completely optional.
For this procedure, you need python and pyscard (python-pyscard For this procedure, you need python and pyscard (python-pyscard
package in Debian) or PyUSB 0.4.3 (python-usb package in Debian). package in Debian) or PyUSB (python-usb package in Debian).
(1) [pyscard] Stop scdaemon (1) [pyscard] Stop scdaemon
[PyUSB] Stop the pcsc daemon. [PyUSB] Stop the pcsc daemon.
@@ -469,7 +487,7 @@ Exception" by "Sharing violation".
In case of PyUSB tool, you need to stop pcscd. In case of PyUSB tool, you need to stop pcscd.
# /etc/init.d/pcscd stop # systemctl stop pcscd
(2) [Optional] Write fixed serial number (2) [Optional] Write fixed serial number
@@ -513,8 +531,8 @@ Type following command to see Gnuk runs:
$ gpg --card-status $ gpg --card-status
Besides, there is a functionality test under test/ directory. See Besides, there is a functionality test under tests/ directory. See
test/README. tests/README.
Personalize the Token, import keys, and change the password Personalize the Token, import keys, and change the password
@@ -536,7 +554,7 @@ Gnuk supports key generation, but this feature is young and should be
considered experimental. considered experimental.
For detail, please see documentation under doc/. You can see the HTML For detail, please see documentation under doc/. You can see the HTML
version at: http://www.fsij.org/doc-gnuk/ version at: https://www.fsij.org/doc-gnuk/
How to debug How to debug
@@ -551,6 +569,10 @@ Inside GDB, we can connect OpenOCD by:
(gdb) target remote localhost:3333 (gdb) target remote localhost:3333
or
(gdb) target extended-remote localhost:3333
You can see the output of PCSCD: You can see the output of PCSCD:
@@ -571,39 +593,33 @@ See doc/note/firmware-update.
Git Repositories 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: 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 It's also available at: www.gniibe.org
You can browse at: http://git.gniibe.org/gitweb?p=gnuk/gnuk.git;a=summary You can browse at: https://git.gniibe.org/cgit/gnuk/gnuk.git/
I put Chopstx as a submodule of Git. Please do this: I put Chopstx as a submodule of Git. Please do this:
$ git submodule init $ git submodule update --init
$ git submodule update
We have migrated from ChibiOS/RT to Chopstx in Gnuk 1.1. If you have
old code of ChibiOS/RT, you need:
Edit .git/config to remove chibios reference
git rm --cached chibios
Information on the Web Information on the Web
====================== ======================
Please visit: http://www.fsij.org/gnuk/ For more information, please visit: https://www.fsij.org/gnuk/
Please see the FST-01 support pages: Please see the FST-01 support pages:
http://www.gniibe.org/category/fst-01.html https://www.gniibe.org/category/fst-01.html
Please consider to join Gnuk-users mailing list: 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
Your Contributions Your Contributions

8
THANKS
View File

@@ -7,16 +7,20 @@ Gnuk was originally written by NIIBE Yutaka. People contributed by
encouraging the development, testing the implementation, suggesting encouraging the development, testing the implementation, suggesting
improvements, or fixing bugs. Here is a list of those people. improvements, or fixing bugs. Here is a list of those people.
Aurelien Jarno aurelien@aurel32.net
Achim Pietig achim@pietig.com Achim Pietig achim@pietig.com
Aidan Thornton Aidan Thornton
Anibal Monsalve Salazar anibal@debian.org Anibal Monsalve Salazar anibal@debian.org
Andre Zepezauer andre.zepezauer@student.uni-halle.de Andre Zepezauer andre.zepezauer@student.uni-halle.de
Anthony Romano anthony.romano@coreos.com
Bertrand Jacquin bertrand@jacquin.bzh Bertrand Jacquin bertrand@jacquin.bzh
Clint Adams clint@softwarefreedom.org Clint Adams clint@softwarefreedom.org
Daniel Kahn Gillmor dkg@fifthhorseman.net Daniel Kahn Gillmor dkg@fifthhorseman.net
Elliott Mitchell Elliott Mitchell
Fabio Utzig utzig@apache.org
Hironobu SUZUKI hironobu@h2np.net Hironobu SUZUKI hironobu@h2np.net
Jan Suhr jan@suhr.info Jan Suhr jan@suhr.info
Jeremy Drake jeremydrake+gnuk@eacceleration.com
Jonathan McDowell noodles@earth.li Jonathan McDowell noodles@earth.li
Kaz Kojima kkojima@rr.iij4u.or.jp Kaz Kojima kkojima@rr.iij4u.or.jp
Kenji Rikitake Kenji Rikitake
@@ -29,9 +33,13 @@ NAGAMI Takeshi nagami-takeshi@aist.go.jp
Nguyễn Hồng Quân quannguyen@mbm.vn Nguyễn Hồng Quân quannguyen@mbm.vn
Nico Rikken nico@nicorikken.eu Nico Rikken nico@nicorikken.eu
NOKUBI Takatsugu knok@daionet.gr.jp NOKUBI Takatsugu knok@daionet.gr.jp
Paul Fertser
Paul Bakker polarssl_maintainer@polarssl.org Paul Bakker polarssl_maintainer@polarssl.org
Peter Lebbing peter@digitalbrains.com
Santiago Ruano Rincón santiago@debian.org Santiago Ruano Rincón santiago@debian.org
Shane Coughlan scoughlan@openinventionnetwork.com Shane Coughlan scoughlan@openinventionnetwork.com
Stanislas Bach sbach@0g.re
Szczepan Zalega szczepan@nitrokey.com
Vasily Evseenko Vasily Evseenko
Werner Koch wk@gnupg.org Werner Koch wk@gnupg.org
Yuji Imai ug@xcast.jp Yuji Imai ug@xcast.jp

View File

@@ -1 +1 @@
release/1.2.1 release/1.2.15

Submodule chopstx updated: 09f27704f5...cc49f4ef23

View File

@@ -40,11 +40,11 @@ We are using "-O3 -Os" for compiler option.
Building Gnuk Building Gnuk
------------- -------------
Change directory to ``src``: Change directory to ``src``: ::
$ cd gnuk-VERSION/src $ cd gnuk-VERSION/src
Then, run ``configure``: Then, run ``configure``: ::
$ ./configure --vidpid=<VID:PID> $ ./configure --vidpid=<VID:PID>
@@ -52,8 +52,14 @@ Here, you need to specify USB vendor ID and product ID. For FSIJ's,
it's: --vidpid=234b:0000 . Please read the section 'USB vendor ID and it's: --vidpid=234b:0000 . Please read the section 'USB vendor ID and
product ID' in README. product ID' in README.
Type: Type: ::
$ make $ make
Then, we will have "gnuk.elf" under src/build directory. Then, we will have "gnuk.elf" under src/build directory.
If you are not the authorized vendor, please never distribute this
file of "gnuk.elf", which includes VID:PID in the image. If you would
like to distribute the image (for example, to check if it's
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
VID:PID.

View File

@@ -16,7 +16,7 @@ In addition to settings of Gnuk, I create a file
# For updating firmware, permission settings are needed. # For updating firmware, permission settings are needed.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \ SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd" ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
@@ -50,39 +50,9 @@ With the script below, I extract public key of the keygrip
$ ./get_raw_public_key.py 5D6C89682D07CCFC034AF508420BF2276D8018ED $ ./get_raw_public_key.py 5D6C89682D07CCFC034AF508420BF2276D8018ED
Here is the script, get_raw_public_key.py:: (The script is available in the directory gnuk/tool. Please note that
it was written in the early stage of the development. The quality of
#! /usr/bin/python the code is somewhat questionable.)
import sys, binascii
from subprocess import check_output
def get_gpg_public_key(keygrip):
result = check_output(["gpg-connect-agent", "READKEY %s" % keygrip, "/bye"])
key = ""
while True:
i = result.find('%')
if i < 0:
key += result
break
hex_str = result[i+1:i+3]
key += result[0:i]
key += chr(int(hex_str,16))
result = result[i+3:]
pos = key.index("D (10:public-key(3:rsa(1:n257:") + 31 # skip NUL too
key = key[pos:-17] # )(1:e3:XYZ)))\nOK\n
if len(key) != 256:
raise ValueError, binascii.hexlify(key)
return key
if __name__ == '__main__':
keygrip = sys.argv[1]
k = get_gpg_public_key(keygrip)
shorthand = keygrip[0:8] + ".bin"
f = open(shorthand,"w")
f.write(k)
f.close()
Then, we can put the data of public key into token by:: Then, we can put the data of public key into token by::

View File

@@ -54,7 +54,7 @@ setting). It should have lines something like: ::
# Gnuk Token by FSIJ # Gnuk Token by FSIJ
SUBSYSTEMS=="usb", ACTION=="add", \ SUBSYSTEMS=="usb", ACTION=="add", \
ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \ ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg" ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
I have those lines in /etc/udev/rules.d/69-gnuk.rules. I have those lines in /etc/udev/rules.d/69-gnuk.rules.
@@ -73,16 +73,21 @@ and make: ::
$ make $ make
Please take care of configure options. The default target in 1.0.x 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. is FST-01.
Then you get build/gnuk.elf.
Then you get build/gnuk.elf and build/gnuk.bin. If you are not the authorized vendor, please never distribute this
file of "gnuk.elf", which includes VID:PID in the image. If you would
like to distribute the image (for example, to check if it's
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
VID:PID.
Invoking configure with FSIJ's USB ID (234b:0000) means that you are Invoking configure with FSIJ's USB ID (234b:0000) and generating
using FSIJ's USB ID (for reGNUal in this case). Please note that FSIJ gnuk.elf means that you are using FSIJ's USB ID (for reGNUal in this
only allows use of its USB ID for specific situations. Please read case). Please note that FSIJ only allows use of its USB ID for
README of Gnuk about that. specific situations. Please read README of Gnuk about that.
Bulding reGNUal Bulding reGNUal
@@ -122,8 +127,8 @@ How to run the script: ::
Then, the script on your host PC invoke the steps described above, and Then, the script on your host PC invoke the steps described above, and
you will get new version of Gnuk installed. you will get new version of Gnuk installed.
You can also specify -p option to enter your password (other than You can also specify -f option to skip entering your password (it
factory setting). assumes the factory setting).
If you already have configured another upgrade key installed, you can If you already have configured another upgrade key installed, you can
specify different slot by -k ``<slot_no>`` option. SLOT_NO can be 0 specify different slot by -k ``<slot_no>`` option. SLOT_NO can be 0

View File

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

View File

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

7
docker/Dockerfile.check Normal file
View File

@@ -0,0 +1,7 @@
FROM gnuk:latest
LABEL Description="Image for checking gnuK"
RUN apt install -y shellcheck
RUN apt install -y clang libfindbin-libs-perl
RUN apt clean

4
docker/Dockerfile.debug Normal file
View File

@@ -0,0 +1,4 @@
FROM gnuk:latest
LABEL Description="Image for building gnuK with debugging"
RUN apt install -y gdb-arm-none-eabi && apt clean

View File

@@ -0,0 +1,6 @@
FROM debian:latest
LABEL Description="Image for building gnuK"
RUN apt update -y && apt install -y make gcc-arm-none-eabi && apt clean
CMD ["/bin/sh", "-c", "cd /gnuk/src && make clean && ./configure $GNUK_CONFIG && make"]

36
docker/Makefile Normal file
View File

@@ -0,0 +1,36 @@
ifndef GNUK_CONFIG
$(warning configuration flags not set in GNUK_CONFIG)
endif
all: ../chopstx docker-build-release
docker run --user=`id -u` --env GNUK_CONFIG --rm -v `pwd`/..:/gnuk/ -t gnuk:latest
clean: docker-build-release
docker run --user=`id -u` --env GNUK_CONFIG --rm -v `pwd`/..:/gnuk/ -w /gnuk/src -t gnuk:latest make clean
gdb: docker-build-debug
docker run --net host --rm -i -v `pwd`/..:/gnuk/ -t gnuk:latest-debug arm-none-eabi-gdb /gnuk/src/build/gnuk.elf
shellcheck: docker-build-check
docker run --rm -v `pwd`/..:/gnuk/ -t gnuk:latest-check shellcheck /gnuk/src/configure
CHECKERS=security optin nullability core deadcode alpha.core alpha.security
scan-build: clean docker-build-check
docker run --user=`id -u` --rm -v `pwd`/..:/gnuk/ -w /gnuk/src -t gnuk:latest-check scan-build -o scan-build \
-analyze-headers -stats $(addprefix -enable-checker ,$(CHECKERS)) -k \
--use-cc=arm-none-eabi-gcc \
make
../chopstx:
git submodule update --init
docker-build-release:
docker build -t gnuk:latest -f `pwd`/Dockerfile.release ..
docker-build-debug: docker-build-release
docker build -t gnuk:latest-debug -f `pwd`/Dockerfile.debug ..
docker-build-check: docker-build-release
docker build -t gnuk:latest-check -f `pwd`/Dockerfile.check ..
.PHONY: all clean gdb shellcheck scan-build \
docker-build-release docker-build-debug docker-build-check

BIN
gnuk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -495,6 +495,67 @@
#endif /* TriCore */ #endif /* TriCore */
#if defined(__arm__) #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 \ #define MULADDC_1024_CORE \
"ldmia %[s]!, { r8, r9, r10 } \n\t" \ "ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \ "ldmia %[d], { r5, r6, r7 } \n\t" \
@@ -556,7 +617,7 @@
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "memory", "cc" ); : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "memory", "cc" );
/* Just for reference (dead code) */ /* Just for reference (dead code) */
#define MULADDC_HUIT \ #define MULADDC_HUIT_DEAD \
"ldmia %0!, { r4, r5 } \n\t" \ "ldmia %0!, { r4, r5 } \n\t" \
"ldmia %1, { r8, r9 } \n\t" \ "ldmia %1, { r8, r9 } \n\t" \
"umull r6, r7, %3, r4 \n\t" \ "umull r6, r7, %3, r4 \n\t" \
@@ -620,6 +681,7 @@
: "r" (b), "0" (s), "1" (d), "2" (c) \ : "r" (b), "0" (s), "1" (d), "2" (c) \
: "r4", "r5", "r6", "r7", "memory", "cc" ); : "r4", "r5", "r6", "r7", "memory", "cc" );
#endif /* __ARM_FEATURE_DSP */
#endif /* ARMv3 */ #endif /* ARMv3 */
#if defined(__alpha__) #if defined(__alpha__)
@@ -811,8 +873,8 @@
#else #else
#define MULADDC_INIT \ #define MULADDC_INIT \
{ \ { \
t_int s0, s1, b0, b1; \ t_uint s0, s1, b0, b1; \
t_int r0, r1, rx, ry; \ t_uint r0, r1, rx, ry; \
b0 = ( b << biH ) >> biH; \ b0 = ( b << biH ) >> biH; \
b1 = ( b >> biH ); b1 = ( b >> biH );

View File

@@ -37,7 +37,7 @@
#include "polarssl/bignum.h" #include "polarssl/bignum.h"
#include "polarssl/bn_mul.h" #include "polarssl/bn_mul.h"
#include <stdlib.h> #include <gnuk-malloc.h>
#define ciL (sizeof(t_uint)) /* chars in limb */ #define ciL (sizeof(t_uint)) /* chars in limb */
#define biL (ciL << 3) /* bits in limb */ #define biL (ciL << 3) /* bits in limb */
@@ -223,6 +223,7 @@ size_t mpi_lsb( const mpi *X )
return( 0 ); return( 0 );
} }
#if !defined(POLARSSL_HAVE_UDBL)
/* /*
* Count leading zero bits in a given integer * Count leading zero bits in a given integer
*/ */
@@ -240,6 +241,7 @@ static size_t int_clz( const t_uint x )
return j; return j;
} }
#endif
/* /*
* Return the number of most significant bits * Return the number of most significant bits
@@ -1140,9 +1142,9 @@ static t_uint int_div_int(t_uint u1, t_uint u0, t_uint d, t_uint *r)
*/ */
if(( 0 == d ) || ( u1 >= d )) if(( 0 == d ) || ( u1 >= d ))
{ {
if (r != NULL) *r = (~0); if (r != NULL) *r = (~0UL);
return (~0); return (~0UL);
} }
#if defined(POLARSSL_HAVE_UDBL) #if defined(POLARSSL_HAVE_UDBL)
@@ -1268,7 +1270,7 @@ int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B )
for( i = n; i > t ; i-- ) for( i = n; i > t ; i-- )
{ {
if( X.p[i] >= Y.p[t] ) if( X.p[i] >= Y.p[t] )
Z.p[i - t - 1] = ~0; Z.p[i - t - 1] = ~0UL;
else else
{ {
Z.p[i - t - 1] = int_div_int( X.p[i], X.p[i-1], Y.p[t], NULL); Z.p[i - t - 1] = int_div_int( X.p[i], X.p[i-1], Y.p[t], NULL);
@@ -1295,7 +1297,7 @@ int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B )
MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) );
if( mpi_cmp_int( &X, 0 ) < 0 ) while( mpi_cmp_int( &X, 0 ) < 0 )
{ {
MPI_CHK( mpi_copy( &T1, &Y ) ); MPI_CHK( mpi_copy( &T1, &Y ) );
MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
@@ -1512,9 +1514,17 @@ static void mpi_montred( size_t n, const t_uint *np, t_uint mm, t_uint *d )
/* /*
* Montgomery square: A = A * A * R^-1 mod N * Montgomery square: A = A * A * R^-1 mod N
* A is placed at the upper half of D. * A is placed at the upper half of D.
*
* n : number of limbs of N
* np: pointer to limbs of bignum N
* mm: m' = -N^(-1) mod b where b = 2^number-of-bit-in-limb
* d (destination): the result [<-- temp -->][<--- A ---->]
* lower part upper part
* n-limb n-limb
*/ */
static void mpi_montsqr( 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 )
{ {
#if defined(POLARSSL_HAVE_ASM) && defined(__arm__)
size_t i; size_t i;
register t_uint c = 0; register t_uint c = 0;
@@ -1526,6 +1536,52 @@ static void mpi_montsqr( size_t n, const t_uint *np, t_uint mm, t_uint *d )
x_i = *xj; x_i = *xj;
*xj++ = c; *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; */ asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */
"mov %[c], #0\n\t" "mov %[c], #0\n\t"
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */ "ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */
@@ -1587,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]), : [x_i] "r" (x_i), [x_max1] "r" (&d[n*2-1]),
"[wij]" (wij), "[xj]" (xj) "[wij]" (wij), "[xj]" (xj)
: "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc"); : "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc");
#endif
c += mpi_mul_hlp( n, np, &d[i], d[i] * mm ); c += mpi_mul_hlp( n, np, &d[i], d[i] * mm );
} }
@@ -1598,16 +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 ); mpi_sub_hlp( n, np, d );
else else
mpi_sub_hlp( n, d - n, d - n); 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) * 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 mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
{ {
int ret; int ret;
size_t i = mpi_msb( E ); 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 > 671 ) ? 6 : ( i > 239 ) ? 5 :
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
size_t wbits, one = 1; size_t wbits, one = 1;
@@ -1632,7 +1702,6 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
* Init temps and window size * Init temps and window size
*/ */
mpi_montg_init( &mm, N ); mpi_montg_init( &mm, N );
MPI_CHK( mpi_grow( X, N->n ) );
/* /*
* If 1st call, pre-compute R^2 mod N * If 1st call, pre-compute R^2 mod N
@@ -1658,6 +1727,8 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
memset (d, 0, N->n * ciL); /* Set lower half of D zero. */ memset (d, 0, N->n * ciL); /* Set lower half of D zero. */
} }
MPI_CHK( mpi_grow( X, N->n ) );
/* /*
* W[1] = A * R^2 * R^-1 mod N = A * R mod N * W[1] = A * R^2 * R^-1 mod N = A * R mod N
*/ */
@@ -2051,17 +2122,19 @@ jkiss (struct jkiss_state *s)
static int mpi_fill_pseudo_random ( mpi *X, size_t size) static int mpi_fill_pseudo_random ( mpi *X, size_t size)
{ {
int ret; int ret;
uint32_t *p; uint32_t *p, *p_end;
MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) ); MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) );
MPI_CHK( mpi_lset( X, 0 ) ); MPI_CHK( mpi_lset( X, 0 ) );
/* Assume little endian. */ /* Assume little endian. */
p = X->p; p = (uint32_t *)X->p;
while (p < X->p + (size/ciL)) p_end = (uint32_t *)(X->p + (size/sizeof (uint32_t)));
while (p < p_end)
*p++ = jkiss (&jkiss_state_v); *p++ = jkiss (&jkiss_state_v);
if ((size % ciL))
*p = jkiss (&jkiss_state_v) & ((1 << (8*(size % ciL))) - 1); if ((size%sizeof (uint32_t)))
*p = jkiss (&jkiss_state_v) & ((1 << (8*(size % sizeof (uint32_t)))) - 1);
cleanup: cleanup:
return ret; return ret;
@@ -2202,10 +2275,24 @@ cleanup:
* Value M: multiply all primes up to 701 (except 97) and 797 * Value M: multiply all primes up to 701 (except 97) and 797
* (so that MAX_A will be convenient value) * (so that MAX_A will be convenient value)
*/ */
#ifdef __LP64__
#define M_LIMBS 16
#else
#define M_LIMBS 31 #define M_LIMBS 31
#endif
#define M_SIZE 122 #define M_SIZE 122
static const t_uint limbs_M[] = { /* Little endian */ static const t_uint limbs_M[] = { /* Little endian */
#ifdef __LP64__
0x9344A6AB84EEB59EUL, 0xEC855CDAFF21529FUL,
0x477E991E009BAB38UL, 0x2EEA23579F5B86F3UL,
0xAC17D30441D6502FUL, 0x38FF52B90A468A6DUL,
0x63630419FD42E5EFUL, 0x48CE17D091DB2572UL,
0x708AB00AE3B57D0EUL, 0xF8A9DE08CD723598UL,
0x731411374432C93BUL, 0x554DF2612779FAB3UL,
0xDEEBDA58953D2BA5UL, 0xD1D66F2F5F57D007UL,
0xB85C9607E84E9F2BUL, 0x000000000000401DUL
#else
0x84EEB59E, 0x9344A6AB, 0xFF21529F, 0xEC855CDA, 0x84EEB59E, 0x9344A6AB, 0xFF21529F, 0xEC855CDA,
0x009BAB38, 0x477E991E, 0x9F5B86F3, 0x2EEA2357, 0x009BAB38, 0x477E991E, 0x9F5B86F3, 0x2EEA2357,
0x41D6502F, 0xAC17D304, 0x0A468A6D, 0x38FF52B9, 0x41D6502F, 0xAC17D304, 0x0A468A6D, 0x38FF52B9,
@@ -2214,6 +2301,7 @@ static const t_uint limbs_M[] = { /* Little endian */
0x4432C93B, 0x73141137, 0x2779FAB3, 0x554DF261, 0x4432C93B, 0x73141137, 0x2779FAB3, 0x554DF261,
0x953D2BA5, 0xDEEBDA58, 0x5F57D007, 0xD1D66F2F, 0x953D2BA5, 0xDEEBDA58, 0x5F57D007, 0xD1D66F2F,
0xE84E9F2B, 0xB85C9607, 0x0000401D 0xE84E9F2B, 0xB85C9607, 0x0000401D
#endif
}; };
static const mpi M[1] = {{ 1, M_LIMBS, (t_uint *)limbs_M }}; static const mpi M[1] = {{ 1, M_LIMBS, (t_uint *)limbs_M }};
@@ -2221,10 +2309,18 @@ static const mpi M[1] = {{ 1, M_LIMBS, (t_uint *)limbs_M }};
/* /*
* MAX_A : 2^1024 / M - 1 * MAX_A : 2^1024 / M - 1
*/ */
#ifdef __LP64__
#define MAX_A_LIMBS 1
#else
#define MAX_A_LIMBS 2 #define MAX_A_LIMBS 2
#endif
#define MAX_A_FILL_SIZE 6 #define MAX_A_FILL_SIZE 6
static const t_uint limbs_MAX_A[] = { /* Little endian */ static const t_uint limbs_MAX_A[] = { /* Little endian */
#ifdef __LP64__
0x0003FE2556A2B35FUL
#else
0x56A2B35F, 0x0003FE25 0x56A2B35F, 0x0003FE25
#endif
}; };
static const mpi MAX_A[1] = {{ 1, MAX_A_LIMBS, (t_uint *)limbs_MAX_A }}; static const mpi MAX_A[1] = {{ 1, MAX_A_LIMBS, (t_uint *)limbs_MAX_A }};
@@ -2274,9 +2370,8 @@ int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
MPI_CHK ( mpi_mul_mpi ( X, X, M ) ); MPI_CHK ( mpi_mul_mpi ( X, X, M ) );
MPI_CHK ( mpi_add_abs ( X, X, B ) ); MPI_CHK ( mpi_add_abs ( X, X, B ) );
if (X->n <= 31 || (X->p[31] & 0xc0000000) == 0) if (X->n <= M_LIMBS || (X->p[M_LIMBS-1] & 0xc0000000) == 0)
continue; continue;
ret = mpi_is_prime ( X ); ret = mpi_is_prime ( X );
if (ret == 0 || ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE) if (ret == 0 || ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE)
break; break;

View File

@@ -39,7 +39,6 @@
#include "polarssl/md.h" #include "polarssl/md.h"
#endif #endif
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
/* /*

View File

@@ -1,8 +1,11 @@
# Makefile for reGNUal # Makefile for reGNUal
PROJECT = regnual PROJECT = regnual-no-vidpid
OBJS = regnual.o usb-stm32f103.o reset.o OBJS = regnual.o usb-stm32f103.o reset.o
include ../src/config.mk
LDSCRIPT= regnual.ld LDSCRIPT= regnual.ld
################################### ###################################
@@ -19,7 +22,7 @@ TOPT = -mthumb -DTHUMB -mno-thumb-interwork
# Define C warning options here # Define C warning options here
CWARN = -Wall -Wextra -Wstrict-prototypes CWARN = -Wall -Wextra -Wstrict-prototypes
MCFLAGS= -mcpu=$(MCU) MCFLAGS= -mcpu=$(MCU)
DEFS = -DFREE_STANDING DEFS += -DFREE_STANDING
CFLAGS = -O2 -g CFLAGS = -O2 -g
CFLAGS += -Wa,-alms=$(notdir $(<:.c=.lst)) -fpie CFLAGS += -Wa,-alms=$(notdir $(<:.c=.lst)) -fpie
@@ -38,13 +41,18 @@ regnual.hex: regnual.elf
$(OBJCOPY) -Obinary regnual.elf regnual.bin $(OBJCOPY) -Obinary regnual.elf regnual.bin
$(OBJCOPY) -Oihex regnual.elf regnual.hex $(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 usb-stm32f103.o: ../chopstx/mcu/usb-stm32f103.c
$(CC) $(CFLAGS) -c -o usb-stm32f103.o ../chopstx/mcu/usb-stm32f103.c $(CC) $(CFLAGS) -c -o usb-stm32f103.o ../chopstx/mcu/usb-stm32f103.c
regnual.elf: $(OBJS) $(LDSCRIPT) regnual-no-vidpid.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS) $(CC) $(LDFLAGS) -o regnual-no-vidpid.elf $(OBJS)
clean: clean:
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin *.lst -rm -f $(OBJS) regnual-no-vidpid.elf regnual.elf regnual.hex regnual.bin \
*.lst
distclean: clean distclean: clean

View File

@@ -1,7 +1,7 @@
/* /*
* regnual.c -- Firmware installation for STM32F103 Flash ROM * regnual.c -- Firmware installation for STM32F103 Flash ROM
* *
* Copyright (C) 2012, 2013, 2015, 2016 * Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -57,7 +57,9 @@ static const uint8_t regnual_device_desc[] = {
0x00, /* bDeviceSubClass */ 0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */ 0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */ 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 */ 1, /* Index of string descriptor describing manufacturer */
2, /* Index of string descriptor describing product */ 2, /* Index of string descriptor describing product */
3, /* Index of string descriptor describing the device's serial number */ 3, /* Index of string descriptor describing the device's serial number */
@@ -147,19 +149,33 @@ static uint32_t fetch (int i)
} }
struct CRC { struct CRC {
__IO uint32_t DR; volatile uint32_t DR;
__IO uint8_t IDR; volatile uint8_t IDR;
uint8_t RESERVED0; uint8_t RESERVED0;
uint16_t RESERVED1; 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 #define CRC_CR_RESET 0x01
static uint32_t calc_crc32 (void) static uint32_t calc_crc32 (void)
{ {
struct CRC *CRC = (struct CRC *)0x40023000;
int i; int i;
RCC->AHBENR |= RCC_AHBENR_CRCEN;
CRC->CR = CRC_CR_RESET; CRC->CR = CRC_CR_RESET;
for (i = 0; i < 256/4; i++) for (i = 0; i < 256/4; i++)
@@ -365,7 +381,11 @@ main (int argc, char *argv[])
set_led (0); set_led (0);
#if defined(STM32F103_OVERRIDE_FLASH_SIZE_KB)
flash_end = FLASH_START_ADDR + STM32F103_OVERRIDE_FLASH_SIZE_KB*1024;
#else
flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024; flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
#endif
/* /*
* NVIC interrupt priority was set by Gnuk. * NVIC interrupt priority was set by Gnuk.

View File

@@ -3,10 +3,9 @@ typedef unsigned long size_t;
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
typedef unsigned short uint16_t; typedef unsigned short uint16_t;
typedef unsigned int uint32_t; typedef unsigned int uint32_t;
typedef unsigned int uintptr_t;
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
#define NULL 0 #define NULL 0
#define __IO volatile

110
src/Makefile Normal file
View File

@@ -0,0 +1,110 @@
# Makefile for Gnuk
# Define project name here
PROJECT = gnuk
CHOPSTX = ../chopstx
CSRC = main.c call-rsa.c \
usb_desc.c usb_ctrl.c \
usb-ccid.c openpgp.c ac.c openpgp-do.c flash.c \
bn.c mod.c \
modp256r1.c jpc_p256r1.c ec_p256r1.c call-ec_p256r1.c \
modp256k1.c jpc_p256k1.c ec_p256k1.c call-ec_p256k1.c \
mod25638.c ecc-edwards.c ecc-mont.c sha512.c \
random.c neug.c sha256.c
INCDIR =
CRYPTDIR = ../polarssl
CRYPTSRCDIR = $(CRYPTDIR)/library
CRYPTINCDIR = $(CRYPTDIR)/include
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/aes.c
CSRC += $(CRYPTSRC)
INCDIR += $(CRYPTINCDIR)
include config.mk
USE_SYS = yes
USE_USB = yes
USE_ADC = yes
USE_EVENTFLAG = yes
ifeq ($(EMULATION),)
DEFS += -DFLASH_UPGRADE_SUPPORT
else
DEFS += -DBN256_C_IMPLEMENTATION
endif
ifneq ($(ENABLE_DEBUG),)
CSRC += debug.c
endif
ifneq ($(ENABLE_PINPAD),)
CSRC += pin-$(ENABLE_PINPAD).c
endif
ifeq ($(ENABLE_PINPAD),dnd)
CSRC += usb-msc.c
endif
ifeq ($(CHIP),stm32f103)
CSRC += mcu-stm32f103.c
endif
ifneq ($(USE_DFU),)
OBJS_ADD += build/stdaln-sys-bin.o
endif
###################################
CC = $(CROSS)gcc
LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
CWARN = -Wall -Wextra -Wstrict-prototypes
OPT = -O3 -Os -g
#######################
include $(CHOPSTX)/rules.mk
board.h:
@echo Please run configure to have a symbolic link \'board.h\'
@exit 1
sys.c: board.h
build/bignum.o: OPT = -O3 -g
build/stdaln-sys.elf: build/sys-$(CHIP).o stdaln-sys.ld
@echo
$(LD) -v $< $(MCFLAGS) -nostartfiles -Tstdaln-sys.ld -Wl,--no-warn-mismatch,--gc-sections $(LLIBDIR) -o $@
build/stdaln-sys-bin.o: build/stdaln-sys.elf
@echo
$(OBJCOPY) -O binary -j .sys $< build/stdaln-sys.bin
$(OBJCOPY) -I binary -O default --rename-section .data=.rodata \
build/stdaln-sys.bin $@
distclean: clean
-rm -f gnuk.ld stdaln-sys.ld config.h board.h config.mk \
usb-strings.c.inc put-vid-pid-ver.sh
ifeq ($(EMULATION),)
build/gnuk.elf: build/gnuk-no-vidpid.elf binary-edit.sh put-vid-pid-ver.sh
cp -p build/gnuk-no-vidpid.elf build/gnuk.elf
env FILE="build/gnuk.elf" bash put-vid-pid-ver.sh
$(OBJCOPY) -O ihex build/gnuk.elf build/gnuk.hex
$(OBJCOPY) -O binary build/gnuk.elf build/gnuk.bin
else
# By specifying DESTDIR on invocation of "make", you can install
# program to different ROOT.
# The variables prefix, exec_prefix, libexecdir are defined in
# config.mk.
install: build/gnuk
test -d "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)"
install -c build/gnuk "$(DESTDIR)$(libexecdir)"
endif

View File

@@ -1,79 +0,0 @@
# Makefile for Gnuk
# Define project name here
PROJECT = gnuk
CHOPSTX = ../chopstx
# Define linker script file here
LDSCRIPT= gnuk.ld
CSRC = main.c usb_desc.c usb_ctrl.c \
call-rsa.c \
usb-ccid.c openpgp.c ac.c openpgp-do.c flash.c \
bn.c mod.c \
modp256r1.c jpc_p256r1.c ec_p256r1.c call-ec_p256r1.c \
modp256k1.c jpc_p256k1.c ec_p256k1.c call-ec_p256k1.c \
mod25638.c ecc-edwards.c ecc-mont.c sha512.c \
random.c neug.c sha256.c
INCDIR =
CRYPTDIR = ../polarssl
CRYPTSRCDIR = $(CRYPTDIR)/library
CRYPTINCDIR = $(CRYPTDIR)/include
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/aes.c
CSRC += $(CRYPTSRC)
INCDIR += $(CRYPTINCDIR)
@PINPAD_MAKE_OPTION@
@DEBUG_MAKE_OPTION@
@HEXOUTPUT_MAKE_OPTION@
USE_EVENTFLAG = yes
ifneq ($(ENABLE_DEBUG),)
CSRC += debug.c
endif
ifneq ($(ENABLE_PINPAD),)
CSRC += pin-$(ENABLE_PINPAD).c
endif
ifeq ($(ENABLE_PINPAD),dnd)
CSRC += usb-msc.c
endif
CHIP=stm32f103
USE_SYS = yes
USE_USB = yes
USE_ADC = yes
###################################
CROSS = arm-none-eabi-
CC = $(CROSS)gcc
LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
MCU = cortex-m3
CWARN = -Wall -Wextra -Wstrict-prototypes
# DEFS: Add
DEFS = @USE_SYS3@
OPT = -O3 -Os -g
LIBS =
#######################
include $(CHOPSTX)/rules.mk
board.h:
@echo Please run configure to have a symbolic link \'board.h\'
@exit 1
sys.c: board.h
build/bignum.o: OPT = -O3 -g
distclean: clean
-rm -f gnuk.ld config.h board.h Makefile \
usb-strings.c.inc usb-vid-pid-ver.c.inc

View File

@@ -1,7 +1,7 @@
/* /*
* ac.c -- Check access condition * 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> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -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) if (ks_pw1 == NULL)
{ {
pw_len = strlen (OPENPGP_CARD_INITIAL_PW1); const uint8_t *initial_pw;
salt = NULL; salt = NULL;
salt_len = 0; salt_len = 0;
gpg_do_get_initial_pw_setting (0, &pw_len, &initial_pw);
if ((pw_len_known >= 0 && pw_len_known != pw_len) if ((pw_len_known >= 0 && pw_len_known != pw_len)
|| buf_len < pw_len || buf_len < pw_len
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW1, pw_len)) || memcmp (pw, initial_pw, pw_len))
goto failure; goto failure;
} }
else else
@@ -220,6 +222,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
} }
else else
{ {
const uint8_t *initial_pw;
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
if (ks_pw1 != NULL) if (ks_pw1 != NULL)
@@ -237,13 +240,13 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
return 0; return 0;
/* /*
* For the case of empty PW3 (with empty PW1), pass phrase * For the case of empty PW3 (with empty PW1), passphrase is
* should be OPENPGP_CARD_INITIAL_PW3 * 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) if ((pw_len_known >=0 && pw_len_known != pw_len)
|| buf_len < pw_len || buf_len < pw_len
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW3, pw_len)) || memcmp (pw, initial_pw, pw_len))
goto failure; goto failure;
admin_authorized = BY_ADMIN; admin_authorized = BY_ADMIN;

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

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

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
* call-ec.c - interface between Gnuk and Elliptic curve over GF(prime) * call-ec.c - interface between Gnuk and Elliptic curve over GF(prime)
* *
* Copyright (C) 2013, 2014 Free Software Initiative of Japan * Copyright (C) 2013, 2014, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -54,28 +54,21 @@ FUNC(ecdsa_sign) (const uint8_t *hash, uint8_t *output,
return 0; return 0;
} }
uint8_t * int
FUNC(ecc_compute_public) (const uint8_t *key_data) FUNC(ecc_compute_public) (const uint8_t *key_data, uint8_t *pubkey)
{ {
uint8_t *p0, *p, *p1; uint8_t *p, *p1;
ac q[1]; ac q[1];
bn256 k[1]; bn256 k[1];
int i; int i;
p0 = (uint8_t *)malloc (ECDSA_BYTE_SIZE * 2);
if (p0 == NULL)
return NULL;
p = (uint8_t *)k; p = (uint8_t *)k;
for (i = 0; i < ECDSA_BYTE_SIZE; i++) for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = key_data[i]; p[ECDSA_BYTE_SIZE - i - 1] = key_data[i];
if (FUNC(compute_kG) (q, k) < 0) if (FUNC(compute_kG) (q, k) < 0)
{ return -1;
free (p0);
return NULL;
}
p = p0; p = pubkey;
p1 = (uint8_t *)q->x; p1 = (uint8_t *)q->x;
for (i = 0; i < ECDSA_BYTE_SIZE; i++) for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*p++ = p1[ECDSA_BYTE_SIZE - i - 1]; *p++ = p1[ECDSA_BYTE_SIZE - i - 1];
@@ -83,7 +76,7 @@ FUNC(ecc_compute_public) (const uint8_t *key_data)
for (i = 0; i < ECDSA_BYTE_SIZE; i++) for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*p++ = p1[ECDSA_BYTE_SIZE - i - 1]; *p++ = p1[ECDSA_BYTE_SIZE - i - 1];
return p0; return 0;
} }
int int

View File

@@ -2,7 +2,7 @@
* call-ec_p256k1.c - interface between Gnuk and Elliptic curve over * call-ec_p256k1.c - interface between Gnuk and Elliptic curve over
* GF(p256k1) * GF(p256k1)
* *
* Copyright (C) 2014 Free Software Initiative of Japan * Copyright (C) 2014, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -23,7 +23,6 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "bn.h" #include "bn.h"
#include "affine.h" #include "affine.h"

View File

@@ -2,7 +2,7 @@
* call-ec_p256r1.c - interface between Gnuk and Elliptic curve over * call-ec_p256r1.c - interface between Gnuk and Elliptic curve over
* GF(p256r1) * GF(p256r1)
* *
* Copyright (C) 2014 Free Software Initiative of Japan * Copyright (C) 2014, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -23,7 +23,6 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "bn.h" #include "bn.h"
#include "affine.h" #include "affine.h"

View File

@@ -1,7 +1,7 @@
/* /*
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol * call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2017
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -24,13 +24,12 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <chopstx.h> #include <chopstx.h>
#include "config.h" #include "config.h"
#include "gnuk.h" #include "gnuk.h"
#include "openpgp.h" #include "status-code.h"
#include "random.h" #include "random.h"
#include "polarssl/config.h" #include "polarssl/config.h"
#include "polarssl/rsa.h" #include "polarssl/rsa.h"
@@ -41,7 +40,7 @@ static struct chx_cleanup clp;
static void static void
rsa_cleanup (void *arg) rsa_cleanup (void *arg)
{ {
free (arg); (void)arg;
rsa_free (&rsa_ctx); rsa_free (&rsa_ctx);
} }
@@ -111,28 +110,23 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
/* /*
* LEN: length in byte * LEN: length in byte
*/ */
uint8_t * int
modulus_calc (const uint8_t *p, int len) modulus_calc (const uint8_t *p, int len, uint8_t *pubkey)
{ {
mpi P, Q, N; mpi P, Q, N;
uint8_t *modulus;
int ret; int ret;
modulus = malloc (len);
if (modulus == NULL)
return NULL;
mpi_init (&P); mpi_init (&Q); mpi_init (&N); mpi_init (&P); mpi_init (&Q); mpi_init (&N);
MPI_CHK( mpi_read_binary (&P, p, len / 2) ); MPI_CHK( mpi_read_binary (&P, p, len / 2) );
MPI_CHK( mpi_read_binary (&Q, p + len / 2, len / 2) ); MPI_CHK( mpi_read_binary (&Q, p + len / 2, len / 2) );
MPI_CHK( mpi_mul_mpi (&N, &P, &Q) ); MPI_CHK( mpi_mul_mpi (&N, &P, &Q) );
MPI_CHK( mpi_write_binary (&N, modulus, len) ); MPI_CHK( mpi_write_binary (&N, pubkey, len) );
cleanup: cleanup:
mpi_free (&P); mpi_free (&Q); mpi_free (&N); mpi_free (&P); mpi_free (&Q); mpi_free (&N);
if (ret != 0) if (ret != 0)
return NULL; return -1;
else
return modulus; return 0;
} }
@@ -142,6 +136,9 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
{ {
mpi P1, Q1, H; mpi P1, Q1, H;
int ret; int ret;
#ifdef GNU_LINUX_EMULATION
size_t output_len;
#endif
DEBUG_INFO ("RSA decrypt:"); DEBUG_INFO ("RSA decrypt:");
DEBUG_WORD ((uint32_t)&ret); DEBUG_WORD ((uint32_t)&ret);
@@ -177,9 +174,16 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
clp.arg = NULL; clp.arg = NULL;
chopstx_cleanup_push (&clp); chopstx_cleanup_push (&clp);
cs = chopstx_setcancelstate (0); /* Allow cancellation. */ cs = chopstx_setcancelstate (0); /* Allow cancellation. */
#ifdef GNU_LINUX_EMULATION
ret = rsa_rsaes_pkcs1_v15_decrypt (&rsa_ctx, NULL, NULL,
RSA_PRIVATE, &output_len, input,
output, MAX_RES_APDU_DATA_SIZE);
*output_len_p = (unsigned int)output_len;
#else
ret = rsa_rsaes_pkcs1_v15_decrypt (&rsa_ctx, NULL, NULL, ret = rsa_rsaes_pkcs1_v15_decrypt (&rsa_ctx, NULL, NULL,
RSA_PRIVATE, output_len_p, input, RSA_PRIVATE, output_len_p, input,
output, MAX_RES_APDU_DATA_SIZE); output, MAX_RES_APDU_DATA_SIZE);
#endif
chopstx_setcancelstate (cs); chopstx_setcancelstate (cs);
chopstx_cleanup_pop (0); chopstx_cleanup_pop (0);
} }
@@ -232,54 +236,39 @@ rsa_verify (const uint8_t *pubkey, int pubkey_len,
#define RSA_EXPONENT 0x10001 #define RSA_EXPONENT 0x10001
uint8_t * int
rsa_genkey (int pubkey_len) rsa_genkey (int pubkey_len, uint8_t *pubkey, uint8_t *p_q)
{ {
int ret; int ret;
uint8_t index = 0; uint8_t index = 0;
uint8_t *p_q_modulus = (uint8_t *)malloc (pubkey_len * 2); uint8_t *p = p_q;
uint8_t *p = p_q_modulus; uint8_t *q = p_q + pubkey_len / 2;
uint8_t *q = p_q_modulus + pubkey_len / 2;
uint8_t *modulus = p_q_modulus + pubkey_len;
int cs; int cs;
extern int prng_seed (int (*f_rng)(void *, unsigned char *, size_t), extern int prng_seed (int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng); void *p_rng);
extern void neug_flush (void); extern void neug_flush (void);
if (p_q_modulus == NULL)
return NULL;
neug_flush (); neug_flush ();
prng_seed (random_gen, &index); prng_seed (random_gen, &index);
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
clp.next = NULL; clp.next = NULL;
clp.routine = rsa_cleanup; clp.routine = rsa_cleanup;
clp.arg = (void *)p_q_modulus; clp.arg = NULL;
chopstx_cleanup_push (&clp); chopstx_cleanup_push (&clp);
cs = chopstx_setcancelstate (0); /* Allow cancellation. */ cs = chopstx_setcancelstate (0); /* Allow cancellation. */
MPI_CHK( rsa_gen_key (&rsa_ctx, random_gen, &index, pubkey_len * 8, MPI_CHK( rsa_gen_key (&rsa_ctx, random_gen, &index, pubkey_len * 8,
RSA_EXPONENT) ); RSA_EXPONENT) );
if (ret != 0)
{
chopstx_setcancelstate (cs);
chopstx_cleanup_pop (0);
free (p_q_modulus);
rsa_free (&rsa_ctx);
return NULL;
}
MPI_CHK( mpi_write_binary (&rsa_ctx.P, p, pubkey_len / 2) ); MPI_CHK( mpi_write_binary (&rsa_ctx.P, p, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.Q, q, pubkey_len / 2) ); MPI_CHK( mpi_write_binary (&rsa_ctx.Q, q, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.N, modulus, pubkey_len) ); MPI_CHK( mpi_write_binary (&rsa_ctx.N, pubkey, pubkey_len) );
cleanup: cleanup:
chopstx_setcancelstate (cs); chopstx_setcancelstate (cs);
chopstx_cleanup_pop (0); chopstx_cleanup_pop (1);
rsa_free (&rsa_ctx);
if (ret != 0) if (ret != 0)
return NULL; return -1;
else else
return p_q_modulus; return 0;
} }

View File

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

301
src/configure vendored
View File

@@ -6,10 +6,11 @@ nl=$'\n'
# #
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka # This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
# #
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016 # Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
# Free Software Initiative of Japan # Free Software Initiative of Japan
# #
# This file is a part of Gnuk, a GnuPG USB Token implementation. # This file is a part of Gnuk, a GnuPG USB Token implementation.
#
# Gnuk is free software: you can redistribute it and/or modify it # Gnuk is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
@@ -36,33 +37,43 @@ fi
help=no help=no
vidpid=none vidpid=none
target=FST_01 target=FST_01
verbose=no
with_dfu=default with_dfu=default
debug=no debug=no
sys1_compat=yes sys1_compat=yes
pinpad=no pinpad=no
certdo=no certdo=no
hid_card_change=no hid_card_change=no
factory_reset=no
ackbtn_support=yes
flash_override=""
# For emulation
prefix=/usr/local
exec_prefix='${prefix}'
libexecdir='${exec_prefix}/libexec'
# Revision number # Revision number
if test -d ../.git; then if test -e ../.git; then
REVISION=`git describe --dirty="-modified"` if type git >/dev/null 2>&1; then
REVISION=$(git describe --dirty="-modified")
else
# echo 'No git available, please install git'
GIT_REVISION=$(sed -e 's/^\(.......\).*$/g\1/' "../.git/$(sed -e 's/^ref: //' ../.git/HEAD)")
REVISION=$(cat ../VERSION)-$GIT_REVISION
fi
else else
REVISION=`cat ../VERSION` REVISION=$(cat ../VERSION)
fi fi
# Process each option # Process each option
for option; do for option; do
case $option in case $option in
*=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;; *=*) optarg=$(expr "X$option" : '[^=]*=\(.*\)') ;;
*) optarg=yes ;; *) optarg=yes ;;
esac esac
case $option in case $option in
-h | --help) -h | --help)
help=yes ;; help=yes ;;
-v | --verbose)
verbose=yes ;;
--vidpid=*) --vidpid=*)
vidpid=$optarg ;; vidpid=$optarg ;;
--target=*) --target=*)
@@ -87,10 +98,23 @@ for option; do
sys1_compat=yes ;; sys1_compat=yes ;;
--disable-sys1-compat) --disable-sys1-compat)
sys1_compat=no ;; sys1_compat=no ;;
--enable-factory-reset)
factory_reset=yes ;;
--disable-factory-reset)
factory_reset=no ;;
--with-dfu) --with-dfu)
with_dfu=yes ;; with_dfu=yes ;;
--without-dfu) --without-dfu)
with_dfu=no ;; with_dfu=no ;;
#
# For emulation
#
--prefix=*)
prefix=optarg ;;
--exec-prefix=*)
exec_prefix=optarg ;;
--libexecdir=*)
libexecdir=optarg ;;
*) *)
echo "Unrecognized option \`$option'" >&2 echo "Unrecognized option \`$option'" >&2
echo "Try \`$0 --help' for more information." >&2 echo "Try \`$0 --help' for more information." >&2
@@ -111,16 +135,22 @@ Configuration:
--target=TARGET specify target [FST_01] --target=TARGET specify target [FST_01]
supported targets are: supported targets are:
FST_01 FST_01
FST_01G
FST_01SZ
OLIMEX_STM32_H103 OLIMEX_STM32_H103
STM32_PRIMER2
STBEE
STBEE_MINI
MAPLE_MINI MAPLE_MINI
ST_DONGLE ST_DONGLE
ST_NUCLEO_F103 ST_NUCLEO_F103
NITROKEY_START NITROKEY_START
BLUE_PILL
STM8S_DISCOVERY
CQ_STARM CQ_STARM
STM32_PRIMER2
STBEE
STBEE_MINI
FST_01_00 (unreleased version with 8MHz XTAL) FST_01_00 (unreleased version with 8MHz XTAL)
--enable-factory-reset
support life cycle management [no]
--enable-debug debug with virtual COM port [no] --enable-debug debug with virtual COM port [no]
--enable-pinpad=cir --enable-pinpad=cir
PIN entry support [no] PIN entry support [no]
@@ -135,15 +165,12 @@ EOF
exit 0 exit 0
fi fi
if test "$vidpid" = "none"; then BOARD_HEADER_FILE=board-$(echo $target | tr '_[:upper:]' '-[:lower:]').h
echo "Please specify Vendor ID and Product ID by --vidpid option." >&2 echo "Header file is: $BOARD_HEADER_FILE"
exit 1 ln -sf "../chopstx/board/$BOARD_HEADER_FILE" board.h
fi
BOARD_HEADER_FILE=board-`echo $target | tr '_[:upper:]' '-[:lower:]'`.h
echo Header file is: $BOARD_HEADER_FILE
ln -sf ../chopstx/board/$BOARD_HEADER_FILE board.h
# Frequency
MHZ=72
# Flash page size in byte # Flash page size in byte
FLASH_PAGE_SIZE=1024 FLASH_PAGE_SIZE=1024
# Flash memory size in KiB # Flash memory size in KiB
@@ -153,6 +180,10 @@ MEMORY_SIZE=20
# Settings for TARGET # Settings for TARGET
case $target in case $target in
BLUE_PILL|STM8S_DISCOVERY)
# It's 64KB version of STM32F103, but actually has 128KB
flash_override="-DSTM32F103_OVERRIDE_FLASH_SIZE_KB=128"
;;
CQ_STARM|STBEE_MINI) CQ_STARM|STBEE_MINI)
if test "$with_dfu" = "default"; then if test "$with_dfu" = "default"; then
with_dfu=yes; with_dfu=yes;
@@ -169,13 +200,55 @@ STBEE)
if test "$with_dfu" = "default"; then if test "$with_dfu" = "default"; then
with_dfu=yes; with_dfu=yes;
fi ;; fi ;;
STM8S_DISCOVERY) BLUE_PILL_G)
FLASH_SIZE=64 MHZ=96
;;
FST_01SZ)
MHZ=96
;; ;;
*) *)
;; ;;
esac esac
if test "$target" = "GNU_LINUX"; then
ldscript=""
chip="gnu-linux"
emulation="yes"
cross=""
mcu="none"
def_emulation="-DGNU_LINUX_EMULATION"
def_memory_size="-DMEMORY_SIZE=1024"
def_mhz=""
enable_hexoutput=""
libs="-lpthread"
else
ldscript="gnuk.ld"
chip="stm32f103"
emulation=""
cross="arm-none-eabi-"
mcu="cortex-m3"
def_emulation=""
def_memory_size="-DMEMORY_SIZE=$MEMORY_SIZE"
def_mhz="-DMHZ=$MHZ"
enable_hexoutput=yes
libs=""
fi
if test "$emulation" = "yes"; then
if test "$vidpid" = "none"; then
vidpid=0000:0000
else
echo "Please don't specify VID:PID for emulation at compile time;"
echo "It is a user who should specify VID:PID at run time."
exit 1
fi
else
if test "$vidpid" = "none"; then
echo "Please specify Vendor ID and Product ID by --vidpid option." >&2
exit 1
fi
fi
# --enable-debug option # --enable-debug option
if test "$debug" = "yes"; then if test "$debug" = "yes"; then
DEBUG_MAKE_OPTION="ENABLE_DEBUG=1" DEBUG_MAKE_OPTION="ENABLE_DEBUG=1"
@@ -187,29 +260,35 @@ else
echo "Debug option disabled" echo "Debug option disabled"
fi fi
ORIGIN_REAL=0x08000000
ORIGIN_REAL_DEFINE="#define ORIGIN_REAL $ORIGIN_REAL"
# --with-dfu option # --with-dfu option
if test "$with_dfu" = "yes"; then if test "$with_dfu" = "yes"; then
if test "$target" = "FST_01" -o "$target" = "FST_01_00"; then if test "$target" = "FST_01" -o "$target" = "FST_01G" \
-o "$target" = "FST_01_00"; then
echo "FST-01 doesn't have DFU loader, you should not use --with-dfu." >&2 echo "FST-01 doesn't have DFU loader, you should not use --with-dfu." >&2
exit 1 exit 1
fi fi
echo "Configured for DFU" echo "Configured for DFU"
ORIGIN=0x08003000 if test "$target" = "MAPLE_MINI"; then
FLASH_SIZE=`expr $FLASH_SIZE - 12` # Note that the default bootloader is too large, need for instance
# STM32duino for DFU on Maple Mini
ORIGIN=0x08002000
FLASH_SIZE=$((FLASH_SIZE - 8))
else
ORIGIN=0x08003000
FLASH_SIZE=$((FLASH_SIZE - 12))
fi
DFU_DEFINE="#define DFU_SUPPORT 1" DFU_DEFINE="#define DFU_SUPPORT 1"
HEXOUTPUT_MAKE_OPTION="ENABLE_OUTPUT_HEX=yes"
else else
with_dfu=no with_dfu=no
echo "Configured for bare system (no-DFU)" echo "Configured for bare system (no-DFU)"
ORIGIN=0x08000000 ORIGIN=${ORIGIN_REAL}
DFU_DEFINE="#undef DFU_SUPPORT" DFU_DEFINE="#undef DFU_SUPPORT"
HEXOUTPUT_MAKE_OPTION=""
fi fi
ORIGIN_DEFINE="#define ORIGIN $ORIGIN"
# --enable-pinpad option # --enable-pinpad option
MSC_SIZE="0"
TIM_SIZE="0"
EXT_SIZE="0"
if test "$pinpad" = "no"; then if test "$pinpad" = "no"; then
PINPAD_MAKE_OPTION="# ENABLE_PINPAD=" PINPAD_MAKE_OPTION="# ENABLE_PINPAD="
PINPAD_DEFINE="#undef PINPAD_SUPPORT" PINPAD_DEFINE="#undef PINPAD_SUPPORT"
@@ -220,12 +299,6 @@ else
PINPAD_DEFINE="#define PINPAD_SUPPORT 1" PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
PINPAD_MORE_DEFINE="#define PINPAD_${pinpad^^[a-z]}_SUPPORT 1" PINPAD_MORE_DEFINE="#define PINPAD_${pinpad^^[a-z]}_SUPPORT 1"
echo "PIN pad option enabled ($pinpad)" echo "PIN pad option enabled ($pinpad)"
if test "$pinpad" = "dnd"; then
MSC_SIZE="0x0200"
elif test "$pinpad" = "cir"; then
TIM_SIZE="0x00c0"
EXT_SIZE="0x00c0"
fi
fi fi
# --enable-certdo option # --enable-certdo option
@@ -246,14 +319,32 @@ else
echo "Card insert/removal by HID device is NOT supported" echo "Card insert/removal by HID device is NOT supported"
fi fi
# --enable-factory-reset option
if test "$factory_reset" = "yes"; then
LIFE_CYCLE_MANAGEMENT_DEFINE="#define LIFE_CYCLE_MANAGEMENT_SUPPORT 1"
echo "Life cycle management is supported"
else
LIFE_CYCLE_MANAGEMENT_DEFINE="#undef LIFE_CYCLE_MANAGEMENT_SUPPORT"
echo "Life cycle management is NOT supported"
fi
# Acknowledge button support
if test "$ackbtn_support" = "yes"; then
ACKBTN_DEFINE="#define ACKBTN_SUPPORT 1"
echo "Acknowledge button is supported"
else
ACKBTN_DEFINE="#undef ACKBTN_SUPPORT"
echo "Acknowledge button is not supported"
fi
### !!! Replace following string of "FSIJ" to yours !!! #### ### !!! Replace following string of "FSIJ" to yours !!! ####
SERIALNO="FSIJ-`cat ../VERSION | sed -e 's%^[^/]*/%%'`-" SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
SERIALNO_STR_LEN_DEFINE="#define SERIALNO_STR_LEN ${#SERIALNO}" SERIALNO_STR_LEN_DEFINE="#define SERIALNO_STR_LEN ${#SERIALNO}"
if test "$sys1_compat" = "yes"; then if test "$sys1_compat" = "yes"; then
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo" CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:factory_reset=$factory_reset"
else else
if test "$with_dfu" = "yes"; then if test "$with_dfu" = "yes"; then
echo "Common binary can't support DFU loader, don't use --with-dfu." >&2 echo "Common binary can't support DFU loader, don't use --with-dfu." >&2
@@ -263,53 +354,82 @@ else
FLASH_PAGE_SIZE=2048 FLASH_PAGE_SIZE=2048
FLASH_SIZE=128 FLASH_SIZE=128
MEMORY_SIZE=20 MEMORY_SIZE=20
CONFIG="common:debug=$debug:pinpad=$pinpad:certdo=$certdo" CONFIG="common:debug=$debug:pinpad=$pinpad:certdo=$certdo:factory_reset=$factory_reset"
fi fi
output_vid_pid_version () { 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 "$VIDPID" | \
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p" 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 () { output_vendor_product_serial_strings () {
prefix=$1 name=$1
echo "static const uint8_t ${prefix}string_vendor[] = {" echo "static const uint8_t ${name}string_vendor[] = {"
echo " ${#VENDOR}*2+2, /* bLength */" echo " ${#VENDOR}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */" echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Manufacturer: \"$VENDOR\" */" echo " /* Manufacturer: \"$VENDOR\" */"
echo $VENDOR | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p" echo "$VENDOR" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};' echo '};'
echo echo
echo "static const uint8_t ${prefix}string_product[] = {" echo "static const uint8_t ${name}string_product[] = {"
echo " ${#PRODUCT}*2+2, /* bLength */" echo " ${#PRODUCT}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */" echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Product name: \"$PRODUCT\" */" echo " /* Product name: \"$PRODUCT\" */"
echo $PRODUCT | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p" echo "$PRODUCT" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};' echo '};'
if test -n "$prefix"; then if test -n "$name"; then
echo echo
echo "const uint8_t ${prefix}string_serial[] = {" echo "const uint8_t ${name}string_serial[] = {"
echo " ${#SERIALNO}*2+2+16, /* bLength */" echo " ${#SERIALNO}*2+2+16, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */" echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Serial number: \"$SERIALNO\" */" echo " /* Serial number: \"$SERIALNO\" */"
echo $SERIALNO | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p" echo "$SERIALNO" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff," if test "$emulation" = "yes"; then
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff," echo " 'E', 0, 'M', 0, 'U', 0, 'L', 0,"
echo " 'A', 0, 'T', 0, 'E', 0, 'D', 0,"
else
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
fi
echo '};' echo '};'
echo echo
echo '#ifdef USB_STRINGS_FOR_GNUK' echo '#ifdef USB_STRINGS_FOR_GNUK'
echo "static const uint8_t ${prefix}revision_detail[] = {" echo "static const uint8_t ${name}revision_detail[] = {"
echo " ${#REVISION}*2+2, /* bLength */" echo " ${#REVISION}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */" echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* revision detail: \"$REVISION\" */" echo " /* revision detail: \"$REVISION\" */"
echo $REVISION | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p" echo "$REVISION" | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};' echo '};'
echo echo
echo "static const uint8_t ${prefix}config_options[] = {" echo "static const uint8_t ${name}config_options[] = {"
echo " ${#CONFIG}*2+2, /* bLength */" echo " ${#CONFIG}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */" echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* configure options: \"$CONFIG\" */" echo " /* configure options: \"$CONFIG\" */"
echo $CONFIG | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p" echo $CONFIG | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};' echo '};'
@@ -317,16 +437,22 @@ output_vendor_product_serial_strings () {
fi fi
} }
(echo "#! /bin/bash"
echo
echo 'source "binary-edit.sh"') > put-vid-pid-ver.sh
if !(IFS=" " if !(IFS=" "
while read VIDPID VERSION PRODUCT VENDOR; do while read -r VIDPID VERSION PRODUCT VENDOR; do
if test "$vidpid" = "$VIDPID"; then 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 output_vendor_product_serial_strings gnuk_ >usb-strings.c.inc
exit 0 exit 0
fi fi
done; exit 1) < ../GNUK_USB_DEVICE_ID done; exit 1) < ../GNUK_USB_DEVICE_ID
then then
echo "Please specify valid Vendor ID and Product ID." >&2 echo "Please specify valid Vendor ID and Product ID." >&2
echo "Check ../GNUK_USB_DEVICE_ID." >&2 echo "Check ../GNUK_USB_DEVICE_ID." >&2
exit 1 exit 1
fi fi
@@ -343,36 +469,55 @@ else
fi fi
sed -e "s%@USE_SYS3@%$use_sys3%" \ (echo "CHIP=$chip";
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \ echo "EMULATION=$emulation";
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \ echo "CROSS=$cross";
-e "s%@HEXOUTPUT_MAKE_OPTION@%$HEXOUTPUT_MAKE_OPTION%" \ echo "MCU=$mcu";
< Makefile.in > Makefile echo "DEFS=$use_sys3 $flash_override $def_emulation $def_memory_size $def_mhz";
echo "LDSCRIPT=$ldscript";
echo "LIBS=$libs";
echo "$DEBUG_MAKE_OPTION";
echo "$PINPAD_MAKE_OPTION";
echo "ENABLE_FRAUCHEKY=$enable_fraucheky";
echo "ENABLE_OUTPUT_HEX=$enable_hexoutput"
if test "$ackbtn_support" = "yes"; then
echo "USE_ACKBTN=yes"
fi
if test "$with_dfu" = "yes"; then
echo "USE_DFU=yes"
fi
if test "$emulation" = "yes"; then
echo "prefix=$prefix"
echo "exec_prefix=$exec_prefix"
echo "libexecdir=$libexecdir"
fi
) > config.mk
if test "$certdo" = "yes"; then if test "$certdo" = "yes"; then
sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \ sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \
-e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \ -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
-e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \ -e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \ -e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
-e "s/@MSC_SIZE@/$MSC_SIZE/" \
-e "s/@TIM_SIZE@/$TIM_SIZE/" \
-e "s/@EXT_SIZE@/$EXT_SIZE/" \
< gnuk.ld.in > gnuk.ld < gnuk.ld.in > gnuk.ld
else else
sed -e "/^@CERTDO_SUPPORT_START@$/,/^@CERTDO_SUPPORT_END@$/ d" \ sed -e "/^@CERTDO_SUPPORT_START@$/,/^@CERTDO_SUPPORT_END@$/ d" \
-e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \ -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
-e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \ -e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \ -e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
-e "s/@MSC_SIZE@/$MSC_SIZE/" \
-e "s/@TIM_SIZE@/$TIM_SIZE/" \
-e "s/@EXT_SIZE@/$EXT_SIZE/" \
< gnuk.ld.in > gnuk.ld < gnuk.ld.in > gnuk.ld
fi fi
sed -e "s/@ORIGIN_REAL@/$ORIGIN_REAL/" -e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
< stdaln-sys.ld.in > stdaln-sys.ld
sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \ sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \ -e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
-e "s/@ORIGIN_DEFINE@/$ORIGIN_DEFINE/" \
-e "s/@ORIGIN_REAL_DEFINE@/$ORIGIN_REAL_DEFINE/" \
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \ -e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \ -e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \ -e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \ -e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
-e "s/@ACKBTN_DEFINE@/$ACKBTN_DEFINE/" \
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \ -e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
< config.h.in > config.h < config.h.in > config.h
exit 0 exit 0

View File

@@ -42,9 +42,11 @@
/* /*
* a = 0, b = 7 * a = 0, b = 7
*/ */
#if 0
static const bn256 coefficient_a[1] = { static const bn256 coefficient_a[1] = {
{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }} {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
}; };
#endif
static const bn256 coefficient_b[1] = { static const bn256 coefficient_b[1] = {
{{ 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }} {{ 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}

View File

@@ -2,7 +2,7 @@
* ecc-edwards.c - Elliptic curve computation for * ecc-edwards.c - Elliptic curve computation for
* the twisted Edwards curve: -x^2 + y^2 = 1 + d*x^2*y^2 * the twisted Edwards curve: -x^2 + y^2 = 1 + d*x^2*y^2
* *
* Copyright (C) 2014 Free Software Initiative of Japan * Copyright (C) 2014, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -23,7 +23,6 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "bn.h" #include "bn.h"
@@ -708,7 +707,7 @@ eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *out,
return 0; return 0;
} }
void static void
eddsa_public_key_25519 (bn256 *pk, const bn256 *a) eddsa_public_key_25519 (bn256 *pk, const bn256 *a)
{ {
ac R[1]; ac R[1];
@@ -730,18 +729,10 @@ eddsa_public_key_25519 (bn256 *pk, const bn256 *a)
} }
uint8_t * void
eddsa_compute_public_25519 (const uint8_t *kd) eddsa_compute_public_25519 (const uint8_t *kd, uint8_t *pubkey)
{ {
uint8_t *p0; eddsa_public_key_25519 ((bn256 *)pubkey, (const bn256 *)kd);
const bn256 *a = (const bn256 *)kd;
p0 = (uint8_t *)malloc (sizeof (bn256));
if (p0 == NULL)
return NULL;
eddsa_public_key_25519 ((bn256 *)p0, a);
return p0;
} }

View File

@@ -2,7 +2,7 @@
* ecc-mont.c - Elliptic curve computation for * ecc-mont.c - Elliptic curve computation for
* the Montgomery curve: y^2 = x^3 + 486662*x^2 + x. * the Montgomery curve: y^2 = x^3 + 486662*x^2 + x.
* *
* Copyright (C) 2014, 2015 Free Software Initiative of Japan * Copyright (C) 2014, 2015, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,7 +24,6 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "bn.h" #include "bn.h"
#include "mod25638.h" #include "mod25638.h"
#include "mod.h" #include "mod.h"
@@ -198,22 +197,17 @@ compute_nQ (bn256 *res, const bn256 *n, const bn256 *q_x)
} }
uint8_t * void
ecdh_compute_public_25519 (const uint8_t *key_data) ecdh_compute_public_25519 (const uint8_t *key_data, uint8_t *pubkey)
{ {
uint8_t *p;
bn256 gx[1]; bn256 gx[1];
bn256 k[1]; bn256 k[1];
memset (gx, 0, sizeof (bn256)); memset (gx, 0, sizeof (bn256));
gx[0].word[0] = 9; /* Gx = 9 */ gx[0].word[0] = 9; /* Gx = 9 */
memcpy (k, key_data, sizeof (bn256)); memcpy (k, key_data, sizeof (bn256));
p = (uint8_t *)malloc (sizeof (bn256));
if (p == NULL)
return NULL;
compute_nQ ((bn256 *)p, k, gx); compute_nQ ((bn256 *)pubkey, k, gx);
return p;
} }
int int

View File

@@ -384,7 +384,7 @@ FUNC(check_secret) (const bn256 *d0, bn256 *d1)
{ {
ac Q0[1], Q1[1]; ac Q0[1], Q1[1];
if (bn256_is_zero (d0) || bn256_sub (d1, N, d0) <= 0) if (bn256_is_zero (d0) || bn256_sub (d1, N, d0) != 0)
/* == 0 or >= N, it's not valid. */ /* == 0 or >= N, it's not valid. */
return 0; return 0;

View File

@@ -1,7 +1,7 @@
/* /*
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM * flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -53,33 +53,40 @@
* <alignment to page> * <alignment to page>
* ch_certificate_startp * ch_certificate_startp
* <2048 bytes> * <2048 bytes>
* _data_pool
* <two pages>
* _keystore_pool * _keystore_pool
* Three flash pages for keystore * Three flash pages for keystore
* a page contains a key data of: * a page contains a key data of:
* For RSA-2048: 512-byte (p, q and N) * For RSA-2048: 512-byte (p, q and N)
* For RSA-4096: 1024-byte (p, q and N) * For RSA-4096: 1024-byte (p, q and N)
* For ECDSA/ECDH and EdDSA, there are padding after public key * For ECDSA/ECDH and EdDSA, there are padding after public key
* _data_pool
* <two pages>
*/ */
#define FLASH_DATA_POOL_HEADER_SIZE 2 #define FLASH_DATA_POOL_HEADER_SIZE 2
#define FLASH_DATA_POOL_SIZE (flash_page_size*2) #define FLASH_DATA_POOL_SIZE (flash_page_size*2)
static uint16_t flash_page_size; static uint16_t flash_page_size;
static const uint8_t *data_pool; static const uint8_t *data_pool;
extern uint8_t _keystore_pool;
static uint8_t *last_p; static uint8_t *last_p;
/* The first halfword is generation for the data page (little endian) */ /* The first halfword is generation for the data page (little endian) */
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = { const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
0x01, 0x00, 0xff, 0xff 0x00, 0x00, 0xff, 0xff
}; };
/* Linker set this symbol */ #ifdef GNU_LINUX_EMULATION
extern uint8_t *flash_addr_key_storage_start;
extern uint8_t *flash_addr_data_storage_start;
#define FLASH_ADDR_KEY_STORAGE_START flash_addr_key_storage_start
#define FLASH_ADDR_DATA_STORAGE_START flash_addr_data_storage_start
#else
/* Linker sets these symbols */
extern uint8_t _keystore_pool;
extern uint8_t _data_pool; extern uint8_t _data_pool;
#define FLASH_ADDR_KEY_STORAGE_START ((&_keystore_pool))
#define FLASH_ADDR_DATA_STORAGE_START ((&_data_pool))
#endif
static int key_available_at (const uint8_t *k, int key_size) static int key_available_at (const uint8_t *k, int key_size)
{ {
@@ -102,42 +109,88 @@ static int key_available_at (const uint8_t *k, int key_size)
#define CHIP_ID_REG ((uint32_t *)0xe0042000) #define CHIP_ID_REG ((uint32_t *)0xe0042000)
const uint8_t * void
flash_init (void) flash_do_storage_init (const uint8_t **p_do_start, const uint8_t **p_do_end)
{ {
uint16_t gen0, gen1; uint16_t gen0, gen1;
uint16_t *gen0_p = (uint16_t *)&_data_pool; uint16_t *gen0_p = (uint16_t *)FLASH_ADDR_DATA_STORAGE_START;
uint16_t *gen1_p; uint16_t *gen1_p;
flash_page_size = 1024; flash_page_size = 1024;
#if !defined (GNU_LINUX_EMULATION)
if (((*CHIP_ID_REG) & 0xfff) == 0x0414) if (((*CHIP_ID_REG) & 0xfff) == 0x0414)
flash_page_size = 2048; flash_page_size = 2048;
#endif
gen1_p = (uint16_t *)(&_data_pool + flash_page_size); gen1_p = (uint16_t *)(FLASH_ADDR_DATA_STORAGE_START + flash_page_size);
data_pool = FLASH_ADDR_DATA_STORAGE_START;
/* Check data pool generation and choose the page */ /* Check data pool generation and choose the page */
gen0 = *gen0_p; gen0 = *gen0_p;
gen1 = *gen1_p; gen1 = *gen1_p;
if (gen0 == 0xffff)
data_pool = &_data_pool + flash_page_size;
else if (gen1 == 0xffff)
data_pool = &_data_pool;
else if (gen1 > gen0)
data_pool = &_data_pool + flash_page_size;
else
data_pool = &_data_pool;
return data_pool + FLASH_DATA_POOL_HEADER_SIZE; if (gen0 == 0xffff && gen1 == 0xffff)
{
/* It's terminated. */
*p_do_start = *p_do_end = NULL;
return;
}
if (gen0 == 0xffff)
/* Use another page if a page is erased. */
data_pool = FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
else if (gen1 == 0xffff)
/* Or use different page if another page is erased. */
data_pool = FLASH_ADDR_DATA_STORAGE_START;
else if ((gen0 == 0xfffe && gen1 == 0) || gen1 > gen0)
/* When both pages have valid header, use newer page. */
data_pool = FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
*p_do_start = data_pool + FLASH_DATA_POOL_HEADER_SIZE;
*p_do_end = data_pool + flash_page_size;
}
static uint8_t *flash_key_getpage (enum kind_of_key kk);
void
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);
flash_erase_page ((uintptr_t)(FLASH_ADDR_DATA_STORAGE_START + flash_page_size));
data_pool = FLASH_ADDR_DATA_STORAGE_START;
last_p = FLASH_ADDR_DATA_STORAGE_START + FLASH_DATA_POOL_HEADER_SIZE;
#if defined(CERTDO_SUPPORT)
flash_erase_page ((uintptr_t)&ch_certificate_start);
if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size)
flash_erase_page ((uintptr_t)(&ch_certificate_start + flash_page_size));
#endif
} }
void void
flash_init_keys (void) flash_activate (void)
{
flash_program_halfword ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START, 0);
}
void
flash_key_storage_init (void)
{ {
const uint8_t *p; const uint8_t *p;
int i; int i;
/* For each key, find its address. */ /* For each key, find its address. */
p = &_keystore_pool; p = FLASH_ADDR_KEY_STORAGE_START;
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
const uint8_t *k; const uint8_t *k;
@@ -195,22 +248,26 @@ flash_copying_gc (void)
uint8_t *src, *dst; uint8_t *src, *dst;
uint16_t generation; uint16_t generation;
if (data_pool == &_data_pool) if (data_pool == FLASH_ADDR_DATA_STORAGE_START)
{ {
src = &_data_pool; src = FLASH_ADDR_DATA_STORAGE_START;
dst = &_data_pool + flash_page_size; dst = FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
} }
else else
{ {
src = &_data_pool + flash_page_size; src = FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
dst = &_data_pool; dst = FLASH_ADDR_DATA_STORAGE_START;
} }
generation = *(uint16_t *)src; generation = *(uint16_t *)src;
data_pool = dst; data_pool = dst;
gpg_data_copy (data_pool + FLASH_DATA_POOL_HEADER_SIZE); gpg_data_copy (data_pool + FLASH_DATA_POOL_HEADER_SIZE);
flash_erase_page ((uint32_t)src); if (generation == 0xfffe)
flash_program_halfword ((uint32_t)dst, generation+1); generation = 0;
else
generation++;
flash_program_halfword ((uintptr_t)dst, generation);
flash_erase_page ((uintptr_t)src);
return 0; return 0;
} }
@@ -240,10 +297,10 @@ void
flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len) flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
{ {
uint16_t hw; uint16_t hw;
uint32_t addr; uintptr_t addr;
int i; int i;
addr = (uint32_t)p; addr = (uintptr_t)p;
hw = nr | (len << 8); hw = nr | (len << 8);
if (flash_program_halfword (addr, hw) != 0) if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR"); flash_warning ("DO WRITE ERROR");
@@ -296,13 +353,14 @@ flash_warning (const char *msg)
void void
flash_do_release (const uint8_t *do_data) flash_do_release (const uint8_t *do_data)
{ {
uint32_t addr = (uint32_t)do_data - 1; uintptr_t addr = (uintptr_t)do_data - 1;
uint32_t addr_tag = addr; uintptr_t addr_tag = addr;
int i; int i;
int len = do_data[0]; int len = do_data[0];
/* Don't filling zero for data in code (such as ds_count_initial_value) */ /* Don't filling zero for data in code (such as ds_count_initial_value) */
if (do_data < &_data_pool || do_data > &_data_pool + FLASH_DATA_POOL_SIZE) if (do_data < FLASH_ADDR_DATA_STORAGE_START
|| do_data > FLASH_ADDR_DATA_STORAGE_START + FLASH_DATA_POOL_SIZE)
return; return;
addr += 2; addr += 2;
@@ -331,7 +389,7 @@ static uint8_t *
flash_key_getpage (enum kind_of_key kk) flash_key_getpage (enum kind_of_key kk)
{ {
/* There is a page for each KK. */ /* There is a page for each KK. */
return &_keystore_pool + (flash_page_size * kk); return FLASH_ADDR_KEY_STORAGE_START + (flash_page_size * kk);
} }
uint8_t * uint8_t *
@@ -365,10 +423,10 @@ flash_key_write (uint8_t *key_addr,
const uint8_t *pubkey, int pubkey_len) const uint8_t *pubkey, int pubkey_len)
{ {
uint16_t hw; uint16_t hw;
uint32_t addr; uintptr_t addr;
int i; int i;
addr = (uint32_t)key_addr; addr = (uintptr_t)key_addr;
for (i = 0; i < key_data_len/2; i ++) for (i = 0; i < key_data_len/2; i ++)
{ {
hw = key_data[i*2] | (key_data[i*2+1]<<8); hw = key_data[i*2] | (key_data[i*2+1]<<8);
@@ -391,7 +449,7 @@ flash_key_write (uint8_t *key_addr,
static int static int
flash_check_all_other_keys_released (const uint8_t *key_addr, int key_size) flash_check_all_other_keys_released (const uint8_t *key_addr, int key_size)
{ {
uint32_t start = (uint32_t)key_addr & ~(flash_page_size - 1); uintptr_t start = (uintptr_t)key_addr & ~(flash_page_size - 1);
const uint32_t *p = (const uint32_t *)start; const uint32_t *p = (const uint32_t *)start;
while (p < (const uint32_t *)(start + flash_page_size)) while (p < (const uint32_t *)(start + flash_page_size))
@@ -410,7 +468,7 @@ static void
flash_key_fill_zero_as_released (uint8_t *key_addr, int key_size) flash_key_fill_zero_as_released (uint8_t *key_addr, int key_size)
{ {
int i; int i;
uint32_t addr = (uint32_t)key_addr; uintptr_t addr = (uintptr_t)key_addr;
for (i = 0; i < key_size/2; i++) for (i = 0; i < key_size/2; i++)
flash_program_halfword (addr + i*2, 0); flash_program_halfword (addr + i*2, 0);
@@ -420,7 +478,7 @@ void
flash_key_release (uint8_t *key_addr, int key_size) flash_key_release (uint8_t *key_addr, int key_size)
{ {
if (flash_check_all_other_keys_released (key_addr, key_size)) if (flash_check_all_other_keys_released (key_addr, key_size))
flash_erase_page (((uint32_t)key_addr & ~(flash_page_size - 1))); flash_erase_page (((uintptr_t)key_addr & ~(flash_page_size - 1)));
else else
flash_key_fill_zero_as_released (key_addr, key_size); flash_key_fill_zero_as_released (key_addr, key_size);
} }
@@ -428,12 +486,12 @@ flash_key_release (uint8_t *key_addr, int key_size)
void void
flash_key_release_page (enum kind_of_key kk) flash_key_release_page (enum kind_of_key kk)
{ {
flash_erase_page ((uint32_t)flash_key_getpage (kk)); flash_erase_page ((uintptr_t)flash_key_getpage (kk));
} }
void void
flash_clear_halfword (uint32_t addr) flash_clear_halfword (uintptr_t addr)
{ {
flash_program_halfword (addr, 0); flash_program_halfword (addr, 0);
} }
@@ -442,7 +500,7 @@ flash_clear_halfword (uint32_t addr)
void void
flash_put_data_internal (const uint8_t *p, uint16_t hw) flash_put_data_internal (const uint8_t *p, uint16_t hw)
{ {
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
} }
void void
@@ -456,7 +514,7 @@ flash_put_data (uint16_t hw)
DEBUG_INFO ("data allocation failure.\r\n"); DEBUG_INFO ("data allocation failure.\r\n");
} }
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
} }
@@ -468,14 +526,14 @@ flash_bool_clear (const uint8_t **addr_p)
if ((p = *addr_p) == NULL) if ((p = *addr_p) == NULL)
return; return;
flash_program_halfword ((uint32_t)p, 0); flash_program_halfword ((uintptr_t)p, 0);
*addr_p = NULL; *addr_p = NULL;
} }
void void
flash_bool_write_internal (const uint8_t *p, int nr) flash_bool_write_internal (const uint8_t *p, int nr)
{ {
flash_program_halfword ((uint32_t)p, nr); flash_program_halfword ((uintptr_t)p, nr);
} }
const uint8_t * const uint8_t *
@@ -491,7 +549,7 @@ flash_bool_write (uint8_t nr)
return NULL; return NULL;
} }
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
return p; return p;
} }
@@ -507,7 +565,7 @@ flash_enum_write_internal (const uint8_t *p, int nr, uint8_t v)
{ {
uint16_t hw = nr | (v << 8); uint16_t hw = nr | (v << 8);
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
} }
const uint8_t * const uint8_t *
@@ -523,7 +581,7 @@ flash_enum_write (uint8_t nr, uint8_t v)
return NULL; return NULL;
} }
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
return p; return p;
} }
@@ -559,14 +617,14 @@ flash_cnt123_write_internal (const uint8_t *p, int which, int v)
uint16_t hw; uint16_t hw;
hw = NR_COUNTER_123 | (which << 8); hw = NR_COUNTER_123 | (which << 8);
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
if (v == 1) if (v == 1)
return; return;
else if (v == 2) else if (v == 2)
flash_program_halfword ((uint32_t)p+2, 0xc3c3); flash_program_halfword ((uintptr_t)p+2, 0xc3c3);
else /* v == 3 */ else /* v == 3 */
flash_program_halfword ((uint32_t)p+2, 0); flash_program_halfword ((uintptr_t)p+2, 0);
} }
void void
@@ -584,7 +642,7 @@ flash_cnt123_increment (uint8_t which, const uint8_t **addr_p)
return; return;
} }
hw = NR_COUNTER_123 | (which << 8); hw = NR_COUNTER_123 | (which << 8);
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
*addr_p = p + 2; *addr_p = p + 2;
} }
else else
@@ -599,7 +657,7 @@ flash_cnt123_increment (uint8_t which, const uint8_t **addr_p)
else else
hw = 0; hw = 0;
flash_program_halfword ((uint32_t)p, hw); flash_program_halfword ((uintptr_t)p, hw);
} }
} }
@@ -611,9 +669,9 @@ flash_cnt123_clear (const uint8_t **addr_p)
if ((p = *addr_p) == NULL) if ((p = *addr_p) == NULL)
return; return;
flash_program_halfword ((uint32_t)p, 0); flash_program_halfword ((uintptr_t)p, 0);
p -= 2; p -= 2;
flash_program_halfword ((uint32_t)p, 0); flash_program_halfword ((uintptr_t)p, 0);
*addr_p = NULL; *addr_p = NULL;
} }
@@ -627,9 +685,9 @@ flash_erase_binary (uint8_t file_id)
const uint8_t *p = &ch_certificate_start; const uint8_t *p = &ch_certificate_start;
if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0) if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0)
{ {
flash_erase_page ((uint32_t)p); flash_erase_page ((uintptr_t)p);
if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size) if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size)
flash_erase_page ((uint32_t)p + flash_page_size); flash_erase_page ((uintptr_t)p + flash_page_size);
} }
return 0; return 0;
@@ -652,17 +710,19 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
maxsize = 6; maxsize = 6;
p = &openpgpcard_aid[8]; p = &openpgpcard_aid[8];
} }
#ifdef FLASH_UPGRADE_SUPPORT
else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3) else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
{ {
maxsize = FIRMWARE_UPDATE_KEY_CONTENT_LEN; maxsize = FIRMWARE_UPDATE_KEY_CONTENT_LEN;
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0); p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
if (len == 0 && offset == 0) if (len == 0 && offset == 0)
{ /* This means removal of update key. */ { /* This means removal of update key. */
if (flash_program_halfword ((uint32_t)p, 0) != 0) if (flash_program_halfword ((uintptr_t)p, 0) != 0)
flash_warning ("DO WRITE ERROR"); flash_warning ("DO WRITE ERROR");
return 0; return 0;
} }
} }
#endif
#if defined(CERTDO_SUPPORT) #if defined(CERTDO_SUPPORT)
else if (file_id == FILEID_CH_CERTIFICATE) else if (file_id == FILEID_CH_CERTIFICATE)
{ {
@@ -678,13 +738,13 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
else else
{ {
uint16_t hw; uint16_t hw;
uint32_t addr; uintptr_t addr;
int i; int i;
if (flash_check_blank (p + offset, len) == 0) if (flash_check_blank (p + offset, len) == 0)
return -1; return -1;
addr = (uint32_t)p + offset; addr = (uintptr_t)p + offset;
for (i = 0; i < len/2; i++) for (i = 0; i < len/2; i++)
{ {
hw = data[i*2] | (data[i*2+1]<<8); hw = data[i*2] | (data[i*2+1]<<8);

16
src/gnuk-malloc.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* Gnuk uses its own malloc functions.
*
* The intention is no-dependency to C library. But, we provide
* malloc and free here, since RSA routines uses malloc/free
* internally.
*
*/
#include <stddef.h> /* NULL and size_t */
#define malloc(size) gnuk_malloc (size)
#define free(p) gnuk_free (p)
void *gnuk_malloc (size_t);
void gnuk_free (void *);

View File

@@ -22,22 +22,20 @@ extern struct apdu apdu;
#define CARD_CHANGE_REMOVE 1 #define CARD_CHANGE_REMOVE 1
#define CARD_CHANGE_TOGGLE 2 #define CARD_CHANGE_TOGGLE 2
void ccid_card_change_signal (int how); void ccid_card_change_signal (int how);
void ccid_usb_reset (int);
/* CCID thread */ /* CCID thread */
#define EV_RX_DATA_READY 1 /* USB Rx data available */ #define EV_CARD_CHANGE 1
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */ #define EV_TX_FINISHED 2 /* CCID Tx finished */
#define EV_TX_FINISHED 4 /* CCID Tx finished */ #define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
#define EV_CARD_CHANGE 8 #define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
#define EV_USB_SET_INTERFACE 16 #define EV_RX_DATA_READY 16 /* USB Rx data available */
#define EV_USB_DEVICE_RESET 32
/* OpenPGPcard thread */ /* OpenPGPcard thread */
#define EV_PINPAD_INPUT_DONE 1 #define EV_MODIFY_CMD_AVAILABLE 1
#define EV_EXIT 2 #define EV_VERIFY_CMD_AVAILABLE 2
#define EV_CMD_AVAILABLE 4 #define EV_CMD_AVAILABLE 4
#define EV_VERIFY_CMD_AVAILABLE 8 #define EV_EXIT 8
#define EV_MODIFY_CMD_AVAILABLE 16 #define EV_PINPAD_INPUT_DONE 16
/* Maximum cmd apdu data is key import 24+4+256+256 (proc_key_import) */ /* Maximum cmd apdu data is key import 24+4+256+256 (proc_key_import) */
#define MAX_CMD_APDU_DATA_SIZE (24+4+256+256) /* without header */ #define MAX_CMD_APDU_DATA_SIZE (24+4+256+256) /* without header */
@@ -56,17 +54,17 @@ enum ccid_state {
CCID_STATE_NOCARD, /* No card available */ CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */ CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */ CCID_STATE_WAIT, /* Waiting APDU */
/* Busy1, Busy2, Busy3, Busy5 */
CCID_STATE_EXECUTE, /* Busy4 */
CCID_STATE_RECEIVE, /* APDU Received Partially */
CCID_STATE_SEND, /* APDU Sent Partially */
CCID_STATE_EXITED, /* ICC Thread Terminated */ CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */ CCID_STATE_EXEC_REQUESTED, /* Exec requested */
}; };
extern enum ccid_state *const ccid_state_p; enum ccid_state ccid_get_ccid_state (void);
extern volatile uint8_t auth_status; extern volatile uint8_t auth_status;
#define AC_NONE_AUTHORIZED 0x00 #define AC_NONE_AUTHORIZED 0x00
@@ -100,16 +98,19 @@ void ac_fini (void);
void set_res_sw (uint8_t sw1, uint8_t sw2); void set_res_sw (uint8_t sw1, uint8_t sw2);
extern uint8_t file_selection;
extern const uint8_t historical_bytes[];
extern uint16_t data_objects_number_of_bytes; extern uint16_t data_objects_number_of_bytes;
#define CHALLENGE_LEN 32 #define CHALLENGE_LEN 32
void gpg_data_scan (const uint8_t *p); void gpg_data_scan (const uint8_t *start, const uint8_t *end);
void gpg_data_copy (const uint8_t *p); void gpg_data_copy (const uint8_t *p);
void gpg_do_terminate (void);
void gpg_do_get_data (uint16_t tag, int with_tag); void gpg_do_get_data (uint16_t tag, int with_tag);
void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len); void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
void gpg_do_public_key (uint8_t kk_byte); void gpg_do_public_key (uint8_t kk_byte);
void gpg_do_keygen (uint8_t kk_byte); void gpg_do_keygen (uint8_t *buf);
const uint8_t *gpg_get_firmware_update_key (uint8_t keyno); const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
@@ -123,8 +124,8 @@ const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
enum kind_of_key { enum kind_of_key {
GPG_KEY_FOR_SIGNING = 0, GPG_KEY_FOR_SIGNING = 0,
GPG_KEY_FOR_DECRYPTION, GPG_KEY_FOR_DECRYPTION = 1,
GPG_KEY_FOR_AUTHENTICATION, GPG_KEY_FOR_AUTHENTICATION = 2,
}; };
enum size_of_key { enum size_of_key {
@@ -136,8 +137,10 @@ enum size_of_key {
int gpg_get_algo_attr (enum kind_of_key kk); int gpg_get_algo_attr (enum kind_of_key kk);
int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s); int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
const uint8_t *flash_init (void); void flash_do_storage_init (const uint8_t **, const uint8_t **);
void flash_init_keys (void); void flash_terminate (void);
void flash_activate (void);
void flash_key_storage_init (void);
void flash_do_release (const uint8_t *); void flash_do_release (const uint8_t *);
const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len); const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
uint8_t *flash_key_alloc (enum kind_of_key); uint8_t *flash_key_alloc (enum kind_of_key);
@@ -147,7 +150,7 @@ int flash_key_write (uint8_t *key_addr,
const uint8_t *key_data, int key_data_len, const uint8_t *key_data, int key_data_len,
const uint8_t *pubkey, int pubkey_len); const uint8_t *pubkey, int pubkey_len);
void flash_set_data_pool_last (const uint8_t *p); void flash_set_data_pool_last (const uint8_t *p);
void flash_clear_halfword (uint32_t addr); void flash_clear_halfword (uintptr_t addr);
void flash_increment_counter (uint8_t counter_tag_nr); void flash_increment_counter (uint8_t counter_tag_nr);
void flash_reset_counter (uint8_t counter_tag_nr); void flash_reset_counter (uint8_t counter_tag_nr);
@@ -260,22 +263,22 @@ void put_binary (const char *s, int len);
#endif #endif
int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *, int); int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *, int);
uint8_t *modulus_calc (const uint8_t *, int); int modulus_calc (const uint8_t *, int, uint8_t *);
int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *, int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *,
unsigned int *); unsigned int *);
int rsa_verify (const uint8_t *, int, const uint8_t *, const uint8_t *); int rsa_verify (const uint8_t *, int, const uint8_t *, const uint8_t *);
uint8_t *rsa_genkey (int); int rsa_genkey (int, uint8_t *, uint8_t *);
int ecdsa_sign_p256r1 (const uint8_t *hash, uint8_t *output, int ecdsa_sign_p256r1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data); const uint8_t *key_data);
uint8_t *ecc_compute_public_p256r1 (const uint8_t *key_data); int ecc_compute_public_p256r1 (const uint8_t *key_data, uint8_t *);
int ecc_check_secret_p256r1 (const uint8_t *d0, uint8_t *d1); int ecc_check_secret_p256r1 (const uint8_t *d0, uint8_t *d1);
int ecdh_decrypt_p256r1 (const uint8_t *input, uint8_t *output, int ecdh_decrypt_p256r1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data); const uint8_t *key_data);
int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output, int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data); const uint8_t *key_data);
uint8_t *ecc_compute_public_p256k1 (const uint8_t *key_data); int ecc_compute_public_p256k1 (const uint8_t *key_data, uint8_t *);
int ecc_check_secret_p256k1 (const uint8_t *d0, uint8_t *d1); int ecc_check_secret_p256k1 (const uint8_t *d0, uint8_t *d1);
int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output, int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data); const uint8_t *key_data);
@@ -283,19 +286,24 @@ int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output,
int eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *output, int eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *output,
const uint8_t *sk_a, const uint8_t *seed, const uint8_t *sk_a, const uint8_t *seed,
const uint8_t *pk); const uint8_t *pk);
uint8_t *eddsa_compute_public_25519 (const uint8_t *a); void eddsa_compute_public_25519 (const uint8_t *a, uint8_t *);
uint8_t *ecdh_compute_public_25519 (const uint8_t *a); void ecdh_compute_public_25519 (const uint8_t *a, uint8_t *);
int ecdh_decrypt_curve25519 (const uint8_t *input, uint8_t *output, int ecdh_decrypt_curve25519 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data); const uint8_t *key_data);
const uint8_t *gpg_do_read_simple (uint8_t); const uint8_t *gpg_do_read_simple (uint8_t);
void gpg_do_write_simple (uint8_t, const uint8_t *, int); void gpg_do_write_simple (uint8_t, const uint8_t *, int);
void gpg_increment_digital_signature_counter (void); void gpg_increment_digital_signature_counter (void);
void gpg_do_get_initial_pw_setting (int is_pw3, int *r_len,
const uint8_t **r_p);
int gpg_do_kdf_check (int len, int how_many);
int gpg_do_get_uif (enum kind_of_key kk);
void fatal (uint8_t code) __attribute__ ((noreturn)); void fatal (uint8_t code) __attribute__ ((noreturn));
#define FATAL_FLASH 1 #define FATAL_FLASH 1
#define FATAL_RANDOM 2 #define FATAL_RANDOM 2
#define FATAL_HEAP 3
extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE]; extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
extern uint8_t admin_authorized; extern uint8_t admin_authorized;
@@ -328,7 +336,8 @@ extern uint8_t admin_authorized;
#define NR_DO_KEYSTRING_PW1 0x11 #define NR_DO_KEYSTRING_PW1 0x11
#define NR_DO_KEYSTRING_RC 0x12 #define NR_DO_KEYSTRING_RC 0x12
#define NR_DO_KEYSTRING_PW3 0x13 #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). */ /* 14-bit counter for DS: Recorded in flash memory by 1-halfword (2-byte). */
/* /*
* Representation of 14-bit counter: * Representation of 14-bit counter:
@@ -371,7 +380,17 @@ extern uint8_t admin_authorized;
#define NR_KEY_ALGO_ATTR_DEC 0xf2 #define NR_KEY_ALGO_ATTR_DEC 0xf2
#define NR_KEY_ALGO_ATTR_AUT 0xf3 #define NR_KEY_ALGO_ATTR_AUT 0xf3
/* /*
* NR_UINT_SOMETHING could be here... Use 0xf[456789abcd] * Representation of User Interaction Flag:
* 0 (UIF disabled): 0xf?00 or No record in flash memory
* 1 (UIF enabled): 0xf?01
* 2 (UIF permanently enabled): 0xf?02
*
*/
#define NR_DO_UIF_SIG 0xf6
#define NR_DO_UIF_DEC 0xf7
#define NR_DO_UIF_AUT 0xf8
/*
* NR_UINT_SOMETHING could be here... Use 0xf[459abcd]
*/ */
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */ /* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
/* /*
@@ -427,6 +446,8 @@ extern const uint8_t gnuk_string_serial[];
#define LED_GNUK_EXEC 32 #define LED_GNUK_EXEC 32
#define LED_START_COMMAND 64 #define LED_START_COMMAND 64
#define LED_FINISH_COMMAND 128 #define LED_FINISH_COMMAND 128
#define LED_WAIT_FOR_BUTTON 256
#define LED_OFF LED_FINISH_COMMAND
void led_blink (int spec); void led_blink (int spec);
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
@@ -453,4 +474,7 @@ int pinpad_getline (int msg_code, uint32_t timeout_usec);
#endif #endif
extern uint8_t _regnual_start, __heap_end__[]; extern uint8_t _regnual_start, __heap_end__[];
uint8_t * sram_address (uint32_t offset);

View File

@@ -1,16 +1,6 @@
/* /*
* ST32F103 memory setup. * ST32F103 memory setup.
*/ */
__main_stack_size__ = 0x0080; /* Exception handlers */
__process0_stack_size__ = 0x0100; /* main */
__process1_stack_size__ = 0x0180; /* ccid */
__process2_stack_size__ = 0x0180; /* rng */
__process3_stack_size__ = 0x1640; /* gpg */
__process4_stack_size__ = 0; /* --- */
__process5_stack_size__ = @MSC_SIZE@; /* msc */
__process6_stack_size__ = @TIM_SIZE@; /* intr: timer */
__process7_stack_size__ = @EXT_SIZE@; /* intr: ext */
MEMORY MEMORY
{ {
flash0 : org = @ORIGIN@, len = 4k flash0 : org = @ORIGIN@, len = 4k
@@ -82,45 +72,18 @@ SECTIONS
_etext = .; _etext = .;
_textdata = _etext; _textdata = _etext;
.stacks : .stacks (NOLOAD) :
{ {
. = ALIGN(8); . = ALIGN(8);
__main_stack_base__ = .; *(.main_stack)
. += __main_stack_size__; *(.process_stack.0)
. = ALIGN(8); *(.process_stack.1)
__main_stack_end__ = .; *(.process_stack.2)
__process0_stack_base__ = .; *(.process_stack.3)
. += __process0_stack_size__; *(.process_stack.4)
. = ALIGN(8); *(.process_stack.5)
__process0_stack_end__ = .; *(.process_stack.6)
__process1_stack_base__ = .; *(.process_stack.7)
. += __process1_stack_size__;
. = ALIGN(8);
__process1_stack_end__ = .;
__process2_stack_base__ = .;
. += __process2_stack_size__;
. = ALIGN(8);
__process2_stack_end__ = .;
__process3_stack_base__ = .;
. += __process3_stack_size__;
. = ALIGN(8);
__process3_stack_end__ = .;
__process4_stack_base__ = .;
. += __process4_stack_size__;
. = ALIGN(8);
__process4_stack_end__ = .;
__process5_stack_base__ = .;
. += __process5_stack_size__;
. = ALIGN(8);
__process5_stack_end__ = .;
__process6_stack_base__ = .;
. += __process6_stack_size__;
. = ALIGN(8);
__process6_stack_end__ = .;
__process7_stack_base__ = .;
. += __process7_stack_size__;
. = ALIGN(8);
__process7_stack_end__ = .;
. = ALIGN(8); . = ALIGN(8);
} > ram } > ram
@@ -171,20 +134,20 @@ SECTIONS
.gnuk_flash : .gnuk_flash :
{ {
. = ALIGN (@FLASH_PAGE_SIZE@); . = ALIGN (@FLASH_PAGE_SIZE@);
_data_pool = .;
KEEP(*(.gnuk_data))
. = ALIGN(@FLASH_PAGE_SIZE@);
. += @FLASH_PAGE_SIZE@;
_keystore_pool = .; _keystore_pool = .;
. += 512; . += 1024;
. = ALIGN(@FLASH_PAGE_SIZE@); . = ALIGN(@FLASH_PAGE_SIZE@);
. += 512; . += 1024;
. = ALIGN(@FLASH_PAGE_SIZE@); . = ALIGN(@FLASH_PAGE_SIZE@);
. += 512; . += 1024;
. = ALIGN(@FLASH_PAGE_SIZE@); . = ALIGN(@FLASH_PAGE_SIZE@);
_updatekey_store = .; _updatekey_store = .;
. += 1024; . += 1024;
. = ALIGN(@FLASH_PAGE_SIZE@); . = ALIGN(@FLASH_PAGE_SIZE@);
_data_pool = .;
KEEP(*(.gnuk_data))
. = ALIGN(@FLASH_PAGE_SIZE@);
. += @FLASH_PAGE_SIZE@;
} > flash =0xffffffff } > flash =0xffffffff
} }

View File

@@ -1,7 +1,7 @@
/* /*
* main.c - main routine of Gnuk * main.c - main routine of Gnuk
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016 * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -35,8 +35,13 @@
#include "usb_lld.h" #include "usb_lld.h"
#include "usb-cdc.h" #include "usb-cdc.h"
#include "random.h" #include "random.h"
#ifdef GNU_LINUX_EMULATION
#include <stdio.h>
#include <stdlib.h>
#define main emulated_main
#else
#include "mcu/stm32f103.h" #include "mcu/stm32f103.h"
#endif
/* /*
* main thread does 1-bit LED display output * main thread does 1-bit LED display output
@@ -46,7 +51,33 @@
#define LED_TIMEOUT_ONE (100*1000) #define LED_TIMEOUT_ONE (100*1000)
#define LED_TIMEOUT_STOP (200*1000) #define LED_TIMEOUT_STOP (200*1000)
#ifdef DFU_SUPPORT
static int
flash_write_any (uintptr_t dst_addr, const uint8_t *src, size_t len)
{
int status;
while (len)
{
uint16_t hw = *src++;
hw |= (*src++ << 8);
status = flash_program_halfword (dst_addr, hw);
if (status != 0)
return 0; /* error return */
dst_addr += 2;
len -= 2;
}
return 1;
}
#endif
#ifdef GNU_LINUX_EMULATION
uint8_t *flash_addr_key_storage_start;
uint8_t *flash_addr_data_storage_start;
#else
#define ID_OFFSET (2+SERIALNO_STR_LEN*2) #define ID_OFFSET (2+SERIALNO_STR_LEN*2)
static void static void
device_initialize_once (void) device_initialize_once (void)
@@ -59,7 +90,7 @@ device_initialize_once (void)
* This is the first time invocation. * This is the first time invocation.
* Setup serial number by unique device ID. * Setup serial number by unique device ID.
*/ */
const uint8_t *u = unique_device_id () + 8; const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
int i; int i;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@@ -74,12 +105,66 @@ device_initialize_once (void)
nibble += (nibble >= 10 ? ('A' - 10) : '0'); nibble += (nibble >= 10 ? ('A' - 10) : '0');
flash_put_data_internal (&p[i*4+2], nibble); flash_put_data_internal (&p[i*4+2], nibble);
} }
#ifdef DFU_SUPPORT
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
/*
* Overwrite DFU bootloader with a copy of SYS linked to ORIGIN_REAL.
* Then protect flash from readout.
*/
{
extern uint8_t _binary_build_stdaln_sys_bin_start;
extern uint8_t _binary_build_stdaln_sys_bin_size;
size_t stdaln_sys_size = (size_t) &_binary_build_stdaln_sys_bin_size;
extern const uint32_t FT0[256], FT1[256], FT2[256];
extern handler vector_table[];
uintptr_t addr;
uint32_t flash_page_size = 1024; /* 1KiB default */
if (((*CHIP_ID_REG)&0x07) == 0x04) /* High density device. */
flash_page_size = 2048; /* It's 2KiB. */
/* Kill DFU */
for (addr = ORIGIN_REAL; addr < ORIGIN;
addr += flash_page_size)
flash_erase_page (addr);
/* Copy SYS */
addr = ORIGIN_REAL;
flash_write_any(addr, &_binary_build_stdaln_sys_bin_start,
stdaln_sys_size);
addr += stdaln_sys_size;
flash_write_any(addr, (const uint8_t *) &FT0, sizeof(FT0));
addr += sizeof(FT0);
flash_write_any(addr, (const uint8_t *) &FT1, sizeof(FT1));
addr += sizeof(FT1);
flash_write_any(addr, (const uint8_t *) &FT2, sizeof(FT2));
addr = ORIGIN_REAL + 0x1000;
if (addr < ORIGIN) {
/* Need to patch top of stack and reset vector there */
handler *new_vector = (handler *) addr;
flash_write((uintptr_t) &new_vector[0], (const uint8_t *)
&vector_table[0], sizeof(handler));
flash_write((uintptr_t) &new_vector[1], (const uint8_t *)
&vector[1], sizeof(handler));
}
flash_protect();
nvic_system_reset();
}
#endif
} }
} }
#endif
static volatile uint8_t fatal_code; static volatile uint8_t fatal_code;
static struct eventflag led_event; 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) static void display_fatal_code (void)
{ {
@@ -120,17 +205,20 @@ static void display_fatal_code (void)
static uint8_t led_inverted; 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); set_led (!led_inverted);
chopstx_usec_wait (on_time); chopstx_poll (&on_time, 1, led_event_poll);
set_led (led_inverted); 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; enum ccid_state ccid_state = ccid_get_ccid_state ();
uint32_t usec;
if (ccid_state == CCID_STATE_START) if (ccid_state == CCID_STATE_START)
emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP); emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
@@ -145,12 +233,15 @@ static void display_status_code (void)
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_INTERVAL); LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_INTERVAL);
if (ccid_state == CCID_STATE_WAIT) 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 else
{ {
chopstx_usec_wait (LED_TIMEOUT_INTERVAL); usec = LED_TIMEOUT_INTERVAL;
emit_led (ccid_state == CCID_STATE_RECEIVE? chopstx_poll (&usec, 1, led_event_poll);
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP); emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
} }
} }
} }
@@ -167,26 +258,30 @@ led_blink (int spec)
eventflag_signal (&led_event, spec); eventflag_signal (&led_event, spec);
} }
#ifdef FLASH_UPGRADE_SUPPORT
/* /*
* In Gnuk 1.0.[12], reGNUal was not relocatable. * In Gnuk 1.0.[12], reGNUal was not relocatable.
* Now, it's relocatable, but we need to calculate its entry address * Now, it's relocatable, but we need to calculate its entry address
* based on it's pre-defined address. * based on it's pre-defined address.
*/ */
#define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400 #define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
static uint32_t static uintptr_t
calculate_regnual_entry_address (const uint8_t *addr) calculate_regnual_entry_address (const uint8_t *addr)
{ {
const uint8_t *p = addr + 4; const uint8_t *p = addr + 4;
uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); uintptr_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
v -= REGNUAL_START_ADDRESS_COMPATIBLE; v -= REGNUAL_START_ADDRESS_COMPATIBLE;
v += (uint32_t)addr; v += (uintptr_t)addr;
return v; return v;
} }
#endif
extern uint8_t __process1_stack_base__[], __process1_stack_size__[]; #define STACK_MAIN
#define STACK_ADDR_CCID ((uint32_t)__process1_stack_base__) #define STACK_PROCESS_1
#define STACK_SIZE_CCID ((uint32_t)__process1_stack_size__) #include "stack-def.h"
#define STACK_ADDR_CCID ((uintptr_t)process1_base)
#define STACK_SIZE_CCID (sizeof process1_base)
#define PRIO_CCID 3 #define PRIO_CCID 3
#define PRIO_MAIN 5 #define PRIO_MAIN 5
@@ -202,18 +297,97 @@ extern uint32_t bDeviceState;
* Entry point. * Entry point.
*/ */
int int
main (int argc, char *argv[]) main (int argc, const char *argv[])
{ {
uint32_t entry; #ifdef GNU_LINUX_EMULATION
uintptr_t flash_addr;
const char *flash_image_path;
char *path_string = NULL;
#endif
#ifdef FLASH_UPGRADE_SUPPORT
uintptr_t entry;
#endif
chopstx_t ccid_thd; chopstx_t ccid_thd;
int wait_for_ack = 0;
(void)argc; chopstx_conf_idle (1);
(void)argv;
gnuk_malloc_init (); gnuk_malloc_init ();
#ifdef GNU_LINUX_EMULATION
#define FLASH_IMAGE_NAME ".gnuk-flash-image"
if (argc >= 4 || (argc == 2 && !strcmp (argv[1], "--help")))
{
fprintf (stdout, "Usage: %s [--vidpid=Vxxx:Pxxx] [flash-image-file]",
argv[0]);
exit (0);
}
if (argc >= 2 && !strncmp (argv[1], "--debug=", 8))
{
debug = strtol (&argv[1][8], NULL, 10);
argc--;
argv++;
}
if (argc >= 2 && !strncmp (argv[1], "--vidpid=", 9))
{
extern uint8_t device_desc[];
uint32_t id;
char *p;
id = (uint32_t)strtol (&argv[1][9], &p, 16);
device_desc[8] = (id & 0xff);
device_desc[9] = (id >> 8);
if (p && p[0] == ':')
{
id = (uint32_t)strtol (&p[1], NULL, 16);
device_desc[10] = (id & 0xff);
device_desc[11] = (id >> 8);
}
argc--;
argv++;
}
if (argc == 1)
{
char *p = getenv ("HOME");
if (p == NULL)
{
fprintf (stderr, "Can't find $HOME\n");
exit (1);
}
path_string = malloc (strlen (p) + strlen (FLASH_IMAGE_NAME) + 2);
p = stpcpy (path_string, p);
*p++ = '/';
strcpy (p, FLASH_IMAGE_NAME);
flash_image_path = path_string;
}
else
flash_image_path = argv[1];
flash_addr = flash_init (flash_image_path);
flash_addr_key_storage_start = (uint8_t *)flash_addr;
flash_addr_data_storage_start = (uint8_t *)flash_addr + 4096;
#else
(void)argc;
(void)argv;
#endif
flash_unlock (); flash_unlock ();
#ifdef GNU_LINUX_EMULATION
if (path_string)
free (path_string);
#else
device_initialize_once (); device_initialize_once ();
#endif
adc_init (); adc_init ();
@@ -239,17 +413,23 @@ main (int argc, char *argv[])
while (1) while (1)
{ {
if (bDeviceState != UNCONNECTED) if (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
break; break;
chopstx_usec_wait (250*1000); chopstx_usec_wait (250*1000);
} }
eventflag_prepare_poll (&led_event, &led_event_poll_desc);
while (1) while (1)
{ {
eventmask_t m; eventmask_t m;
m = eventflag_wait (&led_event); if (wait_for_ack)
m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL);
else
m = eventflag_wait (&led_event);
switch (m) switch (m)
{ {
case LED_ONESHOT: case LED_ONESHOT:
@@ -270,8 +450,11 @@ main (int argc, char *argv[])
break; break;
case LED_GNUK_EXEC: case LED_GNUK_EXEC:
goto exec; goto exec;
case LED_WAIT_FOR_BUTTON:
wait_for_ack ^= 1;
/* fall through */
default: default:
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP); emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_ZERO);
break; break;
} }
} }
@@ -285,30 +468,15 @@ main (int argc, char *argv[])
/* Finish application. */ /* Finish application. */
chopstx_join (ccid_thd, NULL); chopstx_join (ccid_thd, NULL);
#ifdef FLASH_UPGRADE_SUPPORT
/* Set vector */ /* Set vector */
SCB->VTOR = (uint32_t)&_regnual_start; SCB->VTOR = (uintptr_t)&_regnual_start;
entry = calculate_regnual_entry_address (&_regnual_start); entry = calculate_regnual_entry_address (&_regnual_start);
#ifdef DFU_SUPPORT #ifdef DFU_SUPPORT
#define FLASH_SYS_START_ADDR 0x08000000
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
{ {
extern uint8_t _sys; /* Use SYS at ORIGIN_REAL instead of the one at ORIGIN */
uint32_t addr; handler *new_vector = (handler *)ORIGIN_REAL;
handler *new_vector = (handler *)FLASH_SYS_START_ADDR; void (*func) (void (*)(void)) = (void (*)(void (*)(void))) new_vector[9];
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
uint32_t flash_page_size = 1024; /* 1KiB default */
if ((*CHIP_ID_ADDR)&0x07 == 0x04) /* High dencity device. */
flash_page_size = 2048; /* It's 2KiB. */
/* Kill DFU */
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
addr += flash_page_size)
flash_erase_page (addr);
/* copy system service routines */
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
/* Leave Gnuk to exec reGNUal */ /* Leave Gnuk to exec reGNUal */
(*func) ((void (*)(void))entry); (*func) ((void (*)(void))entry);
@@ -318,6 +486,9 @@ main (int argc, char *argv[])
/* Leave Gnuk to exec reGNUal */ /* Leave Gnuk to exec reGNUal */
flash_erase_all_and_exec ((void (*)(void))entry); flash_erase_all_and_exec ((void (*)(void))entry);
#endif #endif
#else
exit (0);
#endif
/* Never reached */ /* Never reached */
return 0; return 0;
@@ -348,30 +519,46 @@ fatal (uint8_t code)
* reclaimed to system. * reclaimed to system.
*/ */
#ifdef GNU_LINUX_EMULATION
#define HEAP_SIZE (32*1024)
uint8_t __heap_base__[HEAP_SIZE];
#define HEAP_START __heap_base__
#define HEAP_END (__heap_base__ + HEAP_SIZE)
#define HEAP_ALIGNMENT 32
#else
extern uint8_t __heap_base__[]; extern uint8_t __heap_base__[];
extern uint8_t __heap_end__[]; extern uint8_t __heap_end__[];
#define MEMORY_END (__heap_end__) #define HEAP_START __heap_base__
#define MEMORY_ALIGNMENT 16 #define HEAP_END (__heap_end__)
#define MEMORY_ALIGN(n) (((n) + MEMORY_ALIGNMENT - 1) & ~(MEMORY_ALIGNMENT - 1)) #define HEAP_ALIGNMENT 16
#define HEAP_SIZE ((uintptr_t)__heap_end__ - (uintptr_t)__heap_base__)
#endif
#define HEAP_ALIGN(n) (((n) + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT - 1))
static uint8_t *heap_p; static uint8_t *heap_p;
static chopstx_mutex_t malloc_mtx; static chopstx_mutex_t malloc_mtx;
struct mem_head { struct mem_head {
uint32_t size; uintptr_t size;
/**/ /**/
struct mem_head *next, *prev; /* free list chain */ struct mem_head *next, *prev; /* free list chain */
struct mem_head *neighbor; /* backlink to neighbor */ struct mem_head *neighbor; /* backlink to neighbor */
}; };
#define MEM_HEAD_IS_CORRUPT(x) \
((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; static struct mem_head *free_list;
static void static void
gnuk_malloc_init (void) gnuk_malloc_init (void)
{ {
chopstx_mutex_init (&malloc_mtx); chopstx_mutex_init (&malloc_mtx);
heap_p = __heap_base__; heap_p = HEAP_START;
free_list = NULL; free_list = NULL;
} }
@@ -380,7 +567,7 @@ sbrk (size_t size)
{ {
void *p = (void *)heap_p; void *p = (void *)heap_p;
if ((size_t)(MEMORY_END - heap_p) < size) if ((size_t)(HEAP_END - heap_p) < size)
return NULL; return NULL;
heap_p += size; heap_p += size;
@@ -405,7 +592,7 @@ gnuk_malloc (size_t size)
struct mem_head *m; struct mem_head *m;
struct mem_head *m0; struct mem_head *m0;
size = MEMORY_ALIGN (size + sizeof (uint32_t)); size = HEAP_ALIGN (size + sizeof (uintptr_t));
chopstx_mutex_lock (&malloc_mtx); chopstx_mutex_lock (&malloc_mtx);
DEBUG_INFO ("malloc: "); DEBUG_INFO ("malloc: ");
@@ -421,7 +608,7 @@ gnuk_malloc (size_t size)
m->size = size; m->size = size;
break; break;
} }
MEM_HEAD_CHECK (m);
if (m->size == size) if (m->size == size)
{ {
remove_from_free_list (m); remove_from_free_list (m);
@@ -445,8 +632,8 @@ gnuk_malloc (size_t size)
} }
else else
{ {
DEBUG_WORD ((uint32_t)m + sizeof (uint32_t)); DEBUG_WORD ((uintptr_t)m + sizeof (uintptr_t));
return (void *)m + sizeof (uint32_t); return (void *)m + sizeof (uintptr_t);
} }
} }
@@ -454,18 +641,23 @@ gnuk_malloc (size_t size)
void void
gnuk_free (void *p) gnuk_free (void *p)
{ {
struct mem_head *m = (struct mem_head *)((void *)p - sizeof (uint32_t)); struct mem_head *m = (struct mem_head *)((void *)p - sizeof (uintptr_t));
struct mem_head *m0; struct mem_head *m0;
if (p == NULL)
return;
chopstx_mutex_lock (&malloc_mtx); chopstx_mutex_lock (&malloc_mtx);
m0 = free_list; m0 = free_list;
DEBUG_INFO ("free: "); DEBUG_INFO ("free: ");
DEBUG_SHORT (m->size); DEBUG_SHORT (m->size);
DEBUG_WORD ((uint32_t)p); DEBUG_WORD ((uintptr_t)p);
MEM_HEAD_CHECK (m);
m->neighbor = NULL; m->neighbor = NULL;
while (m0) while (m0)
{ {
MEM_HEAD_CHECK (m0);
if ((void *)m + m->size == (void *)m0) if ((void *)m + m->size == (void *)m0)
m0->neighbor = m; m0->neighbor = m;
else if ((void *)m0 + m0->size == (void *)m) else if ((void *)m0 + m0->size == (void *)m)
@@ -481,6 +673,7 @@ gnuk_free (void *p)
heap_p -= m->size; heap_p -= m->size;
while (mn) while (mn)
{ {
MEM_HEAD_CHECK (mn);
heap_p -= mn->size; heap_p -= mn->size;
remove_from_free_list (mn); remove_from_free_list (mn);
mn = mn->neighbor; mn = mn->neighbor;

32
src/mcu-stm32f103.c Normal file
View File

@@ -0,0 +1,32 @@
/*
* mcu-stm32f103.c - STM32F103 specific routines
*
* Copyright (C) 2017
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include "mcu/stm32f103.h"
uint8_t *
sram_address (uint32_t offset)
{
return ((uint8_t *)0x20000000) + offset;
}

View File

@@ -36,7 +36,6 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
bn512 q_big[1], tmp[1]; bn512 q_big[1], tmp[1];
uint32_t carry; uint32_t carry;
#define borrow carry #define borrow carry
uint32_t borrow_next;
memset (q, 0, sizeof (bn256)); memset (q, 0, sizeof (bn256));
q->word[0] = A->word[15]; q->word[0] = A->word[15];
@@ -110,9 +109,7 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
= tmp->word[11] = tmp->word[10] = tmp->word[9] = 0; = tmp->word[11] = tmp->word[10] = tmp->word[9] = 0;
borrow = bn256_sub (X, (bn256 *)&q_big->word[0], (bn256 *)&tmp->word[0]); borrow = bn256_sub (X, (bn256 *)&q_big->word[0], (bn256 *)&tmp->word[0]);
borrow_next = (q_big->word[8] < borrow);
q_big->word[8] -= borrow; q_big->word[8] -= borrow;
borrow_next += (q_big->word[8] < tmp->word[8]);
q_big->word[8] -= tmp->word[8]; q_big->word[8] -= tmp->word[8];
carry = q_big->word[8]; carry = q_big->word[8];
@@ -122,7 +119,7 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
bn256_sub (q, X, B); bn256_sub (q, X, B);
if (carry) if (carry)
carry -= bn256_sub (X, X, B); bn256_sub (X, X, B);
else else
bn256_sub (q, X, B); bn256_sub (q, X, B);
@@ -159,6 +156,7 @@ mod_inv (bn256 *C, const bn256 *X, const bn256 *N)
#define borrow carry #define borrow carry
int n = MAX_GCD_STEPS_BN256; int n = MAX_GCD_STEPS_BN256;
memset (tmp, 0, sizeof (bn256));
memset (C, 0, sizeof (bn256)); memset (C, 0, sizeof (bn256));
memcpy (u, X, sizeof (bn256)); memcpy (u, X, sizeof (bn256));
memcpy (v, N, sizeof (bn256)); memcpy (v, N, sizeof (bn256));

View File

@@ -1,7 +1,7 @@
/* /*
* neug.c - true random number generation * neug.c - true random number generation
* *
* Copyright (C) 2011, 2012, 2013, 2016 * Copyright (C) 2011, 2012, 2013, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -29,10 +29,133 @@
#include "sys.h" #include "sys.h"
#include "neug.h" #include "neug.h"
#ifndef GNU_LINUX_EMULATION
#include "mcu/stm32f103.h" #include "mcu/stm32f103.h"
#endif
#include "adc.h" #include "adc.h"
#include "sha256.h" #include "sha256.h"
#ifdef GNU_LINUX_EMULATION
static const uint32_t crc32_rv_table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
static uint32_t crc;
void
crc32_rv_reset (void)
{
crc = 0xffffffff;
}
void
crc32_rv_step (uint32_t v)
{
crc = crc32_rv_table[(crc ^ (v << 0)) >> 24] ^ (crc << 8);
crc = crc32_rv_table[(crc ^ (v << 8)) >> 24] ^ (crc << 8);
crc = crc32_rv_table[(crc ^ (v << 16)) >> 24] ^ (crc << 8);
crc = crc32_rv_table[(crc ^ (v << 24)) >> 24] ^ (crc << 8);
}
uint32_t
crc32_rv_get (void)
{
return crc;
}
uint32_t
rbit (uint32_t v)
{
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
v = ( v >> 16 ) | ( v << 16);
return v;
}
void
crc32_rv_stop (void)
{
}
#else
void
crc32_rv_reset (void)
{
RCC->AHBENR |= RCC_AHBENR_CRCEN;
CRC->CR = CRC_CR_RESET;
}
void
crc32_rv_step (uint32_t v)
{
CRC->DR = v;
}
uint32_t
crc32_rv_get (void)
{
return CRC->DR;
}
uint32_t
rbit (uint32_t v)
{
uint32_t r;
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; static chopstx_mutex_t mode_mtx;
static chopstx_cond_t mode_cond; static chopstx_cond_t mode_cond;
@@ -94,11 +217,11 @@ static void noise_source_continuous_test_word (uint8_t b0, uint8_t b1,
* Then, three-byte from noise source follows. * Then, three-byte from noise source follows.
* *
* One-byte was used in the previous turn, and we have three bytes in * One-byte was used in the previous turn, and we have three bytes in
* CRC->DR. * CRC32.
*/ */
static void ep_fill_initial_string (void) static void ep_fill_initial_string (void)
{ {
uint32_t v = CRC->DR; uint32_t v = crc32_rv_get ();
uint8_t b1, b2, b3; uint8_t b1, b2, b3;
b3 = v >> 24; b3 = v >> 24;
@@ -164,11 +287,11 @@ static int ep_process (int mode)
sha256_ctx_data.wbuf[1] = adc_buf[1]; sha256_ctx_data.wbuf[1] = adc_buf[1];
for (i = 0; i < EP_ROUND_0_INPUTS / 4; i++) for (i = 0; i < EP_ROUND_0_INPUTS / 4; i++)
{ {
CRC->DR = adc_buf[i*4 + 2]; crc32_rv_step (adc_buf[i*4 + 2]);
CRC->DR = adc_buf[i*4 + 3]; crc32_rv_step (adc_buf[i*4 + 3]);
CRC->DR = adc_buf[i*4 + 4]; crc32_rv_step (adc_buf[i*4 + 4]);
CRC->DR = adc_buf[i*4 + 5]; crc32_rv_step (adc_buf[i*4 + 5]);
v = CRC->DR; v = crc32_rv_get ();
ep_fill_wbuf_v (i+2, 1, v); ep_fill_wbuf_v (i+2, 1, v);
} }
@@ -181,11 +304,11 @@ static int ep_process (int mode)
{ {
for (i = 0; i < EP_ROUND_1_INPUTS / 4; i++) for (i = 0; i < EP_ROUND_1_INPUTS / 4; i++)
{ {
CRC->DR = adc_buf[i*4]; crc32_rv_step (adc_buf[i*4]);
CRC->DR = adc_buf[i*4 + 1]; crc32_rv_step (adc_buf[i*4 + 1]);
CRC->DR = adc_buf[i*4 + 2]; crc32_rv_step (adc_buf[i*4 + 2]);
CRC->DR = adc_buf[i*4 + 3]; crc32_rv_step (adc_buf[i*4 + 3]);
v = CRC->DR; v = crc32_rv_get ();
ep_fill_wbuf_v (i, 1, v); ep_fill_wbuf_v (i, 1, v);
} }
@@ -198,23 +321,23 @@ static int ep_process (int mode)
{ {
for (i = 0; i < EP_ROUND_2_INPUTS / 4; i++) for (i = 0; i < EP_ROUND_2_INPUTS / 4; i++)
{ {
CRC->DR = adc_buf[i*4]; crc32_rv_step (adc_buf[i*4]);
CRC->DR = adc_buf[i*4 + 1]; crc32_rv_step (adc_buf[i*4 + 1]);
CRC->DR = adc_buf[i*4 + 2]; crc32_rv_step (adc_buf[i*4 + 2]);
CRC->DR = adc_buf[i*4 + 3]; crc32_rv_step (adc_buf[i*4 + 3]);
v = CRC->DR; v = crc32_rv_get ();
ep_fill_wbuf_v (i, 1, v); ep_fill_wbuf_v (i, 1, v);
} }
CRC->DR = adc_buf[i*4]; crc32_rv_step (adc_buf[i*4]);
CRC->DR = adc_buf[i*4 + 1]; crc32_rv_step (adc_buf[i*4 + 1]);
CRC->DR = adc_buf[i*4 + 2]; crc32_rv_step (adc_buf[i*4 + 2]);
CRC->DR = adc_buf[i*4 + 3]; crc32_rv_step (adc_buf[i*4 + 3]);
v = CRC->DR & 0xff; /* First byte of CRC->DR is used here. */ v = crc32_rv_get () & 0xff; /* First byte of CRC32 is used here. */
noise_source_continuous_test (v); noise_source_continuous_test (v);
sha256_ctx_data.wbuf[i] = v; sha256_ctx_data.wbuf[i] = v;
ep_init (NEUG_MODE_CONDITIONED); /* The rest three-byte of ep_init (NEUG_MODE_CONDITIONED); /* The rest three-byte of
CRC->DR is used here. */ CRC32 is used here. */
n = SHA256_DIGEST_SIZE / 2; n = SHA256_DIGEST_SIZE / 2;
memcpy (((uint8_t *)sha256_ctx_data.wbuf) + EP_ROUND_2_INPUTS, memcpy (((uint8_t *)sha256_ctx_data.wbuf) + EP_ROUND_2_INPUTS,
sha256_output, n); sha256_output, n);
@@ -226,11 +349,11 @@ static int ep_process (int mode)
{ {
for (i = 0; i < EP_ROUND_RAW_INPUTS / 4; i++) for (i = 0; i < EP_ROUND_RAW_INPUTS / 4; i++)
{ {
CRC->DR = adc_buf[i*4]; crc32_rv_step (adc_buf[i*4]);
CRC->DR = adc_buf[i*4 + 1]; crc32_rv_step (adc_buf[i*4 + 1]);
CRC->DR = adc_buf[i*4 + 2]; crc32_rv_step (adc_buf[i*4 + 2]);
CRC->DR = adc_buf[i*4 + 3]; crc32_rv_step (adc_buf[i*4 + 3]);
v = CRC->DR; v = crc32_rv_get ();
ep_fill_wbuf_v (i, 1, v); ep_fill_wbuf_v (i, 1, v);
} }
@@ -640,9 +763,11 @@ rng (void *arg)
static struct rng_rb the_ring_buffer; static struct rng_rb the_ring_buffer;
extern uint8_t __process2_stack_base__[], __process2_stack_size__[]; #define STACK_PROCESS_2
#define STACK_ADDR_RNG ((uint32_t)__process2_stack_base__) #include "stack-def.h"
#define STACK_SIZE_RNG ((uint32_t)__process2_stack_size__) #define STACK_ADDR_RNG ((uintptr_t)process2_base)
#define STACK_SIZE_RNG (sizeof process2_base)
#define PRIO_RNG 2 #define PRIO_RNG 2
/** /**
@@ -655,15 +780,14 @@ neug_init (uint32_t *buf, uint8_t size)
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
int i; int i;
RCC->AHBENR |= RCC_AHBENR_CRCEN; crc32_rv_reset ();
CRC->CR = CRC_CR_RESET;
/* /*
* This initialization ensures that it generates different sequence * This initialization ensures that it generates different sequence
* even if all physical conditions are same. * even if all physical conditions are same.
*/ */
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
CRC->DR = *u++; crc32_rv_step (*u++);
neug_mode = NEUG_MODE_CONDITIONED; neug_mode = NEUG_MODE_CONDITIONED;
rb_init (rb, buf, size); rb_init (rb, buf, size);
@@ -781,6 +905,7 @@ neug_fini (void)
rng_should_terminate = 1; rng_should_terminate = 1;
neug_get (1); neug_get (1);
chopstx_join (rng_thread, NULL); chopstx_join (rng_thread, NULL);
crc32_rv_stop ();
} }
void void

View File

@@ -26,3 +26,8 @@ void neug_fini (void);
void neug_mode_select (uint8_t mode); void neug_mode_select (uint8_t mode);
int neug_consume_random (void (*proc) (uint32_t, int)); int neug_consume_random (void (*proc) (uint32_t, int));
void crc32_rv_reset (void);
void crc32_rv_step (uint32_t v);
uint32_t crc32_rv_get (void);
uint32_t rbit (uint32_t v);

View File

@@ -1,7 +1,7 @@
/* /*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling * openpgp-do.c -- OpenPGP card Data Objects (DO) handling
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -24,13 +24,12 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "config.h" #include "config.h"
#include "sys.h" #include "sys.h"
#include "gnuk.h" #include "gnuk.h"
#include "openpgp.h" #include "status-code.h"
#include "random.h" #include "random.h"
#include "polarssl/config.h" #include "polarssl/config.h"
#include "polarssl/aes.h" #include "polarssl/aes.h"
@@ -40,7 +39,7 @@
#define CLEAN_PAGE_FULL 1 #define CLEAN_PAGE_FULL 1
#define CLEAN_SINGLE 0 #define CLEAN_SINGLE 0
static void gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full); static void gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full);
static void gpg_reset_digital_signature_counter (void);
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */ #define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
static const uint8_t *pw_err_counter_p[3]; static const uint8_t *pw_err_counter_p[3];
@@ -90,11 +89,11 @@ uint16_t data_objects_number_of_bytes;
/* /*
* Compile time vars: * Compile time vars:
* Historical Bytes (template), Extended Capabilities. * Historical Bytes, Extended Capabilities.
*/ */
/* Historical Bytes (template) */ /* Historical Bytes */
static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = { const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
10, 10,
0x00, 0x00,
0x31, 0x84, /* Full DF name, GET DATA, MF */ 0x31, 0x84, /* Full DF name, GET DATA, MF */
@@ -102,19 +101,26 @@ static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
0x80, 0x01, 0x80, /* Full DF name */ 0x80, 0x01, 0x80, /* Full DF name */
/* 1-byte */ /* 1-byte */
/* Command chaining, No extended Lc and Le */ /* Command chaining, No extended Lc and Le */
0x00, 0x90, 0x00 /* Status info (no life cycle management) */ #ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
0x05,
#else
0x00,
#endif
0x90, 0x00 /* Status info */
}; };
/* Extended Capabilities */ /* Extended Capabilities */
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = { static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
10, 10,
0x74, /* 0x75, /*
* No Secure Messaging supported * No Secure Messaging supported
* GET CHALLENGE supported * GET CHALLENGE supported
* Key import supported * Key import supported
* PW status byte can be put * PW status byte can be put
* No private_use_DO * No private_use_DO
* Algorithm attrs are changable * Algorithm attrs are changable
* No DEC with AES
* KDF-DO available
*/ */
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */ 0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
0x00, CHALLENGE_LEN, /* Max size of GET CHALLENGE */ 0x00, CHALLENGE_LEN, /* Max size of GET CHALLENGE */
@@ -129,6 +135,14 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
0x01, 0x00, 0x01, 0x00,
}; };
#ifdef ACKBTN_SUPPORT
/* General Feature Management */
static const uint8_t feature_mngmnt[] __attribute__ ((aligned (1))) = {
3,
0x81, 0x01, 0x20,
};
#endif
/* Algorithm Attributes */ /* Algorithm Attributes */
#define OPENPGP_ALGO_RSA 0x01 #define OPENPGP_ALGO_RSA 0x01
#define OPENPGP_ALGO_ECDH 0x12 #define OPENPGP_ALGO_ECDH 0x12
@@ -245,6 +259,28 @@ gpg_get_algo_attr (enum kind_of_key kk)
return algo_attr_p[1]; return algo_attr_p[1];
} }
static void
gpg_reset_algo_attr (enum kind_of_key kk)
{
gpg_do_delete_prvkey (kk, CLEAN_PAGE_FULL);
if (kk == GPG_KEY_FOR_SIGNING)
{
gpg_reset_digital_signature_counter ();
gpg_do_write_simple (NR_DO_FP_SIG, NULL, 0);
gpg_do_write_simple (NR_DO_KGTIME_SIG, NULL, 0);
}
else if (kk == GPG_KEY_FOR_DECRYPTION)
{
gpg_do_write_simple (NR_DO_FP_DEC, NULL, 0);
gpg_do_write_simple (NR_DO_KGTIME_DEC, NULL, 0);
}
else
{
gpg_do_write_simple (NR_DO_FP_AUT, NULL, 0);
gpg_do_write_simple (NR_DO_KGTIME_AUT, NULL, 0);
}
}
static const uint8_t * static const uint8_t *
get_algo_attr_data_object (enum kind_of_key kk) get_algo_attr_data_object (enum kind_of_key kk)
{ {
@@ -331,7 +367,7 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc)
else else
{ {
hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2); hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2);
hw1 = NR_COUNTER_DS_LSB; hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8);
flash_put_data_internal (p, hw0); flash_put_data_internal (p, hw0);
flash_put_data_internal (p+2, hw1); flash_put_data_internal (p+2, hw1);
return p+4; return p+4;
@@ -426,12 +462,17 @@ static const struct do_table_entry *get_do_entry (uint16_t tag);
#define GPG_DO_KGTIME_DEC 0x00cf #define GPG_DO_KGTIME_DEC 0x00cf
#define GPG_DO_KGTIME_AUT 0x00d0 #define GPG_DO_KGTIME_AUT 0x00d0
#define GPG_DO_RESETTING_CODE 0x00d3 #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_KEY_IMPORT 0x3fff
#define GPG_DO_LANGUAGE 0x5f2d #define GPG_DO_LANGUAGE 0x5f2d
#define GPG_DO_SEX 0x5f35 #define GPG_DO_SEX 0x5f35
#define GPG_DO_URL 0x5f50 #define GPG_DO_URL 0x5f50
#define GPG_DO_HIST_BYTES 0x5f52 #define GPG_DO_HIST_BYTES 0x5f52
#define GPG_DO_CH_CERTIFICATE 0x7f21 #define GPG_DO_CH_CERTIFICATE 0x7f21
#define GPG_DO_FEATURE_MNGMNT 0x7f74
static const uint8_t *do_ptr[NR_DO__LAST__]; static const uint8_t *do_ptr[NR_DO__LAST__];
@@ -468,6 +509,8 @@ do_tag_to_nr (uint16_t tag)
return NR_DO_NAME; return NR_DO_NAME;
case GPG_DO_LANGUAGE: case GPG_DO_LANGUAGE:
return NR_DO_LANGUAGE; return NR_DO_LANGUAGE;
case GPG_DO_KDF:
return NR_DO_KDF;
default: default:
return -1; return -1;
} }
@@ -485,23 +528,6 @@ copy_tag (uint16_t tag)
} }
} }
static int
do_hist_bytes (uint16_t tag, int with_tag)
{
/*
* Currently, we support no life cycle management. In case of Gnuk,
* user could flash the MCU with SWD/JTAG, instead. It is also
* possible for user to do firmware upgrade through USB.
*
* Thus, here, it just returns the template as is.
*
* In future (when Gnuk will be on the real smartcard),
* we can support life cycle management by implementing
* TERMINATE DF / ACTIVATE FILE and fix code around here.
*/
copy_do_1 (tag, historical_bytes, with_tag);
return 1;
}
#define SIZE_FP 20 #define SIZE_FP 20
#define SIZE_KGTIME 4 #define SIZE_KGTIME 4
@@ -631,7 +657,7 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
if (vid == 0xffff || vid == 0x0000) if (vid == 0xffff || vid == 0x0000)
{ {
const uint8_t *u = unique_device_id () + 8; const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
memcpy (res_p, openpgpcard_aid, 8); memcpy (res_p, openpgpcard_aid, 8);
res_p += 8; res_p += 8;
@@ -761,15 +787,15 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
return 0; /* Error. */ return 0; /* Error. */
else if (algo == ALGO_RSA2K && *algo_attr_pp != NULL) else if (algo == ALGO_RSA2K && *algo_attr_pp != NULL)
{ {
gpg_do_delete_prvkey (kk, CLEAN_PAGE_FULL); gpg_reset_algo_attr (kk);
flash_enum_clear (algo_attr_pp); flash_enum_clear (algo_attr_pp);
if (*algo_attr_pp != NULL) if (*algo_attr_pp != NULL)
return 0; return 0;
} }
else if ((algo != ALGO_RSA2K && *algo_attr_pp == NULL) else if ((algo != ALGO_RSA2K && *algo_attr_pp == NULL) ||
|| (*algo_attr_pp)[1] != algo) (*algo_attr_pp != NULL && (*algo_attr_pp)[1] != algo))
{ {
gpg_do_delete_prvkey (kk, CLEAN_PAGE_FULL); gpg_reset_algo_attr (kk);
*algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo); *algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo);
if (*algo_attr_pp == NULL) if (*algo_attr_pp == NULL)
return 0; return 0;
@@ -789,6 +815,215 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
} }
} }
static uint8_t uif_flags; /* Six bits of flags */
#ifdef ACKBTN_SUPPORT
int
gpg_do_get_uif (enum kind_of_key kk)
{
return ((uif_flags >> (kk * 2)) & 3) != 0;
}
static int
rw_uif (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
{
uint8_t nr;
int v;
if (tag != GPG_DO_UIF_SIG && tag != GPG_DO_UIF_DEC && tag != GPG_DO_UIF_AUT)
return 0; /* Failure */
nr = (tag - GPG_DO_UIF_SIG) + NR_DO_UIF_SIG;
v = (uif_flags >> ((tag - GPG_DO_UIF_SIG) * 2)) & 3;
if (is_write)
{
const uint8_t *p;
if (len != 2 || data[1] != 0x20)
return 0;
if (v == 2)
return 0;
if (data[0] != 0x00 && data[0] != 0x01 && data[0] != 0x02)
return 0;
p = flash_enum_write (nr, data[0]);
if (p == NULL)
return 0;
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
uif_flags |= (data[0] & 3) << ((nr - NR_DO_UIF_SIG) * 2);
return 1;
}
else
{
if (with_tag)
{
copy_tag (tag);
*res_p++ = 2;
}
*res_p++ = v;
*res_p++ = 0x20;
return 1;
}
}
#endif
#define SIZE_OF_KDF_DO_MIN 90
#define SIZE_OF_KDF_DO_MAX 110
#define OPENPGP_KDF_ITERSALTED_S2K 3
#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 static int
proc_resetting_code (const uint8_t *data, int len) proc_resetting_code (const uint8_t *data, int len)
{ {
@@ -802,31 +1037,45 @@ proc_resetting_code (const uint8_t *data, int len)
DEBUG_INFO ("Resetting Code!\r\n"); DEBUG_INFO ("Resetting Code!\r\n");
newpw_len = len; if (len == 0)
newpw = data; { /* Removal of resetting code. */
new_ks0[0] = newpw_len; enum kind_of_key kk0;
random_get_salt (salt);
s2k (salt, SALT_SIZE, newpw, newpw_len, new_ks); for (kk0 = 0; kk0 <= GPG_KEY_FOR_AUTHENTICATION; kk0++)
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks); gpg_do_chks_prvkey (kk0, BY_RESETCODE, NULL, 0, NULL);
if (r <= -2) gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
{
DEBUG_INFO ("memory error.\r\n");
return 0;
}
else if (r < 0)
{
DEBUG_INFO ("security error.\r\n");
return 0;
}
else if (r == 0)
{
DEBUG_INFO ("error (no prvkey).\r\n");
return 0;
} }
else else
{ {
DEBUG_INFO ("done.\r\n"); if (gpg_do_kdf_check (len, 1) == 0)
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KS_META_SIZE); return 0;
newpw_len = len;
newpw = data;
new_ks0[0] = newpw_len;
random_get_salt (salt);
s2k (salt, SALT_SIZE, newpw, newpw_len, new_ks);
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
if (r <= -2)
{
DEBUG_INFO ("memory error.\r\n");
return 0;
}
else if (r < 0)
{
DEBUG_INFO ("security error.\r\n");
return 0;
}
else if (r == 0)
{
DEBUG_INFO ("error (no prvkey).\r\n");
return 0;
}
else
{
DEBUG_INFO ("done.\r\n");
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KS_META_SIZE);
}
} }
gpg_pw_reset_err_counter (PW_ERR_RC); gpg_pw_reset_err_counter (PW_ERR_RC);
@@ -838,7 +1087,7 @@ encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
{ {
aes_context aes; aes_context aes;
uint8_t iv0[INITIAL_VECTOR_SIZE]; uint8_t iv0[INITIAL_VECTOR_SIZE];
unsigned int iv_offset; size_t iv_offset;
DEBUG_INFO ("ENC\r\n"); DEBUG_INFO ("ENC\r\n");
DEBUG_BINARY (data, len); DEBUG_BINARY (data, len);
@@ -857,7 +1106,7 @@ decrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
{ {
aes_context aes; aes_context aes;
uint8_t iv0[INITIAL_VECTOR_SIZE]; uint8_t iv0[INITIAL_VECTOR_SIZE];
unsigned int iv_offset; size_t iv_offset;
aes_setkey_enc (&aes, key, 128); /* This is setkey_enc, because of CFB. */ aes_setkey_enc (&aes, key, 128); /* This is setkey_enc, because of CFB. */
memcpy (iv0, iv, INITIAL_VECTOR_SIZE); memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
@@ -1042,6 +1291,28 @@ gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full)
} }
} }
void
gpg_do_terminate (void)
{
int i;
for (i = 0; i < 3; i++)
kd[i].pubkey = NULL;
for (i = 0; i < NR_DO__LAST__; i++)
do_ptr[i] = NULL;
num_prv_keys = 0;
data_objects_number_of_bytes = 0;
digital_signature_counter = 0;
pw1_lifetime_p = NULL;
pw_err_counter_p[PW_ERR_PW1] = NULL;
pw_err_counter_p[PW_ERR_RC] = NULL;
pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
}
static int static int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
int prvkey_len, const uint8_t *keystring_admin, int prvkey_len, const uint8_t *keystring_admin,
@@ -1051,14 +1322,16 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
int attr = gpg_get_algo_attr (kk);; int attr = gpg_get_algo_attr (kk);;
const uint8_t *p; const uint8_t *p;
int r; int r;
struct prvkey_data *pd; struct prvkey_data prv;
struct prvkey_data *pd = &prv;
uint8_t *key_addr; uint8_t *key_addr;
const uint8_t *dek, *iv; const uint8_t *dek, *iv;
struct key_data_internal kdi; struct key_data_internal kdi;
uint8_t *pubkey_allocated_here = NULL;
int pubkey_len; int pubkey_len;
uint8_t ks[KEYSTRING_MD_SIZE]; uint8_t ks[KEYSTRING_MD_SIZE];
enum kind_of_key kk0; enum kind_of_key kk0;
int pw_len;
const uint8_t *initial_pw;
DEBUG_INFO ("Key import\r\n"); DEBUG_INFO ("Key import\r\n");
DEBUG_SHORT (prvkey_len); DEBUG_SHORT (prvkey_len);
@@ -1066,10 +1339,6 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
/* Delete it first, if any. */ /* Delete it first, if any. */
gpg_do_delete_prvkey (kk, CLEAN_SINGLE); gpg_do_delete_prvkey (kk, CLEAN_SINGLE);
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
return -1;
if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1) if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{ {
pubkey_len = prvkey_len * 2; pubkey_len = prvkey_len * 2;
@@ -1097,38 +1366,11 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
return -1; return -1;
} }
if (pubkey == NULL)
{
if (attr == ALGO_SECP256K1)
pubkey_allocated_here = ecc_compute_public_p256k1 (key_data);
else if (attr == ALGO_NISTP256R1)
pubkey_allocated_here = ecc_compute_public_p256r1 (key_data);
else if (attr == ALGO_ED25519)
pubkey_allocated_here = eddsa_compute_public_25519 (key_data);
else if (attr == ALGO_CURVE25519)
pubkey_allocated_here = ecdh_compute_public_25519 (key_data);
else /* RSA */
pubkey_allocated_here = modulus_calc (key_data, prvkey_len);
if (pubkey_allocated_here == NULL)
{
free (pd);
return -1;
}
}
DEBUG_INFO ("Getting keystore address...\r\n"); DEBUG_INFO ("Getting keystore address...\r\n");
key_addr = flash_key_alloc (kk); key_addr = flash_key_alloc (kk);
if (key_addr == NULL) if (key_addr == NULL)
{ return -1;
if (pubkey_allocated_here)
{
memset (pubkey_allocated_here, 0, pubkey_len);
free (pubkey_allocated_here);
}
free (pd);
return -1;
}
kd[kk].pubkey = key_addr + prvkey_len; kd[kk].pubkey = key_addr + prvkey_len;
num_prv_keys++; num_prv_keys++;
@@ -1147,8 +1389,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_2, dek, DATA_ENCRYPTION_KEY_SIZE);
memcpy (pd->dek_encrypted_3, 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, gpg_do_get_initial_pw_setting (0, &pw_len, &initial_pw);
strlen (OPENPGP_CARD_INITIAL_PW1), ks); s2k (NULL, 0, initial_pw, pw_len, ks);
/* Handle existing keys and keystring DOs. */ /* Handle existing keys and keystring DOs. */
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0); gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
@@ -1164,19 +1406,11 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
encrypt (dek, iv, (uint8_t *)&kdi, kdi_len (prvkey_len)); encrypt (dek, iv, (uint8_t *)&kdi, kdi_len (prvkey_len));
r = flash_key_write (key_addr, (const uint8_t *)kdi.data, prvkey_len, r = flash_key_write (key_addr, (const uint8_t *)kdi.data, prvkey_len,
pubkey_allocated_here? pubkey_allocated_here: pubkey, pubkey, pubkey_len);
pubkey_len);
if (pubkey_allocated_here)
{
memset (pubkey_allocated_here, 0, pubkey_len);
free (pubkey_allocated_here);
}
if (r < 0) if (r < 0)
{ {
random_bytes_free (dek); random_bytes_free (dek);
memset (pd, 0, sizeof (struct prvkey_data)); memset (pd, 0, sizeof (struct prvkey_data));
free (pd);
return r; return r;
} }
@@ -1198,7 +1432,6 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
random_bytes_free (dek); random_bytes_free (dek);
memset (pd, 0, sizeof (struct prvkey_data)); memset (pd, 0, sizeof (struct prvkey_data));
free (pd);
if (p == NULL) if (p == NULL)
return -1; return -1;
@@ -1230,18 +1463,15 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
uint8_t nr = get_do_ptr_nr_for_kk (kk); uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *do_data = do_ptr[nr]; const uint8_t *do_data = do_ptr[nr];
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE]; uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
struct prvkey_data *pd; struct prvkey_data prv;
const uint8_t *p; struct prvkey_data *pd = &prv;
uint8_t *dek_p; uint8_t *dek_p;
int update_needed = 0; int update_needed = 0;
int r = 1; /* Success */
if (do_data == NULL) if (do_data == NULL)
return 0; /* No private key */ return 0; /* No private key */
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
return -1;
memcpy (pd, &do_data[1], sizeof (struct prvkey_data)); memcpy (pd, &do_data[1], sizeof (struct prvkey_data));
dek_p = ((uint8_t *)pd) + INITIAL_VECTOR_SIZE dek_p = ((uint8_t *)pd) + INITIAL_VECTOR_SIZE
@@ -1272,18 +1502,19 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
if (update_needed) if (update_needed)
{ {
const uint8_t *p;
flash_do_release (do_data); flash_do_release (do_data);
do_ptr[nr] = NULL; do_ptr[nr] = NULL;
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
do_ptr[nr] = p; do_ptr[nr] = p;
if (p == NULL)
r = -1;
} }
memset (pd, 0, sizeof (struct prvkey_data)); memset (pd, 0, sizeof (struct prvkey_data));
free (pd);
if (update_needed && p == NULL)
return -1;
return 1; return r;
} }
@@ -1338,6 +1569,7 @@ proc_key_import (const uint8_t *data, int len)
const uint8_t *keystring_admin; const uint8_t *keystring_admin;
int attr; int attr;
const uint8_t *p = data; const uint8_t *p = data;
uint8_t pubkey[512];
if (admin_authorized == BY_ADMIN) if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3; keystring_admin = keystring_md_pw3;
@@ -1377,13 +1609,35 @@ proc_key_import (const uint8_t *data, int len)
} }
if (attr == ALGO_RSA2K) if (attr == ALGO_RSA2K)
/* It should starts with 00 01 00 01 (E), skiping E (4-byte) */ {
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL); /* It should starts with 00 01 00 01 (E), skiping E (4-byte) */
r = modulus_calc (&data[26], len - 26, pubkey);
if (r >= 0)
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin,
pubkey);
}
else if (attr == ALGO_RSA4K) else if (attr == ALGO_RSA4K)
/* It should starts with 00 01 00 01 (E), skiping E (4-byte) */ {
r = gpg_do_write_prvkey (kk, &data[28], len - 28, keystring_admin, NULL); /* It should starts with 00 01 00 01 (E), skiping E (4-byte) */
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1) r = modulus_calc (&data[28], len - 28, pubkey);
r = gpg_do_write_prvkey (kk, &data[12], len - 12, keystring_admin, NULL); if (r >= 0)
r = gpg_do_write_prvkey (kk, &data[28], len - 28, keystring_admin,
pubkey);
}
else if (attr == ALGO_NISTP256R1)
{
r = ecc_compute_public_p256r1 (&data[12], pubkey);
if (r >= 0)
r = gpg_do_write_prvkey (kk, &data[12], len - 12, keystring_admin,
pubkey);
}
else if (attr == ALGO_SECP256K1)
{
r = ecc_compute_public_p256k1 (&data[12], pubkey);
if (r >= 0)
r = gpg_do_write_prvkey (kk, &data[12], len - 12, keystring_admin,
pubkey);
}
else if (attr == ALGO_ED25519) else if (attr == ALGO_ED25519)
{ {
uint8_t hash[64]; uint8_t hash[64];
@@ -1395,7 +1649,8 @@ proc_key_import (const uint8_t *data, int len)
hash[0] &= 248; hash[0] &= 248;
hash[31] &= 127; hash[31] &= 127;
hash[31] |= 64; hash[31] |= 64;
r = gpg_do_write_prvkey (kk, hash, 64, keystring_admin, NULL); eddsa_compute_public_25519 (hash, pubkey);
r = gpg_do_write_prvkey (kk, hash, 64, keystring_admin, pubkey);
} }
else if (attr == ALGO_CURVE25519) else if (attr == ALGO_CURVE25519)
{ {
@@ -1407,7 +1662,8 @@ proc_key_import (const uint8_t *data, int len)
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
priv[31-i] = data[12+i]; priv[31-i] = data[12+i];
r = gpg_do_write_prvkey (kk, priv, 32, keystring_admin, NULL); ecdh_compute_public_25519 (priv, pubkey);
r = gpg_do_write_prvkey (kk, priv, 32, keystring_admin, pubkey);
} }
if (r < 0) if (r < 0)
@@ -1424,18 +1680,32 @@ static const uint16_t cmp_ch_data[] = {
}; };
static const uint16_t cmp_app_data[] = { static const uint16_t cmp_app_data[] = {
#ifdef ACKBTN_SUPPORT
4,
#else
3, 3,
#endif
GPG_DO_AID, GPG_DO_AID,
GPG_DO_HIST_BYTES, GPG_DO_HIST_BYTES,
GPG_DO_DISCRETIONARY, GPG_DO_DISCRETIONARY,
#ifdef ACKBTN_SUPPORT
GPG_DO_FEATURE_MNGMNT,
#endif
}; };
static const uint16_t cmp_discretionary[] = { static const uint16_t cmp_discretionary[] = {
#ifdef ACKBTN_SUPPORT
11,
#else
8, 8,
#endif
GPG_DO_EXTCAP, GPG_DO_EXTCAP,
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT, GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
GPG_DO_PW_STATUS, GPG_DO_PW_STATUS,
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL,
#ifdef ACKBTN_SUPPORT
GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT
#endif
}; };
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT }; static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
@@ -1459,7 +1729,6 @@ gpg_do_table[] = {
{ GPG_DO_NAME, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[12] }, { GPG_DO_NAME, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[12] },
{ GPG_DO_LANGUAGE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[13] }, { GPG_DO_LANGUAGE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[13] },
/* Pseudo DO READ: calculated */ /* Pseudo DO READ: calculated */
{ GPG_DO_HIST_BYTES, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_hist_bytes },
{ GPG_DO_FP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_fp_all }, { GPG_DO_FP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_fp_all },
{ GPG_DO_CAFP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_cafp_all }, { GPG_DO_CAFP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_cafp_all },
{ GPG_DO_KGTIME_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_kgtime_all }, { GPG_DO_KGTIME_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_kgtime_all },
@@ -1475,8 +1744,19 @@ gpg_do_table[] = {
rw_algorithm_attr }, rw_algorithm_attr },
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, { GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_algorithm_attr }, rw_algorithm_attr },
#ifdef ACKBTN_SUPPORT
{ GPG_DO_UIF_SIG, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
{ GPG_DO_UIF_DEC, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
{ GPG_DO_UIF_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
#endif
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_kdf },
/* Fixed data */ /* 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 }, { GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
#ifdef ACKBTN_SUPPORT
{ GPG_DO_FEATURE_MNGMNT, DO_FIXED, AC_ALWAYS, AC_NEVER, feature_mngmnt },
#endif
/* Compound data: Read access only */ /* Compound data: Read access only */
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data }, { GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data }, { GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
@@ -1501,7 +1781,7 @@ gpg_do_table[] = {
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc. * Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
*/ */
void void
gpg_data_scan (const uint8_t *p_start) gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
{ {
const uint8_t *p; const uint8_t *p;
int i; int i;
@@ -1514,10 +1794,20 @@ gpg_data_scan (const uint8_t *p_start)
pw_err_counter_p[PW_ERR_RC] = NULL; pw_err_counter_p[PW_ERR_RC] = NULL;
pw_err_counter_p[PW_ERR_PW3] = NULL; pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL; algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
digital_signature_counter = 0;
uif_flags = 0;
/* Clear all data objects. */
for (i = 0; i < NR_DO__LAST__; i++)
do_ptr[i] = NULL;
/* When the card is terminated no data objects are valid. */
if (do_start == NULL)
return;
/* Traverse DO, counters, etc. in DATA pool */ /* Traverse DO, counters, etc. in DATA pool */
p = p_start; p = do_start;
while (*p != NR_EMPTY) while (p < do_end && *p != NR_EMPTY)
{ {
uint8_t nr = *p++; uint8_t nr = *p++;
uint8_t second_byte = *p; uint8_t second_byte = *p;
@@ -1529,10 +1819,12 @@ gpg_data_scan (const uint8_t *p_start)
if (nr < 0x80) if (nr < 0x80)
{ {
/* It's Data Object */ /* It's Data Object */
do_ptr[nr] = p; if (nr < NR_DO__LAST__)
do_ptr[nr] = p;
p += second_byte + 1; /* second_byte has length */ p += second_byte + 1; /* second_byte has length */
if (((uint32_t)p & 1)) if (((uintptr_t)p & 1))
p++; p++;
} }
else if (nr >= 0x80 && nr <= 0xbf) else if (nr >= 0x80 && nr <= 0xbf)
@@ -1566,6 +1858,13 @@ gpg_data_scan (const uint8_t *p_start)
algo_attr_aut_p = p - 1; algo_attr_aut_p = p - 1;
p++; p++;
break; break;
case NR_DO_UIF_SIG:
case NR_DO_UIF_DEC:
case NR_DO_UIF_AUT:
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
uif_flags |= (second_byte & 3) << ((nr - NR_DO_UIF_SIG) * 2);
p++;
break;
case NR_COUNTER_123: case NR_COUNTER_123:
p++; p++;
if (second_byte <= PW_ERR_PW3) if (second_byte <= PW_ERR_PW3)
@@ -1665,6 +1964,13 @@ gpg_data_copy (const uint8_t *p_start)
p += 4; p += 4;
} }
for (i = 0; i < 3; i++)
if ((v = (uif_flags >> (i * 2)) & 3))
{
flash_enum_write_internal (p, NR_DO_UIF_SIG + i, v);
p += 2;
}
data_objects_number_of_bytes = 0; data_objects_number_of_bytes = 0;
for (i = 0; i < NR_DO__LAST__; i++) for (i = 0; i < NR_DO__LAST__; i++)
if (do_ptr[i] != NULL) if (do_ptr[i] != NULL)
@@ -2037,44 +2343,37 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
} }
void void
gpg_do_keygen (uint8_t kk_byte) gpg_do_keygen (uint8_t *buf)
{ {
uint8_t kk_byte = buf[0];
enum kind_of_key kk = kkb_to_kk (kk_byte); enum kind_of_key kk = kkb_to_kk (kk_byte);
int attr = gpg_get_algo_attr (kk);; int attr = gpg_get_algo_attr (kk);;
int prvkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PRIVATE); int prvkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PRIVATE);
const uint8_t *keystring_admin;
uint8_t *p_q_modulus = NULL;
uint8_t d[64];
const uint8_t *rnd;
const uint8_t *prv; const uint8_t *prv;
const uint8_t *pubkey; const uint8_t *rnd;
int r; int r = 0;
#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_INFO ("Keygen\r\n");
DEBUG_BYTE (kk_byte); DEBUG_BYTE (kk_byte);
if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3;
else
keystring_admin = NULL;
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K) if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{ {
p_q_modulus = rsa_genkey (prvkey_len); if (rsa_genkey (prvkey_len, pubkey, p_q) < 0)
if (p_q_modulus == NULL)
{ {
GPG_MEMORY_FAILURE (); GPG_MEMORY_FAILURE ();
return; return;
} }
prv = p_q_modulus; prv = p_q;
pubkey = p_q_modulus + prvkey_len;
} }
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1) else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{ {
uint8_t d1[32];
const uint8_t *p; const uint8_t *p;
int i, r; int i;
rnd = NULL; rnd = NULL;
do do
@@ -2101,7 +2400,10 @@ gpg_do_keygen (uint8_t kk_byte)
random_bytes_free (rnd); random_bytes_free (rnd);
prv = d; prv = d;
pubkey = NULL; if (attr == ALGO_SECP256K1)
r = ecc_compute_public_p256k1 (prv, pubkey);
else if (attr == ALGO_NISTP256R1)
r = ecc_compute_public_p256r1 (prv, pubkey);
} }
else if (attr == ALGO_ED25519) else if (attr == ALGO_ED25519)
{ {
@@ -2112,7 +2414,7 @@ gpg_do_keygen (uint8_t kk_byte)
d[31] &= 127; d[31] &= 127;
d[31] |= 64; d[31] |= 64;
prv = d; prv = d;
pubkey = NULL; eddsa_compute_public_25519 (d, pubkey);
} }
else if (attr == ALGO_CURVE25519) else if (attr == ALGO_CURVE25519)
{ {
@@ -2123,7 +2425,7 @@ gpg_do_keygen (uint8_t kk_byte)
d[31] &= 127; d[31] &= 127;
d[31] |= 64; d[31] |= 64;
prv = d; prv = d;
pubkey = NULL; ecdh_compute_public_25519 (prv, pubkey);
} }
else else
{ {
@@ -2131,12 +2433,21 @@ gpg_do_keygen (uint8_t kk_byte)
return; return;
} }
r = gpg_do_write_prvkey (kk, prv, prvkey_len, keystring_admin, pubkey); if (r >= 0)
if (p_q_modulus)
{ {
memset (p_q_modulus, 0, prvkey_len * 2); const uint8_t *keystring_admin;
free (p_q_modulus);
if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3;
else
keystring_admin = NULL;
r = gpg_do_write_prvkey (kk, prv, prvkey_len, keystring_admin, pubkey);
} }
/* Clear private key data in the buffer. */
memset (buf, 0, 256);
if (r < 0) if (r < 0)
{ {
GPG_ERROR (); GPG_ERROR ();
@@ -2147,14 +2458,16 @@ gpg_do_keygen (uint8_t kk_byte)
if (kk == GPG_KEY_FOR_SIGNING) 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]; uint8_t keystring[KEYSTRING_MD_SIZE];
/* GnuPG expects it's ready for signing. */ /* GnuPG expects it's ready for signing. */
/* Don't call ac_reset_pso_cds here, but load the private key */ /* Don't call ac_reset_pso_cds here, but load the private key */
gpg_reset_digital_signature_counter (); 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); gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
} }
else else

View File

@@ -1,7 +1,8 @@
/* /*
* openpgp.c -- OpenPGP card protocol support * openpgp.c -- OpenPGP card protocol support
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* 2019
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -31,12 +32,13 @@
#include "gnuk.h" #include "gnuk.h"
#include "sys.h" #include "sys.h"
#include "openpgp.h" #include "status-code.h"
#include "sha256.h" #include "sha256.h"
#include "random.h" #include "random.h"
static struct eventflag *openpgp_comm; static struct eventflag *openpgp_comm;
#define USER_PASSWD_MINLEN 6
#define ADMIN_PASSWD_MINLEN 8 #define ADMIN_PASSWD_MINLEN 8
#define CLS(a) a.cmd_apdu_head[0] #define CLS(a) a.cmd_apdu_head[0]
@@ -48,6 +50,7 @@ static struct eventflag *openpgp_comm;
#define INS_CHANGE_REFERENCE_DATA 0x24 #define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_PSO 0x2a #define INS_PSO 0x2a
#define INS_RESET_RETRY_COUNTER 0x2c #define INS_RESET_RETRY_COUNTER 0x2c
#define INS_ACTIVATE_FILE 0x44
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 #define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47
#define INS_EXTERNAL_AUTHENTICATE 0x82 #define INS_EXTERNAL_AUTHENTICATE 0x82
#define INS_GET_CHALLENGE 0x84 #define INS_GET_CHALLENGE 0x84
@@ -59,6 +62,7 @@ static struct eventflag *openpgp_comm;
#define INS_UPDATE_BINARY 0xd6 #define INS_UPDATE_BINARY 0xd6
#define INS_PUT_DATA 0xda #define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb /* For key import */ #define INS_PUT_DATA_ODD 0xdb /* For key import */
#define INS_TERMINATE_DF 0xe6
static const uint8_t *challenge; /* Random bytes */ static const uint8_t *challenge; /* Random bytes */
@@ -96,18 +100,25 @@ set_res_sw (uint8_t sw1, uint8_t sw2)
#define FILE_EF_UPDATE_KEY_2 7 #define FILE_EF_UPDATE_KEY_2 7
#define FILE_EF_UPDATE_KEY_3 8 #define FILE_EF_UPDATE_KEY_3 8
#define FILE_EF_CH_CERTIFICATE 9 #define FILE_EF_CH_CERTIFICATE 9
#define FILE_CARD_TERMINATED 255
static uint8_t file_selection; uint8_t file_selection;
static void static void
gpg_init (void) gpg_init (void)
{ {
const uint8_t *flash_data_start; const uint8_t *flash_do_start;
const uint8_t *flash_do_end;
file_selection = FILE_NONE; flash_do_storage_init (&flash_do_start, &flash_do_end);
flash_data_start = flash_init ();
gpg_data_scan (flash_data_start); if (flash_do_start == NULL)
flash_init_keys (); file_selection = FILE_CARD_TERMINATED;
else
file_selection = FILE_NONE;
gpg_data_scan (flash_do_start, flash_do_end);
flash_key_storage_init ();
} }
static void static void
@@ -135,7 +146,7 @@ get_pinpad_input (int msg_code)
#endif #endif
static void static void
cmd_verify (void) cmd_verify (struct eventflag *ccid_comm)
{ {
int len; int len;
uint8_t p1 = P1 (apdu); uint8_t p1 = P1 (apdu);
@@ -143,6 +154,7 @@ cmd_verify (void)
int r; int r;
const uint8_t *pw; const uint8_t *pw;
(void)ccid_comm;
DEBUG_INFO (" - VERIFY\r\n"); DEBUG_INFO (" - VERIFY\r\n");
DEBUG_BYTE (p2); DEBUG_BYTE (p2);
@@ -161,7 +173,8 @@ cmd_verify (void)
r = ac_check_status (AC_ADMIN_AUTHORIZED); r = ac_check_status (AC_ADMIN_AUTHORIZED);
if (r) if (r)
GPG_SUCCESS (); /* If authentication done already, return success. */ /* If authentication done already, return success. */
GPG_SUCCESS ();
else else
{ /* If not, return retry counter, encoded. */ { /* If not, return retry counter, encoded. */
r = gpg_pw_get_retry_counter (p2); r = gpg_pw_get_retry_counter (p2);
@@ -183,6 +196,12 @@ cmd_verify (void)
return; return;
} }
if (gpg_do_kdf_check (len, 1) == 0)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
/* This is real authentication. */ /* This is real authentication. */
if (p2 == 0x81) if (p2 == 0x81)
r = verify_pso_cds (pw, len); r = verify_pso_cds (pw, len);
@@ -258,7 +277,7 @@ gpg_change_keystring (int who_old, const uint8_t *old_ks,
} }
static void static void
cmd_change_password (void) cmd_change_password (struct eventflag *ccid_comm)
{ {
uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_SIZE]; uint8_t new_ks0[KEYSTRING_SIZE];
@@ -278,6 +297,7 @@ cmd_change_password (void)
int salt_len; int salt_len;
const uint8_t *ks_pw3; const uint8_t *ks_pw3;
(void)ccid_comm;
DEBUG_INFO ("Change PW\r\n"); DEBUG_INFO ("Change PW\r\n");
DEBUG_BYTE (who); DEBUG_BYTE (who);
@@ -290,6 +310,12 @@ cmd_change_password (void)
return; return;
} }
if (gpg_do_kdf_check (len, 2) == 0)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (who == BY_USER) /* PW1 */ if (who == BY_USER) /* PW1 */
{ {
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
@@ -326,8 +352,9 @@ cmd_change_password (void)
newpw_len = len - pw_len; newpw_len = len - pw_len;
ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
/* Check length of password for admin-less mode. */ /* Check length of password */
if (ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN) if ((ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|| newpw_len < USER_PASSWD_MINLEN)
{ {
DEBUG_INFO ("new password length is too short."); DEBUG_INFO ("new password length is too short.");
GPG_CONDITION_NOT_SATISFIED (); GPG_CONDITION_NOT_SATISFIED ();
@@ -342,8 +369,24 @@ cmd_change_password (void)
if (ks_pw3 == NULL) if (ks_pw3 == NULL)
{ {
salt = NULL; if (admin_authorized == BY_USER)
salt_len = 0; {
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
if (ks_pw1 == NULL)
{
GPG_SECURITY_FAILURE ();
return;
}
salt = KS_GET_SALT (ks_pw1);
salt_len = SALT_SIZE;
}
else
{
salt = NULL;
salt_len = 0;
}
} }
else else
{ {
@@ -367,13 +410,22 @@ cmd_change_password (void)
{ {
newpw = pw + pw_len; newpw = pw + pw_len;
newpw_len = len - pw_len; newpw_len = len - pw_len;
if (newpw_len == 0 && admin_authorized == BY_ADMIN) if (newpw_len == 0 && admin_authorized == BY_ADMIN)
{ {
newpw_len = strlen (OPENPGP_CARD_INITIAL_PW3); const uint8_t *initial_pw;
memcpy (newpw, OPENPGP_CARD_INITIAL_PW3, newpw_len);
gpg_do_get_initial_pw_setting (1, &newpw_len, &initial_pw);
memcpy (newpw, initial_pw, newpw_len);
newsalt_len = 0; newsalt_len = 0;
pw3_null = 1; 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; who_old = admin_authorized;
} }
@@ -403,11 +455,26 @@ cmd_change_password (void)
} }
else if (r > 0 && who == BY_USER) 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); gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KS_META_SIZE);
ac_reset_pso_cds (); ac_reset_pso_cds ();
ac_reset_other (); ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n"); DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
GPG_SUCCESS (); GPG_SUCCESS ();
} }
@@ -483,7 +550,7 @@ s2k (const unsigned char *salt, size_t slen,
static void static void
cmd_reset_user_password (void) cmd_reset_user_password (struct eventflag *ccid_comm)
{ {
uint8_t p1 = P1 (apdu); uint8_t p1 = P1 (apdu);
int len; int len;
@@ -497,6 +564,7 @@ cmd_reset_user_password (void)
const uint8_t *salt; const uint8_t *salt;
int salt_len; int salt_len;
(void)ccid_comm;
DEBUG_INFO ("Reset PW1\r\n"); DEBUG_INFO ("Reset PW1\r\n");
DEBUG_BYTE (p1); DEBUG_BYTE (p1);
@@ -507,6 +575,13 @@ cmd_reset_user_password (void)
{ {
const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC); const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t old_ks[KEYSTRING_MD_SIZE];
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
if (gpg_do_kdf_check (len, 2) == 0)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (gpg_pw_locked (PW_ERR_RC)) if (gpg_pw_locked (PW_ERR_RC))
{ {
@@ -527,6 +602,16 @@ cmd_reset_user_password (void)
salt_len = SALT_SIZE; salt_len = SALT_SIZE;
newpw = pw + pw_len; newpw = pw + pw_len;
newpw_len = len - pw_len; newpw_len = len - pw_len;
/* Check length of new password */
if ((ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|| newpw_len < USER_PASSWD_MINLEN)
{
DEBUG_INFO ("new password length is too short.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
random_get_salt (new_salt); random_get_salt (new_salt);
s2k (salt, salt_len, pw, pw_len, old_ks); s2k (salt, salt_len, pw, pw_len, old_ks);
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks); s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
@@ -572,6 +657,12 @@ cmd_reset_user_password (void)
return; return;
} }
if (gpg_do_kdf_check (len, 1) == 0)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
newpw_len = len; newpw_len = len;
newpw = pw; newpw = pw;
random_get_salt (new_salt); random_get_salt (new_salt);
@@ -608,17 +699,15 @@ cmd_reset_user_password (void)
} }
static void static void
cmd_put_data (void) cmd_put_data (struct eventflag *ccid_comm)
{ {
uint8_t *data; uint8_t *data;
uint16_t tag; uint16_t tag;
int len; int len;
(void)ccid_comm;
DEBUG_INFO (" - PUT DATA\r\n"); DEBUG_INFO (" - PUT DATA\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD();
tag = ((P1 (apdu)<<8) | P2 (apdu)); tag = ((P1 (apdu)<<8) | P2 (apdu));
len = apdu.cmd_apdu_data_len; len = apdu.cmd_apdu_data_len;
data = apdu.cmd_apdu_data; data = apdu.cmd_apdu_data;
@@ -626,8 +715,9 @@ cmd_put_data (void)
} }
static void static void
cmd_pgp_gakp (void) cmd_pgp_gakp (struct eventflag *ccid_comm)
{ {
(void)ccid_comm;
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n"); DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
DEBUG_BYTE (P1 (apdu)); DEBUG_BYTE (P1 (apdu));
@@ -638,10 +728,11 @@ cmd_pgp_gakp (void)
{ {
if (!ac_check_status (AC_ADMIN_AUTHORIZED)) if (!ac_check_status (AC_ADMIN_AUTHORIZED))
GPG_SECURITY_FAILURE (); GPG_SECURITY_FAILURE ();
gpg_do_keygen (apdu.cmd_apdu_data[0]); gpg_do_keygen (&apdu.cmd_apdu_data[0]);
} }
} }
#ifdef FLASH_UPGRADE_SUPPORT
const uint8_t * const uint8_t *
gpg_get_firmware_update_key (uint8_t keyno) gpg_get_firmware_update_key (uint8_t keyno)
{ {
@@ -651,6 +742,7 @@ gpg_get_firmware_update_key (uint8_t keyno)
p = &_updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN; p = &_updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
return p; return p;
} }
#endif
#ifdef CERTDO_SUPPORT #ifdef CERTDO_SUPPORT
#define FILEID_CH_CERTIFICATE_IS_VALID 1 #define FILEID_CH_CERTIFICATE_IS_VALID 1
@@ -659,13 +751,13 @@ gpg_get_firmware_update_key (uint8_t keyno)
#endif #endif
static void static void
cmd_read_binary (void) cmd_read_binary (struct eventflag *ccid_comm)
{ {
int is_short_EF = (P1 (apdu) & 0x80) != 0; int is_short_EF = (P1 (apdu) & 0x80) != 0;
uint8_t file_id; uint8_t file_id;
const uint8_t *p;
uint16_t offset; uint16_t offset;
(void)ccid_comm;
DEBUG_INFO (" - Read binary\r\n"); DEBUG_INFO (" - Read binary\r\n");
if (is_short_EF) if (is_short_EF)
@@ -673,13 +765,6 @@ cmd_read_binary (void)
else else
file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO; file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO;
if ((!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE)
|| file_id > FILEID_CH_CERTIFICATE)
{
GPG_NO_FILE ();
return;
}
if (is_short_EF) if (is_short_EF)
{ {
file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO; file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
@@ -699,22 +784,26 @@ cmd_read_binary (void)
} }
return; return;
} }
#ifdef FLASH_UPGRADE_SUPPORT
if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3) else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
{ {
if (offset != 0) if (offset != 0)
GPG_MEMORY_FAILURE (); GPG_MEMORY_FAILURE ();
else else
{ {
const uint8_t *p;
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0); p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
res_APDU_size = FIRMWARE_UPDATE_KEY_CONTENT_LEN; res_APDU_size = FIRMWARE_UPDATE_KEY_CONTENT_LEN;
memcpy (res_APDU, p, FIRMWARE_UPDATE_KEY_CONTENT_LEN); memcpy (res_APDU, p, FIRMWARE_UPDATE_KEY_CONTENT_LEN);
GPG_SUCCESS (); GPG_SUCCESS ();
} }
} }
#endif
#if defined(CERTDO_SUPPORT) #if defined(CERTDO_SUPPORT)
else /* file_id == FILEID_CH_CERTIFICATE */ else if (file_id == FILEID_CH_CERTIFICATE)
{ {
const uint8_t *p;
uint16_t len = 256; uint16_t len = 256;
p = &ch_certificate_start; p = &ch_certificate_start;
@@ -731,11 +820,17 @@ cmd_read_binary (void)
} }
} }
#endif #endif
else
{
GPG_NO_FILE ();
return;
}
} }
static void static void
cmd_select_file (void) cmd_select_file (struct eventflag *ccid_comm)
{ {
(void)ccid_comm;
if (P1 (apdu) == 4) /* Selection by DF name */ if (P1 (apdu) == 4) /* Selection by DF name */
{ {
DEBUG_INFO (" - select DF by name\r\n"); DEBUG_INFO (" - select DF by name\r\n");
@@ -751,19 +846,16 @@ cmd_select_file (void)
return; return;
} }
file_selection = FILE_DF_OPENPGP; if (file_selection == FILE_CARD_TERMINATED)
if ((P2 (apdu) & 0x0c) == 0x0c) /* No FCI */
GPG_SUCCESS ();
else
{ {
gpg_do_get_data (0x004f, 1); /* AID */ GPG_APPLICATION_TERMINATED ();
memmove (res_APDU+2, res_APDU, res_APDU_size); return;
res_APDU[0] = 0x6f;
res_APDU[1] = 0x12;
res_APDU[2] = 0x84; /* overwrite: DF name */
res_APDU_size += 2;
GPG_SUCCESS ();
} }
file_selection = FILE_DF_OPENPGP;
/* Behave just like original OpenPGP card. */
GPG_SUCCESS ();
} }
else if (apdu.cmd_apdu_data_len == 2 else if (apdu.cmd_apdu_data_len == 2
&& apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02) && apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02)
@@ -807,15 +899,13 @@ cmd_select_file (void)
} }
static void static void
cmd_get_data (void) cmd_get_data (struct eventflag *ccid_comm)
{ {
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu)); uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
(void)ccid_comm;
DEBUG_INFO (" - Get Data\r\n"); DEBUG_INFO (" - Get Data\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD ();
gpg_do_get_data (tag, 0); gpg_do_get_data (tag, 0);
} }
@@ -828,7 +918,7 @@ cmd_get_data (void)
#define ECC_CIPHER_DO_HEADER_SIZE 7 #define ECC_CIPHER_DO_HEADER_SIZE 7
static void static void
cmd_pso (void) cmd_pso (struct eventflag *ccid_comm)
{ {
int len = apdu.cmd_apdu_data_len; int len = apdu.cmd_apdu_data_len;
int r = -1; int r = -1;
@@ -855,6 +945,11 @@ cmd_pso (void)
return; return;
} }
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K) if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{ {
/* Check size of digestInfo */ /* Check size of digestInfo */
@@ -946,6 +1041,13 @@ cmd_pso (void)
return; return;
} }
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#else
(void)ccid_comm;
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K) if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{ {
/* Skip padding 0x00 */ /* Skip padding 0x00 */
@@ -1022,7 +1124,7 @@ cmd_pso (void)
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */ #define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
static void static void
cmd_internal_authenticate (void) cmd_internal_authenticate (struct eventflag *ccid_comm)
{ {
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION); int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION, int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
@@ -1052,6 +1154,13 @@ cmd_internal_authenticate (void)
return; return;
} }
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#else
(void)ccid_comm;
#endif
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K) if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{ {
if (len > MAX_RSA_DIGEST_INFO_LEN) if (len > MAX_RSA_DIGEST_INFO_LEN)
@@ -1200,6 +1309,7 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
return; return;
} }
#ifdef FLASH_UPGRADE_SUPPORT
if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3 if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3
&& len == 0 && offset == 0) && len == 0 && offset == 0)
{ {
@@ -1216,9 +1326,10 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
if (i == 4) /* all update keys are removed */ if (i == 4) /* all update keys are removed */
{ {
p = gpg_get_firmware_update_key (0); p = gpg_get_firmware_update_key (0);
flash_erase_page ((uint32_t)p); flash_erase_page ((uintptr_t)p);
} }
} }
#endif
GPG_SUCCESS (); GPG_SUCCESS ();
} }
@@ -1226,10 +1337,11 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
#if defined(CERTDO_SUPPORT) #if defined(CERTDO_SUPPORT)
static void static void
cmd_update_binary (void) cmd_update_binary (struct eventflag *ccid_comm)
{ {
int len = apdu.cmd_apdu_data_len; int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - UPDATE BINARY\r\n"); DEBUG_INFO (" - UPDATE BINARY\r\n");
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len); modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("UPDATE BINARY done.\r\n"); DEBUG_INFO ("UPDATE BINARY done.\r\n");
@@ -1238,18 +1350,20 @@ cmd_update_binary (void)
static void static void
cmd_write_binary (void) cmd_write_binary (struct eventflag *ccid_comm)
{ {
int len = apdu.cmd_apdu_data_len; int len = apdu.cmd_apdu_data_len;
(void)ccid_comm;
DEBUG_INFO (" - WRITE BINARY\r\n"); DEBUG_INFO (" - WRITE BINARY\r\n");
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len); modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
DEBUG_INFO ("WRITE BINARY done.\r\n"); DEBUG_INFO ("WRITE BINARY done.\r\n");
} }
#ifdef FLASH_UPGRADE_SUPPORT
static void static void
cmd_external_authenticate (void) cmd_external_authenticate (struct eventflag *ccid_comm)
{ {
const uint8_t *pubkey; const uint8_t *pubkey;
const uint8_t *signature = apdu.cmd_apdu_data; const uint8_t *signature = apdu.cmd_apdu_data;
@@ -1257,6 +1371,7 @@ cmd_external_authenticate (void)
uint8_t keyno = P2 (apdu); uint8_t keyno = P2 (apdu);
int r; int r;
(void)ccid_comm;
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n"); DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
if (keyno >= 4) if (keyno >= 4)
@@ -1289,12 +1404,14 @@ cmd_external_authenticate (void)
set_res_sw (0xff, 0xff); set_res_sw (0xff, 0xff);
DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n"); DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n");
} }
#endif
static void static void
cmd_get_challenge (void) cmd_get_challenge (struct eventflag *ccid_comm)
{ {
int len = apdu.expected_res_size; int len = apdu.expected_res_size;
(void)ccid_comm;
DEBUG_INFO (" - GET CHALLENGE\r\n"); DEBUG_INFO (" - GET CHALLENGE\r\n");
if (len > CHALLENGE_LEN) if (len > CHALLENGE_LEN)
@@ -1309,6 +1426,13 @@ cmd_get_challenge (void)
if (challenge) if (challenge)
random_bytes_free (challenge); random_bytes_free (challenge);
#ifdef ACKBTN_SUPPORT
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING)
|| gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION)
|| gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
#endif
challenge = random_bytes_get (); challenge = random_bytes_get ();
memcpy (res_APDU, challenge, len); memcpy (res_APDU, challenge, len);
res_APDU_size = len; res_APDU_size = len;
@@ -1317,10 +1441,74 @@ cmd_get_challenge (void)
} }
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
static void
cmd_activate_file (struct eventflag *ccid_comm)
{
(void)ccid_comm;
if (file_selection != FILE_CARD_TERMINATED)
{
GPG_NO_RECORD ();
return;
}
flash_activate ();
file_selection = FILE_DF_OPENPGP;
GPG_SUCCESS ();
}
static void
cmd_terminate_df (struct eventflag *ccid_comm)
{
const uint8_t *ks_pw3;
uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu);
(void)ccid_comm;
if (file_selection != FILE_DF_OPENPGP)
{
GPG_NO_RECORD ();
return;
}
if (p1 != 0 || p2 != 0)
{
GPG_BAD_P1_P2();
return;
}
if (apdu.cmd_apdu_data_len != 0)
{
GPG_WRONG_LENGTH();
return;
}
ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
if (!ac_check_status (AC_ADMIN_AUTHORIZED)
&& !((ks_pw3 && gpg_pw_locked (PW_ERR_PW3))
|| (ks_pw3 == NULL && gpg_pw_locked (PW_ERR_PW1))))
{
/* Only allow the case admin authorized, or, admin pass is locked. */
GPG_SECURITY_FAILURE();
return;
}
ac_reset_admin ();
ac_reset_pso_cds ();
ac_reset_other ();
gpg_do_terminate ();
flash_terminate ();
file_selection = FILE_CARD_TERMINATED;
GPG_SUCCESS ();
}
#endif
struct command struct command
{ {
uint8_t command; uint8_t command;
void (*cmd_handler) (void); void (*cmd_handler) (struct eventflag *ccid_comm);
}; };
const struct command cmds[] = { const struct command cmds[] = {
@@ -1328,13 +1516,18 @@ const struct command cmds[] = {
{ INS_CHANGE_REFERENCE_DATA, cmd_change_password }, { INS_CHANGE_REFERENCE_DATA, cmd_change_password },
{ INS_PSO, cmd_pso }, { INS_PSO, cmd_pso },
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password }, { INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_ACTIVATE_FILE, cmd_activate_file },
#endif
{ INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp }, { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
#ifdef FLASH_UPGRADE_SUPPORT
{ INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */ { INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */
cmd_external_authenticate }, cmd_external_authenticate },
#endif
{ INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */ { INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */
{ INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate }, { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
{ INS_SELECT_FILE, cmd_select_file }, { INS_SELECT_FILE, cmd_select_file },
{ INS_READ_BINARY, cmd_read_binary }, { INS_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */
{ INS_GET_DATA, cmd_get_data }, { INS_GET_DATA, cmd_get_data },
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */ { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
#if defined(CERTDO_SUPPORT) #if defined(CERTDO_SUPPORT)
@@ -1342,11 +1535,14 @@ const struct command cmds[] = {
#endif #endif
{ INS_PUT_DATA, cmd_put_data }, { INS_PUT_DATA, cmd_put_data },
{ INS_PUT_DATA_ODD, cmd_put_data }, { INS_PUT_DATA_ODD, cmd_put_data },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_TERMINATE_DF, cmd_terminate_df},
#endif
}; };
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command))) #define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
static void static void
process_command_apdu (void) process_command_apdu (struct eventflag *ccid_comm)
{ {
int i; int i;
uint8_t cmd = INS (apdu); uint8_t cmd = INS (apdu);
@@ -1357,9 +1553,22 @@ process_command_apdu (void)
if (i < NUM_CMDS) if (i < NUM_CMDS)
{ {
chopstx_setcancelstate (1); if (file_selection == FILE_CARD_TERMINATED
cmds[i].cmd_handler (); && cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
chopstx_setcancelstate (0); && cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE)
GPG_APPLICATION_TERMINATED ();
else if (file_selection != FILE_DF_OPENPGP
&& cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
&& cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE
&& cmd != INS_WRITE_BINARY && cmd != INS_UPDATE_BINARY
&& cmd != INS_READ_BINARY)
GPG_NO_RECORD ();
else
{
chopstx_setcancelstate (1);
cmds[i].cmd_handler (ccid_comm);
chopstx_setcancelstate (0);
}
} }
else else
{ {
@@ -1471,7 +1680,7 @@ openpgp_card_thread (void *arg)
break; break;
led_blink (LED_START_COMMAND); led_blink (LED_START_COMMAND);
process_command_apdu (); process_command_apdu (ccid_comm);
led_blink (LED_FINISH_COMMAND); led_blink (LED_FINISH_COMMAND);
done: done:
eventflag_signal (ccid_comm, EV_EXEC_FINISHED); eventflag_signal (ccid_comm, EV_EXEC_FINISHED);

View File

@@ -40,14 +40,14 @@ cir_ext_disable (void)
int rcvd = (EXTI->PR & EXTI_PR) != 0; int rcvd = (EXTI->PR & EXTI_PR) != 0;
EXTI->IMR &= ~EXTI_IMR; EXTI->IMR &= ~EXTI_IMR;
EXTI->PR = EXTI_PR; EXTI->PR |= EXTI_PR;
return rcvd; return rcvd;
} }
static void static void
cir_ext_enable (void) cir_ext_enable (void)
{ {
EXTI->PR = EXTI_PR; EXTI->PR |= EXTI_PR;
EXTI->IMR |= EXTI_IMR; EXTI->IMR |= EXTI_IMR;
} }
@@ -964,9 +964,14 @@ cir_timer_interrupt (void)
} }
extern uint8_t __process6_stack_base__[], __process6_stack_size__[]; #define STACK_PROCESS_6
#define STACK_ADDR_TIM ((uint32_t)__process6_stack_base__) #define STACK_PROCESS_7
#define STACK_SIZE_TIM ((uint32_t)__process6_stack_size__) #include "stack-def.h"
#define STACK_ADDR_TIM ((uintptr_t)process6_base)
#define STACK_SIZE_TIM (sizeof process6_base)
#define STACK_ADDR_EXT ((uintptr_t)process7_base)
#define STACK_SIZE_EXT (sizeof process7_base)
#define PRIO_TIM 4 #define PRIO_TIM 4
static void * static void *
@@ -981,14 +986,13 @@ tim_main (void *arg)
{ {
chopstx_intr_wait (&interrupt); chopstx_intr_wait (&interrupt);
cir_timer_interrupt (); cir_timer_interrupt ();
chopstx_intr_done (&interrupt);
} }
return NULL; return NULL;
} }
extern uint8_t __process7_stack_base__, __process7_stack_size__;
const uint32_t __stackaddr_ext = (uint32_t)&__process7_stack_base__;
const size_t __stacksize_ext = (size_t)&__process7_stack_size__;
#define PRIO_EXT 4 #define PRIO_EXT 4
static void * static void *
@@ -1003,6 +1007,7 @@ ext_main (void *arg)
{ {
chopstx_intr_wait (&interrupt); chopstx_intr_wait (&interrupt);
cir_ext_interrupt (); cir_ext_interrupt ();
chopstx_intr_done (&interrupt);
} }
return NULL; return NULL;
@@ -1030,8 +1035,8 @@ cir_init (void)
/* EXTIx <= Py */ /* EXTIx <= Py */
AFIO->EXTICR[AFIO_EXTICR_INDEX] = AFIO_EXTICR1_EXTIx_Py; AFIO->EXTICR[AFIO_EXTICR_INDEX] = AFIO_EXTICR1_EXTIx_Py;
EXTI->IMR = 0; EXTI->IMR &= ~EXTI_IMR;
EXTI->FTSR = EXTI_FTSR_TR; EXTI->FTSR |= EXTI_FTSR_TR;
/* TIM */ /* TIM */
#ifdef ENABLE_RCC_APB1 #ifdef ENABLE_RCC_APB1

View File

@@ -47,7 +47,6 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "sha256.h" #include "sha256.h"
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1) #define SHA256_MASK (SHA256_BLOCK_SIZE - 1)

View File

@@ -32,7 +32,6 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "sha512.h" #include "sha512.h"
#define SHA512_MASK (SHA512_BLOCK_SIZE - 1) #define SHA512_MASK (SHA512_BLOCK_SIZE - 1)

65
src/stack-def.h Normal file
View File

@@ -0,0 +1,65 @@
#ifdef GNU_LINUX_EMULATION
#define SIZE_1 4096
#define SIZE_2 4096
#define SIZE_3 (5 * 4096)
#else
#define SIZE_0 0x0160 /* 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) */
#define SIZE_7 0x00c0 /* ext (cir) */
#endif
#if defined(STACK_MAIN) && !defined(GNU_LINUX_EMULATION)
/* Idle+Exception handlers */
char __main_stack_end__[0] __attribute__ ((section(".main_stack")));
char main_base[0x0080] __attribute__ ((section(".main_stack")));
/* Main program */
char __process0_stack_end__[0] __attribute__ ((section(".process_stack.0")));
char process0_base[SIZE_0] __attribute__ ((section(".process_stack.0")));
#endif
/* First thread program */
#if defined(STACK_PROCESS_1)
char process1_base[SIZE_1] __attribute__ ((section(".process_stack.1")));
#endif
/* Second thread program */
#if defined(STACK_PROCESS_2)
char process2_base[SIZE_2] __attribute__ ((section(".process_stack.2")));
#endif
/* Third thread program */
#if defined(STACK_PROCESS_3)
char process3_base[SIZE_3] __attribute__ ((section(".process_stack.3")));
#endif
/* Fourth thread program */
#if defined(STACK_PROCESS_4)
char process4_base[SIZE_4] __attribute__ ((section(".process_stack.4")));
#endif
/* Fifth thread program */
#if defined(STACK_PROCESS_5)
char process5_base[SIZE_5] __attribute__ ((section(".process_stack.5")));
#endif
/* Sixth thread program */
#if defined(STACK_PROCESS_6)
char process6_base[SIZE_6] __attribute__ ((section(".process_stack.6")));
#endif
/* Seventh thread program */
#if defined(STACK_PROCESS_7)
char process7_base[SIZE_7] __attribute__ ((section(".process_stack.7")));
#endif

View File

@@ -1,4 +1,6 @@
#define GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85)
#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81) #define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define GPG_WRONG_LENGTH() set_res_sw (0x67, 0x00)
#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82) #define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82)
#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83) #define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83)
#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85) #define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85)

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

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

View File

@@ -1,13 +0,0 @@
/*
* stdlib.h replacement to replace malloc functions
*/
typedef unsigned int size_t;
#include <stddef.h> /* NULL */
#define malloc(size) gnuk_malloc (size)
#define free(p) gnuk_free (p)
void *gnuk_malloc (size_t);
void gnuk_free (void *);

File diff suppressed because it is too large Load Diff

View File

@@ -31,9 +31,11 @@
#include "usb_lld.h" #include "usb_lld.h"
#include "usb-msc.h" #include "usb-msc.h"
extern uint8_t __process5_stack_base__[], __process5_stack_size__[]; #define STACK_PROCESS_5
#define STACK_ADDR_MSC ((uint32_t)__process5_stack_base__) #include "stack-def.h"
#define STACK_SIZE_MSC ((uint32_t)__process5_stack_size__) #define STACK_ADDR_MSC ((uintptr_t)process5_base)
#define STACK_SIZE_MSC (sizeof process5_base)
#define PRIO_MSC 3 #define PRIO_MSC 3
static chopstx_mutex_t a_pinpad_mutex; static chopstx_mutex_t a_pinpad_mutex;

View File

@@ -1,7 +1,7 @@
/* /*
* usb_ctrl.c - USB control pipe device specific code for Gnuk * usb_ctrl.c - USB control pipe device specific code for Gnuk
* *
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016 * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan * Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
@@ -38,7 +38,7 @@
#include "usb_lld.h" #include "usb_lld.h"
#include "usb_conf.h" #include "usb_conf.h"
#include "gnuk.h" #include "gnuk.h"
#include "mcu/stm32f103.h" #include "neug.h"
#ifdef ENABLE_VIRTUAL_COM_PORT #ifdef ENABLE_VIRTUAL_COM_PORT
#include "usb-cdc.h" #include "usb-cdc.h"
@@ -87,7 +87,7 @@ vcom_port_data_setup (struct usb_dev *dev)
#include "usb-msc.h" #include "usb-msc.h"
#endif #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_REPORT 1
#define USB_HID_REQ_GET_IDLE 2 #define USB_HID_REQ_GET_IDLE 2
@@ -108,15 +108,25 @@ static uint16_t hid_report;
#endif #endif
static void static void
gnuk_setup_endpoints_for_interface (uint16_t interface, int stop) gnuk_setup_endpoints_for_interface (struct usb_dev *dev,
uint16_t interface, int stop)
{ {
#if !defined(GNU_LINUX_EMULATION)
(void)dev;
#endif
if (interface == CCID_INTERFACE) if (interface == CCID_INTERFACE)
{ {
if (!stop) if (!stop)
{ {
#ifdef GNU_LINUX_EMULATION
usb_lld_setup_endp (dev, ENDP1, 1, 1);
usb_lld_setup_endp (dev, ENDP2, 0, 1);
#else
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR,
ENDP1_TXADDR, GNUK_MAX_PACKET_SIZE); ENDP1_TXADDR, GNUK_MAX_PACKET_SIZE);
usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0); usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
#endif
} }
else else
{ {
@@ -129,7 +139,11 @@ gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
else if (interface == HID_INTERFACE) else if (interface == HID_INTERFACE)
{ {
if (!stop) if (!stop)
#ifdef GNU_LINUX_EMULATION
usb_lld_setup_endp (dev, ENDP7, 0, 1);
#else
usb_lld_setup_endpoint (ENDP7, EP_INTERRUPT, 0, 0, ENDP7_TXADDR, 0); usb_lld_setup_endpoint (ENDP7, EP_INTERRUPT, 0, 0, ENDP7_TXADDR, 0);
#endif
else else
usb_lld_stall_tx (ENDP7); usb_lld_stall_tx (ENDP7);
} }
@@ -138,7 +152,11 @@ gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
else if (interface == VCOM_INTERFACE_0) else if (interface == VCOM_INTERFACE_0)
{ {
if (!stop) if (!stop)
#ifdef GNU_LINUX_EMULATION
usb_lld_setup_endp (dev, ENDP4, 0, 1);
#else
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0); usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
#endif
else else
usb_lld_stall_tx (ENDP4); usb_lld_stall_tx (ENDP4);
} }
@@ -146,9 +164,14 @@ gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
{ {
if (!stop) if (!stop)
{ {
#ifdef GNU_LINUX_EMULATION
usb_lld_setup_endp (dev, ENDP3, 0, 1);
usb_lld_setup_endp (dev, ENDP5, 1, 0);
#else
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0); usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0, usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
VIRTUAL_COM_PORT_DATA_SIZE); VIRTUAL_COM_PORT_DATA_SIZE);
#endif
} }
else else
{ {
@@ -161,8 +184,12 @@ gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
else if (interface == MSC_INTERFACE) else if (interface == MSC_INTERFACE)
{ {
if (!stop) if (!stop)
#ifdef GNU_LINUX_EMULATION
usb_lld_setup_endp (dev, ENDP6, 1, 1);
#else
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0, usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
ENDP6_RXADDR, ENDP6_TXADDR, 64); ENDP6_RXADDR, ENDP6_TXADDR, 64);
#endif
else else
{ {
usb_lld_stall_tx (ENDP6); usb_lld_stall_tx (ENDP6);
@@ -175,20 +202,17 @@ gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
void void
usb_device_reset (struct usb_dev *dev) usb_device_reset (struct usb_dev *dev)
{ {
int i;
usb_lld_reset (dev, USB_INITIAL_FEATURE); usb_lld_reset (dev, USB_INITIAL_FEATURE);
/* Initialize Endpoint 0 */ /* Initialize Endpoint 0 */
#ifdef GNU_LINUX_EMULATION
usb_lld_setup_endp (dev, ENDP0, 1, 1);
#else
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
GNUK_MAX_PACKET_SIZE); 64);
#endif
/* Stop the interface */ bDeviceState = USB_DEVICE_STATE_DEFAULT;
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 1);
bDeviceState = ATTACHED;
ccid_usb_reset (1);
} }
#define USB_CCID_REQ_ABORT 0x01 #define USB_CCID_REQ_ABORT 0x01
@@ -202,38 +226,34 @@ static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
static const uint8_t lun_table[] = { 0, 0, 0, 0, }; static const uint8_t lun_table[] = { 0, 0, 0, 0, };
#endif #endif
#ifdef FLASH_UPGRADE_SUPPORT
static const uint8_t *const mem_info[] = { &_regnual_start, __heap_end__, }; static const uint8_t *const mem_info[] = { &_regnual_start, __heap_end__, };
#endif
#define USB_FSIJ_GNUK_MEMINFO 0 #define USB_FSIJ_GNUK_MEMINFO 0
#define USB_FSIJ_GNUK_DOWNLOAD 1 #define USB_FSIJ_GNUK_DOWNLOAD 1
#define USB_FSIJ_GNUK_EXEC 2 #define USB_FSIJ_GNUK_EXEC 2
#define USB_FSIJ_GNUK_CARD_CHANGE 3 #define USB_FSIJ_GNUK_CARD_CHANGE 3
static uint32_t rbit (uint32_t v) #ifdef FLASH_UPGRADE_SUPPORT
{
uint32_t r;
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
return r;
}
/* After calling this function, CRC module remain enabled. */ /* After calling this function, CRC module remain enabled. */
static int download_check_crc32 (struct usb_dev *dev, const uint32_t *end_p) static int
download_check_crc32 (struct usb_dev *dev, const uint32_t *end_p)
{ {
uint32_t crc32 = *end_p; uint32_t crc32 = *end_p;
const uint32_t *p; const uint32_t *p;
RCC->AHBENR |= RCC_AHBENR_CRCEN; crc32_rv_reset ();
CRC->CR = CRC_CR_RESET;
for (p = (const uint32_t *)&_regnual_start; p < end_p; p++) for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
CRC->DR = rbit (*p); crc32_rv_step (rbit (*p));
if ((rbit (CRC->DR) ^ crc32) == 0xffffffff) if ((rbit (crc32_rv_get ()) ^ crc32) == 0xffffffff)
return usb_lld_ctrl_ack (dev); return usb_lld_ctrl_ack (dev);
return -1; return -1;
} }
#endif
int int
usb_setup (struct usb_dev *dev) usb_setup (struct usb_dev *dev)
@@ -245,17 +265,23 @@ usb_setup (struct usb_dev *dev)
{ {
if (USB_SETUP_GET (arg->type)) if (USB_SETUP_GET (arg->type))
{ {
#ifdef FLASH_UPGRADE_SUPPORT
if (arg->request == USB_FSIJ_GNUK_MEMINFO) if (arg->request == USB_FSIJ_GNUK_MEMINFO)
return usb_lld_ctrl_send (dev, mem_info, sizeof (mem_info)); return usb_lld_ctrl_send (dev, mem_info, sizeof (mem_info));
#else
return -1;
#endif
} }
else /* SETUP_SET */ else /* SETUP_SET */
{ {
uint8_t *addr = (uint8_t *)(0x20000000 + arg->value * 0x100 #ifdef FLASH_UPGRADE_SUPPORT
+ arg->index); uint8_t *addr = sram_address ((arg->value * 0x100) + arg->index);
#endif
if (arg->request == USB_FSIJ_GNUK_DOWNLOAD) if (arg->request == USB_FSIJ_GNUK_DOWNLOAD)
{ {
if (*ccid_state_p != CCID_STATE_EXITED) #ifdef FLASH_UPGRADE_SUPPORT
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return -1; return -1;
if (addr < &_regnual_start || addr + arg->len > __heap_end__) if (addr < &_regnual_start || addr + arg->len > __heap_end__)
@@ -266,16 +292,23 @@ usb_setup (struct usb_dev *dev)
256 - (arg->index + arg->len)); 256 - (arg->index + arg->len));
return usb_lld_ctrl_recv (dev, addr, arg->len); return usb_lld_ctrl_recv (dev, addr, arg->len);
#else
return -1;
#endif
} }
else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0) else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0)
{ {
if (*ccid_state_p != CCID_STATE_EXITED) #ifdef FLASH_UPGRADE_SUPPORT
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return -1; return -1;
if (((uint32_t)addr & 0x03)) if (((uintptr_t)addr & 0x03))
return -1; return -1;
return download_check_crc32 (dev, (uint32_t *)addr); return download_check_crc32 (dev, (uint32_t *)addr);
#else
return -1;
#endif
} }
else if (arg->request == USB_FSIJ_GNUK_CARD_CHANGE && arg->len == 0) else if (arg->request == USB_FSIJ_GNUK_CARD_CHANGE && arg->len == 0)
{ {
@@ -371,10 +404,10 @@ usb_ctrl_write_finish (struct usb_dev *dev)
{ {
if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC) if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC)
{ {
if (*ccid_state_p != CCID_STATE_EXITED) if (ccid_get_ccid_state () != CCID_STATE_EXITED)
return; return;
bDeviceState = UNCONNECTED; bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
usb_lld_prepare_shutdown (); /* No further USB communication */ usb_lld_prepare_shutdown (); /* No further USB communication */
led_blink (LED_GNUK_EXEC); /* Notify the main. */ led_blink (LED_GNUK_EXEC); /* Notify the main. */
} }
@@ -435,8 +468,8 @@ usb_set_configuration (struct usb_dev *dev)
usb_lld_set_configuration (dev, 1); usb_lld_set_configuration (dev, 1);
for (i = 0; i < NUM_INTERFACES; i++) for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 0); gnuk_setup_endpoints_for_interface (dev, i, 0);
bDeviceState = CONFIGURED; bDeviceState = USB_DEVICE_STATE_CONFIGURED;
} }
else if (current_conf != dev->dev_req.value) else if (current_conf != dev->dev_req.value)
{ {
@@ -445,9 +478,8 @@ usb_set_configuration (struct usb_dev *dev)
usb_lld_set_configuration (dev, 0); usb_lld_set_configuration (dev, 0);
for (i = 0; i < NUM_INTERFACES; i++) for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 1); gnuk_setup_endpoints_for_interface (dev, i, 1);
bDeviceState = ADDRESSED; bDeviceState = USB_DEVICE_STATE_ADDRESSED;
ccid_usb_reset (1);
} }
/* Do nothing when current_conf == value */ /* Do nothing when current_conf == value */
@@ -468,8 +500,7 @@ usb_set_interface (struct usb_dev *dev)
return -1; return -1;
else else
{ {
gnuk_setup_endpoints_for_interface (interface, 0); gnuk_setup_endpoints_for_interface (dev, interface, 0);
ccid_usb_reset (0);
return usb_lld_ctrl_ack (dev); return usb_lld_ctrl_ack (dev);
} }
} }

View File

@@ -59,15 +59,20 @@ static const uint8_t hid_report_desc[] = {
#define USB_CCID_DATA_SIZE 64 #define USB_CCID_DATA_SIZE 64
/* USB Standard Device Descriptor */ /* USB Standard Device Descriptor */
static const uint8_t device_desc[] = { #if !defined(GNU_LINUX_EMULATION)
static const
#endif
uint8_t device_desc[] = {
18, /* bLength */ 18, /* bLength */
DEVICE_DESCRIPTOR, /* bDescriptorType */ DEVICE_DESCRIPTOR, /* bDescriptorType */
0x10, 0x01, /* bcdUSB = 1.1 */ 0x00, 0x02, /* bcdUSB = 2.0 */
0x00, /* bDeviceClass: 0 means deferred to interface */ 0x00, /* bDeviceClass: 0 means deferred to interface */
0x00, /* bDeviceSubClass */ 0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */ 0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */ 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 */ 1, /* Index of string descriptor describing manufacturer */
2, /* Index of string descriptor describing product */ 2, /* Index of string descriptor describing product */
3, /* Index of string descriptor describing the device's serial number */ 3, /* Index of string descriptor describing the device's serial number */

View File

@@ -4,11 +4,11 @@ Feature: command GET DATA
Scenario: data object historical bytes Scenario: data object historical bytes
When requesting historical bytes: 5f52 When requesting historical bytes: 5f52
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00 Then data should match: \x00\x31\x84\x73\x80\x01\x80[\x00\x05]\x90\x00
Scenario: data object extended capabilities Scenario: data object extended capabilities
When requesting extended capabilities: c0 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 Scenario: data object algorithm attributes 1
When requesting algorithm attributes 1: c1 When requesting algorithm attributes 1: c1
@@ -24,4 +24,4 @@ Feature: command GET DATA
Scenario: data object AID Scenario: data object AID
When requesting AID: 4f When requesting AID: 4f
Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00 Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]\x00\x00

View File

@@ -4,11 +4,11 @@ Feature: command GET DATA
Scenario: data object historical bytes Scenario: data object historical bytes
When requesting historical bytes: 5f52 When requesting historical bytes: 5f52
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00 Then data should match: \x00\x31\x84\x73\x80\x01\x80[\x00\x05]\x90\x00
Scenario: data object extended capabilities Scenario: data object extended capabilities
When requesting extended capabilities: c0 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 Scenario: data object algorithm attributes 1
When requesting algorithm attributes 1: c1 When requesting algorithm attributes 1: c1
@@ -24,4 +24,4 @@ Feature: command GET DATA
Scenario: data object AID Scenario: data object AID
When requesting AID: 4f When requesting AID: 4f
Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00 Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]\x00\x00

View File

@@ -4,11 +4,11 @@ Feature: command GET DATA
Scenario: data object historical bytes Scenario: data object historical bytes
When requesting historical bytes: 5f52 When requesting historical bytes: 5f52
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00 Then data should match: \x00\x31\x84\x73\x80\x01\x80[\x00\x05]\x90\x00
Scenario: data object extended capabilities Scenario: data object extended capabilities
When requesting extended capabilities: c0 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 Scenario: data object algorithm attributes 1
When requesting algorithm attributes 1: c1 When requesting algorithm attributes 1: c1
@@ -24,4 +24,4 @@ Feature: command GET DATA
Scenario: data object AID Scenario: data object AID
When requesting AID: 4f When requesting AID: 4f
Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00 Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]\x00\x00

View File

@@ -11,19 +11,19 @@ from array import array
@Before @Before
def ini(sc): def ini(sc):
if not ftc.token: if not glc.token:
ftc.token = gnuk.get_gnuk_device() glc.token = gnuk.get_gnuk_device()
ftc.token.cmd_select_openpgp() glc.token.cmd_select_openpgp()
@Given("cmd_verify with (.*) and \"(.*)\"") @Given("cmd_verify with (.*) and \"(.*)\"")
def cmd_verify(who_str,pass_str): def cmd_verify(who_str,pass_str):
who = int(who_str) who = int(who_str)
scc.result = ftc.token.cmd_verify(who, pass_str) scc.result = glc.token.cmd_verify(who, pass_str)
@Given("cmd_change_reference_data with (.*) and \"(.*)\"") @Given("cmd_change_reference_data with (.*) and \"(.*)\"")
def cmd_change_reference_data(who_str,pass_str): def cmd_change_reference_data(who_str,pass_str):
who = int(who_str) who = int(who_str)
scc.result = ftc.token.cmd_change_reference_data(who, pass_str) scc.result = glc.token.cmd_change_reference_data(who, pass_str)
@Given("cmd_put_data with (.*) and (\".*\")") @Given("cmd_put_data with (.*) and (\".*\")")
def cmd_put_data(tag_str,content_str_repr): def cmd_put_data(tag_str,content_str_repr):
@@ -31,12 +31,12 @@ def cmd_put_data(tag_str,content_str_repr):
tag = int(tag_str, 16) tag = int(tag_str, 16)
tagh = tag >> 8 tagh = tag >> 8
tagl = tag & 0xff tagl = tag & 0xff
scc.result = ftc.token.cmd_put_data(tagh, tagl, content_str) scc.result = glc.token.cmd_put_data(tagh, tagl, content_str)
@Given("cmd_reset_retry_counter with (.*) and \"(.*)\"") @Given("cmd_reset_retry_counter with (.*) and \"(.*)\"")
def cmd_reset_retry_counter(how_str, data): def cmd_reset_retry_counter(how_str, data):
how = int(how_str) how = int(how_str)
scc.result = ftc.token.cmd_reset_retry_counter(how, data) scc.result = glc.token.cmd_reset_retry_counter(how, 0x81, data)
@Given("a RSA key pair (.*)") @Given("a RSA key pair (.*)")
def set_rsa_key(keyno_str): def set_rsa_key(keyno_str):
@@ -46,7 +46,7 @@ def set_rsa_key(keyno_str):
def import_key(openpgp_keyno_str): def import_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str) openpgp_keyno = int(openpgp_keyno_str)
t = rsa_keys.build_privkey_template(openpgp_keyno, scc.keyno) t = rsa_keys.build_privkey_template(openpgp_keyno, scc.keyno)
scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t) scc.result = glc.token.cmd_put_data_odd(0x3f, 0xff, t)
@Given("a fingerprint of OPENPGP.(.*) key") @Given("a fingerprint of OPENPGP.(.*) key")
def get_key_fpr(openpgp_keyno_str): def get_key_fpr(openpgp_keyno_str):
@@ -63,7 +63,7 @@ def cmd_put_data_with_result(tag_str):
tag = int(tag_str, 16) tag = int(tag_str, 16)
tagh = tag >> 8 tagh = tag >> 8
tagl = tag & 0xff tagl = tag & 0xff
scc.result = ftc.token.cmd_put_data(tagh, tagl, scc.result) scc.result = glc.token.cmd_put_data(tagh, tagl, scc.result)
@Given("a message (\".*\")") @Given("a message (\".*\")")
def set_msg(content_str_repr): def set_msg(content_str_repr):
@@ -73,7 +73,7 @@ def set_msg(content_str_repr):
@Given("a public key from token for OPENPGP.(.*)") @Given("a public key from token for OPENPGP.(.*)")
def get_public_key(openpgp_keyno_str): def get_public_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str) openpgp_keyno = int(openpgp_keyno_str)
scc.pubkey_info = ftc.token.cmd_get_public_key(openpgp_keyno) scc.pubkey_info = glc.token.cmd_get_public_key(openpgp_keyno)
@Given("verify signature") @Given("verify signature")
def verify_signature(): def verify_signature():
@@ -81,11 +81,11 @@ def verify_signature():
@Given("let a token compute digital signature") @Given("let a token compute digital signature")
def compute_signature(): def compute_signature():
scc.sig = int(hexlify(ftc.token.cmd_pso(0x9e, 0x9a, scc.digestinfo)),16) scc.sig = int(hexlify(glc.token.cmd_pso(0x9e, 0x9a, scc.digestinfo)),16)
@Given("let a token authenticate") @Given("let a token authenticate")
def internal_authenticate(): def internal_authenticate():
scc.sig = int(hexlify(ftc.token.cmd_internal_authenticate(scc.digestinfo)),16) scc.sig = int(hexlify(glc.token.cmd_internal_authenticate(scc.digestinfo)),16)
@Given("compute digital signature on host with RSA key pair (.*)") @Given("compute digital signature on host with RSA key pair (.*)")
def compute_signature_on_host(keyno_str): def compute_signature_on_host(keyno_str):
@@ -107,29 +107,29 @@ def encrypt_on_host_public_key():
@Given("let a token decrypt encrypted data") @Given("let a token decrypt encrypted data")
def decrypt(): def decrypt():
scc.result = ftc.token.cmd_pso_longdata(0x80, 0x86, scc.ciphertext).tostring() scc.result = glc.token.cmd_pso_longdata(0x80, 0x86, scc.ciphertext).tostring()
@Given("USB version string of the token") @Given("USB version string of the token")
def usb_version_string(): def usb_version_string():
scc.result = ftc.token.get_string(3) scc.result = glc.token.get_string(3)
@When("requesting (.+): ([0-9a-fA-F]+)") @When("requesting (.+): ([0-9a-fA-F]+)")
def get_data(name, tag_str): def get_data(name, tag_str):
tag = int(tag_str, 16) tag = int(tag_str, 16)
tagh = tag >> 8 tagh = tag >> 8
tagl = tag & 0xff tagl = tag & 0xff
scc.result = ftc.token.cmd_get_data(tagh, tagl) scc.result = glc.token.cmd_get_data(tagh, tagl)
@When("removing a key OPENPGP.(.*)") @When("removing a key OPENPGP.(.*)")
def remove_key(openpgp_keyno_str): def remove_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str) openpgp_keyno = int(openpgp_keyno_str)
t = rsa_keys.build_privkey_template_for_remove(openpgp_keyno) t = rsa_keys.build_privkey_template_for_remove(openpgp_keyno)
scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t) scc.result = glc.token.cmd_put_data_odd(0x3f, 0xff, t)
@When("generating a key of OPENPGP.(.*)") @When("generating a key of OPENPGP.(.*)")
def generate_key(openpgp_keyno_str): def generate_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str) openpgp_keyno = int(openpgp_keyno_str)
pubkey_info = ftc.token.cmd_genkey(openpgp_keyno) pubkey_info = glc.token.cmd_genkey(openpgp_keyno)
scc.data = rsa_keys.calc_fpr(pubkey_info[0].tostring(), pubkey_info[1].tostring()) scc.data = rsa_keys.calc_fpr(pubkey_info[0].tostring(), pubkey_info[1].tostring())
@When("put the first data to (.*)") @When("put the first data to (.*)")
@@ -137,14 +137,14 @@ def cmd_put_data_first_with_result(tag_str):
tag = int(tag_str, 16) tag = int(tag_str, 16)
tagh = tag >> 8 tagh = tag >> 8
tagl = tag & 0xff tagl = tag & 0xff
scc.result = ftc.token.cmd_put_data(tagh, tagl, scc.data[0]) scc.result = glc.token.cmd_put_data(tagh, tagl, scc.data[0])
@When("put the second data to (.*)") @When("put the second data to (.*)")
def cmd_put_data_second_with_result(tag_str): def cmd_put_data_second_with_result(tag_str):
tag = int(tag_str, 16) tag = int(tag_str, 16)
tagh = tag >> 8 tagh = tag >> 8
tagl = tag & 0xff tagl = tag & 0xff
result = ftc.token.cmd_put_data(tagh, tagl, scc.data[1]) result = glc.token.cmd_put_data(tagh, tagl, scc.data[1])
scc.result = (scc.result and result) scc.result = (scc.result and result)
@Then("you should get: (.*)") @Then("you should get: (.*)")

View File

@@ -60,7 +60,7 @@ def build_privkey_template(openpgp_keyno, keyno):
suffix = b'\x5f\x48' + b'\x82\x01\x04' suffix = b'\x5f\x48' + b'\x82\x01\x04'
t = b'\x4d' + b'\x82\01\16' + exthdr + suffix + e_bytes + p_bytes + q_bytes t = b'\x4d' + b'\x82\x01\x16' + exthdr + suffix + e_bytes + p_bytes + q_bytes
return t return t
def build_privkey_template_for_remove(openpgp_keyno): def build_privkey_template_for_remove(openpgp_keyno):

13
tests/README Normal file
View File

@@ -0,0 +1,13 @@
Here is a test suite for OpenPGP card.
For now, only TPDU card reader is supported for OpenPGP card.
Gnuk Token is supported as well.
You need to install:
$ sudo apt install python3-pytest python3-usb python3-cffi
Please run test by typing:
$ py.test-3 -x

4
tests/card_const.py Normal file
View File

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

337
tests/card_reader.py Normal file
View File

@@ -0,0 +1,337 @@
"""
card_reader.py - a library for smartcard reader
Copyright (C) 2016, 2017, 2019 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
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/>.
"""
import usb.core
from struct import pack
from usb.util import find_descriptor, claim_interface, get_string, \
endpoint_type, endpoint_direction, \
ENDPOINT_TYPE_BULK, ENDPOINT_OUT, ENDPOINT_IN
from binascii import hexlify
# USB class, subclass, protocol
CCID_CLASS = 0x0B
CCID_SUBCLASS = 0x00
CCID_PROTOCOL_0 = 0x00
def ccid_compose(msg_type, seq, slot=0, rsv=0, param=0, data=b""):
return pack('<BiBBBH', msg_type, len(data), slot, seq, rsv, param) + data
IFSC=254
def compute_edc(pcb, info):
edc = pcb
edc ^= len(info)
for i in range(len(info)):
edc ^= info[i]
return edc
def compose_i_block(ns, info, more):
pcb = 0x00
if ns:
pcb |= 0x40
if more:
pcb |= 0x20
edc = compute_edc(pcb, info)
return bytes([0, pcb, len(info)]) + info + bytes([edc])
def compose_r_block(nr, edc_error=0):
pcb = 0x80
if nr:
pcb |= 0x10
if edc_error:
pcb |= 0x01
return bytes([0, pcb, 0, pcb])
def is_r_block_no_error_or_other(blk):
return (((blk[1] & 0xC0) == 0x80 and (blk[1] & 0x2f) == 0x00)) or \
((blk[1] & 0xC0) != 0x80)
def is_s_block_time_ext(blk):
return (blk[1] == 0xC3)
def is_i_block_last(blk):
return ((blk[1] & 0x80) == 0 and (blk[1] & 0x20) == 0)
def is_i_block_more(blk):
return ((blk[1] & 0x80) == 0 and (blk[1] & 0x20) == 0x20)
def is_edc_error(blk):
# to be implemented
return 0
def i_block_content(blk):
return blk[3:-1]
class CardReader(object):
def __init__(self, dev):
"""
__init__(dev) -> None
Initialize the DEV of CCID.
device: usb.core.Device object.
"""
cfg = dev.get_active_configuration()
intf = find_descriptor(cfg, bInterfaceClass=CCID_CLASS,
bInterfaceSubClass=CCID_SUBCLASS,
bInterfaceProtocol=CCID_PROTOCOL_0)
if intf is None:
raise ValueError("Not a CCID device")
claim_interface(dev, intf)
for ep in intf:
if endpoint_type(ep.bmAttributes) == ENDPOINT_TYPE_BULK and \
endpoint_direction(ep.bEndpointAddress) == ENDPOINT_OUT:
self.__bulkout = ep.bEndpointAddress
if endpoint_type(ep.bmAttributes) == ENDPOINT_TYPE_BULK and \
endpoint_direction(ep.bEndpointAddress) == ENDPOINT_IN:
self.__bulkin = ep.bEndpointAddress
assert len(intf.extra_descriptors) == 54
assert intf.extra_descriptors[1] == 33
if (intf.extra_descriptors[42] & 0x02):
# Short APDU level exchange
self.__use_APDU = True
elif (intf.extra_descriptors[42] & 0x04):
# Short and extended APDU level exchange
self.__use_APDU = True
elif (intf.extra_descriptors[42] & 0x01):
# TPDU level exchange
self.__use_APDU = False
else:
raise ValueError("Unknown exchange level")
# Check other bits???
# intf.extra_descriptors[40]
# intf.extra_descriptors[41]
self.__dev = dev
self.__timeout = 10000
self.__seq = 0
def get_string(self, num):
return get_string(self.__dev, num)
def increment_seq(self):
self.__seq = (self.__seq + 1) & 0xff
def reset_device(self):
try:
self.__dev.reset()
except:
pass
def is_tpdu_reader(self):
return not self.__use_APDU
def ccid_get_result(self):
msg = self.__dev.read(self.__bulkin, 1024, self.__timeout)
if len(msg) < 10:
print(msg)
raise ValueError("ccid_get_result")
msg_type = msg[0]
data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24)
slot = msg[5]
seq = msg[6]
status = msg[7]
error = msg[8]
chain = msg[9]
data = msg[10:]
# XXX: check msg_type, data_len, slot, seq, error
return (status, chain, data.tobytes())
def ccid_get_status(self):
msg = ccid_compose(0x65, self.__seq)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data = self.ccid_get_result()
# XXX: check chain, data
return status
def ccid_power_on(self):
msg = ccid_compose(0x62, self.__seq, rsv=2) # Vcc=3.3V
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data = self.ccid_get_result()
# XXX: check status, chain
self.atr = data
#
if self.__use_APDU == False:
# TPDU reader configuration
self.ns = 0
self.nr = 0
# 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
msg = ccid_compose(0x61, self.__seq, rsv=0x1, data=param)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, ret_param = self.ccid_get_result()
# Send an S-block of changing IFSD=254
sblk = b"\x00\xC1\x01\xFE\x3E"
status, chain, ret_sblk = self.ccid_send_data_block(sblk)
return self.atr
def ccid_power_off(self):
msg = ccid_compose(0x63, self.__seq)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data = self.ccid_get_result()
# XXX: check chain, data
return status
def ccid_send_data_block(self, data):
msg = ccid_compose(0x6f, self.__seq, data=data)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
return self.ccid_get_result()
def ccid_send_cmd(self, data):
status, chain, data_rcv = self.ccid_send_data_block(data)
if chain == 0:
while status == 0x80:
status, chain, data_rcv = self.ccid_get_result()
return data_rcv
elif chain == 1:
d = data_rcv
while True:
msg = ccid_compose(0x6f, self.__seq, param=0x10)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
status, chain, data_rcv = self.ccid_get_result()
# XXX: check status
d += data_rcv
if chain == 2:
break
elif chain == 3:
continue
else:
raise ValueError("ccid_send_cmd chain")
return d
else:
raise ValueError("ccid_send_cmd")
def send_tpdu(self, info=None, more=0, response_time_ext=0,
edc_error=0, no_error=0):
rsv = 0
if info:
data = compose_i_block(self.ns, info, more)
elif response_time_ext:
# compose S-block response
pcb = 0xe3
bwi_byte = bytes([response_time_ext])
edc = compute_edc(pcb, bwi_byte)
data = bytes([0, pcb, 1]) + bwi_byte + bytes([edc])
rsv = response_time_ext
elif edc_error:
data = compose_r_block(self.nr, edc_error=1)
elif no_error:
data = compose_r_block(self.nr)
msg = ccid_compose(0x6f, self.__seq, rsv=rsv, data=data)
self.__dev.write(self.__bulkout, msg, self.__timeout)
self.increment_seq()
def recv_tpdu(self):
status, chain, data = self.ccid_get_result()
return data
def send_cmd(self, cmd):
# Simple APDU case
if self.__use_APDU:
return self.ccid_send_cmd(cmd)
# TPDU case
while len(cmd) > 254:
blk = cmd[0:254]
cmd = cmd[254:]
while True:
self.send_tpdu(info=blk,more=1)
rblk = self.recv_tpdu()
if is_r_block_no_error_or_other(rblk):
break
self.ns = self.ns ^ 1
while True:
self.send_tpdu(info=cmd)
blk = self.recv_tpdu()
if is_r_block_no_error_or_other(blk):
break
self.ns = self.ns ^ 1
res = b""
while True:
if is_s_block_time_ext(blk):
self.send_tpdu(response_time_ext=blk[3])
elif is_i_block_last(blk):
self.nr = self.nr ^ 1
if is_edc_error(blk):
self.send_tpdu(edc_error=1)
else:
res += i_block_content(blk)
break
elif is_i_block_more(blk):
self.nr = self.nr ^ 1
if is_edc_error(blk):
self.send_tpdu(edc_error=1)
else:
res += i_block_content(blk)
self.send_tpdu(no_error=1)
blk = self.recv_tpdu()
return res
class find_class(object):
def __init__(self, usb_class):
self.__class = usb_class
def __call__(self, device):
if device.bDeviceClass == self.__class:
return True
for cfg in device:
intf = find_descriptor(cfg, bInterfaceClass=self.__class)
if intf is not None:
return True
return False
def get_ccid_device():
ccid = None
dev_list = usb.core.find(find_all=True, custom_match=find_class(CCID_CLASS))
for dev in dev_list:
try:
ccid = CardReader(dev)
print("CCID device: Bus %03d Device %03d" % (dev.bus, dev.address))
break
except:
pass
if not ccid:
raise ValueError("No CCID device present")
status = ccid.ccid_get_status()
if status == 0:
# It's ON already
atr = ccid.ccid_power_on()
elif status == 1:
atr = ccid.ccid_power_on()
else:
raise ValueError("Unknown CCID status", status)
return ccid

View File

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

View File

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

84
tests/card_test_keygen.py Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

19
tests/conftest.py Normal file
View File

@@ -0,0 +1,19 @@
import pytest
from card_reader import get_ccid_device
from openpgp_card import OpenPGP_Card
def pytest_addoption(parser):
parser.addoption("--reader", dest="reader", type=str, action="store",
default="gnuk", help="specify reader: gnuk or gemalto")
@pytest.fixture(scope="session")
def card():
print()
print("Test start!")
reader = get_ccid_device()
print("Reader:", reader.get_string(1), reader.get_string(2))
card = OpenPGP_Card(reader)
card.cmd_select_openpgp()
yield card
del card
reader.ccid_power_off()

View File

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

1
tests/kdf_calc.py Symbolic link
View File

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

465
tests/openpgp_card.py Normal file
View File

@@ -0,0 +1,465 @@
"""
openpgp_card.py - a library for OpenPGP card
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018, 2019
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 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)
if data_len == 0:
if not le:
return pack('>BBBB', cls, ins, p1, p2)
else:
return pack('>BBBBB', cls, ins, p1, p2, le)
else:
if not le:
if data_len <= 255:
return pack('>BBBBB', cls, ins, p1, p2, data_len) + data
else:
return pack('>BBBBBH', cls, ins, p1, p2, 0, data_len) \
+ data
else:
if data_len <= 255 and le < 256:
return pack('>BBBBB', cls, ins, p1, p2, data_len) \
+ data + pack('>B', le)
else:
return pack('>BBBBBH', cls, ins, p1, p2, 0, data_len) \
+ data + pack('>H', le)
class OpenPGP_Card(object):
def __init__(self, reader):
"""
__init__(reader) -> None
Initialize a OpenPGP card with a CardReader.
reader: CardReader object.
"""
self.__reader = reader
self.__kdf_iters = None
self.__kdf_salt_user = None
self.__kdf_salt_reset = None
self.__kdf_salt_admin = None
self.is_gnuk = (reader.get_string(2) == "Gnuk Token")
def configure_with_kdf(self):
kdf_data = self.cmd_get_data(0x00, 0xf9)
if kdf_data != b"":
algo, subalgo, iters, salt_user, salt_reset, salt_admin, hash_user, hash_admin = parse_kdf_data(kdf_data)
self.__kdf_iters = iters
self.__kdf_salt_user = salt_user
self.__kdf_salt_reset = salt_reset
self.__kdf_salt_admin = salt_admin
else:
self.__kdf_iters = None
self.__kdf_salt_user = None
self.__kdf_salt_reset = None
self.__kdf_salt_admin = None
# Higher layer VERIFY possibly using KDF Data Object
def verify(self, who, passwd):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if who == 3 and self.__kdf_salt_admin:
salt = self.__kdf_salt_admin
pw_hash = kdf_calc(passwd, salt, self.__kdf_iters)
return self.cmd_verify(who, pw_hash)
else:
return self.cmd_verify(who, passwd)
# Higher layer CHANGE_PASSWD possibly using KDF Data Object
def change_passwd(self, who, passwd_old, passwd_new):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if who == 3 and self.__kdf_salt_admin:
salt = self.__kdf_salt_admin
hash_old = kdf_calc(passwd_old, salt, self.__kdf_iters)
if passwd_new:
hash_new = kdf_calc(passwd_new, salt, self.__kdf_iters)
else:
hash_new = b""
return self.cmd_change_reference_data(who, hash_old + hash_new)
else:
if not passwd_new:
passwd_new = b""
return self.cmd_change_reference_data(who, passwd_old + passwd_new)
# Higher layer SETUP_RESET_CODE possibly using KDF Data Object
def setup_reset_code(self, resetcode):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if self.__kdf_salt_reset:
salt = self.__kdf_salt_user
reset_hash = kdf_calc(resetcode, salt, self.__kdf_iters)
return self.cmd_put_data(0x00, 0xd3, reset_hash)
else:
return self.cmd_put_data(0x00, 0xd3, resetcode)
# Higher layer reset passwd possibly using KDF Data Object
def reset_passwd_by_resetcode(self, resetcode, pw1):
if self.__kdf_iters:
salt = self.__kdf_salt_user
if self.__kdf_salt_reset:
salt = self.__kdf_salt_user
reset_hash = kdf_calc(resetcode, salt, self.__kdf_iters)
pw1_hash = kdf_calc(pw1, self.__kdf_salt_user, self.__kdf_iters)
return self.cmd_reset_retry_counter(0, 0x81, reset_hash + pw1_hash)
else:
return self.cmd_reset_retry_counter(0, 0x81, resetcode + pw1)
# Higher layer reset passwd possibly using KDF Data Object
def reset_passwd_by_admin(self, pw1):
if self.__kdf_iters:
pw1_hash = kdf_calc(pw1, self.__kdf_salt_user, self.__kdf_iters)
return self.cmd_reset_retry_counter(2, 0x81, pw1_hash)
else:
return self.cmd_reset_retry_counter(2, 0x81, pw1)
def cmd_get_response(self, expected_len):
result = b""
while True:
cmd_data = iso7816_compose(0xc0, 0x00, 0x00, b'') + pack('>B', expected_len)
response = self.__reader.send_cmd(cmd_data)
result += response[:-2]
sw = response[-2:]
if sw[0] == 0x90 and sw[1] == 0x00:
return result
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
else:
expected_len = sw[1]
def cmd_verify(self, who, passwd):
cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_read_binary(self, fileid):
cmd_data = iso7816_compose(0xb0, 0x80+fileid, 0x00, b'')
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_write_binary(self, fileid, data, is_update):
count = 0
data_len = len(data)
if is_update:
ins = 0xd6
else:
ins = 0xd0
while count*256 < data_len:
if count == 0:
if len(data) < 128:
cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128], 0x10)
cmd_data1 = iso7816_compose(ins, 0x80+fileid, 0x00, data[128:256])
else:
if len(data[256*count:256*count+128]) < 128:
cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128], 0x10)
cmd_data1 = iso7816_compose(ins, count, 0x00, data[256*count+128:256*(count+1)])
sw = self.__reader.send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError("cmd_write_binary 0")
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("cmd_write_binary 0", "%02x%02x" % (sw[0], sw[1]))
if cmd_data1:
sw = self.__reader.send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError("cmd_write_binary 1", sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("cmd_write_binary 1", "%02x%02x" % (sw[0], sw[1]))
count += 1
def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x00, b"\xD2\x76\x00\x01\x24\x01")
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
self.cmd_get_response(sw[1])
return True
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_get_data(self, tagh, tagl):
cmd_data = iso7816_compose(0xca, tagh, tagl, b"", le=254)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) < 2:
raise ValueError(sw)
if sw[0] == 0x61:
return self.cmd_get_response(sw[1])
elif sw[-2] == 0x90 and sw[-1] == 0x00:
return sw[0:-2]
if sw[0] == 0x6a and sw[1] == 0x88:
return None
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def cmd_change_reference_data(self, who, data):
cmd_data = iso7816_compose(0x24, 0x00, 0x80+who, data)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_put_data(self, tagh, tagl, content):
cmd_data = iso7816_compose(0xda, tagh, tagl, content)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_put_data_odd(self, tagh, tagl, content):
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0xdb, tagh, tagl, content)
sw = self.__reader.send_cmd(cmd_data)
else:
cmd_data0 = iso7816_compose(0xdb, tagh, tagl, content[:128], 0x10)
cmd_data1 = iso7816_compose(0xdb, tagh, tagl, content[128:])
sw = self.__reader.send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
sw = self.__reader.send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_reset_retry_counter(self, how, who, data):
cmd_data = iso7816_compose(0x2c, how, who, data)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_pso(self, p1, p2, data):
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x2a, p1, p2, data, le=256)
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
return self.cmd_get_response(sw[1])
elif sw[0] == 0x90 and sw[1] == 0x00:
return r
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
else:
if len(data) > 128:
cmd_data0 = iso7816_compose(0x2a, p1, p2, data[:128], 0x10)
cmd_data1 = iso7816_compose(0x2a, p1, p2, data[128:])
sw = self.__reader.send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
sw = self.__reader.send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError(sw)
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
else:
cmd_data = iso7816_compose(0x2a, p1, p2, data)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if sw[0] == 0x90 and sw[1] == 0x00:
return b""
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_internal_authenticate(self, data):
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x88, 0, 0, data, le=256)
else:
cmd_data = iso7816_compose(0x88, 0, 0, data)
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
return self.cmd_get_response(sw[1])
elif sw[0] == 0x90 and sw[1] == 0x00:
return r
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def cmd_genkey(self, keyno):
if keyno == 1:
data = b'\xb6\x00'
elif keyno == 2:
data = b'\xb8\x00'
else:
data = b'\xa4\x00'
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x47, 0x80, 0, data, le=512)
else:
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) < 2:
raise ValueError(sw)
if sw[-2] == 0x61:
pk = self.cmd_get_response(sw[1])
elif sw[-2] == 0x90 and sw[-1] == 0x00:
pk = sw
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return (pk[9:9+256], pk[9+256+2:-2])
def cmd_get_public_key(self, keyno):
if keyno == 1:
data = b'\xb6\x00'
elif keyno == 2:
data = b'\xb8\x00'
else:
data = b'\xa4\x00'
if self.__reader.is_tpdu_reader():
cmd_data = iso7816_compose(0x47, 0x81, 0, data, le=512)
else:
cmd_data = iso7816_compose(0x47, 0x81, 0, data)
r = self.__reader.send_cmd(cmd_data)
if len(r) < 2:
raise ValueError(r)
sw = r[-2:]
r = r[0:-2]
if sw[0] == 0x61:
pk = self.cmd_get_response(sw[1])
elif sw[0] == 0x90 and sw[1] == 0x00:
pk = r
else:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return pk
def cmd_put_data_remove(self, tagh, tagl):
cmd_data = iso7816_compose(0xda, tagh, tagl, b"")
sw = self.__reader.send_cmd(cmd_data)
if sw[0] != 0x90 and sw[1] != 0x00:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def cmd_put_data_key_import_remove(self, keyno):
if keyno == 1:
keyspec = b"\xb6\x00" # SIG
elif keyno == 2:
keyspec = b"\xb8\x00" # DEC
else:
keyspec = b"\xa4\x00" # AUT
cmd_data = iso7816_compose(0xdb, 0x3f, 0xff, b"\x4d\x02" + keyspec)
sw = self.__reader.send_cmd(cmd_data)
if sw[0] != 0x90 and sw[1] != 0x00:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
def cmd_get_challenge(self):
cmd_data = iso7816_compose(0x84, 0x00, 0x00, '')
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_external_authenticate(self, keyno, signed):
cmd_data = iso7816_compose(0x82, 0x00, keyno, signed[0:128], cls=0x10)
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
cmd_data = iso7816_compose(0x82, 0x00, keyno, signed[128:])
sw = self.__reader.send_cmd(cmd_data)
if len(sw) != 2:
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 )

4
tests/rsa-aut.key Normal file
View File

@@ -0,0 +1,4 @@
9cf7192b51a574d1ad3ccb08ba09b87f228573893eee355529ff243e90fd4b86f79a82097cc7922c0485bed1616b1656a9b0b19ef78ea8ec34c384019adc5d5bf4db2d2a0a2d9cf14277bdcb7056f48b81214e3f7f7742231e29673966f9b1106862112cc798dba8d4a138bb5abfc6d4c12d53a5d39b2f783da916da20852ee139bbafda61d429caf2a4f30847ce7e7ae32ab4061e27dd9e4d00d60910249db8d8559dd85f7ca59659ef400c8f6318700f4e97f0c6f4165de80641490433c88da8682befe68eb311f54af2b07d97ac74edb5399cf054764211694fbb8d1d333f3269f235abe025067f811ff83a2224826219b309ea3e6c968f42b3e52f245dc9
010001
b5ab7b159220b18e363258f61ebde08bae83d6ce2dbfe4adc143628c527887acde9de09bf9b49f438019004d71855f30c2d69b6c29bb9882ab641b3387409fe9199464a7faa4b5230c56d9e17cd9ed074bc00180ebed62bae3af28e6ff2ac2654ad968834c5d5c88f8d9d3cc5e167b10453b049d4e454a5761fb0ac717185907
dd2fffa9814296156a6926cd17b65564187e424dcadce9b032246ad7e46448bb0f9e0ff3c64f987424b1a40bc694e2e9ac4fb1930d163582d7acf20653a1c44b97846c1c5fd8a7b19bb225fb39c30e25410483deaf8c2538d222b748c4d8103b11cec04f666a5c0dbcbf5d5f625f158f65746c3fafe6418145f7cffa5fadeeaf

4
tests/rsa-dec.key Normal file
View File

@@ -0,0 +1,4 @@
d392714c29738aac6372f2c8654a08c25a1299fed7004bd512cd2452b503ebad6301130816ac525ba528dc155be6347a5c70407fb4fbdaed751dfc0a7cd5e3910272ff236c4ed1ce5de6620b191a172e5b247347b8cab73a43d79221708755c959a2f83f486439da30917384554331532aabc8326db48866f8c91198834a86ab94679f6175db737bdf399e3f0b737dcb1f4208279d3e1cc694e78686785e4f363a377dec912b7c2f757b1422d866fb9fa85c96b83adfd6a223989a9a02988bdee81ad17eff6385e7b38cec8611fdf367ba4ac8e90d5f48ac7715c5f47aea06a4a37cdaa3029ce59d29bc66853bf6758ef4a7da5a5953f5e557a5a22f67c368c3
010001
dae085952c5beee38f25f09bc37a4ca2434c31f78055469d0d5f0bf3337e3a70ba6c91734f195b742e211a5fe283befdf66820008e6ef2c8ca54a91922838fce07d9e33a331ce20dac36803e777d5ee2195ed28d6a4045e28623a6a60b0661e45f7c4f84ae2b1dfad0cf1ec30605158323382a819e730c09a33fad704dd67501
f774be43ea198aa2f089274e4fffd7d0092ee7b35a1d2f854cdb166f698caab72fdeb099e690e78438b2e043e452d4d2f19d7f44ba6b286642f0ce5204966ff98ecd9e3b448877324631365dc860797429b9414a21a7e166d504cace156588b9a145657eeb1afb43b8ff65d8d6d93cea2ba4ef8aab047885c4de64ffef0b49c3

4
tests/rsa-sig.key Normal file
View File

@@ -0,0 +1,4 @@
c6c877dfd3b441f8fb1b8dc504093a51c2efe4883fe0a6379205acc6e673709905e4d767ddf46143c535cc6d7f10b616f520d8346320ef69ff4a2c4f4a148edc65f7ad24ed7d4fe23bb862a0ae71f4f7904abac0397abf3213df91326b1a25554b3b18cf54584d8bf220169fc92b2aa511e8313983e72b4c9110b3a1aea087aebef95873865608e8faea9ef10e7f7f3a66ca8def2d499c3149c127491e0e4339fd6abe10bfc6c13e43d522004f1485767328eabe35d6ffa8df4c15f0fbcd4eb1c07cc6d85e275139ac69e2962273ae987236926dd6c1144fce3e7ae567fa58ea60620dfafc52f95299fea601739fce27ee71eea978d0074f21e7086f60ba8331
010001
cc365b5702714bf203e8c49b0b8afa8dad586e929cf5edca38ad07fa45efd5c2d89022d29f40283a57e50ca24c5f28c8e911a74faaf796f112e7e48195956f9a4df7668a5342523b27179cec958f363211ee11d0ec0e0e1b92ca007a61e8c9ac14e00229b9a7624850199e6667afa1a44db8f3c5de0a8eef0e6de050ac0ac633
f931a3c12f0e3a5276f712b7706590ba02e14a97ff9b8ce3152af0fc4d9cdc690ea9bc4c82cb16c7d23136cbdab58fbec69880a88bca85c4214df01045082cbe9f4192e3e39c79896533c37dad9eb9e73c2643b9c0a704a4f93d81573537963d6b6e5140a24c702d9f26e06a2095de906daa8824172a6b39f563b7153907050b

148
tests/rsa_keys.py Normal file
View File

@@ -0,0 +1,148 @@
from binascii import hexlify, unhexlify
from time import time
from struct import pack
from hashlib import sha1, sha256
import string
from os import urandom
def read_key_from_file(file):
f = open(file)
n_str = f.readline()[:-1]
e_str = f.readline()[:-1]
p_str = f.readline()[:-1]
q_str = f.readline()[:-1]
f.close()
e = int(e_str, 16)
p = int(p_str, 16)
q = int(q_str, 16)
n = int(n_str, 16)
if n != p * q:
raise ValueError("wrong key", p, q, n)
return (unhexlify(n_str), unhexlify(e_str), unhexlify(p_str), unhexlify(q_str), e, p, q, n)
def calc_fpr(n,e):
timestamp = int(time())
timestamp_data = pack('>I', timestamp)
m_len = 6 + 2 + 256 + 2 + 4
m = b'\x99' + pack('>H', m_len) + b'\x04' + timestamp_data + b'\x01' + \
pack('>H', 2048) + n + pack('>H', 17) + e
fpr = sha1(m).digest()
return (fpr, timestamp_data)
key = [ None, None, None ]
fpr = [ None, None, None ]
timestamp = [ None, None, None ]
key[0] = read_key_from_file('rsa-sig.key')
key[1] = read_key_from_file('rsa-dec.key')
key[2] = read_key_from_file('rsa-aut.key')
(fpr[0], timestamp[0]) = calc_fpr(key[0][0], key[0][1])
(fpr[1], timestamp[1]) = calc_fpr(key[1][0], key[1][1])
(fpr[2], timestamp[2]) = calc_fpr(key[2][0], key[2][1])
def build_privkey_template(openpgp_keyno, keyno):
n_bytes = key[keyno][0]
e_bytes = b'\x00' + key[keyno][1]
p_bytes = key[keyno][2]
q_bytes = key[keyno][3]
if openpgp_keyno == 1:
keyspec = b'\xb6'
elif openpgp_keyno == 2:
keyspec = b'\xb8'
else:
keyspec = b'\xa4'
key_template = b'\x91\x04'+ b'\x92\x81\x80' + b'\x93\x81\x80'
exthdr = keyspec + b'\x00' + b'\x7f\x48' + b'\x08' + key_template
suffix = b'\x5f\x48' + b'\x82\x01\x04'
t = b'\x4d' + b'\x82\x01\x16' + exthdr + suffix + e_bytes + p_bytes + q_bytes
return t
def build_privkey_template_for_remove(openpgp_keyno):
if openpgp_keyno == 1:
keyspec = b'\xb6'
elif openpgp_keyno == 2:
keyspec = b'\xb8'
else:
keyspec = b'\xa4'
return b'\x4d\02' + keyspec + b'\0x00'
def compute_digestinfo(msg):
digest = sha256(msg).digest()
prefix = b'\x30\31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
return prefix + digest
# egcd and modinv are from wikibooks
# https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
def pkcs1_pad_for_sign(digestinfo):
byte_repr = b'\x00' + b'\x01' + bytes.ljust(b'', 256 - 19 - 32 - 3, b'\xff') \
+ b'\x00' + digestinfo
return int(hexlify(byte_repr), 16)
def pkcs1_pad_for_crypt(msg):
padlen = 256 - 3 - len(msg)
byte_repr = b'\x00' + b'\x02' \
+ bytes.replace(urandom(padlen), b'\x00', b'\x01') + b'\x00' + msg
return int(hexlify(byte_repr), 16)
def compute_signature(keyno, digestinfo):
e = key[keyno][4]
p = key[keyno][5]
q = key[keyno][6]
n = key[keyno][7]
p1 = p - 1
q1 = q - 1
h = p1 * q1
d = modinv(e, h)
dp = d % p1
dq = d % q1
qp = modinv(q, p)
input = pkcs1_pad_for_sign(digestinfo)
t1 = pow(input, dp, p)
t2 = pow(input, dq, q)
t = ((t1 - t2) * qp) % p
sig = t2 + t * q
return sig
def integer_to_bytes_256(i):
return i.to_bytes(256, byteorder='big')
def encrypt(keyno, plaintext):
e = key[keyno][4]
n = key[keyno][7]
m = pkcs1_pad_for_crypt(plaintext)
return b'\x00' + integer_to_bytes_256(pow(m, e, n))
def encrypt_with_pubkey(pubkey_info, plaintext):
n = int(hexlify(pubkey_info[0]), 16)
e = int(hexlify(pubkey_info[1]), 16)
m = pkcs1_pad_for_crypt(plaintext)
return b'\x00' + integer_to_bytes_256(pow(m, e, n))
def verify_signature(pubkey_info, digestinfo, sig):
n = int(hexlify(pubkey_info[0]), 16)
e = int(hexlify(pubkey_info[1]), 16)
di_pkcs1 = pow(sig,e,n)
m = pkcs1_pad_for_sign(digestinfo)
return di_pkcs1 == m

View File

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

View File

@@ -0,0 +1,187 @@
"""
test_empty_card.py - test empty card
Copyright (C) 2016, 2018 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from 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)
def test_login(card):
login = get_data_object(card, 0x5e)
assert check_null(login)
"""
def test_name(card):
name = get_data_object(card, 0x5b)
assert check_null(name)
def test_lang(card):
lang = get_data_object(card, 0x5f2d)
assert check_null(lang)
def test_sex(card):
sex = get_data_object(card, 0x5f35)
assert check_null(sex)
"""
def test_name_lang_sex(card):
name = b""
lang = b""
lang_de = b"de"
sex = b"9"
expected = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
+ b'\x5f\x35' + pack('B', len(sex)) + sex
expected_de = b'\x5b' + pack('B', len(name)) + name \
+ b'\x5f\x2d' + pack('B', len(lang_de)) + lang_de \
+ b'\x5f\x35' + pack('B', len(sex)) + sex
name_lang_sex = get_data_object(card, 0x65)
assert name_lang_sex == b'' or name_lang_sex == expected or name_lang_sex == expected_de
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_url(card):
url = get_data_object(card, 0x5f50)
assert check_null(url)
def test_ds_counter(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'\x00...\x03[\x00\x03]\x03', s, DOTALL)
def test_fingerprint_0(card):
fprlist = get_data_object(card, 0xC5)
assert fprlist == None or fprlist == EMPTY_60
def test_fingerprint_1(card):
fpr = get_data_object(card, 0xC7)
assert check_null(fpr)
def test_fingerprint_2(card):
fpr = get_data_object(card, 0xC8)
assert check_null(fpr)
def test_fingerprint_3(card):
fpr = get_data_object(card, 0xC9)
assert check_null(fpr)
def test_ca_fingerprint_0(card):
cafprlist = get_data_object(card, 0xC6)
assert cafprlist == None or cafprlist == EMPTY_60
def test_ca_fingerprint_1(card):
cafp = get_data_object(card, 0xCA)
assert check_null(cafp)
def test_ca_fingerprint_2(card):
cafp = get_data_object(card, 0xCB)
assert check_null(cafp)
def test_ca_fingerprint_3(card):
cafp = get_data_object(card, 0xCC)
assert check_null(cafp)
def test_timestamp_0(card):
t = get_data_object(card, 0xCD)
assert t == None or t == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
def test_timestamp_1(card):
t = get_data_object(card, 0xCE)
assert check_null(t)
def test_timestamp_2(card):
t = get_data_object(card, 0xCF)
assert check_null(t)
def test_timestamp_3(card):
t = get_data_object(card, 0xD0)
assert check_null(t)
def test_verify_pw1_1(card):
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
assert v
def test_verify_pw1_2(card):
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
assert v
def test_verify_pw3(card):
v = card.cmd_verify(3, FACTORY_PASSPHRASE_PW3)
assert v
def test_historical_bytes(card):
h = get_data_object(card, 0x5f52)
assert h == b'\x001\xc5s\xc0\x01@\x05\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x00\x90\x00' or \
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00' or \
h == b'\x00\x31\xf5\x73\xc0\x01\x60\x05\x90\x00'
def test_extended_capabilities(card):
a = get_data_object(card, 0xc0)
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)
assert a == None or a == b'\x01\x08\x00\x00\x20\x00'
def test_algorithm_attributes_2(card):
a = get_data_object(card, 0xc2)
assert a == None or a == b'\x01\x08\x00\x00\x20\x00'
def test_algorithm_attributes_3(card):
a = get_data_object(card, 0xc3)
assert a == None or a == b'\x01\x08\x00\x00\x20\x00'
def test_public_key_1(card):
with pytest.raises(Exception) as excinfo:
pk = card.cmd_get_public_key(1)
assert excinfo.value.args[0] == "6a88"
def test_public_key_2(card):
with pytest.raises(Exception) as excinfo:
pk = card.cmd_get_public_key(2)
assert excinfo.value.args[0] == "6a88"
def test_public_key_3(card):
with pytest.raises(Exception) as excinfo:
pk = card.cmd_get_public_key(3)
assert excinfo.value.args[0] == "6a88"
def test_AID(card):
a = get_data_object(card, 0x4f)
print()
print("OpenPGP card version: %d.%d" % (a[6], a[7]))
print("Card Manufacturer: ", hexlify(a[8:10]).decode("UTF-8"))
print("Card serial: ", hexlify(a[10:14]).decode("UTF-8"))
assert match(b'\xd2\x76\x00\x01\\$\x01........\x00\x00', a, DOTALL)

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
"""
test_005_personalize_admin_less.py - test admin-less mode
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from skip_gnuk_only_tests import *
from card_test_personalize_admin_less import *
from card_test_personalize_reset import *
from card_test_remove_keys import *
from card_test_reset_pw3 import *

24
tests/test_009_keygen.py Normal file
View File

@@ -0,0 +1,24 @@
"""
test_005_keygen.py - test key generation
Copyright (C) 2018, 2019 g10 Code GmbH
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gnuk is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from card_test_keygen import *
from card_test_remove_keys import *

View File

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

View File

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

View File

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

View File

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

7
tests/util.py Normal file
View File

@@ -0,0 +1,7 @@
def get_data_object(card, tag):
tagh = tag >> 8
tagl = tag & 0xff
return card.cmd_get_data(tagh, tagl)
def check_null(data_object):
return data_object == None or len(data_object) == 0

View File

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

Some files were not shown because too many files have changed in this diff Show More