Compare commits
147 Commits
release/1.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
| 2519f799fd | |||
| 32f563a28d | |||
| 7b471948b4 | |||
| d2363c8ad8 | |||
| 9306ad5043 | |||
| 54d031bc27 | |||
| 6909e0359c | |||
| 5acd8a23d9 | |||
| d5a539986e | |||
| 8a19a2cb66 | |||
| 5e4a264ac0 | |||
| a9079e8b5c | |||
| 057920600f | |||
| 7d1b5e4b71 | |||
| fe66b67317 | |||
| 14f0acd749 | |||
| 9ccbd5804a | |||
| b4b82e1557 | |||
| 357a4b3510 | |||
| 1fdb74eb10 | |||
| 977a09f69f | |||
| cd271fbeb5 | |||
| 7e17548610 | |||
| fd7a7c7dfa | |||
| 8de235b26f | |||
| 53cbb62738 | |||
| 511f6de8b1 | |||
| 0132723c7a | |||
| a37f7aca5c | |||
| 531be827dd | |||
| d6c040400a | |||
| b8ada80163 | |||
| 1d63372017 | |||
| 8dfbf63452 | |||
| b9f6c3be7a | |||
|
|
9d3c08bd2b | ||
|
|
a909502388 | ||
|
|
286b620648 | ||
|
|
cce65c6d34 | ||
|
|
57fdadf283 | ||
|
|
870de72ee2 | ||
|
|
fa667b04f7 | ||
|
|
2a72f3df08 | ||
|
|
db2527459f | ||
|
|
1ca3bbdaae | ||
|
|
98119dc991 | ||
|
|
03cca1e451 | ||
|
|
3f65bf73e8 | ||
|
|
07be37f45e | ||
|
|
dcef6e0ffa | ||
|
|
d31687ebd6 | ||
|
|
92443f8f07 | ||
|
|
4af98308e0 | ||
|
|
baec3a1c1e | ||
|
|
4f1325794d | ||
|
|
0acf6485ae | ||
|
|
4d15700580 | ||
|
|
8822fcae77 | ||
|
|
20a2f99691 | ||
|
|
acfccb729d | ||
|
|
5283506755 | ||
|
|
c688df7c2c | ||
|
|
594896ac57 | ||
|
|
dfe046e08d | ||
|
|
c66b01e74b | ||
|
|
21a46306ae | ||
|
|
e5158572ee | ||
|
|
2142d0aa35 | ||
|
|
dd47cf4312 | ||
|
|
ffbb754fc0 | ||
|
|
d85750d791 | ||
|
|
d20e9e9b1e | ||
|
|
bf30144144 | ||
|
|
934daf3585 | ||
|
|
22420ed1f4 | ||
|
|
e97e3b1810 | ||
|
|
49f2544918 | ||
|
|
d156fc6261 | ||
|
|
81d6945081 | ||
|
|
c3e9db14e8 | ||
|
|
9180c35420 | ||
|
|
cc0d59cfe6 | ||
|
|
9c1368fdd0 | ||
|
|
2dd5a76002 | ||
|
|
f68ff0bddc | ||
|
|
add3299306 | ||
|
|
e28ec2c4c4 | ||
|
|
1ba05a0f0f | ||
|
|
2d50795d0a | ||
|
|
fd493562c3 | ||
|
|
16c6af215a | ||
|
|
177ef67edf | ||
|
|
126283b1ac | ||
|
|
076d727061 | ||
|
|
41fa424450 | ||
|
|
940332c47f | ||
|
|
aedf8267ec | ||
|
|
e9d9de3ae2 | ||
|
|
fc109fd8af | ||
|
|
3d06051a32 | ||
|
|
b7368e41e9 | ||
|
|
e760d5b780 | ||
|
|
b57c33c204 | ||
|
|
ca3312eb25 | ||
|
|
6a1f50abda | ||
|
|
66f39c57cd | ||
|
|
4b5f93624e | ||
|
|
0ef687ea4c | ||
|
|
786b4adc42 | ||
|
|
385261c9a0 | ||
|
|
65689199e7 | ||
|
|
8d15086d06 | ||
|
|
c17fd5401b | ||
|
|
56cd4ae7b5 | ||
|
|
fc36773c6a | ||
|
|
7249775c17 | ||
|
|
980cff0a2f | ||
|
|
8f44f5d3c6 | ||
|
|
37a84ed218 | ||
|
|
6c72147248 | ||
|
|
3d37003d8c | ||
|
|
becf8fabc5 | ||
|
|
17492287f3 | ||
|
|
c800dee95e | ||
|
|
2c390dc763 | ||
|
|
5aee75fd4b | ||
|
|
69e8c0f334 | ||
|
|
317cc2036d | ||
|
|
312d15c3fa | ||
|
|
d356f1b1e0 | ||
|
|
9cb6591491 | ||
|
|
ebec8ee156 | ||
|
|
f810fb83d3 | ||
|
|
12079974fd | ||
|
|
ca79f5421f | ||
|
|
c438367d67 | ||
|
|
4c6511231c | ||
|
|
ba750d153d | ||
|
|
72647f01d0 | ||
|
|
c6e32a36fb | ||
|
|
c3a0eb1439 | ||
|
|
030a9c576d | ||
|
|
8a5e0eb783 | ||
|
|
bce53546e7 | ||
|
|
b2b19e1ad4 | ||
|
|
58fa773bb7 | ||
|
|
ea88c3da66 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,7 @@ src/.dep
|
||||
src/config.mk
|
||||
src/config.h
|
||||
src/gnuk.ld
|
||||
src/stdaln-sys.ld
|
||||
src/board.h
|
||||
src/build/*
|
||||
src/*.inc
|
||||
@@ -16,3 +17,4 @@ regnual/regnual.elf
|
||||
doc/_build
|
||||
tests/.cache
|
||||
tests/__pycache__
|
||||
tests/.pytest_cache
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "chopstx"]
|
||||
path = chopstx
|
||||
url = ../../chopstx/chopstx.git
|
||||
url = ../chopstx.git
|
||||
|
||||
67
AUTHORS
67
AUTHORS
@@ -1,67 +0,0 @@
|
||||
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:
|
||||
Added STM32 Primer2 support.
|
||||
|
||||
NIIBE Yutaka:
|
||||
Founder of the project.
|
||||
Wrote tools for STLink/V2:
|
||||
tool/stlinkv2.py
|
||||
Wrote tools for DfuSe:
|
||||
tool/dfuse.py
|
||||
tool/dump_mem.py
|
||||
tool/intel_hex.py
|
||||
Wrote a tool for Gnuk:
|
||||
tool/gnuk_put_binary.py
|
||||
tool/gnuk_put_binary_libusb.py
|
||||
tool/gnuk_remove_keys.py
|
||||
tool/gnuk_upgrade.py
|
||||
Wrote a tool for USB Hub:
|
||||
tool/hub_ctrl.py
|
||||
Wrote a tool for testing card reader with pinpad:
|
||||
tool/pinpadtest.py
|
||||
Wrote reGNUal implementation:
|
||||
regnual/regnual.c
|
||||
regnual/sys.c
|
||||
Wrote Gnuk implementation:
|
||||
gnuk.svg
|
||||
src/configure
|
||||
src/ac.c
|
||||
src/call-rsa.c
|
||||
src/debug.c
|
||||
src/flash.c
|
||||
src/gnuk.h
|
||||
src/main.c
|
||||
src/neug.c
|
||||
src/openpgp-do.c
|
||||
src/openpgp.c
|
||||
src/openpgp.h
|
||||
src/pin-cir.c
|
||||
src/pin-dial.c
|
||||
src/pin-dnd.c
|
||||
src/random.c
|
||||
src/sys.c
|
||||
src/usb-icc.c
|
||||
src/usb-msc.c
|
||||
src/usb-msc.h
|
||||
src/usb_ctrl.c
|
||||
src/usb_desc.c
|
||||
src/usb_lld.c
|
||||
src/usb_lld.h
|
||||
*
|
||||
and others.
|
||||
2477
ChangeLog-1_0
2477
ChangeLog-1_0
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
# VID:PID bcdDev Product_STRING Vendor_STRING
|
||||
0000:0000 0200 Gnuk Emulation Free Software Initiative of Japan
|
||||
0000: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
|
||||
1209:2440 0200 Gnuk Token GnuPG e.V.
|
||||
1337:0010 0200 Gnuk Token Deon Spengler
|
||||
##########<TAB> ##<TAB> ##########<TAB> #################
|
||||
|
||||
176
NEWS
176
NEWS
@@ -1,6 +1,175 @@
|
||||
Gnuk NEWS - User visible changes
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.20
|
||||
|
||||
Released 2022-04-22, by NIIBE Yutaka
|
||||
|
||||
** Minor fixes for newer compiler
|
||||
|
||||
For build with newer compiler, Gnuk and regnual are fixed for address
|
||||
calculation and access to object on memory, as well as declarations of
|
||||
function and type in standard C library.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
|
||||
We use Chopstx 1.21. This includes fix to silence compiler warnings.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.19
|
||||
|
||||
Released 2021-10-12, by NIIBE Yutaka
|
||||
|
||||
** KDF Data Object configuration
|
||||
KDF Data Object should be highly recommended for all configurations.
|
||||
Nevertheless, for backward compatibillity, in Gnuk 1.2, it is optional
|
||||
by default; It is up to user to configure KDF Data Object before
|
||||
importing private keys. In this situation, it is not good to
|
||||
introduce new build-time option like --enable-always-require-kdf-do,
|
||||
because it might wrongly encourage use of Gnuk with no KDF Data Object
|
||||
setting, by confusion. If needed, please run configure:
|
||||
|
||||
kdf_do=required ./configure --enable-factory-reset --target...
|
||||
|
||||
or
|
||||
|
||||
kdf_do=optional ./configure --enable-factory-reset --target...
|
||||
|
||||
Please note that such a use of variable by shell command line is not
|
||||
well supported by the configure script (for other variables), but
|
||||
override of kdf_do is needed in some situations.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.20. This enables use with PC/SC for GNU/Linux
|
||||
emulation.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.18
|
||||
|
||||
Released 2021-04-02, by NIIBE Yutaka
|
||||
|
||||
** GNU/Linux emulation bug fix
|
||||
This time, for GNU/Linux emulation, KDF Data Object is required before
|
||||
keygen and key import, really.
|
||||
|
||||
** tool/upgrade_by_passwd.py
|
||||
Now, it checks if the target of binary being written and the
|
||||
configured target of running device are same. This check can be
|
||||
skipped by -s option. Please note that FST-01 and FST-01SZ are
|
||||
different target, as it's MHz is different.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.17
|
||||
|
||||
Released 2021-02-25, by NIIBE Yutaka
|
||||
|
||||
** GNU/Linux: KDF Data Object is required before keygen and key import
|
||||
For GNU/Linux emulation, KDF Data Object is required before keygen and
|
||||
key import.
|
||||
|
||||
** GNU/Linux emulation
|
||||
Since 1.2.10, it was not build-able because of MHZ definition. It is
|
||||
build-able again, and its USB product string is now "Gnuk Token". It
|
||||
has ACK button support using terminal. It now has start-up message,
|
||||
and its driver show useful information to setup USBIP. When no file
|
||||
for the .gnuk-flash-image file, it is automatically created.
|
||||
|
||||
** Removal of tool/gnuk-emulation-setup
|
||||
Because it is automatically created, the tool is not needed any more.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.19.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.16
|
||||
|
||||
Released 2020-09-10, by NIIBE Yutaka
|
||||
|
||||
** New Data Object (Algorithm Information) of OpenPGP card v3.4
|
||||
The tag is 0x00FA. This is useful for user interaction to show which
|
||||
algorithms are supported by the device.
|
||||
|
||||
** Ed25519 signing allowing longer message
|
||||
For OpenPGP, it does hashing on host side before requesting signing to
|
||||
the device. Thus, the length of message to be signed is limited and
|
||||
determined by the hash algorithm. That's good feature of OpenPGP. On
|
||||
the other hand, there is a use case, like OpenSSH certificate signing,
|
||||
where the length of message is a kind of arbitrary. Even though Gnuk
|
||||
(or OpenPGP card protocol itself) has limitation, we removed the
|
||||
length check against EDDSA_HASH_LEN_MAX at cmd_pso.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.15
|
||||
|
||||
Released 2020-01-24, by NIIBE Yutaka
|
||||
|
||||
** Switch to Python3
|
||||
Scripts under tool/ are switched to Python3.
|
||||
Thanks to Bertrand Jacquin.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.18.
|
||||
|
||||
** Tests also support OpenPGPcard
|
||||
Now, a test suite under "tests" may be used to OpenPGPcard.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.14
|
||||
|
||||
Released 2019-03-05, by NIIBE Yutaka
|
||||
|
||||
** Timeout for ACK button support
|
||||
When a user doesn't acknowledge (> 15 seconds), the operation
|
||||
timeouts, and authentication state is cleared.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.14.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.13
|
||||
|
||||
Released 2018-12-26, by NIIBE Yutaka
|
||||
|
||||
** DFU support and its firmware upgrade fix
|
||||
DFU support was not well maintained, and firmware upgrade was not
|
||||
possible for boards with DFU. Now, at least for Maple Mini, it is
|
||||
tested. Note that using Gnuk with DFU on a board is only for an
|
||||
experiment, because DFU can access the content of flash ROM. DFU
|
||||
should be killed by upgrading to normal Gnuk, so that you can have
|
||||
your private keys.
|
||||
|
||||
** Fix for UIF Data Object
|
||||
When flash ROM is full and coping to new page, UIF DO was not properly
|
||||
copied. This bug resulted losing the flag for user interaction. Now,
|
||||
it's properly copied, keeping the setting of the feature.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.13.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.12
|
||||
|
||||
Released 2018-11-25, by NIIBE Yutaka
|
||||
|
||||
** FST-01SZ fixes
|
||||
Fixes for Ack button support and serial number.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.11
|
||||
|
||||
Released 2018-11-12, by NIIBE Yutaka
|
||||
|
||||
** Experimental ACK button support with FST-01SZ
|
||||
While OpenPGP card specification verison 3 has description for the
|
||||
"user interaction" button and data objects, there were no
|
||||
implementation. To evaluate the feature, experimental support is
|
||||
added.
|
||||
|
||||
** Upgrade of Chopstx
|
||||
We use Chopstx 1.12, which comes with ACK button driver and supports
|
||||
FST-01SZ.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.2.10
|
||||
|
||||
Released 2018-05-10, by NIIBE Yutaka
|
||||
@@ -864,6 +1033,7 @@ Gnuk Token could run with GPG4WIN on MS Windows. GPG4WIN runs with
|
||||
|
||||
** This is initial release. Only it supports digital signing.
|
||||
|
||||
Local Variables:
|
||||
mode: outline
|
||||
End:
|
||||
|
||||
# Local Variables:
|
||||
# mode: outline
|
||||
# End:
|
||||
|
||||
642
README
642
README
@@ -1,642 +0,0 @@
|
||||
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
|
||||
|
||||
Version 1.2.10
|
||||
2018-05-10
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
This is the release of Gnuk, version 1.2.10, which has major
|
||||
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
|
||||
overriding key import, but importing keys (or generating keys) results
|
||||
password reset. Also, you need to import private keys before changing
|
||||
your password. Please update your documentation for Gnuk Token, so
|
||||
that the instruction of importing keys won't cause any confusion.
|
||||
|
||||
It has supports of EdDSA, ECDSA (with NIST P256 and secp256k1), and
|
||||
ECDH (with X25519, NIST P256 and secp256k1), but this ECC feature is
|
||||
somehow experimental, and it requires modern GnuPG 2.2 with libgcrypt
|
||||
1.7.0 or later.
|
||||
|
||||
It also supports RSA-4096, but users should know that it takes more
|
||||
than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails,
|
||||
because the device doesn't have enough memory.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
What's Gnuk?
|
||||
============
|
||||
|
||||
Gnuk is an implementation of USB cryptographic token for GNU Privacy
|
||||
Guard. Gnuk supports OpenPGP card protocol version 3, and it runs on
|
||||
STM32F103 processor (and its compatible).
|
||||
|
||||
I wish that Gnuk will be a developer's soother who uses GnuPG. I have
|
||||
been nervous of storing secret key(s) on usual secondary storage.
|
||||
There is a solution with OpenPGP card, but it is not the choice for
|
||||
me, as card reader is not common device. With Gnuk, this issue will
|
||||
be solved by a USB token.
|
||||
|
||||
Please look at the graphics of "gnuk.svg" for the software name. My
|
||||
son used to be with his NUK(R), always, everywhere. Now, I am with a
|
||||
USB Cryptographic Token by "Gnuk", always, everywhere.
|
||||
|
||||
|
||||
FAQ
|
||||
===
|
||||
|
||||
Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
|
||||
card 2.0, YubiKey, etc.) ?
|
||||
https://www.g10code.de/p-card.html
|
||||
https://www.yubico.com/
|
||||
A0: Good points of Gnuk are:
|
||||
* If you have skill of electronics and like DIY, you can build
|
||||
Gnuk Token cheaper (see Q8-A8).
|
||||
* You can study Gnuk to modify and to enhance. For example, you
|
||||
can implement your own authentication method with some sensor
|
||||
such as an acceleration sensor.
|
||||
* It is "of Free Software"; Gnuk is distributed under GPLv3+,
|
||||
"by Free Software"; Gnuk development requires only Free Software
|
||||
(GNU Toolchain, Python, etc.),
|
||||
"for Free Software"; Gnuk supports GnuPG.
|
||||
|
||||
Q1: What kind of key algorithm is supported?
|
||||
A1: Gnuk version 1.0 only supports RSA-2048.
|
||||
Gnuk version 1.2.x supports 255-bit EdDSA, as well as RSA-4096.
|
||||
(Note that it takes long time to sign with RSA-4096.)
|
||||
|
||||
Q2: How long does it take for digital signing?
|
||||
A2: It takes a second and a half or so for RSA-2048.
|
||||
It takes more than 8 secondd for RSA-4096.
|
||||
|
||||
Q3: What's your recommendation for target board?
|
||||
A3: Orthodox choice is Olimex STM32-H103.
|
||||
FST-01 (Flying Stone Tiny 01) is available for sale, and it is a
|
||||
kind of the best choice, hopefully.
|
||||
If you have a skill of electronics, STM32 Nucleo F103 is the best
|
||||
choice for experiment.
|
||||
|
||||
Q4: What's version of GnuPG are you using?
|
||||
A4: In Debian GNU/Linux system, I use GnuPG modern 2.1.18 in
|
||||
unstable.
|
||||
|
||||
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
|
||||
Token without them.
|
||||
I tested pcscd 1.5.5-4 and libccid 1.3.11-2 which were in Debian
|
||||
squeeze.
|
||||
|
||||
Q6: What kinds of hardware is required for development?
|
||||
A6: You need a target board plus a JTAG/SWD debugger. If you just
|
||||
want to test Gnuk for target boards with DfuSe, JTAG debugger is
|
||||
not the requirement. Note that for real use, you need JTAG/SWD
|
||||
debugger to enable flash ROM protection.
|
||||
|
||||
Q7: How much does it cost?
|
||||
A7: Olimex STM32-H103 plus ARM-USB-TINY-H cost 70 Euro or so.
|
||||
|
||||
Q8: How much does it cost for DIY version?
|
||||
A8: STM32 Nucleo F103 costs about $10 USD.
|
||||
|
||||
Q9: I got an error like "gpg: selecting openpgp failed: ec=6.108", what's up?
|
||||
A9: Older GnuPG's SCDaemon has problems for handling insertion/removal of
|
||||
card/reader. When your newly inserted token is not found by
|
||||
GnuPG, try killing scdaemon and let it to be invoked again. I do:
|
||||
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
and confirm scdaemon doesn't exist, then,
|
||||
|
||||
$ gpg-connect-agent learn /bye
|
||||
|
||||
Qa: With GNOME 2, I can't use Gnuk Token for SSH. How can we use it for SSH?
|
||||
Aa: You need to deactivate seahorse-agent and gnome-keyring, but use
|
||||
gpg-agant for the role of ssh-agent. For gnome-keyring please do:
|
||||
|
||||
$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
|
||||
|
||||
Qb: With GNOME 3.0, I can't use Gnuk Token at all. Why?
|
||||
Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
|
||||
|
||||
$ gnome-session-properties
|
||||
|
||||
and at the tab of "Startup Programs", disable check buttons for
|
||||
"GPG Password Agent" and "SSH Key Agent".
|
||||
|
||||
Qc: With GNOME 3.x (x >= 8?), I can't use Gnuk Token at all. Why?
|
||||
Ac: That's because gnome-keyring-daemon interferes GnuPG. Please
|
||||
disable the invocation of gnome-keyring-daemon. In Debian
|
||||
wheezy, it's in the files /etc/xdg/autostart/gnome-keyring-ssh.desktop
|
||||
and /etc/xdg/autostart/gnome-keyring-gpg.desktop.
|
||||
We have a line something like:
|
||||
|
||||
OnlyShowIn=GNOME;Unity;MATE;
|
||||
|
||||
Please edit this line to:
|
||||
|
||||
OnlyShowIn=
|
||||
|
||||
Qd: Do you know a good SWD debugger to connect FST-01 or something?
|
||||
Ad: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
|
||||
writer program. STM32 Nucleo F103 comes with the valiant of
|
||||
ST-Link/V2. However, the firmware of ST-Link/V2 is proprietary.
|
||||
Now, I develop BBG-SWD, SWD debugger by BeagleBone Green.
|
||||
|
||||
|
||||
Tested features
|
||||
===============
|
||||
|
||||
Gnuk is tested by test suite. Please see the test directory.
|
||||
|
||||
* Personalization of the card
|
||||
* Changing Login name, URL, Name, Sex, Language, etc.
|
||||
* Password handling (PW1, RC, PW3)
|
||||
* Key import for three types:
|
||||
* key for digital signing
|
||||
* key for decryption
|
||||
* key for authentication
|
||||
* PSO: Digital Signature
|
||||
* PSO: Decipher
|
||||
* INTERNAL AUTHENTICATE
|
||||
* Changing value of password status bytes (0x00C4): forcesig
|
||||
* Verify with pin pad
|
||||
* Modify with pin pad
|
||||
* Card holder certificate (read)
|
||||
* Removal of keys
|
||||
* Key generation on device side for RSA-2048
|
||||
* Overriding key import
|
||||
|
||||
Original features of Gnuk, tested manually lightly:
|
||||
|
||||
* OpenPGP card serial number setup
|
||||
* Card holder certificate (write by UPDATE BINARY)
|
||||
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
|
||||
|
||||
It is known not-working well:
|
||||
|
||||
* It is known that the specific combination of libccid 1.4.1
|
||||
(or newer) with libusb 1.0.8 (or older) had a minor problem.
|
||||
It is rare but it is possible for USB communication to be
|
||||
failed, because of a bug in libusb implementation. Use
|
||||
libusbx 1.0.9 or newer, or don't use PC/SC, but use internal
|
||||
CCID driver of GnuPG.
|
||||
|
||||
|
||||
Targets
|
||||
=======
|
||||
|
||||
We use Olimex STM32-H103 board and Flying Stone Tiny 01 (FST-01).
|
||||
|
||||
With DfuSe support, STBee is also our targets. But this target with
|
||||
DfuSe is for experiment only, because it is impossible for DfuSe to
|
||||
disable read from flash. For real use, please consider killing DfuSe
|
||||
and enabling read protection using JTAG debugger.
|
||||
|
||||
For experimental PIN-pad support, I connect a consumer IR receive
|
||||
module to FST-01, and use controller for TV. PIN verification is
|
||||
supported by this configuration. Yes, it is not secure at all, since
|
||||
it is very easy to monitor IR output of the controllers. It is just
|
||||
an experiment. Note that hardware needed for this experiment is only
|
||||
a consumer IR receive module which is as cheap as 50 JPY.
|
||||
|
||||
Note that you need pinpad support for GnuPG to use PIN-pad enabled
|
||||
Gnuk. The pinpad support for GnuPG is only available in version 2.
|
||||
|
||||
|
||||
Build system and Host system
|
||||
============================
|
||||
|
||||
Makefile is written for GNU make. You need Bash 4.x for configure.
|
||||
|
||||
If your bash is not installed as /bin/bash, you need to run configure
|
||||
script prepending 'bash' before './configure'.
|
||||
|
||||
Some tools are written in Python. If your Python is not installed as
|
||||
/usr/bin/python, please prepend 'python' for your command invocation.
|
||||
Python 2.7 and PyUSB 0.4.3 is assumed.
|
||||
|
||||
|
||||
Source code
|
||||
===========
|
||||
|
||||
Gnuk source code is under src/ directory.
|
||||
|
||||
Note that SHA-2 hash function implementation, src/sha256.c, is based
|
||||
on the original implementation by Dr. Brian Gladman. See:
|
||||
|
||||
http://brg.a2hosted.com//oldsite/cryptography_technology/sha/index.php
|
||||
(was at:
|
||||
http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php)
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
It is distributed under GNU General Public Licence version 3 or later
|
||||
(GPLv3+). Please see src/COPYING.
|
||||
|
||||
Please note that it is distributed with external source code too.
|
||||
Please read relevant licenses for external source code as well.
|
||||
|
||||
The author(s) of Gnuk expect users of Gnuk will be able to access the
|
||||
source code of Gnuk, so that users can study the code and can modify
|
||||
if needed. This doesn't mean person who has a Gnuk Token should be
|
||||
able to access everything on the Token, regardless of its protections.
|
||||
Private keys, and other information should be protected properly.
|
||||
|
||||
|
||||
External source code
|
||||
====================
|
||||
|
||||
Gnuk is distributed with external source code.
|
||||
|
||||
* chopstx/ -- Chopstx 1.8
|
||||
|
||||
We use Chopstx as the kernel for Gnuk.
|
||||
|
||||
Chopstx is distributed under GPLv3+ (with a special exception).
|
||||
|
||||
|
||||
* polarssl/ -- based on PolarSSL 1.2.10 (now mbedTLS)
|
||||
|
||||
Souce code taken from: http://polarssl.org/
|
||||
|
||||
We use PolarSSL for RSA computation, and AES encryption/decryption.
|
||||
|
||||
PolarSSL is distributed under GPLv2+. We use PolarSSL under GPLv3
|
||||
as our options.
|
||||
|
||||
The file include/polarssl/bn_mul.h is heavily modified for ARM
|
||||
Cortex-M3.
|
||||
|
||||
The function rsa_private in polarssl/library/rsa.c is modified so
|
||||
that it doesn't check T against N. The function rsa_pkcs1_sign is
|
||||
modified to avoid warnings in case of !POLARSSL_PKCS1_V21.
|
||||
|
||||
The functions rsa_pkcs1_verify and rsa_rsassa_pkcs1_v15_verify in
|
||||
include/polarssl/rsa.h and polarssl/library/rsa.c are modified
|
||||
(fixed) for last argument SIG, as the memory at SIG aren't modified
|
||||
by those routines.
|
||||
|
||||
The constant POLARSSL_MPI_MAX_SIZE in include/polarssl/bignum.h is
|
||||
modified for 2048-bit keys only Gnuk.
|
||||
|
||||
The function mpi_mul_hlp in library/bignum.c is modified for more
|
||||
optimization for ARM Cortex-M3. Functions mpi_montred, mpi_sub_hlp,
|
||||
mpi_sub_abs, mpi_mul_mpi, mpi_montmul, and mpi_exp_mod are modified
|
||||
to avoid side channel attacks. Note that we don't use RSA-blinding
|
||||
technique for Gnuk. Function mpi_gen_prime and mpi_is_prime are
|
||||
modified to use Fouque-Tibouchi method. Function mpi_exp_mod is
|
||||
modified to use new function mpi_montsqr for speed up.
|
||||
|
||||
The file library/aes.c is modified so that some constants can
|
||||
go to .sys section.
|
||||
|
||||
The file include/polarssl/config.h are modified not to define
|
||||
POLARSSL_HAVE_LONGLONG to avoid linking libgcc, to define
|
||||
POLARSSL_AES_ROM_TABLES to have AES tables, not to define
|
||||
POLARSSL_CIPHER_MODE_CTR, POLARSSL_FS_IO, POLARSSL_PKCS1_V21,
|
||||
POLARSSL_SELF_TEST, and POLARSSL_PADLOCK_C, and only define
|
||||
POLARSSL_GENPRIME when defined KEYGEN_SUPPORT.
|
||||
|
||||
And polarssl/library/bignum.c is modified to work on 64-bit machine.
|
||||
|
||||
Aurelien Jarno also modified:
|
||||
|
||||
polarssl/include/polarssl/bn_mul.h
|
||||
polarssl/library/bignum.c
|
||||
|
||||
See ChangeLog (and/or history of git) for detail.
|
||||
|
||||
|
||||
USB vendor ID and product ID (USB device ID)
|
||||
============================================
|
||||
|
||||
When you have a vendor ID and assign a product ID for Gnuk, edit the
|
||||
file GNUK_USB_DEVICE_ID and add an entry for yours. In this case,
|
||||
please contact Niibe, so that it is listed to the file in the official
|
||||
release of the source code.
|
||||
|
||||
When you are modifing Gnuk and installing the binary to device, you
|
||||
should replace the vendor string and serial number to yours (in the
|
||||
file GNUK_USB_DEVICE_ID and SERIALNO of the script of src/configure),
|
||||
so that users can see it's not by original vendor, and it is modified
|
||||
version.
|
||||
|
||||
FSIJ allows you to use USB device ID of FSIJ (234b:0000) for devices
|
||||
with Gnuk under one of following conditions:
|
||||
|
||||
* For everyone for experimental purpose:
|
||||
|
||||
- You must not distribute a binary with FSIJ's USB device ID, but
|
||||
must use the binary by yourself only for your experiment. Note
|
||||
that "Distributing binary" includes distributing a device which
|
||||
holds the binary.
|
||||
|
||||
* For general individuals:
|
||||
|
||||
- You must use your Gnuk device with a card serial number which is
|
||||
*not* by FSIJ. Easy one would be a card serial number generated
|
||||
by chip unique ID.
|
||||
|
||||
* For individuals with explicit permission from FSIJ.
|
||||
|
||||
- You should have an assigned card serial number by FSIJ,
|
||||
please use that number for your device.
|
||||
(There a file 'GNUK_SERIAL_NUMBER' in the official release.)
|
||||
|
||||
FSIJ could give companies or business entities "second source
|
||||
manufacturer" license to use USB device ID of FSIJ for devices with
|
||||
unmodified version of Gnuk, provided they support Free Software and
|
||||
respect users' freedom for computing. Please ask FSIJ for the
|
||||
license.
|
||||
|
||||
Otherwise, companies which want to distribute Gnuk devices, please use
|
||||
your own USB vendor ID and product ID. Please replace vendor string
|
||||
and possibly product string to yours, when you modify Gnuk.
|
||||
|
||||
|
||||
Host Requirements
|
||||
=================
|
||||
|
||||
For GNU/Linux, PC/SC service is an option, you can use GnuPG's
|
||||
internal CCID driver instead. If you chose using PC/SC service,
|
||||
libccid version >= 1.3.11 is recommended for GNU/Linux.
|
||||
|
||||
|
||||
How to compile
|
||||
==============
|
||||
|
||||
You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
||||
|
||||
On Debian we can install the packages of gcc-arm-none-eabi,
|
||||
gdb-arm-none-eabi and its friends. I'm using:
|
||||
|
||||
binutils-arm-none-eabi 2.28-4+9+b3
|
||||
gcc-arm-none-eabi 15:6.3.1+svn253039-1
|
||||
gdb-arm-none-eabi 7.12-6+9+b2
|
||||
libnewlib-arm-none-eabi 2.4.0.20160527-3
|
||||
|
||||
Or else, see https://launchpad.net/gcc-arm-embedded for preparation of
|
||||
GNU Toolchain for 'arm-none-eabi' target.
|
||||
|
||||
Change directory to `src':
|
||||
|
||||
$ cd gnuk-VERSION/src
|
||||
|
||||
Then, run `configure':
|
||||
|
||||
$ ./configure --vidpid=<VID:PID>
|
||||
|
||||
Here, you need to specify USB vendor ID and product ID. For FSIJ's,
|
||||
it's: --vidpid=234b:0000 . Please read section 'USB vendor ID and
|
||||
product ID' above.
|
||||
|
||||
|
||||
Then, type:
|
||||
|
||||
$ make
|
||||
|
||||
Then, we will have "gnuk.elf" under src/build directory.
|
||||
|
||||
If you are not the authorized vendor, please never distribute this
|
||||
file of "gnuk.elf", which includes VID:PID in the image. If you would
|
||||
like to distribute the image (for example, to check if it's
|
||||
reproducible or not), the file "gnuk-no-vidpid.elf" is the one with no
|
||||
VID:PID.
|
||||
|
||||
|
||||
How to install
|
||||
==============
|
||||
|
||||
Olimex STM32-H103 board
|
||||
-----------------------
|
||||
|
||||
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD
|
||||
and write "gnuk-vidpid.elf" to Flash ROM:
|
||||
|
||||
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg \
|
||||
-f board/olimex_stm32_h103.cfg \
|
||||
-c "program build/gnuk-vidpid.elf verify reset exit"
|
||||
|
||||
Command invocation is assumed in src/ directory.
|
||||
|
||||
|
||||
Flying Stone Tiny 01
|
||||
--------------------
|
||||
|
||||
If you are using Flying Stone Tiny 01, you need a SWD writer.
|
||||
|
||||
OpenOCD 0.9.0 now supports ST-Link/V2. We can use it like:
|
||||
|
||||
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
|
||||
-c "program build/gnuk-vidpid.elf verify reset exit"
|
||||
|
||||
|
||||
|
||||
STBee
|
||||
-----
|
||||
|
||||
Reset the board with "USER" switch pushed. Type following to write
|
||||
to flash:
|
||||
|
||||
# cd ../tool
|
||||
# ./dfuse.py ../src/build/gnuk-vidpid.hex
|
||||
|
||||
Then, reset the board.
|
||||
|
||||
|
||||
How to protect flash ROM
|
||||
========================
|
||||
|
||||
To protect, invoke OpenOCD like (for FST-01):
|
||||
|
||||
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
|
||||
-c init -c "reset halt" -c "stm32f1x lock 0" -c reset -c exit
|
||||
|
||||
After power-off / power-on sequence, the contents of flash ROM cannot
|
||||
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
|
||||
to access the contents, even if it's protected. If you really want to
|
||||
protect, killing DfuSe and accessing by JTAG debugger is recommended.
|
||||
|
||||
|
||||
(Optional) Configure serial number and X.509 certificate
|
||||
========================================================
|
||||
|
||||
This is completely optional.
|
||||
|
||||
For this procedure, you need python and pyscard (python-pyscard
|
||||
package in Debian) or PyUSB 0.4.3 (python-usb package in Debian).
|
||||
|
||||
(1) [pyscard] Stop scdaemon
|
||||
[PyUSB] Stop the pcsc daemon.
|
||||
|
||||
If scdaemon is running, please kill it, or you will get "Smartcard
|
||||
Exception" by "Sharing violation".
|
||||
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
In case of PyUSB tool, you need to stop pcscd.
|
||||
|
||||
# /etc/init.d/pcscd stop
|
||||
|
||||
|
||||
(2) [Optional] Write fixed serial number
|
||||
|
||||
If you use fixed serial number in the file 'GNUK_SERIAL_NUMBER', you can do:
|
||||
|
||||
$ EMAIL=<YOUR-EMAIL-ADDRESS> ../tool/gnuk_put_binary_usb.py -s ../GNUK_SERIAL_NUMBER
|
||||
Writing serial number
|
||||
...
|
||||
|
||||
(3) [Optional] Write card holder certificate
|
||||
|
||||
If you have card holder certificate binary file, you can do:
|
||||
|
||||
$ ../tool/gnuk_put_binary_usb.py ../../<YOUR-CERTIFICATE>.bin
|
||||
../../<YOUR-CERTIFICATE>.bin: <LENGTH-OF-YOUR-CERTIFICATE>
|
||||
Updating card holder certificate
|
||||
...
|
||||
|
||||
|
||||
How to run
|
||||
==========
|
||||
|
||||
Debug enabled
|
||||
-------------
|
||||
|
||||
If you compiled with --enable-debug option, Gnuk has two interfaces
|
||||
(one is CCID/ICCD device and another is virtual COM port). Open
|
||||
virtual COM port by:
|
||||
|
||||
$ cu -l /dev/ttyACM0
|
||||
|
||||
and you will see debug output of Gnuk.
|
||||
|
||||
|
||||
Testing Gnuk
|
||||
------------
|
||||
|
||||
Type following command to see Gnuk runs:
|
||||
|
||||
$ gpg --card-status
|
||||
|
||||
|
||||
Besides, there is a functionality test under test/ directory. See
|
||||
test/README.
|
||||
|
||||
|
||||
Personalize the Token, import keys, and change the password
|
||||
-----------------------------------------------------------
|
||||
|
||||
You can personalize the token, putting your information like: Name,
|
||||
Login name, Sex, Languages, URL. To do so, GnuPG command is:
|
||||
|
||||
$ gpg --card-edit
|
||||
|
||||
Note that the factory setting of user password is "123456" and admin
|
||||
password is "12345678" as the specification.
|
||||
|
||||
It is recommended to create your keys on your computer, and import
|
||||
them to Gnuk Token. After you create your keys (they must be 2048-bit
|
||||
RSA), you can import them.
|
||||
|
||||
Gnuk supports key generation, but this feature is young and should be
|
||||
considered experimental.
|
||||
|
||||
For detail, please see documentation under doc/. You can see the HTML
|
||||
version at: https://www.fsij.org/doc-gnuk/
|
||||
|
||||
|
||||
How to debug
|
||||
============
|
||||
|
||||
We can use GDB.
|
||||
|
||||
$ arm-none-eabi-gdb gnuk.elf
|
||||
|
||||
|
||||
Inside GDB, we can connect OpenOCD by:
|
||||
|
||||
(gdb) target remote localhost:3333
|
||||
|
||||
or
|
||||
|
||||
(gdb) target extended-remote localhost:3333
|
||||
|
||||
|
||||
You can see the output of PCSCD:
|
||||
|
||||
# /etc/init.d/pcscd stop
|
||||
# LIBCCID_ifdLogLevel=7 /usr/sbin/pcscd --debug --foreground
|
||||
|
||||
|
||||
You can observe the traffic of USB using "usbmon". See the file:
|
||||
linux/Documentation/usb/usbmon.txt
|
||||
|
||||
|
||||
Firmware update
|
||||
===============
|
||||
|
||||
See doc/note/firmware-update.
|
||||
|
||||
|
||||
Git Repositories
|
||||
================
|
||||
|
||||
Please use: https://salsa.debian.org/gnuk-team/gnuk/
|
||||
|
||||
You can get it by:
|
||||
|
||||
$ git clone https://salsa.debian.org/gnuk-team/gnuk/gnuk.git
|
||||
|
||||
It's also available at: www.gniibe.org
|
||||
You can browse at: https://git.gniibe.org/gitweb?p=gnuk/gnuk.git;a=summary
|
||||
|
||||
I put Chopstx as a submodule of Git. Please do this:
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
|
||||
Information on the Web
|
||||
======================
|
||||
|
||||
For more information, please visit: https://www.fsij.org/gnuk/
|
||||
|
||||
Please see the FST-01 support pages:
|
||||
|
||||
https://www.gniibe.org/category/fst-01.html
|
||||
|
||||
Please consider to join Gnuk-users mailing list:
|
||||
|
||||
https://lists.gnupg.org/mailman/listinfo/gnuk-users
|
||||
|
||||
|
||||
|
||||
Your Contributions
|
||||
==================
|
||||
|
||||
FSIJ welcomes your contributions. Please assign your copyright
|
||||
to FSIJ (if possible), as I do.
|
||||
|
||||
|
||||
Foot note
|
||||
==========
|
||||
|
||||
* NUK(R) is a registered trademark owend by MAPA GmbH, Germany.
|
||||
--
|
||||
138
README.md
Normal file
138
README.md
Normal file
@@ -0,0 +1,138 @@
|
||||
***Note:*** *This fork of Gnuk fixes some compiling bugs and focuses on using the "ST-Link V2" clone hardware.*
|
||||
|
||||
Here is the link to the original project: <http://git.gniibe.org/cgit/gnuk/gnuk.git/>
|
||||
|
||||
What's Gnuk?
|
||||
============
|
||||
Gnuk is an implementation of a USB cryptographic security token that supports the OpenPGP card protocol version 2. It runs on a STM32F103 processor (and its compatible). In short it allows one to convert a cheap $2 "ST-Link V2" clone device into a hardware security token.
|
||||
|
||||
It has supports of Ed25519 and X25519 (ECDH on Curve25519). It also has experimental support of ECDSA (on NIST P256 and secp256k1) and ECDH (on NIST P256 and secp256k1).
|
||||
|
||||
Gnuk supports the Key Derived Function (KDF) functionality. To use this feature one will need to use GnuPG 2.2.6 or later.
|
||||
|
||||
How to build the Gnuk firmware
|
||||
==============================
|
||||
You will need the GNU toolchain for arm-none-eabi and newlib.
|
||||
|
||||
To clone the source code and compile, use the following commands.
|
||||
```
|
||||
git clone --recursive https://git.spengler.co.za/deon/gnuk.git gnuk
|
||||
cd gnuk/src
|
||||
./configure --vidpid=1337:0010
|
||||
make
|
||||
```
|
||||
|
||||
Then, you will have "gnuk.bin" under src/build directory.
|
||||
|
||||
***Please read section 'USB vendor ID and product ID' below.***
|
||||
|
||||
How to flash the Gnuk firmware
|
||||
==============================
|
||||
In order to flash the firmware ensure that you have openocd installed.
|
||||
|
||||
Execute openocd and connect with telnet
|
||||
```
|
||||
openocd -f ../misc/stm32f103.cfg
|
||||
telnet localhost 4444
|
||||
```
|
||||
|
||||
Use the following commands to unlock, flash the firmware and lock the device again.
|
||||
```
|
||||
reset halt
|
||||
stm32f1x unlock 0
|
||||
reset halt
|
||||
flash write_bank 0 ./build/gnuk.bin 0
|
||||
stm32f1x lock 0
|
||||
reset halt
|
||||
```
|
||||
|
||||
How to reflash the ST-LINK
|
||||
==========================
|
||||
To reflash the ST-LINK, connect the device to a programmer as before while keeping pins 7 and 8 shorted. While the LED is blinking, run openocd. Once it’s running (i.e. it doesn’t show any errors), you can unshort the pins.
|
||||
|
||||
Then use the following to unlock and reflash.
|
||||
```
|
||||
reset halt
|
||||
stm32f1x unlock 0
|
||||
reset halt
|
||||
stm32f1x mass_erase 0
|
||||
flash write_bank 0 ./build/gnuk.bin 0
|
||||
stm32f1x lock 0
|
||||
reset halt
|
||||
```
|
||||
|
||||
***Note: That reprograming will wipe the flash memory and you will lose all key's that was on the device.***
|
||||
|
||||
Testing Gnuk
|
||||
============
|
||||
Type following command to see if GnuPG detects the Gnuk token.
|
||||
```
|
||||
gpg --card-status
|
||||
```
|
||||
|
||||
***See tests/README for functionality tests.***
|
||||
|
||||
Personalize the Token, import keys, and change the password
|
||||
===========================================================
|
||||
You can personalize your token by putting in your information like: Name, Login and Language.
|
||||
|
||||
The KDF setting needs to be enabled before any keys are imported into the Gnuk token. Once a key has been imported the KDF setting can't be changed until the token has been reset.
|
||||
|
||||
***Note:*** That the factory user password is "123456" and admin password is "12345678". It is recommended to create your keys on your computer, and import them into the token. Gnuk supports key generation, but this feature is young and should be considered experimental.
|
||||
|
||||
To configure your Gnuk token use the following command.
|
||||
```
|
||||
gpg --card-edit
|
||||
```
|
||||
|
||||
For further details, please see documentation under doc.
|
||||
|
||||
Firmware update
|
||||
===============
|
||||
See doc/note/firmware-update.
|
||||
|
||||
How to debug
|
||||
============
|
||||
Ensure that you have arm-none-eabi-gdb installed and then you must configure and compile the Gnuk firmware with --enable-debug option. After flashing Gnuk debug firmware one will see two interfaces, one is CCID/ICCD device and the another is a virtual COM port.
|
||||
|
||||
Open the virtual COM with the following command:
|
||||
```
|
||||
picocom /dev/ttyACM0
|
||||
```
|
||||
and you will see debug output of Gnuk firmware.
|
||||
|
||||
You can now use GDB with the following command.
|
||||
```
|
||||
arm-none-eabi-gdb src/build/gnuk.elf
|
||||
```
|
||||
|
||||
Inside GDB, we can connect OpenOCD by:
|
||||
```
|
||||
(gdb) target remote localhost:3333
|
||||
```
|
||||
|
||||
You can see the output of PCSCD with the following command:
|
||||
```
|
||||
/usr/bin/pcscd --debug --foreground
|
||||
```
|
||||
|
||||
You can also observe the traffic of the USB interface using "usbmon".
|
||||
|
||||
USB vendor ID and product ID (USB device ID)
|
||||
============================================
|
||||
When you have a vendor ID and assign a product ID for Gnuk, edit the file GNUK_USB_DEVICE_ID and add an entry for yours. In this case, please contact Niibe, so that it is listed to the file in the official release of the source code.
|
||||
|
||||
When you are modifing Gnuk and installing the binary to device, you should replace the vendor string and serial number to yours (in the file GNUK_USB_DEVICE_ID and SERIALNO of the script of src/configure), so that users can see it's not by original vendor, and it is modified version.
|
||||
|
||||
FSIJ allows you to use USB device ID of FSIJ (234b:0000) for devices with Gnuk under one of following conditions:
|
||||
* For everyone for experimental purpose:
|
||||
- You must not distribute a binary with FSIJ's USB device ID, but must use the binary by yourself only for your experiment. Note that "Distributing binary" includes distributing a device which holds the binary.
|
||||
* For general individuals:
|
||||
- You must use your Gnuk device with a card serial number which is *not* by FSIJ. Easy one would be a card serial number generated by chip unique ID.
|
||||
* For individuals with explicit permission from FSIJ.
|
||||
- You should have an assigned card serial number by FSIJ, please use that number for your device.
|
||||
(There a file 'GNUK_SERIAL_NUMBER' in the official release.)
|
||||
|
||||
FSIJ could give companies or business entities "second source manufacturer" license to use USB device ID of FSIJ for devices with unmodified version of Gnuk, provided they support Free Software and respect users' freedom for computing. Please ask FSIJ for the license.
|
||||
|
||||
Otherwise, companies which want to distribute Gnuk devices, please use your own USB vendor ID and product ID. Please replace vendor string and possibly product string to yours, when you modify Gnuk.
|
||||
43
THANKS
43
THANKS
@@ -1,43 +0,0 @@
|
||||
-*- coding: utf-8 -*-
|
||||
|
||||
We would like to express our gratitudes to Werner Koch for GnuPG, and
|
||||
Giovanni Di Sirio for ChibiOS/RT.
|
||||
|
||||
Gnuk was originally written by NIIBE Yutaka. People contributed by
|
||||
encouraging the development, testing the implementation, suggesting
|
||||
improvements, or fixing bugs. Here is a list of those people.
|
||||
|
||||
Aurelien Jarno aurelien@aurel32.net
|
||||
Achim Pietig achim@pietig.com
|
||||
Aidan Thornton
|
||||
Anibal Monsalve Salazar anibal@debian.org
|
||||
Andre Zepezauer andre.zepezauer@student.uni-halle.de
|
||||
Anthony Romano anthony.romano@coreos.com
|
||||
Bertrand Jacquin bertrand@jacquin.bzh
|
||||
Clint Adams clint@softwarefreedom.org
|
||||
Daniel Kahn Gillmor dkg@fifthhorseman.net
|
||||
Elliott Mitchell
|
||||
Hironobu SUZUKI hironobu@h2np.net
|
||||
Jan Suhr jan@suhr.info
|
||||
Jeremy Drake jeremydrake+gnuk@eacceleration.com
|
||||
Jonathan McDowell noodles@earth.li
|
||||
Kaz Kojima kkojima@rr.iij4u.or.jp
|
||||
Kenji Rikitake
|
||||
Ludovic Rousseau ludovic.rousseau@free.fr
|
||||
Luis Felipe R. Murillo luisfelipe@ucla.edu
|
||||
Mateusz Zalega mateusz@nitrokey.com
|
||||
MATSUU Takuto matsuu@gentoo.org
|
||||
Micah Anderson micah@debian.org
|
||||
NAGAMI Takeshi nagami-takeshi@aist.go.jp
|
||||
Nguyễn Hồng Quân quannguyen@mbm.vn
|
||||
Nico Rikken nico@nicorikken.eu
|
||||
NOKUBI Takatsugu knok@daionet.gr.jp
|
||||
Paul Fertser
|
||||
Paul Bakker polarssl_maintainer@polarssl.org
|
||||
Santiago Ruano Rincón santiago@debian.org
|
||||
Shane Coughlan scoughlan@openinventionnetwork.com
|
||||
Stanislas Bach sbach@0g.re
|
||||
Szczepan Zalega szczepan@nitrokey.com
|
||||
Vasily Evseenko
|
||||
Werner Koch wk@gnupg.org
|
||||
Yuji Imai ug@xcast.jp
|
||||
2
chopstx
2
chopstx
Submodule chopstx updated: 802dbbd639...a8e9074faf
@@ -16,7 +16,7 @@ In addition to settings of Gnuk, I create a file
|
||||
|
||||
# For updating firmware, permission settings are needed.
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
||||
SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
|
||||
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
|
||||
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ setting). It should have lines something like: ::
|
||||
# Gnuk Token by FSIJ
|
||||
|
||||
SUBSYSTEMS=="usb", ACTION=="add", \
|
||||
ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
||||
ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
|
||||
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
|
||||
I have those lines in /etc/udev/rules.d/69-gnuk.rules.
|
||||
@@ -122,7 +122,7 @@ your environment for Gnuk Token.
|
||||
How to run the script: ::
|
||||
|
||||
$ cd tool
|
||||
$ ./upgrade_by_passwd.py ../regnual/regnual.bin ../src/build/gnuk.bin
|
||||
$ ./upgrade_by_passwd.py
|
||||
|
||||
Then, the script on your host PC invoke the steps described above, and
|
||||
you will get new version of Gnuk installed.
|
||||
|
||||
@@ -30,9 +30,9 @@ command.
|
||||
|
||||
Or, you can use ``gpgconf`` command. Type::
|
||||
|
||||
$ gpgconf --reload scdameon
|
||||
$ gpgconf --reload scdaemon
|
||||
|
||||
will do the samething.
|
||||
will do the same thing.
|
||||
|
||||
|
||||
Let GPG-AGENT/SCDAEMON learn
|
||||
|
||||
@@ -37,7 +37,7 @@ When we only install "gnupg2" package for 2.0 (with no "gnupg" package),
|
||||
there will be no udev rules (there is a bug report #543217 for this issue).
|
||||
In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules::
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
||||
SUBSYSTEMS=="usb", ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", \
|
||||
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
|
||||
Usually, udev daemon automatically handles for the changes of configuration
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
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
|
||||
@@ -1,4 +0,0 @@
|
||||
FROM gnuk:latest
|
||||
LABEL Description="Image for building gnuK with debugging"
|
||||
|
||||
RUN apt install -y gdb-arm-none-eabi && apt clean
|
||||
@@ -1,6 +0,0 @@
|
||||
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"]
|
||||
@@ -1,36 +0,0 @@
|
||||
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
|
||||
@@ -1,553 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
id="svg3961"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="gnuk-sticers.svg">
|
||||
<defs
|
||||
id="defs3">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3967" />
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="1031.615"
|
||||
x2="240.89818"
|
||||
y1="1031.615"
|
||||
x1="85.996228"
|
||||
id="linearGradient4296"
|
||||
xlink:href="#linearGradient4290"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
id="perspective3903" />
|
||||
<filter
|
||||
id="filter3875"
|
||||
inkscape:collect="always">
|
||||
<feBlend
|
||||
id="feBlend3877"
|
||||
in2="BackgroundImage"
|
||||
mode="screen"
|
||||
inkscape:collect="always" />
|
||||
</filter>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
id="perspective3830" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective10-5" />
|
||||
<linearGradient
|
||||
id="linearGradient0">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3620" />
|
||||
<stop
|
||||
id="stop3632"
|
||||
offset="0.07"
|
||||
style="stop-color:#c8c8e0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3630"
|
||||
offset="0.17"
|
||||
style="stop-color:#9696c8;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3628"
|
||||
offset="0.33"
|
||||
style="stop-color:#6464b4;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#3232a0;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop3634" />
|
||||
<stop
|
||||
id="stop3636"
|
||||
offset="0.66"
|
||||
style="stop-color:#282898;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3626"
|
||||
offset="0.85"
|
||||
style="stop-color:#1e1e90;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#000088;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3622" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient0"
|
||||
id="radialGradient0"
|
||||
cx="450"
|
||||
cy="750"
|
||||
fx="450"
|
||||
fy="750"
|
||||
r="201.5"
|
||||
gradientTransform="matrix(1,0,0,0.75369458,-1.760006,108.15135)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient1">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop0" />
|
||||
<stop
|
||||
id="stop1"
|
||||
offset="0.0625"
|
||||
style="stop-color:#f8fcff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2"
|
||||
offset="0.17166339"
|
||||
style="stop-color:#f0f8ff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3"
|
||||
offset="0.30279359"
|
||||
style="stop-color:#ecf4ff;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#e8f0ff;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop4" />
|
||||
<stop
|
||||
id="stop5"
|
||||
offset="0.65893352"
|
||||
style="stop-color:#e0ecff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop6"
|
||||
offset="0.83552629"
|
||||
style="stop-color:#d8e8ff;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#d0e0ff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop7" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1"
|
||||
id="radialGradient1"
|
||||
cx="0"
|
||||
cy="440"
|
||||
fx="0"
|
||||
fy="440"
|
||||
r="80"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter0"
|
||||
x="-0.1423529"
|
||||
width="1.2847058"
|
||||
y="-0.13404847"
|
||||
height="1.2680969">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="2.0538481"
|
||||
id="feGaussianBlur0" />
|
||||
</filter>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
id="perspective2884" />
|
||||
<inkscape:perspective
|
||||
id="perspective10"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
id="linearGradient4290"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop4292"
|
||||
offset="0"
|
||||
style="stop-color:#000734;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop4294"
|
||||
offset="1"
|
||||
style="stop-color:#000734;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
inkscape:document-units="mm"
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="-75.714286"
|
||||
inkscape:cy="520"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1122"
|
||||
inkscape:window-height="692"
|
||||
inkscape:window-x="150"
|
||||
inkscape:window-y="51"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
style="display:inline"
|
||||
transform="translate(0.5,-946.62598)"
|
||||
id="layer1-63"
|
||||
inkscape:label="Layer1"
|
||||
inkscape:tile-cx="124.59931"
|
||||
inkscape:tile-cy="53.118107"
|
||||
inkscape:tile-w="248.19862"
|
||||
inkscape:tile-h="105.23622"
|
||||
inkscape:tile-x0="0.5"
|
||||
inkscape:tile-y0="0.49999656">
|
||||
<rect
|
||||
y="947.12598"
|
||||
x="0"
|
||||
height="105.23622"
|
||||
width="248.19862"
|
||||
id="rect0"
|
||||
style="fill:#d9fffe;fill-opacity:1;stroke:none" />
|
||||
<line id="line0"
|
||||
x1="0" y1="947.12598" x2="20" y2="947.12598"
|
||||
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
|
||||
<line id="line1"
|
||||
x1="248.19862" y1="947.12598" x2="248.19862" y2="957.12598"
|
||||
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
|
||||
<line id="line2"
|
||||
x1="248.19862" y1="1052.3622" x2="228.19862" y2="1052.3622"
|
||||
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
|
||||
<line id="line3"
|
||||
x1="0" y1="1052.3622" x2="0" y2="1042.3622"
|
||||
style="stroke:#000044;stroke-width:0.5;stroke-opacity:1;stroke-dasharray:2,1;stroke-dashoffset:1" />
|
||||
<image
|
||||
xlink:href="FSIJ-s.png"
|
||||
width="41.757679"
|
||||
height="28.346457"
|
||||
id="image2886"
|
||||
x="202.27382"
|
||||
y="951.12598" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text2890"
|
||||
y="1014.9048"
|
||||
x="94.433884"
|
||||
style="font-size:52.27830124px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#032b7f;fill-opacity:1;stroke:none;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch Bold"
|
||||
xml:space="preserve"><tspan
|
||||
y="1014.9048"
|
||||
x="94.433884"
|
||||
id="tspan2892"
|
||||
sodipodi:role="line">GNUK</tspan></text>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
id="layer1-6"
|
||||
transform="matrix(-0.1014557,0,0,0.1014557,90.73972,926.6016)">
|
||||
<path
|
||||
style="fill:#000050;fill-opacity:1;stroke:#000000;stroke-width:2.29999995px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 0,0 c 0,0 0,0 -76,0 0,0 -8,-9 -12,-12 -18,-15 -48,-48 -36,-84 4,-14 12,-36 12,-36 -10,6 -50,26 -66,54 -8,16 -18,30 -18,54 0,24 25,100 48,108 0,0 0,0 150,0 0,0 0,0 150,0 23,-8 48,-84 48,-108 0,-24 -10,-38 -18,-54 -16,-28 -46,-48 -66,-54 0,0 8,22 12,36 12,36 -18,69 -36,84 C 88,-9 80,0 80,0 z"
|
||||
transform="matrix(-1.76,0,0,1.76,410,560)"
|
||||
id="path0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000040;fill-opacity:1;stroke:none"
|
||||
d="m 411.01194,560.94628 c 0,0 0,0 133.76,0 0,0 14.08,-15.84 21.12,-21.12 31.68,-26.4 84.48,-84.48 63.36,-147.84 -7.04,-24.64 -21.12,-63.36 -21.12,-63.36 17.6,10.56 38,45.76 66.16,95.04 14.08,28.16 19.18,52.8 19.18,95.04 0,42.24 -44,176 -84.48,190.08 0,0 62.5,0 -201.5,0 0,0 62.5,0 -201.5,0 -40.48,-14.08 -84.48,-147.84 -84.48,-190.08 0,-42.24 5.1,-66.88 19.18,-95.04 28.16,-49.28 30.96,-84.48 66.16,-95.04 0,0 -14.08,38.72 -21.12,63.36 -21.12,63.36 31.68,121.44 63.36,147.84 7.04,5.28 21.12,21.12 21.12,21.12 z"
|
||||
id="path0-9"
|
||||
sodipodi:nodetypes="ccccccscccscccccc" />
|
||||
<path
|
||||
style="fill:#c0c0fd;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 409.21999,592 c 0,0 90,0 90,-33 0,-20 -4,-28 -12,-40 -5,-8 -8,-18 -8,-28 -1,-13 -1,-20 8,-36 6,-9 8,-23 5,-33 -5,-14 -19,-23 -33,-25 -16,-5 -35,-4 -50,-5 -15,1 -34,0 -50,5 -14,2 -28,9 -33,25 -3,10 1,24 5,33 9,16 9,23 8,36 0,10 -3,20 -8,28 -8,12 -12,20 -12,40 0,33 90,33 90,33 z"
|
||||
id="path1" />
|
||||
<path
|
||||
style="fill:url(#radialGradient1);fill-opacity:1;fill-rule:evenodd;stroke:#d0e0ff;stroke-width:10px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 0,592 c 0,0 -90,0 -90,-33 0,-20 4,-28 12,-40 5,-8 8,-18 8,-28 1,-13 1,-20 -8,-36 -6,-9 -8,-23 -5,-33 5,-14 19,-23 33,-25 16,-5 35,-4 50,-5 15,1 34,0 50,5 14,2 28,9 33,25 3,10 -1,24 -5,33 -9,16 -9,23 -8,36 0,10 3,20 8,28 8,12 12,20 12,40 0,33 -90,33 -90,33 z"
|
||||
id="path1-1"
|
||||
transform="matrix(-0.75,0,0,0.8,410,100)" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)"
|
||||
d="m 344.11439,411.54794 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
|
||||
id="path1-2"
|
||||
sodipodi:nodetypes="ccccsc" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter0)"
|
||||
d="m 474.68123,406.16125 c 7.16035,-2.82917 12.68023,-7.05316 25.88561,-1.83463 -11.82218,3.36559 -30.19974,8.74598 -28.4554,30.10894 0,1.43822 0.19526,2.84651 0.53302,4.18858 -5.07909,-3.45362 -6.70449,-9.04022 -6.70449,-15.93734 0,-10.74221 5.00989,-12.63545 8.74126,-16.52555 z"
|
||||
id="path1-3"
|
||||
sodipodi:nodetypes="ccccsc"
|
||||
transform="matrix(-1,0,0,1,949.00681,5.38669)" />
|
||||
<path
|
||||
style="fill:#afcfff;fill-opacity:1;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 236.90125,452.90625 C 135.34805,496.35376 97.060607,634.496 151.37,761.4375 c 50.02335,116.92341 158.1859,159.40625 257.75,159.40625 99.5641,0 207.72665,-42.48284 257.75,-159.40625 C 721.17939,634.496 682.89195,496.35376 581.33875,452.90625 526.07714,429.26367 466.8919,524.375 409.12,524.375 c -57.7719,0 -116.77668,-94.67646 -172.21875,-71.46875 z"
|
||||
id="path2"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:url(#radialGradient0);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="path3"
|
||||
d="m 538.23999,720 a 130,150 0 0 1 -260,0 130,150 0 1 1 260,0 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4.47213602px;stroke-opacity:1"
|
||||
d="m 538.30032,722.21875 c 56.32313,26.16396 100.82185,68.68738 119.76563,119.4375 33.50451,82.59901 -5.55269,179.72665 -93.67188,230.71875 -89.66782,55.4574 -224.43374,55.4574 -314.10156,0 -88.11919,-50.9921 -127.13733,-148.11974 -93.63281,-230.71875 18.61816,-50.41349 63.06491,-92.92973 119.25781,-119.1875 11.1304,10.32118 18.58377,23.0939 22.34375,36.6875 -5.94376,3.59375 -11.63988,7.47175 -16.99219,11.625 -73.95399,55.19241 -81.85302,155.28934 -18.59375,218.125 47.75721,51.30795 139.68,72.55545 213.4375,46.68755 87.41094,-28.2229 135.47694,-110.93384 113.94531,-183.2813 -9.09953,-36.85675 -36.47131,-70.33241 -73.67187,-92.96875 2.51871,-9.1715 6.69761,-18.00492 12.57812,-26 2.55237,-3.99852 5.70954,-7.71801 9.33594,-11.125 z"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<text
|
||||
sodipodi:linespacing="85.000002%"
|
||||
id="text3817"
|
||||
y="1038.1145"
|
||||
x="98.368591"
|
||||
style="font-size:18px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:85.00000238%;writing-mode:lr-tb;text-anchor:start;fill:#120054;fill-opacity:1;stroke:none;display:inline;font-family:Gentium Basic;-inkscape-font-specification:Gentium Basic Bold Italic"
|
||||
xml:space="preserve"><tspan
|
||||
y="1038.1145"
|
||||
x="98.368591"
|
||||
style="fill:#120054;fill-opacity:1"
|
||||
id="tspan4288"
|
||||
sodipodi:role="line">GnuPG USB Token</tspan></text>
|
||||
</g>
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
id="use4758" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,105.23622)"
|
||||
id="use4760" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,210.47244)"
|
||||
id="use4762" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,315.70866)"
|
||||
id="use4764" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,420.94489)"
|
||||
id="use4766" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,526.18111)"
|
||||
id="use4768" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,631.41733)"
|
||||
id="use4770" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,736.65355)"
|
||||
id="use4772" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,841.88977)"
|
||||
id="use4774" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(0,947.12599)"
|
||||
id="use4776" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,0)"
|
||||
id="use4778" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,105.23622)"
|
||||
id="use4780" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,210.47244)"
|
||||
id="use4782" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,315.70866)"
|
||||
id="use4784" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,420.94489)"
|
||||
id="use4786" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,526.18111)"
|
||||
id="use4788" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,631.41733)"
|
||||
id="use4790" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,736.65355)"
|
||||
id="use4792" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,841.88977)"
|
||||
id="use4794" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(248.19862,947.12599)"
|
||||
id="use4796" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,0)"
|
||||
id="use4798" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,105.23622)"
|
||||
id="use4800" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,210.47244)"
|
||||
id="use4802" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,315.70866)"
|
||||
id="use4804" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,420.94489)"
|
||||
id="use4806" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,526.18111)"
|
||||
id="use4808" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,631.41733)"
|
||||
id="use4810" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,736.65355)"
|
||||
id="use4812" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,841.88977)"
|
||||
id="use4814" />
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:tiled-clone-of="#layer1-63"
|
||||
xlink:href="#layer1-63"
|
||||
transform="translate(496.39725,947.12599)"
|
||||
id="use4816" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 20 KiB |
4
misc/stm32f103.cfg
Normal file
4
misc/stm32f103.cfg
Normal file
@@ -0,0 +1,4 @@
|
||||
telnet_port 4444
|
||||
source [find interface/stlink.cfg]
|
||||
source [find target/stm32f1x.cfg]
|
||||
set WORKAREASIZE 0x10000
|
||||
@@ -52,6 +52,7 @@ regnual-no-vidpid.elf: $(OBJS) $(LDSCRIPT)
|
||||
$(CC) $(LDFLAGS) -o regnual-no-vidpid.elf $(OBJS)
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin *.lst
|
||||
-rm -f $(OBJS) regnual-no-vidpid.elf regnual.elf regnual.hex regnual.bin \
|
||||
*.lst
|
||||
|
||||
distclean: clean
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
* ReGNUal
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "usb_lld.h"
|
||||
#include "sys.h"
|
||||
|
||||
extern void *memset (void *s, int c, size_t n);
|
||||
|
||||
extern void set_led (int);
|
||||
extern int flash_write (uint32_t dst_addr, const uint8_t *src, size_t len);
|
||||
extern int flash_protect (void);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
typedef unsigned long size_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
@@ -7,5 +5,3 @@ typedef unsigned int uintptr_t;
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define NULL 0
|
||||
|
||||
18
src/Makefile
18
src/Makefile
@@ -53,6 +53,10 @@ ifeq ($(CHIP),stm32f103)
|
||||
CSRC += mcu-stm32f103.c
|
||||
endif
|
||||
|
||||
ifneq ($(USE_DFU),)
|
||||
OBJS_ADD += build/stdaln-sys-bin.o
|
||||
endif
|
||||
|
||||
###################################
|
||||
CC = $(CROSS)gcc
|
||||
LD = $(CROSS)gcc
|
||||
@@ -72,9 +76,19 @@ sys.c: board.h
|
||||
|
||||
build/bignum.o: OPT = -O3 -g
|
||||
|
||||
build/stdaln-sys.elf: build/sys-$(CHIP).o stdaln-sys.ld
|
||||
@echo
|
||||
$(LD) -v $< $(MCFLAGS) -nostartfiles -Tstdaln-sys.ld -Wl,--no-warn-mismatch,--gc-sections $(LLIBDIR) -o $@
|
||||
|
||||
build/stdaln-sys-bin.o: build/stdaln-sys.elf
|
||||
@echo
|
||||
$(OBJCOPY) -O binary -j .sys $< build/stdaln-sys.bin
|
||||
$(OBJCOPY) -I binary -O default --rename-section .data=.rodata \
|
||||
build/stdaln-sys.bin $@
|
||||
|
||||
distclean: clean
|
||||
-rm -f gnuk.ld config.h board.h config.mk \
|
||||
usb-strings.c.inc usb-vid-pid-ver.c.inc
|
||||
-rm -f gnuk.ld stdaln-sys.ld config.h board.h config.mk \
|
||||
usb-strings.c.inc put-vid-pid-ver.sh
|
||||
|
||||
ifeq ($(EMULATION),)
|
||||
build/gnuk.elf: build/gnuk-no-vidpid.elf binary-edit.sh put-vid-pid-ver.sh
|
||||
|
||||
39
src/ac.c
39
src/ac.c
@@ -63,7 +63,7 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
const uint8_t *ks_pw1, int save_ks)
|
||||
{
|
||||
int pw_len;
|
||||
int r1, r2;
|
||||
int r;
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *salt;
|
||||
int salt_len;
|
||||
@@ -99,21 +99,31 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
|
||||
|
||||
if (access == AC_PSO_CDS_AUTHORIZED)
|
||||
{
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
r2 = 0;
|
||||
}
|
||||
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
else
|
||||
{
|
||||
int r1, r2;
|
||||
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring);
|
||||
r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, keystring);
|
||||
|
||||
if (r1 < 0 || r2 < 0)
|
||||
r = -1;
|
||||
else if (r1 == 0)
|
||||
{
|
||||
if (r2 == 0)
|
||||
/* No encryption/authentication keys, then, check signing key. */
|
||||
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
else
|
||||
r = r2;
|
||||
}
|
||||
else if (r2 == 0)
|
||||
r = r1;
|
||||
else
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (r1 < 0 || r2 < 0
|
||||
|| (r1 == 0 && r2 == 0 && ks_pw1 != NULL
|
||||
&& ((ks_pw1[0] & PW_LEN_KEYSTRING_BIT) == 0
|
||||
|| memcmp (KS_GET_KEYSTRING (ks_pw1),
|
||||
keystring, KEYSTRING_MD_SIZE) != 0)))
|
||||
if (r < 0)
|
||||
{
|
||||
failure:
|
||||
gpg_pw_increment_err_counter (PW_ERR_PW1);
|
||||
@@ -163,7 +173,7 @@ verify_admin_00 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
const uint8_t *ks, int save_ks)
|
||||
{
|
||||
int pw_len;
|
||||
int r1, r2;
|
||||
int r;
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *salt;
|
||||
int salt_len;
|
||||
@@ -179,12 +189,11 @@ verify_admin_00 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
if (save_ks)
|
||||
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
|
||||
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring);
|
||||
r2 = 0;
|
||||
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring);
|
||||
|
||||
if (r1 < 0 || r2 < 0)
|
||||
if (r < 0)
|
||||
return -1;
|
||||
else if (r1 == 0 && r2 == 0)
|
||||
else if (r == 0)
|
||||
if ((ks[0] & PW_LEN_KEYSTRING_BIT) == 0
|
||||
|| memcmp (KS_GET_KEYSTRING (ks), keystring, KEYSTRING_MD_SIZE) != 0)
|
||||
return -1;
|
||||
|
||||
23
src/bn.c
23
src/bn.c
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* bn.c -- 256-bit (and 512-bit) bignum calculation
|
||||
*
|
||||
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
|
||||
* Copyright (C) 2011, 2013, 2014, 2019
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -412,17 +413,15 @@ bn256_cmp (const bn256 *A, const bn256 *B)
|
||||
void
|
||||
bn256_random (bn256 *X)
|
||||
{
|
||||
const uint8_t *rand = random_bytes_get ();
|
||||
int i, j;
|
||||
const uint8_t *rand;
|
||||
|
||||
X->word[7] = ((uint32_t *)rand)[7];
|
||||
X->word[6] = ((uint32_t *)rand)[6];
|
||||
X->word[5] = ((uint32_t *)rand)[5];
|
||||
X->word[4] = ((uint32_t *)rand)[4];
|
||||
X->word[3] = ((uint32_t *)rand)[3];
|
||||
X->word[2] = ((uint32_t *)rand)[2];
|
||||
X->word[1] = ((uint32_t *)rand)[1];
|
||||
X->word[0] = ((uint32_t *)rand)[0];
|
||||
|
||||
random_bytes_free (rand);
|
||||
for (i = 0; i < 256/256; i++)
|
||||
{
|
||||
rand = random_bytes_get ();
|
||||
for (j = 0; j < BN256_WORDS; j++)
|
||||
X->word[i*BN256_WORDS+j] = ((uint32_t *)rand)[j];
|
||||
random_bytes_free (rand);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
#define ENABLE_VIRTUAL_COM_PORT 1
|
||||
#endif
|
||||
@DFU_DEFINE@
|
||||
@ORIGIN_DEFINE@
|
||||
@ORIGIN_REAL_DEFINE@
|
||||
@PINPAD_DEFINE@
|
||||
@PINPAD_MORE_DEFINE@
|
||||
@CERTDO_DEFINE@
|
||||
@HID_CARD_CHANGE_DEFINE@
|
||||
@SERIALNO_STR_LEN_DEFINE@
|
||||
@LIFE_CYCLE_MANAGEMENT_DEFINE@
|
||||
@ACKBTN_DEFINE@
|
||||
@SERIALNO_STR_LEN_DEFINE@
|
||||
@KDF_DO_REQUIRED_DEFINE@
|
||||
|
||||
70
src/configure
vendored
70
src/configure
vendored
@@ -6,7 +6,7 @@ nl=$'\n'
|
||||
#
|
||||
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
|
||||
#
|
||||
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||
# Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2021
|
||||
# Free Software Initiative of Japan
|
||||
#
|
||||
# This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -36,15 +36,17 @@ fi
|
||||
# Default settings
|
||||
help=no
|
||||
vidpid=none
|
||||
target=FST_01
|
||||
target=ST_DONGLE
|
||||
with_dfu=default
|
||||
debug=no
|
||||
sys1_compat=yes
|
||||
pinpad=no
|
||||
certdo=no
|
||||
hid_card_change=no
|
||||
factory_reset=no
|
||||
factory_reset=yes
|
||||
ackbtn_support=yes
|
||||
flash_override=""
|
||||
kdf_do=${kdf_do:-optional}
|
||||
# For emulation
|
||||
prefix=/usr/local
|
||||
exec_prefix='${prefix}'
|
||||
@@ -135,6 +137,7 @@ Configuration:
|
||||
supported targets are:
|
||||
FST_01
|
||||
FST_01G
|
||||
FST_01SZ
|
||||
OLIMEX_STM32_H103
|
||||
MAPLE_MINI
|
||||
ST_DONGLE
|
||||
@@ -201,30 +204,35 @@ STBEE)
|
||||
BLUE_PILL_G)
|
||||
MHZ=96
|
||||
;;
|
||||
FST_01SZ)
|
||||
MHZ=96
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
def_mhz="-DMHZ=$MHZ"
|
||||
if test "$target" = "GNU_LINUX"; then
|
||||
ldscript=""
|
||||
chip="gnu-linux"
|
||||
arch="gnu-linux"
|
||||
emulation="yes"
|
||||
cross=""
|
||||
mcu="none"
|
||||
kdf_do=${kdf_do:-required}
|
||||
def_emulation="-DGNU_LINUX_EMULATION"
|
||||
def_memory_size="-DMEMORY_SIZE=1024"
|
||||
def_mhz=""
|
||||
enable_hexoutput=""
|
||||
libs="-lpthread"
|
||||
else
|
||||
ldscript="gnuk.ld"
|
||||
chip="stm32f103"
|
||||
arch="cortex-m"
|
||||
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
|
||||
@@ -255,6 +263,8 @@ else
|
||||
echo "Debug option disabled"
|
||||
fi
|
||||
|
||||
ORIGIN_REAL=0x08000000
|
||||
ORIGIN_REAL_DEFINE="#define ORIGIN_REAL $ORIGIN_REAL"
|
||||
# --with-dfu option
|
||||
if test "$with_dfu" = "yes"; then
|
||||
if test "$target" = "FST_01" -o "$target" = "FST_01G" \
|
||||
@@ -263,15 +273,23 @@ if test "$with_dfu" = "yes"; then
|
||||
exit 1
|
||||
fi
|
||||
echo "Configured for DFU"
|
||||
ORIGIN=0x08003000
|
||||
FLASH_SIZE=$((FLASH_SIZE - 12))
|
||||
if test "$target" = "MAPLE_MINI"; then
|
||||
# Note that the default bootloader is too large, need for instance
|
||||
# STM32duino for DFU on Maple Mini
|
||||
ORIGIN=0x08002000
|
||||
FLASH_SIZE=$((FLASH_SIZE - 8))
|
||||
else
|
||||
ORIGIN=0x08003000
|
||||
FLASH_SIZE=$((FLASH_SIZE - 12))
|
||||
fi
|
||||
DFU_DEFINE="#define DFU_SUPPORT 1"
|
||||
else
|
||||
with_dfu=no
|
||||
echo "Configured for bare system (no-DFU)"
|
||||
ORIGIN=0x08000000
|
||||
ORIGIN=${ORIGIN_REAL}
|
||||
DFU_DEFINE="#undef DFU_SUPPORT"
|
||||
fi
|
||||
ORIGIN_DEFINE="#define ORIGIN $ORIGIN"
|
||||
|
||||
# --enable-pinpad option
|
||||
if test "$pinpad" = "no"; then
|
||||
@@ -313,14 +331,31 @@ else
|
||||
echo "Life cycle management is NOT supported"
|
||||
fi
|
||||
|
||||
# Acknowledge button support
|
||||
if test "$ackbtn_support" = "yes"; then
|
||||
ACKBTN_DEFINE="#define ACKBTN_SUPPORT 1"
|
||||
echo "Acknowledge button is supported"
|
||||
else
|
||||
ACKBTN_DEFINE="#undef ACKBTN_SUPPORT"
|
||||
echo "Acknowledge button is not supported"
|
||||
fi
|
||||
|
||||
# KDF Data Object is always required for GNU/Linux emulation
|
||||
if test "$kdf_do" = "required"; then
|
||||
KDF_DO_REQUIRED_DEFINE="#define KDF_DO_REQUIRED 1"
|
||||
echo "KDF DO is required before key import/generation"
|
||||
else
|
||||
KDF_DO_REQUIRED_DEFINE="#undef KDF_DO_REQUIRED"
|
||||
fi
|
||||
|
||||
### !!! Replace following string of "FSIJ" to yours !!! ####
|
||||
SERIALNO="FSIJ-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
|
||||
SERIALNO="DTS-$(sed -e 's%^[^/]*/%%' <../VERSION)-"
|
||||
|
||||
SERIALNO_STR_LEN_DEFINE="#define SERIALNO_STR_LEN ${#SERIALNO}"
|
||||
|
||||
|
||||
if test "$sys1_compat" = "yes"; then
|
||||
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:factory_reset=$factory_reset"
|
||||
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:factory_reset=$factory_reset:kdf=$kdf_do"
|
||||
else
|
||||
if test "$with_dfu" = "yes"; then
|
||||
echo "Common binary can't support DFU loader, don't use --with-dfu." >&2
|
||||
@@ -330,7 +365,7 @@ else
|
||||
FLASH_PAGE_SIZE=2048
|
||||
FLASH_SIZE=128
|
||||
MEMORY_SIZE=20
|
||||
CONFIG="common:debug=$debug:pinpad=$pinpad:certdo=$certdo:factory_reset=$factory_reset"
|
||||
CONFIG="common:debug=$debug:pinpad=$pinpad:certdo=$certdo:factory_reset=$factory_reset:kdf=$kdf_do"
|
||||
fi
|
||||
|
||||
output_vid_pid_version () {
|
||||
@@ -446,6 +481,7 @@ fi
|
||||
|
||||
|
||||
(echo "CHIP=$chip";
|
||||
echo "ARCH=$arch";
|
||||
echo "EMULATION=$emulation";
|
||||
echo "CROSS=$cross";
|
||||
echo "MCU=$mcu";
|
||||
@@ -456,6 +492,12 @@ fi
|
||||
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"
|
||||
@@ -476,13 +518,19 @@ else
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
< gnuk.ld.in > gnuk.ld
|
||||
fi
|
||||
sed -e "s/@ORIGIN_REAL@/$ORIGIN_REAL/" -e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
|
||||
< stdaln-sys.ld.in > stdaln-sys.ld
|
||||
sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
|
||||
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
|
||||
-e "s/@ORIGIN_DEFINE@/$ORIGIN_DEFINE/" \
|
||||
-e "s/@ORIGIN_REAL_DEFINE@/$ORIGIN_REAL_DEFINE/" \
|
||||
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
|
||||
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
|
||||
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
|
||||
-e "s/@HID_CARD_CHANGE_DEFINE@/$HID_CARD_CHANGE_DEFINE/" \
|
||||
-e "s/@LIFE_CYCLE_MANAGEMENT_DEFINE@/$LIFE_CYCLE_MANAGEMENT_DEFINE/" \
|
||||
-e "s/@ACKBTN_DEFINE@/$ACKBTN_DEFINE/" \
|
||||
-e "s/@SERIALNO_STR_LEN_DEFINE@/$SERIALNO_STR_LEN_DEFINE/" \
|
||||
-e "s/@KDF_DO_REQUIRED_DEFINE@/$KDF_DO_REQUIRED_DEFINE/" \
|
||||
< config.h.in > config.h
|
||||
exit 0
|
||||
|
||||
10
src/flash.c
10
src/flash.c
@@ -71,7 +71,7 @@ static const uint8_t *data_pool;
|
||||
static uint8_t *last_p;
|
||||
|
||||
/* The first halfword is generation for the data page (little endian) */
|
||||
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
|
||||
const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
|
||||
0x00, 0x00, 0xff, 0xff
|
||||
};
|
||||
|
||||
@@ -82,10 +82,10 @@ extern uint8_t *flash_addr_data_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;
|
||||
#define FLASH_ADDR_KEY_STORAGE_START ((&_keystore_pool))
|
||||
#define FLASH_ADDR_DATA_STORAGE_START ((&_data_pool))
|
||||
extern uint8_t _keystore_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)
|
||||
|
||||
50
src/gnuk.h
50
src/gnuk.h
@@ -24,17 +24,18 @@ extern struct apdu apdu;
|
||||
void ccid_card_change_signal (int how);
|
||||
|
||||
/* CCID thread */
|
||||
#define EV_RX_DATA_READY 1 /* USB Rx data available */
|
||||
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */
|
||||
#define EV_TX_FINISHED 4 /* CCID Tx finished */
|
||||
#define EV_CARD_CHANGE 8
|
||||
#define EV_CARD_CHANGE 1
|
||||
#define EV_TX_FINISHED 2 /* CCID Tx finished */
|
||||
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
|
||||
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
|
||||
#define EV_RX_DATA_READY 16 /* USB Rx data available */
|
||||
|
||||
/* OpenPGPcard thread */
|
||||
#define EV_PINPAD_INPUT_DONE 1
|
||||
#define EV_EXIT 2
|
||||
#define EV_MODIFY_CMD_AVAILABLE 1
|
||||
#define EV_VERIFY_CMD_AVAILABLE 2
|
||||
#define EV_CMD_AVAILABLE 4
|
||||
#define EV_VERIFY_CMD_AVAILABLE 8
|
||||
#define EV_MODIFY_CMD_AVAILABLE 16
|
||||
#define EV_EXIT 8
|
||||
#define EV_PINPAD_INPUT_DONE 16
|
||||
|
||||
/* Maximum cmd apdu data is key import 24+4+256+256 (proc_key_import) */
|
||||
#define MAX_CMD_APDU_DATA_SIZE (24+4+256+256) /* without header */
|
||||
@@ -53,17 +54,17 @@ enum ccid_state {
|
||||
CCID_STATE_NOCARD, /* No card available */
|
||||
CCID_STATE_START, /* Initial */
|
||||
CCID_STATE_WAIT, /* Waiting APDU */
|
||||
/* Busy1, Busy2, Busy3, Busy5 */
|
||||
CCID_STATE_EXECUTE, /* Busy4 */
|
||||
CCID_STATE_RECEIVE, /* APDU Received Partially */
|
||||
CCID_STATE_SEND, /* APDU Sent Partially */
|
||||
|
||||
CCID_STATE_EXITED, /* ICC Thread Terminated */
|
||||
CCID_STATE_EXECUTE, /* Executing command */
|
||||
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
|
||||
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
|
||||
|
||||
CCID_STATE_EXITED, /* CCID Thread Terminated */
|
||||
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
|
||||
};
|
||||
|
||||
|
||||
extern enum ccid_state *const ccid_state_p;
|
||||
enum ccid_state ccid_get_ccid_state (void);
|
||||
|
||||
extern volatile uint8_t auth_status;
|
||||
#define AC_NONE_AUTHORIZED 0x00
|
||||
@@ -123,8 +124,8 @@ const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
|
||||
|
||||
enum kind_of_key {
|
||||
GPG_KEY_FOR_SIGNING = 0,
|
||||
GPG_KEY_FOR_DECRYPTION,
|
||||
GPG_KEY_FOR_AUTHENTICATION,
|
||||
GPG_KEY_FOR_DECRYPTION = 1,
|
||||
GPG_KEY_FOR_AUTHENTICATION = 2,
|
||||
};
|
||||
|
||||
enum size_of_key {
|
||||
@@ -296,6 +297,7 @@ void gpg_increment_digital_signature_counter (void);
|
||||
void gpg_do_get_initial_pw_setting (int is_pw3, int *r_len,
|
||||
const uint8_t **r_p);
|
||||
int gpg_do_kdf_check (int len, int how_many);
|
||||
int gpg_do_get_uif (enum kind_of_key kk);
|
||||
|
||||
|
||||
void fatal (uint8_t code) __attribute__ ((noreturn));
|
||||
@@ -378,7 +380,17 @@ extern uint8_t admin_authorized;
|
||||
#define NR_KEY_ALGO_ATTR_DEC 0xf2
|
||||
#define NR_KEY_ALGO_ATTR_AUT 0xf3
|
||||
/*
|
||||
* NR_UINT_SOMETHING could be here... Use 0xf[456789abcd]
|
||||
* Representation of User Interaction Flag:
|
||||
* 0 (UIF disabled): 0xf?00 or No record in flash memory
|
||||
* 1 (UIF enabled): 0xf?01
|
||||
* 2 (UIF permanently enabled): 0xf?02
|
||||
*
|
||||
*/
|
||||
#define NR_DO_UIF_SIG 0xf6
|
||||
#define NR_DO_UIF_DEC 0xf7
|
||||
#define NR_DO_UIF_AUT 0xf8
|
||||
/*
|
||||
* NR_UINT_SOMETHING could be here... Use 0xf[459abcd]
|
||||
*/
|
||||
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
||||
/*
|
||||
@@ -434,6 +446,7 @@ extern const uint8_t gnuk_string_serial[];
|
||||
#define LED_GNUK_EXEC 32
|
||||
#define LED_START_COMMAND 64
|
||||
#define LED_FINISH_COMMAND 128
|
||||
#define LED_WAIT_FOR_BUTTON 256
|
||||
#define LED_OFF LED_FINISH_COMMAND
|
||||
void led_blink (int spec);
|
||||
|
||||
@@ -461,6 +474,7 @@ int pinpad_getline (int msg_code, uint32_t timeout_usec);
|
||||
|
||||
#endif
|
||||
|
||||
extern uint8_t _regnual_start, __heap_end__[];
|
||||
|
||||
extern uint8_t _regnual_start[], __heap_end__[];
|
||||
|
||||
uint8_t * sram_address (uint32_t offset);
|
||||
|
||||
157
src/main.c
157
src/main.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* main.c - main routine of Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018, 2021
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -36,6 +36,11 @@
|
||||
#include "usb-cdc.h"
|
||||
#include "random.h"
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define main emulated_main
|
||||
@@ -51,6 +56,28 @@
|
||||
#define LED_TIMEOUT_ONE (100*1000)
|
||||
#define LED_TIMEOUT_STOP (200*1000)
|
||||
|
||||
#ifdef DFU_SUPPORT
|
||||
static int
|
||||
flash_write_any (uintptr_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (len)
|
||||
{
|
||||
uint16_t hw = *src++;
|
||||
|
||||
hw |= (*src++ << 8);
|
||||
status = flash_program_halfword (dst_addr, hw);
|
||||
if (status != 0)
|
||||
return 0; /* error return */
|
||||
|
||||
dst_addr += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
uint8_t *flash_addr_key_storage_start;
|
||||
@@ -68,7 +95,7 @@ device_initialize_once (void)
|
||||
* This is the first time invocation.
|
||||
* Setup serial number by unique device ID.
|
||||
*/
|
||||
const uint8_t *u = unique_device_id () + 8;
|
||||
const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
@@ -83,6 +110,55 @@ device_initialize_once (void)
|
||||
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
||||
flash_put_data_internal (&p[i*4+2], nibble);
|
||||
}
|
||||
|
||||
#ifdef DFU_SUPPORT
|
||||
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
|
||||
/*
|
||||
* Overwrite DFU bootloader with a copy of SYS linked to ORIGIN_REAL.
|
||||
* Then protect flash from readout.
|
||||
*/
|
||||
{
|
||||
extern uint8_t _binary_build_stdaln_sys_bin_start;
|
||||
extern uint8_t _binary_build_stdaln_sys_bin_size;
|
||||
size_t stdaln_sys_size = (size_t) &_binary_build_stdaln_sys_bin_size;
|
||||
extern const uint32_t FT0[256], FT1[256], FT2[256];
|
||||
extern handler vector_table[];
|
||||
uintptr_t addr;
|
||||
uint32_t flash_page_size = 1024; /* 1KiB default */
|
||||
|
||||
if (((*CHIP_ID_REG)&0x07) == 0x04) /* High density device. */
|
||||
flash_page_size = 2048; /* It's 2KiB. */
|
||||
|
||||
/* Kill DFU */
|
||||
for (addr = ORIGIN_REAL; addr < ORIGIN;
|
||||
addr += flash_page_size)
|
||||
flash_erase_page (addr);
|
||||
|
||||
/* Copy SYS */
|
||||
addr = ORIGIN_REAL;
|
||||
flash_write_any(addr, &_binary_build_stdaln_sys_bin_start,
|
||||
stdaln_sys_size);
|
||||
addr += stdaln_sys_size;
|
||||
flash_write_any(addr, (const uint8_t *) &FT0, sizeof(FT0));
|
||||
addr += sizeof(FT0);
|
||||
flash_write_any(addr, (const uint8_t *) &FT1, sizeof(FT1));
|
||||
addr += sizeof(FT1);
|
||||
flash_write_any(addr, (const uint8_t *) &FT2, sizeof(FT2));
|
||||
|
||||
addr = ORIGIN_REAL + 0x1000;
|
||||
if (addr < ORIGIN) {
|
||||
/* Need to patch top of stack and reset vector there */
|
||||
handler *new_vector = (handler *) addr;
|
||||
flash_write((uintptr_t) &new_vector[0], (const uint8_t *)
|
||||
&vector_table[0], sizeof(handler));
|
||||
flash_write((uintptr_t) &new_vector[1], (const uint8_t *)
|
||||
&vector[1], sizeof(handler));
|
||||
}
|
||||
|
||||
flash_protect();
|
||||
nvic_system_reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -146,7 +222,7 @@ emit_led (uint32_t on_time, uint32_t off_time)
|
||||
static void
|
||||
display_status_code (void)
|
||||
{
|
||||
enum ccid_state ccid_state = *ccid_state_p;
|
||||
enum ccid_state ccid_state = ccid_get_ccid_state ();
|
||||
uint32_t usec;
|
||||
|
||||
if (ccid_state == CCID_STATE_START)
|
||||
@@ -170,8 +246,7 @@ display_status_code (void)
|
||||
{
|
||||
usec = LED_TIMEOUT_INTERVAL;
|
||||
chopstx_poll (&usec, 1, led_event_poll);
|
||||
emit_led (ccid_state == CCID_STATE_RECEIVE?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
||||
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,6 +313,7 @@ main (int argc, const char *argv[])
|
||||
uintptr_t entry;
|
||||
#endif
|
||||
chopstx_t ccid_thd;
|
||||
int wait_for_ack = 0;
|
||||
|
||||
chopstx_conf_idle (1);
|
||||
|
||||
@@ -301,6 +377,34 @@ main (int argc, const char *argv[])
|
||||
else
|
||||
flash_image_path = argv[1];
|
||||
|
||||
if (access (flash_image_path, F_OK) < 0)
|
||||
{
|
||||
int fd;
|
||||
char buf[8192];
|
||||
|
||||
memset (buf, 0xff, sizeof buf);
|
||||
memset (buf+4*1024, 0, 2);
|
||||
fd = open (flash_image_path, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror ("creating flash file");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (write (fd, buf, sizeof buf) != sizeof buf)
|
||||
{
|
||||
perror ("initializing flash file");
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
puts ("Gnuk (emulation with USBIP), a GnuPG USB Token implementation");
|
||||
puts ("Copyright (C) 2021 Free Software Initiative of Japan");
|
||||
puts ("This is free software under GPLv3+.");
|
||||
|
||||
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;
|
||||
@@ -354,7 +458,11 @@ main (int argc, const char *argv[])
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
m = eventflag_wait (&led_event);
|
||||
if (wait_for_ack)
|
||||
m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL);
|
||||
else
|
||||
m = eventflag_wait (&led_event);
|
||||
|
||||
switch (m)
|
||||
{
|
||||
case LED_ONESHOT:
|
||||
@@ -375,8 +483,11 @@ main (int argc, const char *argv[])
|
||||
break;
|
||||
case LED_GNUK_EXEC:
|
||||
goto exec;
|
||||
case LED_WAIT_FOR_BUTTON:
|
||||
wait_for_ack ^= 1;
|
||||
/* fall through */
|
||||
default:
|
||||
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP);
|
||||
emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_ZERO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -392,29 +503,13 @@ main (int argc, const char *argv[])
|
||||
|
||||
#ifdef FLASH_UPGRADE_SUPPORT
|
||||
/* Set vector */
|
||||
SCB->VTOR = (uintptr_t)&_regnual_start;
|
||||
entry = calculate_regnual_entry_address (&_regnual_start);
|
||||
SCB->VTOR = (uintptr_t)_regnual_start;
|
||||
entry = calculate_regnual_entry_address (_regnual_start);
|
||||
#ifdef DFU_SUPPORT
|
||||
#define FLASH_SYS_START_ADDR 0x08000000
|
||||
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
|
||||
#define CHIP_ID_REG ((uint32_t *)0xE0042000)
|
||||
{
|
||||
extern uint8_t _sys;
|
||||
uintptr_t addr;
|
||||
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
|
||||
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
|
||||
uint32_t flash_page_size = 1024; /* 1KiB default */
|
||||
|
||||
if ((*CHIP_ID_REG)&0x07 == 0x04) /* High dencity device. */
|
||||
flash_page_size = 2048; /* It's 2KiB. */
|
||||
|
||||
/* Kill DFU */
|
||||
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
|
||||
addr += flash_page_size)
|
||||
flash_erase_page (addr);
|
||||
|
||||
/* copy system service routines */
|
||||
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
|
||||
/* Use SYS at ORIGIN_REAL instead of the one at ORIGIN */
|
||||
handler *new_vector = (handler *)ORIGIN_REAL;
|
||||
void (*func) (void (*)(void)) = (void (*)(void (*)(void))) new_vector[9];
|
||||
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
(*func) ((void (*)(void))entry);
|
||||
@@ -501,11 +596,11 @@ gnuk_malloc_init (void)
|
||||
}
|
||||
|
||||
static void *
|
||||
sbrk (size_t size)
|
||||
gnuk_sbrk (intptr_t size)
|
||||
{
|
||||
void *p = (void *)heap_p;
|
||||
|
||||
if ((size_t)(HEAP_END - heap_p) < size)
|
||||
if ((HEAP_END - heap_p) < size)
|
||||
return NULL;
|
||||
|
||||
heap_p += size;
|
||||
@@ -541,7 +636,7 @@ gnuk_malloc (size_t size)
|
||||
{
|
||||
if (m == NULL)
|
||||
{
|
||||
m = (struct mem_head *)sbrk (size);
|
||||
m = (struct mem_head *)gnuk_sbrk (size);
|
||||
if (m)
|
||||
m->size = size;
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* modp256k1.c -- modulo arithmetic for p256k1
|
||||
*
|
||||
* Copyright (C) 2014, 2016 Free Software Initiative of Japan
|
||||
* Copyright (C) 2014, 2016, 2020 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -71,14 +71,12 @@ modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
{
|
||||
uint32_t cond;
|
||||
bn256 tmp[1];
|
||||
bn256 dummy[1];
|
||||
|
||||
cond = (bn256_add (X, A, B) == 0);
|
||||
cond &= bn256_sub (tmp, X, P256K1);
|
||||
if (cond)
|
||||
/* No-carry AND borrow */
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
else
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
memcpy (cond?dummy:X, tmp, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,13 +87,12 @@ modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
{
|
||||
uint32_t borrow;
|
||||
bn256 tmp[1];
|
||||
bn256 dummy[1];
|
||||
|
||||
borrow = bn256_sub (X, A, B);
|
||||
bn256_add (tmp, X, P256K1);
|
||||
if (borrow)
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
else
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
memcpy (borrow?X:dummy, tmp, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* modp256r1.c -- modulo arithmetic for p256r1
|
||||
*
|
||||
* Copyright (C) 2011, 2013, 2014, 2016
|
||||
* Copyright (C) 2011, 2013, 2014, 2016, 2020
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -66,14 +66,12 @@ modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
{
|
||||
uint32_t cond;
|
||||
bn256 tmp[1];
|
||||
bn256 dummy[1];
|
||||
|
||||
cond = (bn256_add (X, A, B) == 0);
|
||||
cond &= bn256_sub (tmp, X, P256R1);
|
||||
if (cond)
|
||||
/* No-carry AND borrow */
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
else
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
memcpy (cond?dummy:X, tmp, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,13 +82,12 @@ modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B)
|
||||
{
|
||||
uint32_t borrow;
|
||||
bn256 tmp[1];
|
||||
bn256 dummy[1];
|
||||
|
||||
borrow = bn256_sub (X, A, B);
|
||||
bn256_add (tmp, X, P256R1);
|
||||
if (borrow)
|
||||
memcpy (X, tmp, sizeof (bn256));
|
||||
else
|
||||
memcpy (tmp, tmp, sizeof (bn256));
|
||||
memcpy (borrow?X:dummy, tmp, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +97,7 @@ void
|
||||
modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
{
|
||||
bn256 tmp[1], tmp0[1];
|
||||
bn256 dummy[1];
|
||||
uint32_t borrow;
|
||||
|
||||
#define S1 X
|
||||
@@ -121,10 +119,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S1->word[1] = A->word[1];
|
||||
S1->word[0] = A->word[0];
|
||||
borrow = bn256_sub (tmp0, S1, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S1, tmp0, sizeof (bn256));
|
||||
memcpy (borrow?dummy:S1, tmp0, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
/* X = S1 */
|
||||
|
||||
S2->word[7] = A->word[15];
|
||||
@@ -165,10 +161,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S5->word[1] = A->word[10];
|
||||
S5->word[0] = A->word[9];
|
||||
borrow = bn256_sub (tmp0, S5, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S5, tmp0, sizeof (bn256));
|
||||
memcpy (borrow?dummy:S5, tmp0, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
/* X += S5 */
|
||||
modp256r1_add (X, X, S5);
|
||||
|
||||
@@ -179,10 +173,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S6->word[1] = A->word[12];
|
||||
S6->word[0] = A->word[11];
|
||||
borrow = bn256_sub (tmp0, S6, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S6, tmp0, sizeof (bn256));
|
||||
memcpy (borrow?dummy:S6, tmp0, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
/* X -= S6 */
|
||||
modp256r1_sub (X, X, S6);
|
||||
|
||||
@@ -194,10 +186,8 @@ modp256r1_reduce (bn256 *X, const bn512 *A)
|
||||
S7->word[1] = A->word[13];
|
||||
S7->word[0] = A->word[12];
|
||||
borrow = bn256_sub (tmp0, S7, P256R1);
|
||||
if (borrow)
|
||||
memcpy (tmp0, tmp0, sizeof (bn256));
|
||||
else
|
||||
memcpy (S7, tmp0, sizeof (bn256));
|
||||
memcpy (borrow?dummy:S7, tmp0, sizeof (bn256));
|
||||
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
|
||||
/* X -= S7 */
|
||||
modp256r1_sub (X, X, S7);
|
||||
|
||||
|
||||
195
src/openpgp-do.c
195
src/openpgp-do.c
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
|
||||
* 2020
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -135,6 +136,14 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
|
||||
0x01, 0x00,
|
||||
};
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
/* General Feature Management */
|
||||
static const uint8_t feature_mngmnt[] __attribute__ ((aligned (1))) = {
|
||||
3,
|
||||
0x81, 0x01, 0x20,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Algorithm Attributes */
|
||||
#define OPENPGP_ALGO_RSA 0x01
|
||||
#define OPENPGP_ALGO_ECDH 0x12
|
||||
@@ -458,6 +467,7 @@ static const struct do_table_entry *get_do_entry (uint16_t tag);
|
||||
#define GPG_DO_UIF_DEC 0x00d7
|
||||
#define GPG_DO_UIF_AUT 0x00d8
|
||||
#define GPG_DO_KDF 0x00f9
|
||||
#define GPG_DO_ALG_INFO 0x00fa
|
||||
#define GPG_DO_KEY_IMPORT 0x3fff
|
||||
#define GPG_DO_LANGUAGE 0x5f2d
|
||||
#define GPG_DO_SEX 0x5f35
|
||||
@@ -524,7 +534,7 @@ copy_tag (uint16_t tag)
|
||||
#define SIZE_FP 20
|
||||
#define SIZE_KGTIME 4
|
||||
|
||||
static int
|
||||
static void
|
||||
do_fp_all (uint16_t tag, int with_tag)
|
||||
{
|
||||
const uint8_t *data;
|
||||
@@ -555,10 +565,9 @@ do_fp_all (uint16_t tag, int with_tag)
|
||||
else
|
||||
memset (res_p, 0, SIZE_FP);
|
||||
res_p += SIZE_FP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_cafp_all (uint16_t tag, int with_tag)
|
||||
{
|
||||
const uint8_t *data;
|
||||
@@ -589,10 +598,9 @@ do_cafp_all (uint16_t tag, int with_tag)
|
||||
else
|
||||
memset (res_p, 0, SIZE_FP);
|
||||
res_p += SIZE_FP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_kgtime_all (uint16_t tag, int with_tag)
|
||||
{
|
||||
const uint8_t *data;
|
||||
@@ -623,7 +631,6 @@ do_kgtime_all (uint16_t tag, int with_tag)
|
||||
else
|
||||
memset (res_p, 0, SIZE_KGTIME);
|
||||
res_p += SIZE_KGTIME;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint8_t openpgpcard_aid[] = {
|
||||
@@ -635,7 +642,7 @@ const uint8_t openpgpcard_aid[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
|
||||
};
|
||||
|
||||
static int
|
||||
static void
|
||||
do_openpgpcard_aid (uint16_t tag, int with_tag)
|
||||
{
|
||||
const volatile uint8_t *p = openpgpcard_aid;
|
||||
@@ -649,7 +656,7 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
|
||||
|
||||
if (vid == 0xffff || vid == 0x0000)
|
||||
{
|
||||
const uint8_t *u = unique_device_id () + 8;
|
||||
const uint8_t *u = unique_device_id () + (MHZ < 96 ? 8: 0);
|
||||
|
||||
memcpy (res_p, openpgpcard_aid, 8);
|
||||
res_p += 8;
|
||||
@@ -671,11 +678,9 @@ do_openpgpcard_aid (uint16_t tag, int with_tag)
|
||||
|
||||
*res_p++ = 0;
|
||||
*res_p++ = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
do_ds_count (uint16_t tag, int with_tag)
|
||||
{
|
||||
if (with_tag)
|
||||
@@ -687,7 +692,37 @@ do_ds_count (uint16_t tag, int with_tag)
|
||||
*res_p++ = (digital_signature_counter >> 16) & 0xff;
|
||||
*res_p++ = (digital_signature_counter >> 8) & 0xff;
|
||||
*res_p++ = digital_signature_counter & 0xff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
do_alg_info (uint16_t tag, int with_tag)
|
||||
{
|
||||
uint8_t *len_p = NULL;
|
||||
int i;
|
||||
|
||||
if (with_tag)
|
||||
{
|
||||
copy_tag (tag);
|
||||
len_p = res_p;
|
||||
*res_p++ = 0; /* Filled later, assuming length is <= 127 */
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
uint16_t tag_algo = GPG_DO_ALG_SIG + i;
|
||||
|
||||
copy_do_1 (tag_algo, algorithm_attr_rsa2k, 1);
|
||||
copy_do_1 (tag_algo, algorithm_attr_rsa4k, 1);
|
||||
copy_do_1 (tag_algo, algorithm_attr_p256r1, 1);
|
||||
copy_do_1 (tag_algo, algorithm_attr_p256k1, 1);
|
||||
if (i == 0 || i == 2)
|
||||
copy_do_1 (tag_algo, algorithm_attr_ed25519, 1);
|
||||
if (i == 1)
|
||||
copy_do_1 (tag_algo, algorithm_attr_cv25519, 1);
|
||||
};
|
||||
|
||||
if (len_p)
|
||||
*len_p = res_p - len_p - 1; /* Actually, it's 127-byte long. */
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -780,6 +815,8 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
|
||||
else if (algo == ALGO_RSA2K && *algo_attr_pp != NULL)
|
||||
{
|
||||
gpg_reset_algo_attr (kk);
|
||||
/* Read it again, since GC may occur. */
|
||||
algo_attr_pp = get_algo_attr_pointer (kk);
|
||||
flash_enum_clear (algo_attr_pp);
|
||||
if (*algo_attr_pp != NULL)
|
||||
return 0;
|
||||
@@ -788,6 +825,10 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
|
||||
(*algo_attr_pp != NULL && (*algo_attr_pp)[1] != algo))
|
||||
{
|
||||
gpg_reset_algo_attr (kk);
|
||||
/* Read it again, since GC may occur. */
|
||||
algo_attr_pp = get_algo_attr_pointer (kk);
|
||||
if (*algo_attr_pp)
|
||||
flash_enum_clear (algo_attr_pp);
|
||||
*algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo);
|
||||
if (*algo_attr_pp == NULL)
|
||||
return 0;
|
||||
@@ -807,6 +848,64 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t uif_flags; /* Six bits of flags */
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
int
|
||||
gpg_do_get_uif (enum kind_of_key kk)
|
||||
{
|
||||
return ((uif_flags >> (kk * 2)) & 3) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rw_uif (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
|
||||
{
|
||||
uint8_t nr;
|
||||
int v;
|
||||
|
||||
if (tag != GPG_DO_UIF_SIG && tag != GPG_DO_UIF_DEC && tag != GPG_DO_UIF_AUT)
|
||||
return 0; /* Failure */
|
||||
|
||||
nr = (tag - GPG_DO_UIF_SIG) + NR_DO_UIF_SIG;
|
||||
v = (uif_flags >> ((tag - GPG_DO_UIF_SIG) * 2)) & 3;
|
||||
if (is_write)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
if (len != 2 || data[1] != 0x20)
|
||||
return 0;
|
||||
|
||||
if (v == 2)
|
||||
return 0;
|
||||
|
||||
if (data[0] != 0x00 && data[0] != 0x01 && data[0] != 0x02)
|
||||
return 0;
|
||||
|
||||
p = flash_enum_write (nr, data[0]);
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
|
||||
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
|
||||
uif_flags |= (data[0] & 3) << ((nr - NR_DO_UIF_SIG) * 2);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (with_tag)
|
||||
{
|
||||
copy_tag (tag);
|
||||
*res_p++ = 2;
|
||||
}
|
||||
|
||||
*res_p++ = v;
|
||||
*res_p++ = 0x20;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define SIZE_OF_KDF_DO_MIN 90
|
||||
#define SIZE_OF_KDF_DO_MAX 110
|
||||
#define OPENPGP_KDF_ITERSALTED_S2K 3
|
||||
@@ -893,11 +992,25 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check LEN is valid for HOW_MANY of passphrase string.
|
||||
*
|
||||
* HOW_MANY = 1: LEN is valid for a single passphrase string.
|
||||
* HOW_MANY = 2: LEN is valid for two single passphrase strings.
|
||||
* This is used to change passphrase.
|
||||
* The second passphrase may be nothing.
|
||||
*
|
||||
* LEN = 0: Check if KDF-DO is available.
|
||||
*/
|
||||
int
|
||||
gpg_do_kdf_check (int len, int how_many)
|
||||
{
|
||||
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
|
||||
|
||||
if (len == 0)
|
||||
return kdf_do != NULL;
|
||||
|
||||
if (kdf_do)
|
||||
{
|
||||
const uint8_t *kdf_spec = kdf_do+1;
|
||||
@@ -1505,6 +1618,13 @@ proc_key_import (const uint8_t *data, int len)
|
||||
const uint8_t *p = data;
|
||||
uint8_t pubkey[512];
|
||||
|
||||
#ifdef KDF_DO_REQUIRED
|
||||
const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
|
||||
|
||||
if (kdf_do == NULL)
|
||||
return 0; /* Error. */
|
||||
#endif
|
||||
|
||||
if (admin_authorized == BY_ADMIN)
|
||||
keystring_admin = keystring_md_pw3;
|
||||
else
|
||||
@@ -1614,18 +1734,32 @@ static const uint16_t cmp_ch_data[] = {
|
||||
};
|
||||
|
||||
static const uint16_t cmp_app_data[] = {
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
4,
|
||||
#else
|
||||
3,
|
||||
#endif
|
||||
GPG_DO_AID,
|
||||
GPG_DO_HIST_BYTES,
|
||||
GPG_DO_DISCRETIONARY,
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
GPG_DO_FEATURE_MNGMNT,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const uint16_t cmp_discretionary[] = {
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
11,
|
||||
#else
|
||||
8,
|
||||
#endif
|
||||
GPG_DO_EXTCAP,
|
||||
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
|
||||
GPG_DO_PW_STATUS,
|
||||
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL
|
||||
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL,
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT
|
||||
#endif
|
||||
};
|
||||
|
||||
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
|
||||
@@ -1655,6 +1789,7 @@ gpg_do_table[] = {
|
||||
/* Pseudo DO READ: calculated, not changeable by user */
|
||||
{ GPG_DO_DS_COUNT, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_ds_count },
|
||||
{ GPG_DO_AID, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_openpgpcard_aid },
|
||||
{ GPG_DO_ALG_INFO, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_alg_info },
|
||||
/* Pseudo DO READ/WRITE: calculated */
|
||||
{ GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||
rw_pw_status },
|
||||
@@ -1664,11 +1799,19 @@ gpg_do_table[] = {
|
||||
rw_algorithm_attr },
|
||||
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||
rw_algorithm_attr },
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
{ GPG_DO_UIF_SIG, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||
{ GPG_DO_UIF_DEC, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||
{ GPG_DO_UIF_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||
#endif
|
||||
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||
rw_kdf },
|
||||
/* Fixed data */
|
||||
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
|
||||
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
{ GPG_DO_FEATURE_MNGMNT, DO_FIXED, AC_ALWAYS, AC_NEVER, feature_mngmnt },
|
||||
#endif
|
||||
/* Compound data: Read access only */
|
||||
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
|
||||
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
|
||||
@@ -1707,6 +1850,11 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
|
||||
pw_err_counter_p[PW_ERR_PW3] = NULL;
|
||||
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
|
||||
digital_signature_counter = 0;
|
||||
uif_flags = 0;
|
||||
|
||||
/* Clear all data objects. */
|
||||
for (i = 0; i < NR_DO__LAST__; i++)
|
||||
do_ptr[i] = NULL;
|
||||
|
||||
/* When the card is terminated no data objects are valid. */
|
||||
if (do_start == NULL)
|
||||
@@ -1765,6 +1913,13 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end)
|
||||
algo_attr_aut_p = p - 1;
|
||||
p++;
|
||||
break;
|
||||
case NR_DO_UIF_SIG:
|
||||
case NR_DO_UIF_DEC:
|
||||
case NR_DO_UIF_AUT:
|
||||
uif_flags &= ~(3 << ((nr - NR_DO_UIF_SIG) * 2));
|
||||
uif_flags |= (second_byte & 3) << ((nr - NR_DO_UIF_SIG) * 2);
|
||||
p++;
|
||||
break;
|
||||
case NR_COUNTER_123:
|
||||
p++;
|
||||
if (second_byte <= PW_ERR_PW3)
|
||||
@@ -1864,6 +2019,13 @@ gpg_data_copy (const uint8_t *p_start)
|
||||
p += 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if ((v = (uif_flags >> (i * 2)) & 3))
|
||||
{
|
||||
flash_enum_write_internal (p, NR_DO_UIF_SIG + i, v);
|
||||
p += 2;
|
||||
}
|
||||
|
||||
data_objects_number_of_bytes = 0;
|
||||
for (i = 0; i < NR_DO__LAST__; i++)
|
||||
if (do_ptr[i] != NULL)
|
||||
@@ -1977,9 +2139,10 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
|
||||
}
|
||||
case DO_PROC_READ:
|
||||
{
|
||||
int (*do_func)(uint16_t, int) = (int (*)(uint16_t, int))do_p->obj;
|
||||
void (*do_func)(uint16_t, int) = (void (*)(uint16_t, int))do_p->obj;
|
||||
|
||||
return do_func (do_p->tag, with_tag);
|
||||
do_func (do_p->tag, with_tag);
|
||||
return 1;
|
||||
}
|
||||
case DO_PROC_READWRITE:
|
||||
{
|
||||
|
||||
119
src/openpgp.c
119
src/openpgp.c
@@ -2,6 +2,7 @@
|
||||
* openpgp.c -- OpenPGP card protocol support
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* 2019
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -145,7 +146,7 @@ get_pinpad_input (int msg_code)
|
||||
#endif
|
||||
|
||||
static void
|
||||
cmd_verify (void)
|
||||
cmd_verify (struct eventflag *ccid_comm)
|
||||
{
|
||||
int len;
|
||||
uint8_t p1 = P1 (apdu);
|
||||
@@ -153,6 +154,7 @@ cmd_verify (void)
|
||||
int r;
|
||||
const uint8_t *pw;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - VERIFY\r\n");
|
||||
DEBUG_BYTE (p2);
|
||||
|
||||
@@ -275,7 +277,7 @@ gpg_change_keystring (int who_old, const uint8_t *old_ks,
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_change_password (void)
|
||||
cmd_change_password (struct eventflag *ccid_comm)
|
||||
{
|
||||
uint8_t old_ks[KEYSTRING_MD_SIZE];
|
||||
uint8_t new_ks0[KEYSTRING_SIZE];
|
||||
@@ -295,6 +297,7 @@ cmd_change_password (void)
|
||||
int salt_len;
|
||||
const uint8_t *ks_pw3;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO ("Change PW\r\n");
|
||||
DEBUG_BYTE (who);
|
||||
|
||||
@@ -547,7 +550,7 @@ s2k (const unsigned char *salt, size_t slen,
|
||||
|
||||
|
||||
static void
|
||||
cmd_reset_user_password (void)
|
||||
cmd_reset_user_password (struct eventflag *ccid_comm)
|
||||
{
|
||||
uint8_t p1 = P1 (apdu);
|
||||
int len;
|
||||
@@ -558,9 +561,11 @@ cmd_reset_user_password (void)
|
||||
uint8_t new_ks0[KEYSTRING_SIZE];
|
||||
uint8_t *new_ks = KS_GET_KEYSTRING (new_ks0);
|
||||
uint8_t *new_salt = KS_GET_SALT (new_ks0);
|
||||
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
||||
const uint8_t *salt;
|
||||
int salt_len;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO ("Reset PW1\r\n");
|
||||
DEBUG_BYTE (p1);
|
||||
|
||||
@@ -571,7 +576,6 @@ cmd_reset_user_password (void)
|
||||
{
|
||||
const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
|
||||
uint8_t old_ks[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
||||
|
||||
if (gpg_do_kdf_check (len, 2) == 0)
|
||||
{
|
||||
@@ -661,6 +665,16 @@ cmd_reset_user_password (void)
|
||||
|
||||
newpw_len = len;
|
||||
newpw = pw;
|
||||
|
||||
/* Check length of new password */
|
||||
if ((ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN)
|
||||
|| newpw_len < USER_PASSWD_MINLEN)
|
||||
{
|
||||
DEBUG_INFO ("new password length is too short.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
random_get_salt (new_salt);
|
||||
s2k (new_salt, SALT_SIZE, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
@@ -695,12 +709,13 @@ cmd_reset_user_password (void)
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_put_data (void)
|
||||
cmd_put_data (struct eventflag *ccid_comm)
|
||||
{
|
||||
uint8_t *data;
|
||||
uint16_t tag;
|
||||
int len;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - PUT DATA\r\n");
|
||||
|
||||
tag = ((P1 (apdu)<<8) | P2 (apdu));
|
||||
@@ -710,8 +725,9 @@ cmd_put_data (void)
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_pgp_gakp (void)
|
||||
cmd_pgp_gakp (struct eventflag *ccid_comm)
|
||||
{
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
|
||||
DEBUG_BYTE (P1 (apdu));
|
||||
|
||||
@@ -722,7 +738,12 @@ cmd_pgp_gakp (void)
|
||||
{
|
||||
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
|
||||
GPG_SECURITY_FAILURE ();
|
||||
gpg_do_keygen (&apdu.cmd_apdu_data[0]);
|
||||
#ifdef KDF_DO_REQUIRED
|
||||
else if (!gpg_do_kdf_check (0, 0))
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
#endif
|
||||
else
|
||||
gpg_do_keygen (&apdu.cmd_apdu_data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,10 +751,10 @@ cmd_pgp_gakp (void)
|
||||
const uint8_t *
|
||||
gpg_get_firmware_update_key (uint8_t keyno)
|
||||
{
|
||||
extern uint8_t _updatekey_store;
|
||||
extern uint8_t _updatekey_store[1024];
|
||||
const uint8_t *p;
|
||||
|
||||
p = &_updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
|
||||
p = _updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
@@ -745,12 +766,13 @@ gpg_get_firmware_update_key (uint8_t keyno)
|
||||
#endif
|
||||
|
||||
static void
|
||||
cmd_read_binary (void)
|
||||
cmd_read_binary (struct eventflag *ccid_comm)
|
||||
{
|
||||
int is_short_EF = (P1 (apdu) & 0x80) != 0;
|
||||
uint8_t file_id;
|
||||
uint16_t offset;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - Read binary\r\n");
|
||||
|
||||
if (is_short_EF)
|
||||
@@ -821,8 +843,9 @@ cmd_read_binary (void)
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_select_file (void)
|
||||
cmd_select_file (struct eventflag *ccid_comm)
|
||||
{
|
||||
(void)ccid_comm;
|
||||
if (P1 (apdu) == 4) /* Selection by DF name */
|
||||
{
|
||||
DEBUG_INFO (" - select DF by name\r\n");
|
||||
@@ -891,10 +914,11 @@ cmd_select_file (void)
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_get_data (void)
|
||||
cmd_get_data (struct eventflag *ccid_comm)
|
||||
{
|
||||
uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu));
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - Get Data\r\n");
|
||||
|
||||
gpg_do_get_data (tag, 0);
|
||||
@@ -909,7 +933,7 @@ cmd_get_data (void)
|
||||
#define ECC_CIPHER_DO_HEADER_SIZE 7
|
||||
|
||||
static void
|
||||
cmd_pso (void)
|
||||
cmd_pso (struct eventflag *ccid_comm)
|
||||
{
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
int r = -1;
|
||||
@@ -936,6 +960,11 @@ cmd_pso (void)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING))
|
||||
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||
#endif
|
||||
|
||||
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
||||
{
|
||||
/* Check size of digestInfo */
|
||||
@@ -981,13 +1010,6 @@ cmd_pso (void)
|
||||
{
|
||||
uint32_t output[64/4]; /* Require 4-byte alignment. */
|
||||
|
||||
if (len > EDDSA_HASH_LEN_MAX)
|
||||
{
|
||||
DEBUG_INFO ("wrong hash length.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
cs = chopstx_setcancelstate (0);
|
||||
result_len = EDDSA_SIGNATURE_LENGTH;
|
||||
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
|
||||
@@ -1027,6 +1049,13 @@ cmd_pso (void)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
if (gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION))
|
||||
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||
#else
|
||||
(void)ccid_comm;
|
||||
#endif
|
||||
|
||||
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
||||
{
|
||||
/* Skip padding 0x00 */
|
||||
@@ -1103,7 +1132,7 @@ cmd_pso (void)
|
||||
|
||||
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
|
||||
static void
|
||||
cmd_internal_authenticate (void)
|
||||
cmd_internal_authenticate (struct eventflag *ccid_comm)
|
||||
{
|
||||
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
|
||||
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
|
||||
@@ -1133,6 +1162,13 @@ cmd_internal_authenticate (void)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
if (gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
|
||||
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||
#else
|
||||
(void)ccid_comm;
|
||||
#endif
|
||||
|
||||
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
|
||||
{
|
||||
if (len > MAX_RSA_DIGEST_INFO_LEN)
|
||||
@@ -1180,13 +1216,6 @@ cmd_internal_authenticate (void)
|
||||
{
|
||||
uint32_t output[64/4]; /* Require 4-byte alignment. */
|
||||
|
||||
if (len > EDDSA_HASH_LEN_MAX)
|
||||
{
|
||||
DEBUG_INFO ("wrong hash length.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
cs = chopstx_setcancelstate (0);
|
||||
result_len = EDDSA_SIGNATURE_LENGTH;
|
||||
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
|
||||
@@ -1309,10 +1338,11 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
|
||||
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
static void
|
||||
cmd_update_binary (void)
|
||||
cmd_update_binary (struct eventflag *ccid_comm)
|
||||
{
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - UPDATE BINARY\r\n");
|
||||
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
|
||||
DEBUG_INFO ("UPDATE BINARY done.\r\n");
|
||||
@@ -1321,10 +1351,11 @@ cmd_update_binary (void)
|
||||
|
||||
|
||||
static void
|
||||
cmd_write_binary (void)
|
||||
cmd_write_binary (struct eventflag *ccid_comm)
|
||||
{
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - WRITE BINARY\r\n");
|
||||
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
|
||||
DEBUG_INFO ("WRITE BINARY done.\r\n");
|
||||
@@ -1333,7 +1364,7 @@ cmd_write_binary (void)
|
||||
|
||||
#ifdef FLASH_UPGRADE_SUPPORT
|
||||
static void
|
||||
cmd_external_authenticate (void)
|
||||
cmd_external_authenticate (struct eventflag *ccid_comm)
|
||||
{
|
||||
const uint8_t *pubkey;
|
||||
const uint8_t *signature = apdu.cmd_apdu_data;
|
||||
@@ -1341,6 +1372,7 @@ cmd_external_authenticate (void)
|
||||
uint8_t keyno = P2 (apdu);
|
||||
int r;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
|
||||
|
||||
if (keyno >= 4)
|
||||
@@ -1376,10 +1408,11 @@ cmd_external_authenticate (void)
|
||||
#endif
|
||||
|
||||
static void
|
||||
cmd_get_challenge (void)
|
||||
cmd_get_challenge (struct eventflag *ccid_comm)
|
||||
{
|
||||
int len = apdu.expected_res_size;
|
||||
|
||||
(void)ccid_comm;
|
||||
DEBUG_INFO (" - GET CHALLENGE\r\n");
|
||||
|
||||
if (len > CHALLENGE_LEN)
|
||||
@@ -1394,6 +1427,13 @@ cmd_get_challenge (void)
|
||||
if (challenge)
|
||||
random_bytes_free (challenge);
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
if (gpg_do_get_uif (GPG_KEY_FOR_SIGNING)
|
||||
|| gpg_do_get_uif (GPG_KEY_FOR_DECRYPTION)
|
||||
|| gpg_do_get_uif (GPG_KEY_FOR_AUTHENTICATION))
|
||||
eventflag_signal (ccid_comm, EV_EXEC_ACK_REQUIRED);
|
||||
#endif
|
||||
|
||||
challenge = random_bytes_get ();
|
||||
memcpy (res_APDU, challenge, len);
|
||||
res_APDU_size = len;
|
||||
@@ -1404,8 +1444,9 @@ cmd_get_challenge (void)
|
||||
|
||||
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
|
||||
static void
|
||||
cmd_activate_file (void)
|
||||
cmd_activate_file (struct eventflag *ccid_comm)
|
||||
{
|
||||
(void)ccid_comm;
|
||||
if (file_selection != FILE_CARD_TERMINATED)
|
||||
{
|
||||
GPG_NO_RECORD ();
|
||||
@@ -1418,13 +1459,13 @@ cmd_activate_file (void)
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_terminate_df (void)
|
||||
cmd_terminate_df (struct eventflag *ccid_comm)
|
||||
{
|
||||
const uint8_t *ks_pw3;
|
||||
|
||||
uint8_t p1 = P1 (apdu);
|
||||
uint8_t p2 = P2 (apdu);
|
||||
|
||||
(void)ccid_comm;
|
||||
if (file_selection != FILE_DF_OPENPGP)
|
||||
{
|
||||
GPG_NO_RECORD ();
|
||||
@@ -1468,7 +1509,7 @@ cmd_terminate_df (void)
|
||||
struct command
|
||||
{
|
||||
uint8_t command;
|
||||
void (*cmd_handler) (void);
|
||||
void (*cmd_handler) (struct eventflag *ccid_comm);
|
||||
};
|
||||
|
||||
const struct command cmds[] = {
|
||||
@@ -1502,7 +1543,7 @@ const struct command cmds[] = {
|
||||
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
|
||||
|
||||
static void
|
||||
process_command_apdu (void)
|
||||
process_command_apdu (struct eventflag *ccid_comm)
|
||||
{
|
||||
int i;
|
||||
uint8_t cmd = INS (apdu);
|
||||
@@ -1526,7 +1567,7 @@ process_command_apdu (void)
|
||||
else
|
||||
{
|
||||
chopstx_setcancelstate (1);
|
||||
cmds[i].cmd_handler ();
|
||||
cmds[i].cmd_handler (ccid_comm);
|
||||
chopstx_setcancelstate (0);
|
||||
}
|
||||
}
|
||||
@@ -1640,7 +1681,7 @@ openpgp_card_thread (void *arg)
|
||||
break;
|
||||
|
||||
led_blink (LED_START_COMMAND);
|
||||
process_command_apdu ();
|
||||
process_command_apdu (ccid_comm);
|
||||
led_blink (LED_FINISH_COMMAND);
|
||||
done:
|
||||
eventflag_signal (ccid_comm, EV_EXEC_FINISHED);
|
||||
|
||||
@@ -986,6 +986,7 @@ tim_main (void *arg)
|
||||
{
|
||||
chopstx_intr_wait (&interrupt);
|
||||
cir_timer_interrupt ();
|
||||
chopstx_intr_done (&interrupt);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -1006,6 +1007,7 @@ ext_main (void *arg)
|
||||
{
|
||||
chopstx_intr_wait (&interrupt);
|
||||
cir_ext_interrupt ();
|
||||
chopstx_intr_done (&interrupt);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#define SIZE_2 4096
|
||||
#define SIZE_3 (5 * 4096)
|
||||
#else
|
||||
#define SIZE_0 0x0150 /* Main */
|
||||
#define SIZE_0 0x0160 /* Main */
|
||||
#define SIZE_1 0x01a0 /* CCID */
|
||||
#define SIZE_2 0x0180 /* RNG */
|
||||
#if MEMORY_SIZE >= 32
|
||||
|
||||
39
src/stdaln-sys.ld.in
Normal file
39
src/stdaln-sys.ld.in
Normal 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
|
||||
}
|
||||
172
src/usb-ccid.c
172
src/usb-ccid.c
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* usb-ccid.c -- USB CCID protocol handling
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
|
||||
* 2019
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -29,6 +30,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
#include <contrib/ackbtn.h>
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "usb-cdc.h"
|
||||
#include "debug.h"
|
||||
@@ -182,9 +187,11 @@ struct ccid_header {
|
||||
|
||||
/* Data structure handled by CCID layer */
|
||||
struct ccid {
|
||||
enum ccid_state ccid_state;
|
||||
uint8_t state;
|
||||
uint8_t err;
|
||||
uint32_t ccid_state : 4;
|
||||
uint32_t state : 4;
|
||||
uint32_t err : 1;
|
||||
uint32_t tx_busy : 1;
|
||||
uint32_t timeout_cnt: 3;
|
||||
|
||||
uint8_t *p;
|
||||
size_t len;
|
||||
@@ -241,6 +248,7 @@ struct ccid {
|
||||
static void ccid_reset (struct ccid *c)
|
||||
{
|
||||
c->err = 0;
|
||||
c->tx_busy = 0;
|
||||
c->state = APDU_STATE_WAIT_COMMAND;
|
||||
c->p = c->a->cmd_apdu_data;
|
||||
c->len = MAX_CMD_APDU_DATA_SIZE;
|
||||
@@ -252,10 +260,11 @@ static void ccid_init (struct ccid *c, struct ep_in *epi, struct ep_out *epo,
|
||||
struct apdu *a)
|
||||
{
|
||||
c->ccid_state = CCID_STATE_START;
|
||||
c->err = 0;
|
||||
c->tx_busy = 0;
|
||||
c->state = APDU_STATE_WAIT_COMMAND;
|
||||
c->p = a->cmd_apdu_data;
|
||||
c->len = MAX_CMD_APDU_DATA_SIZE;
|
||||
c->err = 0;
|
||||
memset (&c->ccid_header, 0, sizeof (struct ccid_header));
|
||||
c->sw1sw2[0] = 0x90;
|
||||
c->sw1sw2[1] = 0x00;
|
||||
@@ -765,6 +774,7 @@ usb_tx_done (uint8_t ep_num, uint16_t len)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ATR (Answer To Reset) string
|
||||
*
|
||||
@@ -820,6 +830,7 @@ static void ccid_error (struct ccid *c, int offset)
|
||||
#else
|
||||
usb_lld_write (c->epi->ep_num, ccid_reply, CCID_MSG_HEADER_SIZE);
|
||||
#endif
|
||||
c->tx_busy = 1;
|
||||
}
|
||||
|
||||
extern void *openpgp_card_thread (void *arg);
|
||||
@@ -893,7 +904,7 @@ ccid_power_on (struct ccid *c)
|
||||
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE + size_atr);
|
||||
#endif
|
||||
DEBUG_INFO ("ON\r\n");
|
||||
|
||||
c->tx_busy = 1;
|
||||
return CCID_STATE_WAIT;
|
||||
}
|
||||
|
||||
@@ -934,6 +945,7 @@ ccid_send_status (struct ccid *c)
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("St\r\n");
|
||||
#endif
|
||||
c->tx_busy = 1;
|
||||
}
|
||||
|
||||
static enum ccid_state
|
||||
@@ -949,6 +961,7 @@ ccid_power_off (struct ccid *c)
|
||||
c->ccid_state = CCID_STATE_START; /* This status change should be here */
|
||||
ccid_send_status (c);
|
||||
DEBUG_INFO ("OFF\r\n");
|
||||
c->tx_busy = 1;
|
||||
return CCID_STATE_START;
|
||||
}
|
||||
|
||||
@@ -982,12 +995,16 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
|
||||
#endif
|
||||
if (len == 0)
|
||||
{
|
||||
c->epi->buf = NULL;
|
||||
c->epi->tx_done = 1;
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
usb_lld_tx_enable_buf (c->epi->ep_num, endp1_tx_buf,
|
||||
CCID_MSG_HEADER_SIZE);
|
||||
#else
|
||||
usb_lld_tx_enable (c->epi->ep_num, CCID_MSG_HEADER_SIZE);
|
||||
#endif
|
||||
c->tx_busy = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1065,6 +1082,7 @@ ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error)
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("DATA\r\n");
|
||||
#endif
|
||||
c->tx_busy = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1076,7 +1094,8 @@ ccid_send_data_block (struct ccid *c)
|
||||
static void
|
||||
ccid_send_data_block_time_extension (struct ccid *c)
|
||||
{
|
||||
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT, 1);
|
||||
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT,
|
||||
c->ccid_state == CCID_STATE_EXECUTE? 1: 0xff);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1115,6 +1134,7 @@ ccid_send_data_block_0x9000 (struct ccid *c)
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("DATA\r\n");
|
||||
#endif
|
||||
c->tx_busy = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1211,6 +1231,7 @@ ccid_send_data_block_gr (struct ccid *c, size_t chunk_len)
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("DATA\r\n");
|
||||
#endif
|
||||
c->tx_busy = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1259,6 +1280,7 @@ ccid_send_params (struct ccid *c)
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("PARAMS\r\n");
|
||||
#endif
|
||||
c->tx_busy = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1413,6 +1435,7 @@ ccid_handle_data (struct ccid *c)
|
||||
c->a->res_apdu_data_len = 0;
|
||||
c->a->res_apdu_data = &c->p[5];
|
||||
|
||||
c->state = APDU_STATE_COMMAND_RECEIVED;
|
||||
eventflag_signal (&c->openpgp_comm, EV_VERIFY_CMD_AVAILABLE);
|
||||
next_state = CCID_STATE_EXECUTE;
|
||||
}
|
||||
@@ -1447,6 +1470,7 @@ ccid_handle_data (struct ccid *c)
|
||||
c->a->res_apdu_data_len = 0;
|
||||
c->a->res_apdu_data = &ccid_buffer[5];
|
||||
|
||||
c->state = APDU_STATE_COMMAND_RECEIVED;
|
||||
eventflag_signal (&c->openpgp_comm, EV_MODIFY_CMD_AVAILABLE);
|
||||
next_state = CCID_STATE_EXECUTE;
|
||||
}
|
||||
@@ -1461,6 +1485,8 @@ ccid_handle_data (struct ccid *c)
|
||||
}
|
||||
break;
|
||||
case CCID_STATE_EXECUTE:
|
||||
case CCID_STATE_ACK_REQUIRED_0:
|
||||
case CCID_STATE_ACK_REQUIRED_1:
|
||||
if (c->ccid_header.msg_type == CCID_POWER_OFF)
|
||||
next_state = ccid_power_off (c);
|
||||
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
|
||||
@@ -1489,6 +1515,8 @@ ccid_handle_timeout (struct ccid *c)
|
||||
switch (c->ccid_state)
|
||||
{
|
||||
case CCID_STATE_EXECUTE:
|
||||
case CCID_STATE_ACK_REQUIRED_0:
|
||||
case CCID_STATE_ACK_REQUIRED_1:
|
||||
ccid_send_data_block_time_extension (c);
|
||||
break;
|
||||
default:
|
||||
@@ -1500,7 +1528,13 @@ ccid_handle_timeout (struct ccid *c)
|
||||
}
|
||||
|
||||
static struct ccid ccid;
|
||||
enum ccid_state *const ccid_state_p = &ccid.ccid_state;
|
||||
|
||||
enum ccid_state
|
||||
ccid_get_ccid_state (void)
|
||||
{
|
||||
return ccid.ccid_state;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ccid_card_change_signal (int how)
|
||||
@@ -1545,7 +1579,7 @@ ccid_notify_slot_change (struct ccid *c)
|
||||
#define USB_CCID_TIMEOUT (1950*1000)
|
||||
|
||||
#define GPG_THREAD_TERMINATED 0xffff
|
||||
|
||||
#define GPG_ACK_TIMEOUT 0x6600
|
||||
|
||||
extern uint32_t bDeviceState;
|
||||
extern void usb_device_reset (struct usb_dev *dev);
|
||||
@@ -1561,6 +1595,10 @@ extern int usb_get_descriptor (struct usb_dev *dev);
|
||||
extern void random_init (void);
|
||||
extern void random_fini (void);
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
static chopstx_intr_t ack_intr;
|
||||
#endif
|
||||
static chopstx_intr_t usb_intr;
|
||||
|
||||
/*
|
||||
* Return 0 for normal USB event
|
||||
@@ -1575,6 +1613,7 @@ usb_event_handle (struct usb_dev *dev)
|
||||
|
||||
e = usb_lld_event_handler (dev);
|
||||
ep_num = USB_EVENT_ENDP (e);
|
||||
chopstx_intr_done (&usb_intr);
|
||||
|
||||
/* Transfer to endpoint (not control endpoint) */
|
||||
if (ep_num != 0)
|
||||
@@ -1674,11 +1713,13 @@ usb_event_handle (struct usb_dev *dev)
|
||||
}
|
||||
|
||||
|
||||
static chopstx_intr_t interrupt;
|
||||
static chopstx_poll_cond_t ccid_event_poll_desc;
|
||||
static struct chx_poll_head *const ccid_poll[] = {
|
||||
(struct chx_poll_head *const)&interrupt,
|
||||
(struct chx_poll_head *const)&ccid_event_poll_desc
|
||||
(struct chx_poll_head *const)&usb_intr,
|
||||
(struct chx_poll_head *const)&ccid_event_poll_desc,
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
(struct chx_poll_head *const)&ack_intr
|
||||
#endif
|
||||
};
|
||||
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
|
||||
|
||||
@@ -1689,6 +1730,7 @@ ccid_thread (void *arg)
|
||||
struct usb_dev dev;
|
||||
struct ccid *c = &ccid;
|
||||
uint32_t *timeout_p;
|
||||
int ackbtn_active = 0;
|
||||
|
||||
(void)arg;
|
||||
|
||||
@@ -1696,9 +1738,12 @@ ccid_thread (void *arg)
|
||||
eventflag_init (&ccid.openpgp_comm);
|
||||
|
||||
usb_lld_init (&dev, USB_INITIAL_FEATURE);
|
||||
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
usb_event_handle (&dev); /* For old SYS < 3.0 */
|
||||
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
ackbtn_init (&ack_intr);
|
||||
#endif
|
||||
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
|
||||
|
||||
reset:
|
||||
@@ -1707,6 +1752,13 @@ ccid_thread (void *arg)
|
||||
struct ep_out *epo = &endpoint_out;
|
||||
struct apdu *a = &apdu;
|
||||
|
||||
if (ackbtn_active)
|
||||
{
|
||||
ackbtn_active = 0;
|
||||
ackbtn_disable ();
|
||||
led_blink (LED_WAIT_FOR_BUTTON);
|
||||
}
|
||||
|
||||
epi_init (epi, ENDP1, c);
|
||||
epo_init (epo, ENDP1, c);
|
||||
apdu_init (a);
|
||||
@@ -1724,14 +1776,21 @@ ccid_thread (void *arg)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
if (bDeviceState == USB_DEVICE_STATE_CONFIGURED)
|
||||
if (!c->tx_busy && bDeviceState == USB_DEVICE_STATE_CONFIGURED)
|
||||
timeout_p = &timeout;
|
||||
else
|
||||
timeout_p = NULL;
|
||||
|
||||
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
|
||||
eventflag_set_mask (&c->ccid_comm, c->tx_busy ? EV_TX_FINISHED : ~0);
|
||||
|
||||
if (interrupt.ready)
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
chopstx_poll (timeout_p, CCID_POLL_NUM - (c->tx_busy || !ackbtn_active),
|
||||
ccid_poll);
|
||||
#else
|
||||
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
|
||||
#endif
|
||||
|
||||
if (usb_intr.ready)
|
||||
{
|
||||
if (usb_event_handle (&dev) == 0)
|
||||
continue;
|
||||
@@ -1751,7 +1810,26 @@ ccid_thread (void *arg)
|
||||
goto reset;
|
||||
}
|
||||
|
||||
timeout = USB_CCID_TIMEOUT;
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
if (!c->tx_busy && ack_intr.ready)
|
||||
{
|
||||
ackbtn_active = 0;
|
||||
ackbtn_disable ();
|
||||
led_blink (LED_WAIT_FOR_BUTTON);
|
||||
chopstx_intr_done (&ack_intr);
|
||||
if (c->ccid_state == CCID_STATE_ACK_REQUIRED_1)
|
||||
goto exec_done;
|
||||
|
||||
c->ccid_state = CCID_STATE_EXECUTE;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
timeout = USB_CCID_TIMEOUT;
|
||||
c->timeout_cnt++;
|
||||
}
|
||||
m = eventflag_get (&c->ccid_comm);
|
||||
|
||||
if (m == EV_CARD_CHANGE)
|
||||
@@ -1774,10 +1852,17 @@ ccid_thread (void *arg)
|
||||
ccid_notify_slot_change (c);
|
||||
}
|
||||
else if (m == EV_RX_DATA_READY)
|
||||
c->ccid_state = ccid_handle_data (c);
|
||||
{
|
||||
c->ccid_state = ccid_handle_data (c);
|
||||
timeout = 0;
|
||||
c->timeout_cnt = 0;
|
||||
}
|
||||
else if (m == EV_EXEC_FINISHED)
|
||||
if (c->ccid_state == CCID_STATE_EXECUTE)
|
||||
{
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
exec_done:
|
||||
#endif
|
||||
if (c->a->sw == GPG_THREAD_TERMINATED)
|
||||
{
|
||||
c->sw1sw2[0] = 0x90;
|
||||
@@ -1807,21 +1892,35 @@ ccid_thread (void *arg)
|
||||
c->ccid_state = CCID_STATE_WAIT;
|
||||
}
|
||||
}
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
else if (c->ccid_state == CCID_STATE_ACK_REQUIRED_0)
|
||||
c->ccid_state = CCID_STATE_ACK_REQUIRED_1;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("ERR07\r\n");
|
||||
DEBUG_INFO ("ERR05\r\n");
|
||||
}
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
else if (m == EV_EXEC_ACK_REQUIRED)
|
||||
if (c->ccid_state == CCID_STATE_EXECUTE)
|
||||
{
|
||||
ackbtn_enable ();
|
||||
ackbtn_active = 1;
|
||||
led_blink (LED_WAIT_FOR_BUTTON);
|
||||
c->ccid_state = CCID_STATE_ACK_REQUIRED_0;
|
||||
ccid_send_data_block_time_extension (c);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("ERR06\r\n");
|
||||
}
|
||||
#endif
|
||||
else if (m == EV_TX_FINISHED)
|
||||
{
|
||||
if (c->state == APDU_STATE_RESULT)
|
||||
{
|
||||
c->state = APDU_STATE_WAIT_COMMAND;
|
||||
c->p = c->a->cmd_apdu_data;
|
||||
c->len = MAX_CMD_APDU_DATA_SIZE;
|
||||
c->err = 0;
|
||||
c->a->cmd_apdu_data_len = 0;
|
||||
c->a->expected_res_size = 0;
|
||||
}
|
||||
ccid_reset (c);
|
||||
else
|
||||
c->tx_busy = 0;
|
||||
|
||||
if (c->state == APDU_STATE_WAIT_COMMAND
|
||||
|| c->state == APDU_STATE_COMMAND_CHAINING
|
||||
@@ -1829,7 +1928,22 @@ ccid_thread (void *arg)
|
||||
ccid_prepare_receive (c);
|
||||
}
|
||||
else /* Timeout */
|
||||
c->ccid_state = ccid_handle_timeout (c);
|
||||
{
|
||||
#ifdef ACKBTN_SUPPORT
|
||||
if (c->timeout_cnt == 7
|
||||
&& c->ccid_state == CCID_STATE_ACK_REQUIRED_1)
|
||||
{
|
||||
ackbtn_active = 0;
|
||||
ackbtn_disable ();
|
||||
led_blink (LED_WAIT_FOR_BUTTON);
|
||||
c->a->sw = GPG_ACK_TIMEOUT;
|
||||
c->a->res_apdu_data_len = 0;
|
||||
goto exec_done;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
c->ccid_state = ccid_handle_timeout (c);
|
||||
}
|
||||
}
|
||||
|
||||
if (c->application)
|
||||
@@ -1841,7 +1955,7 @@ ccid_thread (void *arg)
|
||||
/* Loading reGNUal. */
|
||||
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
|
||||
{
|
||||
chopstx_intr_wait (&interrupt);
|
||||
chopstx_intr_wait (&usb_intr);
|
||||
usb_event_handle (&dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017
|
||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
|
||||
* Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -227,7 +227,7 @@ static const uint8_t lun_table[] = { 0, 0, 0, 0, };
|
||||
#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
|
||||
@@ -281,10 +281,10 @@ usb_setup (struct usb_dev *dev)
|
||||
if (arg->request == USB_FSIJ_GNUK_DOWNLOAD)
|
||||
{
|
||||
#ifdef FLASH_UPGRADE_SUPPORT
|
||||
if (*ccid_state_p != CCID_STATE_EXITED)
|
||||
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
|
||||
return -1;
|
||||
|
||||
if (addr < &_regnual_start || addr + arg->len > __heap_end__)
|
||||
if (addr < _regnual_start || addr + arg->len > __heap_end__)
|
||||
return -1;
|
||||
|
||||
if (arg->index + arg->len < 256)
|
||||
@@ -299,7 +299,7 @@ usb_setup (struct usb_dev *dev)
|
||||
else if (arg->request == USB_FSIJ_GNUK_EXEC && arg->len == 0)
|
||||
{
|
||||
#ifdef FLASH_UPGRADE_SUPPORT
|
||||
if (*ccid_state_p != CCID_STATE_EXITED)
|
||||
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
|
||||
return -1;
|
||||
|
||||
if (((uintptr_t)addr & 0x03))
|
||||
@@ -404,7 +404,7 @@ usb_ctrl_write_finish (struct usb_dev *dev)
|
||||
{
|
||||
if (USB_SETUP_SET (arg->type) && arg->request == USB_FSIJ_GNUK_EXEC)
|
||||
{
|
||||
if (*ccid_state_p != CCID_STATE_EXITED)
|
||||
if (ccid_get_ccid_state () != CCID_STATE_EXITED)
|
||||
return;
|
||||
|
||||
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
||||
|
||||
@@ -4,7 +4,7 @@ Feature: setup pass phrase
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: setup PW1 (admin-full mode)
|
||||
Given cmd_change_reference_data with 1 and "123456user pass phrase"
|
||||
Given cmd_change_reference_data with 1 and "another user pass phraseuser pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1)
|
||||
|
||||
@@ -70,11 +70,11 @@ def build_privkey_template_for_remove(openpgp_keyno):
|
||||
keyspec = b'\xb8'
|
||||
else:
|
||||
keyspec = b'\xa4'
|
||||
return b'\x4d\02' + keyspec + b'\0x00'
|
||||
return b'\x4d\x02' + keyspec + b'\x00'
|
||||
|
||||
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'
|
||||
prefix = b'\x30\x31\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
|
||||
|
||||
@@ -2,3 +2,11 @@ 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"
|
||||
KEY_ATTRIBUTES_ECDH_ANSIX9P256R1=b"\x12\x2a\x86\x48\xce\x3d\x03\x01\x07"
|
||||
KEY_ATTRIBUTES_ECDH_ANSIX9P384R1=b"\x12\x2b\x81\x04\x00\x22"
|
||||
KEY_ATTRIBUTES_ECDH_ANSIX9P521R1=b"\x12\x2b\x81\x04\x00\x23"
|
||||
KEY_ATTRIBUTES_ECDH_BRAINPOOLP256R1=b"\x12\x2b\x24\x03\x03\x02\x08\x01\x01\x07"
|
||||
KEY_ATTRIBUTES_ECDH_BRAINPOOLP384R1=b"\x12\x2b\x24\x03\x03\x02\x08\x01\x01\x0b"
|
||||
KEY_ATTRIBUTES_ECDH_BRAINPOOLP512R1=b"\x12\x2b\x24\x03\x03\x02\x08\x01\x01\x0d"
|
||||
KEY_ATTRIBUTES_X25519=b"\x12\x2b\x06\x01\x04\x01\x97\x55\x01\x05\x01"
|
||||
KEY_ATTRIBUTES_ED25519=b"\x16\x2b\x06\x01\x04\x01\xda\x47\x0f\x01"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
card_reader.py - a library for smartcard reader
|
||||
|
||||
Copyright (C) 2016, 2017 Free Software Initiative of Japan
|
||||
Copyright (C) 2016, 2017, 2019 Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -25,6 +25,7 @@ from struct import pack
|
||||
from usb.util import find_descriptor, claim_interface, get_string, \
|
||||
endpoint_type, endpoint_direction, \
|
||||
ENDPOINT_TYPE_BULK, ENDPOINT_OUT, ENDPOINT_IN
|
||||
from binascii import hexlify
|
||||
|
||||
# USB class, subclass, protocol
|
||||
CCID_CLASS = 0x0B
|
||||
@@ -125,9 +126,12 @@ class CardReader(object):
|
||||
# intf.extra_descriptors[41]
|
||||
|
||||
self.__dev = dev
|
||||
self.__timeout = 10000
|
||||
self.__timeout = 100000
|
||||
self.__seq = 0
|
||||
|
||||
if self.ccid_get_status() & 0x03 not in (0, 1):
|
||||
raise ValueError("Card absent")
|
||||
|
||||
def get_string(self, num):
|
||||
return get_string(self.__dev, num)
|
||||
|
||||
@@ -168,7 +172,7 @@ class CardReader(object):
|
||||
return status
|
||||
|
||||
def ccid_power_on(self):
|
||||
msg = ccid_compose(0x62, self.__seq, rsv=1) # Vcc=5V
|
||||
msg = ccid_compose(0x62, self.__seq, rsv=2) # Vcc=3.3V
|
||||
self.__dev.write(self.__bulkout, msg, self.__timeout)
|
||||
self.increment_seq()
|
||||
status, chain, data = self.ccid_get_result()
|
||||
@@ -237,16 +241,21 @@ class CardReader(object):
|
||||
|
||||
def send_tpdu(self, info=None, more=0, response_time_ext=0,
|
||||
edc_error=0, no_error=0):
|
||||
rsv = 0
|
||||
if info:
|
||||
data = compose_i_block(self.ns, info, more)
|
||||
elif response_time_ext:
|
||||
# compose S-block
|
||||
data = b"\x00\xE3\x00\xE3"
|
||||
# compose S-block response
|
||||
pcb = 0xe3
|
||||
bwi_byte = bytes([response_time_ext])
|
||||
edc = compute_edc(pcb, bwi_byte)
|
||||
data = bytes([0, pcb, 1]) + bwi_byte + bytes([edc])
|
||||
rsv = response_time_ext
|
||||
elif edc_error:
|
||||
data = compose_r_block(self.nr, edc_error=1)
|
||||
elif no_error:
|
||||
data = compose_r_block(self.nr)
|
||||
msg = ccid_compose(0x6f, self.__seq, data=data)
|
||||
msg = ccid_compose(0x6f, self.__seq, rsv=rsv, data=data)
|
||||
self.__dev.write(self.__bulkout, msg, self.__timeout)
|
||||
self.increment_seq()
|
||||
|
||||
@@ -277,7 +286,7 @@ class CardReader(object):
|
||||
res = b""
|
||||
while True:
|
||||
if is_s_block_time_ext(blk):
|
||||
self.send_tpdu(response_time_ext=1)
|
||||
self.send_tpdu(response_time_ext=blk[3])
|
||||
elif is_i_block_last(blk):
|
||||
self.nr = self.nr ^ 1
|
||||
if is_edc_error(blk):
|
||||
|
||||
58
tests/card_test_ansix9p256r1.py
Normal file
58
tests/card_test_ansix9p256r1.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
card_test_ansix9p256r1.py - test ansix9p256r1 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_AnsiX9P256R1(object):
|
||||
def test_ECDH_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc5903#section-8.1
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=1,
|
||||
key_attributes=KEY_ATTRIBUTES_ECDH_ANSIX9P256R1,
|
||||
key_attribute_caption='ECDH ansix9p256r1',
|
||||
private_key=(
|
||||
b'\xC8\x8F\x01\xF5\x10\xD9\xAC\x3F\x70\xA2\x92\xDA\xA2\x31\x6D\xE5'
|
||||
b'\x44\xE9\xAA\xB8\xAF\xE8\x40\x49\xC6\x2A\x9C\x57\x86\x2D\x14\x33'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\x04'
|
||||
b'\xDA\xD0\xB6\x53\x94\x22\x1C\xF9\xB0\x51\xE1\xFE\xCA\x57\x87\xD0'
|
||||
b'\x98\xDF\xE6\x37\xFC\x90\xB9\xEF\x94\x5D\x0C\x37\x72\x58\x11\x80'
|
||||
b'\x52\x71\xA0\x46\x1C\xDB\x82\x52\xD6\x1F\x1C\x45\x6F\xA3\xE5\x9A'
|
||||
b'\xB1\xF4\x5B\x33\xAC\xCF\x5F\x58\x38\x9E\x05\x77\xB8\x99\x0B\xB3'
|
||||
),
|
||||
pso_input=(
|
||||
b'\xa6\x46\x7f\x49\x43\x86\x41'
|
||||
b'\x04'
|
||||
b'\xD1\x2D\xFB\x52\x89\xC8\xD4\xF8\x12\x08\xB7\x02\x70\x39\x8C\x34'
|
||||
b'\x22\x96\x97\x0A\x0B\xCC\xB7\x4C\x73\x6F\xC7\x55\x44\x94\xBF\x63'
|
||||
b'\x56\xFB\xF3\xCA\x36\x6C\xC2\x3E\x81\x57\x85\x4C\x13\xC5\x8D\x6A'
|
||||
b'\xAC\x23\xF0\x46\xAD\xA3\x0F\x83\x53\xE7\x4F\x33\x03\x98\x72\xAB'
|
||||
),
|
||||
expected_pso_output=(
|
||||
b'\xD6\x84\x0F\x6B\x42\xF6\xED\xAF\xD1\x31\x16\xE0\xE1\x25\x65\x20'
|
||||
b'\x2F\xEF\x8E\x9E\xCE\x7D\xCE\x03\x81\x24\x64\xD0\x4B\x94\x42\xDE'
|
||||
),
|
||||
)
|
||||
64
tests/card_test_ansix9p384r1.py
Normal file
64
tests/card_test_ansix9p384r1.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
card_test_ansix9p384r1.py - test ansix9p384r1 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_AnsiX9P384R1(object):
|
||||
def test_ECDH_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc5903#section-8.2
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=1,
|
||||
key_attributes=KEY_ATTRIBUTES_ECDH_ANSIX9P384R1,
|
||||
key_attribute_caption='ECDH ansix9p384r1',
|
||||
private_key=(
|
||||
b'\x09\x9F\x3C\x70\x34\xD4\xA2\xC6\x99\x88\x4D\x73\xA3\x75\xA6\x7F'
|
||||
b'\x76\x24\xEF\x7C\x6B\x3C\x0F\x16\x06\x47\xB6\x74\x14\xDC\xE6\x55'
|
||||
b'\xE3\x5B\x53\x80\x41\xE6\x49\xEE\x3F\xAE\xF8\x96\x78\x3A\xB1\x94'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\x04'
|
||||
b'\x66\x78\x42\xD7\xD1\x80\xAC\x2C\xDE\x6F\x74\xF3\x75\x51\xF5\x57'
|
||||
b'\x55\xC7\x64\x5C\x20\xEF\x73\xE3\x16\x34\xFE\x72\xB4\xC5\x5E\xE6'
|
||||
b'\xDE\x3A\xC8\x08\xAC\xB4\xBD\xB4\xC8\x87\x32\xAE\xE9\x5F\x41\xAA'
|
||||
b'\x94\x82\xED\x1F\xC0\xEE\xB9\xCA\xFC\x49\x84\x62\x5C\xCF\xC2\x3F'
|
||||
b'\x65\x03\x21\x49\xE0\xE1\x44\xAD\xA0\x24\x18\x15\x35\xA0\xF3\x8E'
|
||||
b'\xEB\x9F\xCF\xF3\xC2\xC9\x47\xDA\xE6\x9B\x4C\x63\x45\x73\xA8\x1C'
|
||||
),
|
||||
pso_input=(
|
||||
b'\xa6\x66\x7f\x49\x63\x86\x61'
|
||||
b'\x04'
|
||||
b'\xE5\x58\xDB\xEF\x53\xEE\xCD\xE3\xD3\xFC\xCF\xC1\xAE\xA0\x8A\x89'
|
||||
b'\xA9\x87\x47\x5D\x12\xFD\x95\x0D\x83\xCF\xA4\x17\x32\xBC\x50\x9D'
|
||||
b'\x0D\x1A\xC4\x3A\x03\x36\xDE\xF9\x6F\xDA\x41\xD0\x77\x4A\x35\x71'
|
||||
b'\xDC\xFB\xEC\x7A\xAC\xF3\x19\x64\x72\x16\x9E\x83\x84\x30\x36\x7F'
|
||||
b'\x66\xEE\xBE\x3C\x6E\x70\xC4\x16\xDD\x5F\x0C\x68\x75\x9D\xD1\xFF'
|
||||
b'\xF8\x3F\xA4\x01\x42\x20\x9D\xFF\x5E\xAA\xD9\x6D\xB9\xE6\x38\x6C'
|
||||
),
|
||||
expected_pso_output=(
|
||||
b'\x11\x18\x73\x31\xC2\x79\x96\x2D\x93\xD6\x04\x24\x3F\xD5\x92\xCB'
|
||||
b'\x9D\x0A\x92\x6F\x42\x2E\x47\x18\x75\x21\x28\x7E\x71\x56\xC5\xC4'
|
||||
b'\xD6\x03\x13\x55\x69\xB9\xE9\xD0\x9C\xF5\xD4\xA2\x70\xF5\x97\x46'
|
||||
),
|
||||
)
|
||||
76
tests/card_test_ansix9p512r1.py
Normal file
76
tests/card_test_ansix9p512r1.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
card_test_ansix9p512r1.py - test ansix9p512r1 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_AnsiX9P512R1(object):
|
||||
def test_ECDH_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc5903#section-8.3
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=1,
|
||||
key_attributes=KEY_ATTRIBUTES_ECDH_ANSIX9P521R1,
|
||||
key_attribute_caption='ECDH ansix9p521r1',
|
||||
private_key=(
|
||||
b'\x00\x37\xAD\xE9\x31\x9A\x89\xF4\xDA\xBD\xB3\xEF\x41\x1A\xAC\xCC'
|
||||
b'\xA5\x12\x3C\x61\xAC\xAB\x57\xB5\x39\x3D\xCE\x47\x60\x81\x72\xA0'
|
||||
b'\x95\xAA\x85\xA3\x0F\xE1\xC2\x95\x2C\x67\x71\xD9\x37\xBA\x97\x77'
|
||||
b'\xF5\x95\x7B\x26\x39\xBA\xB0\x72\x46\x2F\x68\xC2\x7A\x57\x38\x2D'
|
||||
b'\x4A\x52'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\x04'
|
||||
b'\x00\x15\x41\x7E\x84\xDB\xF2\x8C\x0A\xD3\xC2\x78\x71\x33\x49\xDC'
|
||||
b'\x7D\xF1\x53\xC8\x97\xA1\x89\x1B\xD9\x8B\xAB\x43\x57\xC9\xEC\xBE'
|
||||
b'\xE1\xE3\xBF\x42\xE0\x0B\x8E\x38\x0A\xEA\xE5\x7C\x2D\x10\x75\x64'
|
||||
b'\x94\x18\x85\x94\x2A\xF5\xA7\xF4\x60\x17\x23\xC4\x19\x5D\x17\x6C'
|
||||
b'\xED\x3E'
|
||||
b'\x01\x7C\xAE\x20\xB6\x64\x1D\x2E\xEB\x69\x57\x86\xD8\xC9\x46\x14'
|
||||
b'\x62\x39\xD0\x99\xE1\x8E\x1D\x5A\x51\x4C\x73\x9D\x7C\xB4\xA1\x0A'
|
||||
b'\xD8\xA7\x88\x01\x5A\xC4\x05\xD7\x79\x9D\xC7\x5E\x7B\x7D\x5B\x6C'
|
||||
b'\xF2\x26\x1A\x6A\x7F\x15\x07\x43\x8B\xF0\x1B\xEB\x6C\xA3\x92\x6F'
|
||||
b'\x95\x82'
|
||||
),
|
||||
pso_input=(
|
||||
b'\xa6\x81\x8c\x7f\x49\x81\x88\x86\x81\x85'
|
||||
b'\x04'
|
||||
b'\x00\xD0\xB3\x97\x5A\xC4\xB7\x99\xF5\xBE\xA1\x6D\x5E\x13\xE9\xAF'
|
||||
b'\x97\x1D\x5E\x9B\x98\x4C\x9F\x39\x72\x8B\x5E\x57\x39\x73\x5A\x21'
|
||||
b'\x9B\x97\xC3\x56\x43\x6A\xDC\x6E\x95\xBB\x03\x52\xF6\xBE\x64\xA6'
|
||||
b'\xC2\x91\x2D\x4E\xF2\xD0\x43\x3C\xED\x2B\x61\x71\x64\x00\x12\xD9'
|
||||
b'\x46\x0F'
|
||||
b'\x01\x5C\x68\x22\x63\x83\x95\x6E\x3B\xD0\x66\xE7\x97\xB6\x23\xC2'
|
||||
b'\x7C\xE0\xEA\xC2\xF5\x51\xA1\x0C\x2C\x72\x4D\x98\x52\x07\x7B\x87'
|
||||
b'\x22\x0B\x65\x36\xC5\xC4\x08\xA1\xD2\xAE\xBB\x8E\x86\xD6\x78\xAE'
|
||||
b'\x49\xCB\x57\x09\x1F\x47\x32\x29\x65\x79\xAB\x44\xFC\xD1\x7F\x0F'
|
||||
b'\xC5\x6A'
|
||||
),
|
||||
expected_pso_output=(
|
||||
b'\x01\x14\x4C\x7D\x79\xAE\x69\x56\xBC\x8E\xDB\x8E\x7C\x78\x7C\x45'
|
||||
b'\x21\xCB\x08\x6F\xA6\x44\x07\xF9\x78\x94\xE5\xE6\xB2\xD7\x9B\x04'
|
||||
b'\xD1\x42\x7E\x73\xCA\x4B\xAA\x24\x0A\x34\x78\x68\x59\x81\x0C\x06'
|
||||
b'\xB3\xC7\x15\xA3\xA8\xCC\x31\x51\xF2\xBE\xE4\x17\x99\x6D\x19\xF3'
|
||||
b'\xDD\xEA'
|
||||
),
|
||||
)
|
||||
58
tests/card_test_brainpoolp256r1.py
Normal file
58
tests/card_test_brainpoolp256r1.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
card_test_brainpoolp256r1.py - test brainpoolp256r1 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_BrainpoolP256R1(object):
|
||||
def test_ECDH_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc7027#appendix-A.1
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=1,
|
||||
key_attributes=KEY_ATTRIBUTES_ECDH_BRAINPOOLP256R1,
|
||||
key_attribute_caption='ECDH brainpoolp256r1',
|
||||
private_key=(
|
||||
b'\x81\xDB\x1E\xE1\x00\x15\x0F\xF2\xEA\x33\x8D\x70\x82\x71\xBE\x38'
|
||||
b'\x30\x0C\xB5\x42\x41\xD7\x99\x50\xF7\x7B\x06\x30\x39\x80\x4F\x1D'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\x04'
|
||||
b'\x44\x10\x6E\x91\x3F\x92\xBC\x02\xA1\x70\x5D\x99\x53\xA8\x41\x4D'
|
||||
b'\xB9\x5E\x1A\xAA\x49\xE8\x1D\x9E\x85\xF9\x29\xA8\xE3\x10\x0B\xE5'
|
||||
b'\x8A\xB4\x84\x6F\x11\xCA\xCC\xB7\x3C\xE4\x9C\xBD\xD1\x20\xF5\xA9'
|
||||
b'\x00\xA6\x9F\xD3\x2C\x27\x22\x23\xF7\x89\xEF\x10\xEB\x08\x9B\xDC'
|
||||
),
|
||||
pso_input=(
|
||||
b'\xa6\x46\x7f\x49\x43\x86\x41'
|
||||
b'\x04'
|
||||
b'\x8D\x2D\x68\x8C\x6C\xF9\x3E\x11\x60\xAD\x04\xCC\x44\x29\x11\x7D'
|
||||
b'\xC2\xC4\x18\x25\xE1\xE9\xFC\xA0\xAD\xDD\x34\xE6\xF1\xB3\x9F\x7B'
|
||||
b'\x99\x0C\x57\x52\x08\x12\xBE\x51\x26\x41\xE4\x70\x34\x83\x21\x06'
|
||||
b'\xBC\x7D\x3E\x8D\xD0\xE4\xC7\xF1\x13\x6D\x70\x06\x54\x7C\xEC\x6A'
|
||||
),
|
||||
expected_pso_output=(
|
||||
b'\x89\xAF\xC3\x9D\x41\xD3\xB3\x27\x81\x4B\x80\x94\x0B\x04\x25\x90'
|
||||
b'\xF9\x65\x56\xEC\x91\xE6\xAE\x79\x39\xBC\xE3\x1F\x3A\x18\xBF\x2B'
|
||||
),
|
||||
)
|
||||
64
tests/card_test_brainpoolp384r1.py
Normal file
64
tests/card_test_brainpoolp384r1.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
card_test_brainpoolp384r1.py - test brainpoolp384r1 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_BrainpoolP384R1(object):
|
||||
def test_ECDH_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc7027#appendix-A.2
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=1,
|
||||
key_attributes=KEY_ATTRIBUTES_ECDH_BRAINPOOLP384R1,
|
||||
key_attribute_caption='ECDH brainpoolp384r1',
|
||||
private_key=(
|
||||
b'\x1E\x20\xF5\xE0\x48\xA5\x88\x6F\x1F\x15\x7C\x74\xE9\x1B\xDE\x2B'
|
||||
b'\x98\xC8\xB5\x2D\x58\xE5\x00\x3D\x57\x05\x3F\xC4\xB0\xBD\x65\xD6'
|
||||
b'\xF1\x5E\xB5\xD1\xEE\x16\x10\xDF\x87\x07\x95\x14\x36\x27\xD0\x42'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\x04'
|
||||
b'\x68\xB6\x65\xDD\x91\xC1\x95\x80\x06\x50\xCD\xD3\x63\xC6\x25\xF4'
|
||||
b'\xE7\x42\xE8\x13\x46\x67\xB7\x67\xB1\xB4\x76\x79\x35\x88\xF8\x85'
|
||||
b'\xAB\x69\x8C\x85\x2D\x4A\x6E\x77\xA2\x52\xD6\x38\x0F\xCA\xF0\x68'
|
||||
b'\x55\xBC\x91\xA3\x9C\x9E\xC0\x1D\xEE\x36\x01\x7B\x7D\x67\x3A\x93'
|
||||
b'\x12\x36\xD2\xF1\xF5\xC8\x39\x42\xD0\x49\xE3\xFA\x20\x60\x74\x93'
|
||||
b'\xE0\xD0\x38\xFF\x2F\xD3\x0C\x2A\xB6\x7D\x15\xC8\x5F\x7F\xAA\x59'
|
||||
),
|
||||
pso_input=(
|
||||
b'\xa6\x66\x7f\x49\x63\x86\x61'
|
||||
b'\x04'
|
||||
b'\x4D\x44\x32\x6F\x26\x9A\x59\x7A\x5B\x58\xBB\xA5\x65\xDA\x55\x56'
|
||||
b'\xED\x7F\xD9\xA8\xA9\xEB\x76\xC2\x5F\x46\xDB\x69\xD1\x9D\xC8\xCE'
|
||||
b'\x6A\xD1\x8E\x40\x4B\x15\x73\x8B\x20\x86\xDF\x37\xE7\x1D\x1E\xB4'
|
||||
b'\x62\xD6\x92\x13\x6D\xE5\x6C\xBE\x93\xBF\x5F\xA3\x18\x8E\xF5\x8B'
|
||||
b'\xC8\xA3\xA0\xEC\x6C\x1E\x15\x1A\x21\x03\x8A\x42\xE9\x18\x53\x29'
|
||||
b'\xB5\xB2\x75\x90\x3D\x19\x2F\x8D\x4E\x1F\x32\xFE\x9C\xC7\x8C\x48'
|
||||
),
|
||||
expected_pso_output=(
|
||||
b'\x0B\xD9\xD3\xA7\xEA\x0B\x3D\x51\x9D\x09\xD8\xE4\x8D\x07\x85\xFB'
|
||||
b'\x74\x4A\x6B\x35\x5E\x63\x04\xBC\x51\xC2\x29\xFB\xBC\xE2\x39\xBB'
|
||||
b'\xAD\xF6\x40\x37\x15\xC3\x5D\x4F\xB2\xA5\x44\x4F\x57\x5D\x4F\x42'
|
||||
),
|
||||
)
|
||||
70
tests/card_test_brainpoolp512r1.py
Normal file
70
tests/card_test_brainpoolp512r1.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
card_test_brainpoolp512r1.py - test brainpoolp512r1 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_BrainpoolP512R1(object):
|
||||
def test_ECDH_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc7027#appendix-A.3
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=1,
|
||||
key_attributes=KEY_ATTRIBUTES_ECDH_BRAINPOOLP512R1,
|
||||
key_attribute_caption='ECDH brainpoolp512r1',
|
||||
private_key=(
|
||||
b'\x16\x30\x2F\xF0\xDB\xBB\x5A\x8D\x73\x3D\xAB\x71\x41\xC1\xB4\x5A'
|
||||
b'\xCB\xC8\x71\x59\x39\x67\x7F\x6A\x56\x85\x0A\x38\xBD\x87\xBD\x59'
|
||||
b'\xB0\x9E\x80\x27\x96\x09\xFF\x33\x3E\xB9\xD4\xC0\x61\x23\x1F\xB2'
|
||||
b'\x6F\x92\xEE\xB0\x49\x82\xA5\xF1\xD1\x76\x4C\xAD\x57\x66\x54\x22'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\x04'
|
||||
b'\x0A\x42\x05\x17\xE4\x06\xAA\xC0\xAC\xDC\xE9\x0F\xCD\x71\x48\x77'
|
||||
b'\x18\xD3\xB9\x53\xEF\xD7\xFB\xEC\x5F\x7F\x27\xE2\x8C\x61\x49\x99'
|
||||
b'\x93\x97\xE9\x1E\x02\x9E\x06\x45\x7D\xB2\xD3\xE6\x40\x66\x8B\x39'
|
||||
b'\x2C\x2A\x7E\x73\x7A\x7F\x0B\xF0\x44\x36\xD1\x16\x40\xFD\x09\xFD'
|
||||
b'\x72\xE6\x88\x2E\x8D\xB2\x8A\xAD\x36\x23\x7C\xD2\x5D\x58\x0D\xB2'
|
||||
b'\x37\x83\x96\x1C\x8D\xC5\x2D\xFA\x2E\xC1\x38\xAD\x47\x2A\x0F\xCE'
|
||||
b'\xF3\x88\x7C\xF6\x2B\x62\x3B\x2A\x87\xDE\x5C\x58\x83\x01\xEA\x3E'
|
||||
b'\x5F\xC2\x69\xB3\x73\xB6\x07\x24\xF5\xE8\x2A\x6A\xD1\x47\xFD\xE7'
|
||||
),
|
||||
pso_input=(
|
||||
b'\xa6\x81\x88\x7f\x49\x81\x84\x86\x81\x81'
|
||||
b'\x04'
|
||||
b'\x9D\x45\xF6\x6D\xE5\xD6\x7E\x2E\x6D\xB6\xE9\x3A\x59\xCE\x0B\xB4'
|
||||
b'\x81\x06\x09\x7F\xF7\x8A\x08\x1D\xE7\x81\xCD\xB3\x1F\xCE\x8C\xCB'
|
||||
b'\xAA\xEA\x8D\xD4\x32\x0C\x41\x19\xF1\xE9\xCD\x43\x7A\x2E\xAB\x37'
|
||||
b'\x31\xFA\x96\x68\xAB\x26\x8D\x87\x1D\xED\xA5\x5A\x54\x73\x19\x9F'
|
||||
b'\x2F\xDC\x31\x30\x95\xBC\xDD\x5F\xB3\xA9\x16\x36\xF0\x7A\x95\x9C'
|
||||
b'\x8E\x86\xB5\x63\x6A\x1E\x93\x0E\x83\x96\x04\x9C\xB4\x81\x96\x1D'
|
||||
b'\x36\x5C\xC1\x14\x53\xA0\x6C\x71\x98\x35\x47\x5B\x12\xCB\x52\xFC'
|
||||
b'\x3C\x38\x3B\xCE\x35\xE2\x7E\xF1\x94\x51\x2B\x71\x87\x62\x85\xFA'
|
||||
),
|
||||
expected_pso_output=(
|
||||
b'\xA7\x92\x70\x98\x65\x5F\x1F\x99\x76\xFA\x50\xA9\xD5\x66\x86\x5D'
|
||||
b'\xC5\x30\x33\x18\x46\x38\x1C\x87\x25\x6B\xAF\x32\x26\x24\x4B\x76'
|
||||
b'\xD3\x64\x03\xC0\x24\xD7\xBB\xF0\xAA\x08\x03\xEA\xFF\x40\x5D\x3D'
|
||||
b'\x24\xF1\x1A\x9B\x5C\x0B\xEF\x67\x9F\xE1\x45\x4B\x21\xC4\xCD\x1F'
|
||||
),
|
||||
)
|
||||
51
tests/card_test_ed25519.py
Normal file
51
tests/card_test_ed25519.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
card_test_ed25519.py - test ed25519 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 hashlib
|
||||
from func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_ED25519(object):
|
||||
def test_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc8032#section-7.3
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=0,
|
||||
key_attributes=KEY_ATTRIBUTES_ED25519,
|
||||
key_attribute_caption='ed25519',
|
||||
private_key=(
|
||||
b'\x83\x3f\xe6\x24\x09\x23\x7b\x9d\x62\xec\x77\x58\x75\x20\x91\x1e'
|
||||
b'\x9a\x75\x9c\xec\x1d\x19\x75\x5b\x7d\xa9\x01\xb9\x6d\xca\x3d\x42'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\xec\x17\x2b\x93\xad\x5e\x56\x3b\xf4\x93\x2c\x70\xe1\x24\x50\x34'
|
||||
b'\xc3\x54\x67\xef\x2e\xfd\x4d\x64\xeb\xf8\x19\x68\x34\x67\xe2\xbf'
|
||||
),
|
||||
pso_input=hashlib.sha512(b'\x61\x62\x63').digest(),
|
||||
expected_pso_output=(
|
||||
b'\x98\xa7\x02\x22\xf0\xb8\x12\x1a\xa9\xd3\x0f\x81\x3d\x68\x3f\x80'
|
||||
b'\x9e\x46\x2b\x46\x9c\x7f\xf8\x76\x39\x49\x9b\xb9\x4e\x6d\xae\x41'
|
||||
b'\x31\xf8\x50\x42\x46\x3c\x2a\x35\x5a\x20\x03\xd0\x62\xad\xf5\xaa'
|
||||
b'\xa1\x0b\x8c\x61\xe6\x36\x06\x2a\xaa\xd1\x1c\x2a\x26\x08\x34\x06'
|
||||
),
|
||||
)
|
||||
36
tests/card_test_kdf_full.py
Normal file
36
tests/card_test_kdf_full.py
Normal 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
|
||||
35
tests/card_test_kdf_single.py
Normal file
35
tests/card_test_kdf_single.py
Normal 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
84
tests/card_test_keygen.py
Normal 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
|
||||
312
tests/card_test_personalize_admin_less.py
Normal file
312
tests/card_test_personalize_admin_less.py
Normal 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
|
||||
|
||||
277
tests/card_test_personalize_card.py
Normal file
277
tests/card_test_personalize_card.py
Normal 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
|
||||
82
tests/card_test_personalize_reset.py
Normal file
82
tests/card_test_personalize_reset.py
Normal 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
|
||||
45
tests/card_test_remove_keys.py
Normal file
45
tests/card_test_remove_keys.py
Normal 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
|
||||
46
tests/card_test_reset_pw3.py
Normal file
46
tests/card_test_reset_pw3.py
Normal 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
|
||||
52
tests/card_test_x25519.py
Normal file
52
tests/card_test_x25519.py
Normal file
@@ -0,0 +1,52 @@
|
||||
"""
|
||||
card_test_x25519.py - test x25519 support
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 func_pso_auth import assert_ec_pso
|
||||
from card_const import *
|
||||
|
||||
class Test_Card_X25519(object):
|
||||
def test_reference_vectors(self, card):
|
||||
assert card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
# https://tools.ietf.org/html/rfc7748#section-6.1
|
||||
assert_ec_pso(
|
||||
card=card,
|
||||
key_index=1,
|
||||
key_attributes=KEY_ATTRIBUTES_X25519,
|
||||
key_attribute_caption='x25519',
|
||||
private_key=(
|
||||
b'\x77\x07\x6d\x0a\x73\x18\xa5\x7d\x3c\x16\xc1\x72\x51\xb2\x66\x45'
|
||||
b'\xdf\x4c\x2f\x87\xeb\xc0\x99\x2a\xb1\x77\xfb\xa5\x1d\xb9\x2c\x2a'
|
||||
),
|
||||
expected_public_key=(
|
||||
b'\x85\x20\xf0\x09\x89\x30\xa7\x54\x74\x8b\x7d\xdc\xb4\x3e\xf7\x5a'
|
||||
b'\x0d\xbf\x3a\x0d\x26\x38\x1a\xf4\xeb\xa4\xa9\x8e\xaa\x9b\x4e\x6a'
|
||||
),
|
||||
pso_input=(
|
||||
b'\xa6\x25\x7f\x49\x22\x86\x20'
|
||||
b'\xde\x9e\xdb\x7d\x7b\x7d\xc1\xb4\xd3\x5b\x61\xc2\xec\xe4\x35\x37'
|
||||
b'\x3f\x83\x43\xc8\x5b\x78\x67\x4d\xad\xfc\x7e\x14\x6f\x88\x2b\x4f'
|
||||
),
|
||||
expected_pso_output=(
|
||||
b'\x4a\x5d\x9d\x5b\xa4\xce\x2d\xe1\x72\x8e\x3b\xf4\x80\x35\x0f\x25'
|
||||
b'\xe0\x7e\x21\xc9\x47\xd1\x9e\x33\x76\xf0\x9b\x3c\x1e\x16\x17\x42'
|
||||
),
|
||||
)
|
||||
@@ -16,3 +16,4 @@ def card():
|
||||
card.cmd_select_openpgp()
|
||||
yield card
|
||||
del card
|
||||
reader.ccid_power_off()
|
||||
|
||||
108
tests/func_pso_auth.py
Normal file
108
tests/func_pso_auth.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
func_pso_auth.py - functions for testing PSO commands
|
||||
|
||||
Copyright (C) 2021 Vincent Pelletier <plr.vincent@gmail.com>
|
||||
|
||||
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 pytest
|
||||
from card_const import KEY_ATTRIBUTES_RSA2K
|
||||
|
||||
def _encodeDERLength(length):
|
||||
if length < 0x80:
|
||||
return length.to_bytes(1, 'big')
|
||||
if length < 0x100:
|
||||
return b'\x81' + length.to_bytes(1, 'big')
|
||||
return b'\x82' + length.to_bytes(2, 'big')
|
||||
|
||||
def get_ec_pso(
|
||||
card,
|
||||
key_index,
|
||||
key_attributes,
|
||||
key_attribute_caption,
|
||||
private_key, expected_public_key,
|
||||
pso_input,
|
||||
):
|
||||
"""
|
||||
If card supports, change key attributes for given key slot, store
|
||||
given private key, check that the card could derive the expected
|
||||
public key from it, then call the appropriate PSO for this key slot
|
||||
and return its result.
|
||||
Sets key attributes to RSA2K before returning to caller.
|
||||
Skips the test if initial key attribute change is rejected by the card.
|
||||
"""
|
||||
key_attribute_index, control_reference_template, pso_p1, pso_p2 = (
|
||||
(0xc1, b'\xb6\x00', 0x9e, 0x9a), # Sign
|
||||
(0xc2, b'\xb8\x00', 0x80, 0x86), # Decrypt
|
||||
(0xc3, b'\xa4\x00', 0x9e, 0x9a), # Authenticate
|
||||
)[key_index]
|
||||
try:
|
||||
card.cmd_put_data(0x00, key_attribute_index, key_attributes)
|
||||
except ValueError:
|
||||
pytest.skip('No %s support' % (key_attribute_caption, ))
|
||||
try:
|
||||
private_key_len = len(private_key)
|
||||
r = card.cmd_put_data_odd(
|
||||
0x3f,
|
||||
0xff,
|
||||
b'\x4d' + _encodeDERLength(private_key_len + 10) +
|
||||
control_reference_template +
|
||||
b'\x7f\x48\x02'
|
||||
b'\x92' + _encodeDERLength(private_key_len) +
|
||||
b'\x5f\x48' + _encodeDERLength(private_key_len) +
|
||||
private_key,
|
||||
)
|
||||
assert r
|
||||
r = card.cmd_get_public_key(key_index + 1)
|
||||
expected_public_key_len = len(expected_public_key)
|
||||
encoded_expected_public_key_len = _encodeDERLength(
|
||||
expected_public_key_len,
|
||||
)
|
||||
expected_public_key_response = (
|
||||
b'\x7f\x49' + _encodeDERLength(
|
||||
expected_public_key_len +
|
||||
len(encoded_expected_public_key_len) + 1,
|
||||
) +
|
||||
b'\x86' + encoded_expected_public_key_len +
|
||||
expected_public_key
|
||||
)
|
||||
assert r == expected_public_key_response
|
||||
return card.cmd_pso(pso_p1, pso_p2, pso_input)
|
||||
finally:
|
||||
card.cmd_put_data(0x00, key_attribute_index, KEY_ATTRIBUTES_RSA2K)
|
||||
|
||||
def assert_ec_pso(
|
||||
card,
|
||||
key_index,
|
||||
key_attributes,
|
||||
key_attribute_caption,
|
||||
private_key, expected_public_key,
|
||||
pso_input, expected_pso_output,
|
||||
):
|
||||
"""
|
||||
Calls get_ec_pso and checks if produced output matches the expected value.
|
||||
"""
|
||||
r = get_ec_pso(
|
||||
card=card,
|
||||
key_index=key_index,
|
||||
key_attributes=key_attributes,
|
||||
key_attribute_caption=key_attribute_caption,
|
||||
private_key=private_key,
|
||||
expected_public_key=expected_public_key,
|
||||
pso_input=pso_input,
|
||||
)
|
||||
assert r == expected_pso_output
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
openpgp_card.py - a library for OpenPGP card
|
||||
|
||||
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018
|
||||
Copyright (C) 2011, 2012, 2013, 2015, 2016, 2018, 2019
|
||||
Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
@@ -59,6 +59,8 @@ class OpenPGP_Card(object):
|
||||
self.__kdf_salt_user = None
|
||||
self.__kdf_salt_reset = None
|
||||
self.__kdf_salt_admin = None
|
||||
self.is_gnuk = (reader.get_string(2) == "Gnuk Token")
|
||||
self.is_emulated_gnuk = (reader.get_string(3)[-8:] == "EMULATED")
|
||||
|
||||
def configure_with_kdf(self):
|
||||
kdf_data = self.cmd_get_data(0x00, 0xf9)
|
||||
@@ -338,16 +340,20 @@ class OpenPGP_Card(object):
|
||||
data = b'\xb8\x00'
|
||||
else:
|
||||
data = b'\xa4\x00'
|
||||
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
|
||||
if self.__reader.is_tpdu_reader():
|
||||
cmd_data = iso7816_compose(0x47, 0x80, 0, data, le=512)
|
||||
else:
|
||||
cmd_data = iso7816_compose(0x47, 0x80, 0, data)
|
||||
sw = self.__reader.send_cmd(cmd_data)
|
||||
if len(sw) != 2:
|
||||
if len(sw) < 2:
|
||||
raise ValueError(sw)
|
||||
if sw[0] == 0x90 and sw[1] == 0x00:
|
||||
return b""
|
||||
elif sw[0] != 0x61:
|
||||
if sw[-2] == 0x61:
|
||||
pk = self.cmd_get_response(sw[1])
|
||||
elif sw[-2] == 0x90 and sw[-1] == 0x00:
|
||||
pk = sw
|
||||
else:
|
||||
raise ValueError("%02x%02x" % (sw[0], sw[1]))
|
||||
pk = self.cmd_get_response(sw[1])
|
||||
return (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
||||
return (pk[9:9+256], pk[9+256+2:-2])
|
||||
|
||||
def cmd_get_public_key(self, keyno):
|
||||
if keyno == 1:
|
||||
@@ -358,10 +364,9 @@ class OpenPGP_Card(object):
|
||||
data = b'\xa4\x00'
|
||||
if self.__reader.is_tpdu_reader():
|
||||
cmd_data = iso7816_compose(0x47, 0x81, 0, data, le=512)
|
||||
r = self.__reader.send_cmd(cmd_data)
|
||||
else:
|
||||
cmd_data = iso7816_compose(0x47, 0x81, 0, data)
|
||||
r = self.__reader.send_cmd(cmd_data)
|
||||
r = self.__reader.send_cmd(cmd_data)
|
||||
if len(r) < 2:
|
||||
raise ValueError(r)
|
||||
sw = r[-2:]
|
||||
|
||||
@@ -70,11 +70,11 @@ def build_privkey_template_for_remove(openpgp_keyno):
|
||||
keyspec = b'\xb8'
|
||||
else:
|
||||
keyspec = b'\xa4'
|
||||
return b'\x4d\02' + keyspec + b'\0x00'
|
||||
return b'\x4d\x02' + keyspec + b'\x00'
|
||||
|
||||
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'
|
||||
prefix = b'\x30\x31\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
|
||||
|
||||
6
tests/skip_gnuk_only_tests.py
Normal file
6
tests/skip_gnuk_only_tests.py
Normal 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)
|
||||
6
tests/skip_if_emulation.py
Normal file
6
tests/skip_if_emulation.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope="module",autouse=True)
|
||||
def check_emulation(card):
|
||||
if card.is_emulated_gnuk:
|
||||
pytest.skip("Emulation requires KDF setup", allow_module_level=True)
|
||||
6
tests/skip_if_gnuk.py
Normal file
6
tests/skip_if_gnuk.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope="module",autouse=True)
|
||||
def check_gnuk(card):
|
||||
if card.is_gnuk:
|
||||
pytest.skip("Gnuk has no support for those features", allow_module_level=True)
|
||||
@@ -50,12 +50,21 @@ def test_sex(card):
|
||||
def test_name_lang_sex(card):
|
||||
name = b""
|
||||
lang = b""
|
||||
lang_de = b"de"
|
||||
sex = b"9"
|
||||
sex_alt = b"0"
|
||||
expected = b'\x5b' + pack('B', len(name)) + name \
|
||||
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||
expected_de = b'\x5b' + pack('B', len(name)) + name \
|
||||
+ b'\x5f\x2d' + pack('B', len(lang_de)) + lang_de \
|
||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||
expected_de_alt = b'\x5b' + pack('B', len(name)) + name \
|
||||
+ b'\x5f\x2d' + pack('B', len(lang_de)) + lang_de \
|
||||
+ b'\x5f\x35' + pack('B', len(sex_alt)) + sex_alt
|
||||
name_lang_sex = get_data_object(card, 0x65)
|
||||
assert name_lang_sex == b'' or name_lang_sex == expected
|
||||
assert name_lang_sex == b'' or name_lang_sex == expected \
|
||||
or name_lang_sex == expected_de or name_lang_sex == expected_de_alt
|
||||
|
||||
def test_app_data(card):
|
||||
app_data = get_data_object(card, 0x6e)
|
||||
@@ -140,7 +149,8 @@ def test_historical_bytes(card):
|
||||
h = get_data_object(card, 0x5f52)
|
||||
assert h == b'\x001\xc5s\xc0\x01@\x05\x90\x00' or \
|
||||
h == b'\x00\x31\x84\x73\x80\x01\x80\x00\x90\x00' or \
|
||||
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00'
|
||||
h == b'\x00\x31\x84\x73\x80\x01\x80\x05\x90\x00' or \
|
||||
h == b'\x00\x31\xf5\x73\xc0\x01\x60\x05\x90\x00'
|
||||
|
||||
def test_extended_capabilities(card):
|
||||
a = get_data_object(card, 0xc0)
|
||||
|
||||
@@ -1,276 +1,2 @@
|
||||
"""
|
||||
test_personalize_card.py - test personalizing card
|
||||
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from struct import pack
|
||||
from re import match, DOTALL
|
||||
from util import *
|
||||
import rsa_keys
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_setup_pw3_0(card):
|
||||
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, PW3_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_0(card):
|
||||
v = card.verify(3, PW3_TEST0)
|
||||
assert v
|
||||
|
||||
def test_login_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||
assert r
|
||||
|
||||
def test_name_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
|
||||
assert r
|
||||
|
||||
def test_lang_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
|
||||
assert r
|
||||
|
||||
def test_sex_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x35, b"1")
|
||||
assert r
|
||||
|
||||
def test_url_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
|
||||
assert r
|
||||
|
||||
def test_pw1_status_put(card):
|
||||
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
|
||||
assert r
|
||||
|
||||
def test_login(card):
|
||||
login = get_data_object(card, 0x5e)
|
||||
assert login == b"gpg_user"
|
||||
|
||||
def test_name_lang_sex(card):
|
||||
name = b"GnuPG User"
|
||||
lang = b"ja"
|
||||
sex = b"1"
|
||||
expected = b'\x5b' + pack('B', len(name)) + name \
|
||||
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||
name_lang_sex = get_data_object(card, 0x65)
|
||||
assert name_lang_sex == expected
|
||||
|
||||
def test_url(card):
|
||||
url = get_data_object(card, 0x5f50)
|
||||
assert url == b"https://www.fsij.org/gnuk/"
|
||||
|
||||
def test_pw1_status(card):
|
||||
s = get_data_object(card, 0xc4)
|
||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||
|
||||
def test_rsa_import_key_1(card):
|
||||
t = rsa_keys.build_privkey_template(1, 0)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_rsa_import_key_2(card):
|
||||
t = rsa_keys.build_privkey_template(2, 1)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_rsa_import_key_3(card):
|
||||
t = rsa_keys.build_privkey_template(3, 2)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_1_put(card):
|
||||
fpr1 = rsa_keys.fpr[0]
|
||||
r = card.cmd_put_data(0x00, 0xc7, fpr1)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_2_put(card):
|
||||
fpr2 = rsa_keys.fpr[1]
|
||||
r = card.cmd_put_data(0x00, 0xc8, fpr2)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_3_put(card):
|
||||
fpr3 = rsa_keys.fpr[2]
|
||||
r = card.cmd_put_data(0x00, 0xc9, fpr3)
|
||||
assert r
|
||||
|
||||
def test_timestamp_1_put(card):
|
||||
timestamp1 = rsa_keys.timestamp[0]
|
||||
r = card.cmd_put_data(0x00, 0xce, timestamp1)
|
||||
assert r
|
||||
|
||||
def test_timestamp_2_put(card):
|
||||
timestamp2 = rsa_keys.timestamp[1]
|
||||
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
|
||||
assert r
|
||||
|
||||
def test_timestamp_3_put(card):
|
||||
timestamp3 = rsa_keys.timestamp[2]
|
||||
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
|
||||
assert r
|
||||
|
||||
def test_ds_counter_0(card):
|
||||
c = get_data_object(card, 0x7a)
|
||||
assert c == b'\x93\x03\x00\x00\x00'
|
||||
|
||||
def test_pw1_status(card):
|
||||
s = get_data_object(card, 0xc4)
|
||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||
|
||||
def test_app_data(card):
|
||||
app_data = get_data_object(card, 0x6e)
|
||||
hist_len = app_data[20]
|
||||
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
|
||||
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
|
||||
app_data[18:18+2] == b"\x5f\x52"
|
||||
|
||||
def test_public_key_1(card):
|
||||
pk = card.cmd_get_public_key(1)
|
||||
assert rsa_keys.key[0][0] == pk[9:9+256]
|
||||
|
||||
def test_public_key_2(card):
|
||||
pk = card.cmd_get_public_key(2)
|
||||
assert rsa_keys.key[1][0] == pk[9:9+256]
|
||||
|
||||
def test_public_key_3(card):
|
||||
pk = card.cmd_get_public_key(3)
|
||||
assert rsa_keys.key[2][0] == pk[9:9+256]
|
||||
|
||||
def test_setup_pw1_0(card):
|
||||
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_0(card):
|
||||
v = card.verify(1, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_0_2(card):
|
||||
v = card.verify(2, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_1(card):
|
||||
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_1(card):
|
||||
v = card.verify(1, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_1_2(card):
|
||||
v = card.verify(2, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_setup_reset_code(card):
|
||||
r = card.setup_reset_code(RESETCODE_TEST)
|
||||
assert r
|
||||
|
||||
def test_reset_code(card):
|
||||
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.verify(1, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_2_2(card):
|
||||
v = card.verify(2, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_setup_pw3_1(card):
|
||||
r = card.change_passwd(3, PW3_TEST0, PW3_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_1(card):
|
||||
v = card.verify(3, PW3_TEST1)
|
||||
assert v
|
||||
|
||||
def test_reset_userpass_admin(card):
|
||||
r = card.reset_passwd_by_admin(PW1_TEST3)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_3(card):
|
||||
v = card.verify(1, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_3_2(card):
|
||||
v = card.verify(2, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_4(card):
|
||||
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_4(card):
|
||||
v = card.verify(1, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_4_2(card):
|
||||
v = card.verify(2, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_setup_pw3_2(card):
|
||||
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_2(card):
|
||||
v = card.verify(3, PW3_TEST0)
|
||||
assert v
|
||||
|
||||
def test_sign_0(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||
sig = rsa_keys.compute_signature(0, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_sign_1(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||
sig = rsa_keys.compute_signature(0, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_ds_counter_1(card):
|
||||
c = get_data_object(card, 0x7a)
|
||||
assert c == b'\x93\x03\x00\x00\x02'
|
||||
|
||||
def test_sign_auth_0(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||
r = card.cmd_internal_authenticate(digestinfo)
|
||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_sign_auth_1(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||
r = card.cmd_internal_authenticate(digestinfo)
|
||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_decrypt_0(card):
|
||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == PLAIN_TEXT0
|
||||
|
||||
def test_decrypt_1(card):
|
||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == PLAIN_TEXT1
|
||||
from skip_if_emulation import *
|
||||
from card_test_personalize_card import *
|
||||
|
||||
@@ -1,81 +1,2 @@
|
||||
"""
|
||||
test_personalize_reset.py - test resetting personalization of card
|
||||
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from struct import pack
|
||||
from re import match, DOTALL
|
||||
from util import *
|
||||
import rsa_keys
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
def test_login_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5e, b"")
|
||||
assert r
|
||||
|
||||
def test_name_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5b, b"")
|
||||
assert r
|
||||
|
||||
def test_lang_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x2d, b"")
|
||||
assert r
|
||||
|
||||
def test_sex_put(card):
|
||||
try:
|
||||
# Gnuk
|
||||
r = card.cmd_put_data(0x5f, 0x35, b"")
|
||||
except ValueError:
|
||||
# OpenPGP card which doesn't allow b""
|
||||
r = card.cmd_put_data(0x5f, 0x35, b"9")
|
||||
assert r
|
||||
|
||||
def test_url_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x50, b"")
|
||||
assert r
|
||||
|
||||
def test_pw1_status_put(card):
|
||||
r = card.cmd_put_data(0x00, 0xc4, b"\x00")
|
||||
assert r
|
||||
|
||||
def test_setup_pw3_0(card):
|
||||
r = card.change_passwd(3, PW3_TEST0, FACTORY_PASSPHRASE_PW3)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_0(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_0(card):
|
||||
r = card.change_passwd(1, PW1_TEST4, FACTORY_PASSPHRASE_PW1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_0(card):
|
||||
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_0_2(card):
|
||||
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_delete_reset_code(card):
|
||||
r = card.cmd_put_data(0x00, 0xd3, b"")
|
||||
assert r
|
||||
from skip_if_emulation import *
|
||||
from card_test_personalize_reset import *
|
||||
|
||||
@@ -1,43 +1,2 @@
|
||||
"""
|
||||
test_remove_keys.py - test removing keys on card
|
||||
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
# Remove a key material on card by changing algorithm attributes of the key
|
||||
|
||||
from card_const import *
|
||||
|
||||
def test_rsa_keyattr_change_1(card):
|
||||
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA4K)
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xc1, KEY_ATTRIBUTES_RSA2K)
|
||||
assert r
|
||||
|
||||
def test_rsa_keyattr_change_2(card):
|
||||
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA4K)
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xc2, KEY_ATTRIBUTES_RSA2K)
|
||||
assert r
|
||||
|
||||
def test_rsa_keyattr_change_3(card):
|
||||
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA4K)
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xc3, KEY_ATTRIBUTES_RSA2K)
|
||||
assert r
|
||||
from skip_if_emulation import *
|
||||
from card_test_remove_keys import *
|
||||
|
||||
@@ -1,41 +1,2 @@
|
||||
"""
|
||||
test_004_reset_pw3.py - test resetting pw3
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from card_const import *
|
||||
|
||||
# Gnuk specific feature of clear PW3
|
||||
def test_setup_pw3_null(card):
|
||||
r = card.change_passwd(3, FACTORY_PASSPHRASE_PW3, None)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
# Check PW1 again to see the possiblity of admin-less mode
|
||||
def test_verify_pw1(card):
|
||||
v = card.verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
from skip_if_emulation import *
|
||||
from card_test_reset_pw3 import *
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_005_personalize_admin_less.py - test admin-less mode
|
||||
|
||||
Copyright (C) 2016, 2018 g10 Code GmbH
|
||||
Copyright (C) 2016, 2018, 2019 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -20,291 +20,10 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from struct import pack
|
||||
from re import match, DOTALL
|
||||
from util import *
|
||||
import rsa_keys
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
from skip_if_emulation import *
|
||||
from skip_gnuk_only_tests import *
|
||||
|
||||
def test_verify_pw3_0(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_rsa_import_key_1(card):
|
||||
t = rsa_keys.build_privkey_template(1, 0)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_rsa_import_key_2(card):
|
||||
t = rsa_keys.build_privkey_template(2, 1)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_rsa_import_key_3(card):
|
||||
t = rsa_keys.build_privkey_template(3, 2)
|
||||
r = card.cmd_put_data_odd(0x3f, 0xff, t)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_1_put(card):
|
||||
fpr1 = rsa_keys.fpr[0]
|
||||
r = card.cmd_put_data(0x00, 0xc7, fpr1)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_2_put(card):
|
||||
fpr2 = rsa_keys.fpr[1]
|
||||
r = card.cmd_put_data(0x00, 0xc8, fpr2)
|
||||
assert r
|
||||
|
||||
def test_fingerprint_3_put(card):
|
||||
fpr3 = rsa_keys.fpr[2]
|
||||
r = card.cmd_put_data(0x00, 0xc9, fpr3)
|
||||
assert r
|
||||
|
||||
def test_timestamp_1_put(card):
|
||||
timestamp1 = rsa_keys.timestamp[0]
|
||||
r = card.cmd_put_data(0x00, 0xce, timestamp1)
|
||||
assert r
|
||||
|
||||
def test_timestamp_2_put(card):
|
||||
timestamp2 = rsa_keys.timestamp[1]
|
||||
r = card.cmd_put_data(0x00, 0xcf, timestamp2)
|
||||
assert r
|
||||
|
||||
def test_timestamp_3_put(card):
|
||||
timestamp3 = rsa_keys.timestamp[2]
|
||||
r = card.cmd_put_data(0x00, 0xd0, timestamp3)
|
||||
assert r
|
||||
|
||||
def test_ds_counter_0(card):
|
||||
c = get_data_object(card, 0x7a)
|
||||
assert c == b'\x93\x03\x00\x00\x00'
|
||||
|
||||
def test_pw1_status(card):
|
||||
s = get_data_object(card, 0xc4)
|
||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||
|
||||
def test_app_data(card):
|
||||
app_data = get_data_object(card, 0x6e)
|
||||
hist_len = app_data[20]
|
||||
# FIXME: parse and check DO of C0, C1, C2, C3, C4, and C6
|
||||
assert app_data[0:8] == b"\x4f\x10\xd2\x76\x00\x01\x24\x01" and \
|
||||
app_data[18:18+2] == b"\x5f\x52"
|
||||
|
||||
def test_public_key_1(card):
|
||||
pk = card.cmd_get_public_key(1)
|
||||
assert rsa_keys.key[0][0] == pk[9:9+256]
|
||||
|
||||
def test_public_key_2(card):
|
||||
pk = card.cmd_get_public_key(2)
|
||||
assert rsa_keys.key[1][0] == pk[9:9+256]
|
||||
|
||||
def test_public_key_3(card):
|
||||
pk = card.cmd_get_public_key(3)
|
||||
assert rsa_keys.key[2][0] == pk[9:9+256]
|
||||
|
||||
# Changing PW1 to admin-less mode
|
||||
|
||||
def test_setup_pw1_0(card):
|
||||
r = card.change_passwd(1, FACTORY_PASSPHRASE_PW1, PW1_TEST0)
|
||||
assert r
|
||||
|
||||
# Now, it's admin-less mode, auth-status admin cleared
|
||||
|
||||
def test_verify_pw3_fail_1(card):
|
||||
try:
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
except ValueError as e:
|
||||
v = False
|
||||
assert not v
|
||||
|
||||
def test_verify_pw1_0(card):
|
||||
v = card.verify(1, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_0_2(card):
|
||||
v = card.verify(2, PW1_TEST0)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_1(card):
|
||||
r = card.change_passwd(1, PW1_TEST0, PW1_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_1(card):
|
||||
v = card.verify(1, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_1_2(card):
|
||||
v = card.verify(2, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_verify_pw3_admin_less_1(card):
|
||||
v = card.verify(3, PW1_TEST1)
|
||||
assert v
|
||||
|
||||
def test_setup_reset_code(card):
|
||||
r = card.setup_reset_code(RESETCODE_TEST)
|
||||
assert r
|
||||
|
||||
def test_reset_code(card):
|
||||
r = card.reset_passwd_by_resetcode(RESETCODE_TEST, PW1_TEST2)
|
||||
assert r
|
||||
|
||||
# Changing PW1, auth status for admin cleared
|
||||
def test_login_put_fail(card):
|
||||
try:
|
||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||
except ValueError as e:
|
||||
r = e.args[0]
|
||||
assert r == "6982"
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.verify(1, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_2_2(card):
|
||||
v = card.verify(2, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_verify_pw3_fail_2(card):
|
||||
try:
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
except ValueError as e:
|
||||
v = e.args[0]
|
||||
assert v == "6982"
|
||||
|
||||
def test_sign_0(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||
sig = rsa_keys.compute_signature(0, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
# Since forcesig setting, failed
|
||||
def test_sign_1(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||
try:
|
||||
r = card.cmd_pso(0x9e, 0x9a, digestinfo)
|
||||
except ValueError as e:
|
||||
r = e.args[0]
|
||||
assert r == "6982"
|
||||
|
||||
def test_ds_counter_1(card):
|
||||
c = get_data_object(card, 0x7a)
|
||||
assert c == b'\x93\x03\x00\x00\x01'
|
||||
|
||||
def test_sign_auth_0(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0)
|
||||
r = card.cmd_internal_authenticate(digestinfo)
|
||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_sign_auth_1(card):
|
||||
digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1)
|
||||
r = card.cmd_internal_authenticate(digestinfo)
|
||||
sig = rsa_keys.compute_signature(2, digestinfo)
|
||||
sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big')
|
||||
assert r == sig_bytes
|
||||
|
||||
def test_decrypt_0(card):
|
||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == PLAIN_TEXT0
|
||||
|
||||
def test_decrypt_1(card):
|
||||
ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == PLAIN_TEXT1
|
||||
|
||||
def test_verify_pw3_admin_less_2(card):
|
||||
v = card.verify(3, PW1_TEST2)
|
||||
assert v
|
||||
|
||||
def test_login_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5e, b"gpg_user")
|
||||
assert r
|
||||
|
||||
def test_name_put(card):
|
||||
r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User")
|
||||
assert r
|
||||
|
||||
def test_lang_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x2d, b"ja")
|
||||
assert r
|
||||
|
||||
def test_sex_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x35, b"1")
|
||||
assert r
|
||||
|
||||
def test_url_put(card):
|
||||
r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/")
|
||||
assert r
|
||||
|
||||
def test_pw1_status_put(card):
|
||||
r = card.cmd_put_data(0x00, 0xc4, b"\x01")
|
||||
assert r
|
||||
|
||||
def test_login(card):
|
||||
login = get_data_object(card, 0x5e)
|
||||
assert login == b"gpg_user"
|
||||
|
||||
def test_name_lang_sex(card):
|
||||
name = b"GnuPG User"
|
||||
lang = b"ja"
|
||||
sex = b"1"
|
||||
expected = b'\x5b' + pack('B', len(name)) + name \
|
||||
+ b'\x5f\x2d' + pack('B', len(lang)) + lang \
|
||||
+ b'\x5f\x35' + pack('B', len(sex)) + sex
|
||||
name_lang_sex = get_data_object(card, 0x65)
|
||||
assert name_lang_sex == expected
|
||||
|
||||
def test_url(card):
|
||||
url = get_data_object(card, 0x5f50)
|
||||
assert url == b"https://www.fsij.org/gnuk/"
|
||||
|
||||
def test_pw1_status(card):
|
||||
s = get_data_object(card, 0xc4)
|
||||
assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL)
|
||||
|
||||
# Setting PW3, changed to admin-full mode
|
||||
|
||||
def test_setup_pw3_1(card):
|
||||
r = card.change_passwd(3, PW1_TEST2, PW3_TEST1)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_1(card):
|
||||
v = card.verify(3, PW3_TEST1)
|
||||
assert v
|
||||
|
||||
def test_reset_userpass_admin(card):
|
||||
r = card.reset_passwd_by_admin(PW1_TEST3)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_3(card):
|
||||
v = card.verify(1, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_3_2(card):
|
||||
v = card.verify(2, PW1_TEST3)
|
||||
assert v
|
||||
|
||||
def test_setup_pw1_4(card):
|
||||
r = card.change_passwd(1, PW1_TEST3, PW1_TEST4)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_4(card):
|
||||
v = card.verify(1, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_verify_pw1_4_2(card):
|
||||
v = card.verify(2, PW1_TEST4)
|
||||
assert v
|
||||
|
||||
def test_setup_pw3_2(card):
|
||||
r = card.change_passwd(3, PW3_TEST1, PW3_TEST0)
|
||||
assert r
|
||||
|
||||
def test_verify_pw3_2(card):
|
||||
v = card.verify(3, PW3_TEST0)
|
||||
assert v
|
||||
from card_test_personalize_admin_less import *
|
||||
from card_test_personalize_reset import *
|
||||
from card_test_remove_keys import *
|
||||
from card_test_reset_pw3 import *
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
test_002_personalize_reset.py
|
||||
9
tests/test_006_pso.py
Normal file
9
tests/test_006_pso.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from skip_if_gnuk import *
|
||||
from card_test_ed25519 import *
|
||||
from card_test_x25519 import *
|
||||
from card_test_ansix9p256r1 import *
|
||||
from card_test_ansix9p384r1 import *
|
||||
from card_test_ansix9p512r1 import *
|
||||
from card_test_brainpoolp256r1 import *
|
||||
from card_test_brainpoolp384r1 import *
|
||||
from card_test_brainpoolp512r1 import *
|
||||
@@ -1 +0,0 @@
|
||||
test_003_remove_keys.py
|
||||
@@ -1 +0,0 @@
|
||||
test_004_reset_pw3.py
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_005_keygen.py - test key generation
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -20,64 +20,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from binascii import hexlify
|
||||
import rsa_keys
|
||||
from card_const import *
|
||||
|
||||
def test_keygen_1(card):
|
||||
pk = card.cmd_genkey(1)
|
||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||
r = card.cmd_put_data(0x00, 0xc7, fpr_date[0])
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xce, fpr_date[1])
|
||||
assert r
|
||||
|
||||
def test_keygen_2(card):
|
||||
pk = card.cmd_genkey(2)
|
||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||
r = card.cmd_put_data(0x00, 0xc8, fpr_date[0])
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xcf, fpr_date[1])
|
||||
assert r
|
||||
|
||||
def test_keygen_3(card):
|
||||
pk = card.cmd_genkey(3)
|
||||
fpr_date = rsa_keys.calc_fpr(pk[0], pk[1])
|
||||
r = card.cmd_put_data(0x00, 0xc9, fpr_date[0])
|
||||
if r:
|
||||
r = card.cmd_put_data(0x00, 0xd0, fpr_date[1])
|
||||
assert r
|
||||
|
||||
def test_verify_pw1(card):
|
||||
v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_signature_sigkey(card):
|
||||
msg = b"Sign me please"
|
||||
pk = card.cmd_get_public_key(1)
|
||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
||||
digest = rsa_keys.compute_digestinfo(msg)
|
||||
sig = int(hexlify(card.cmd_pso(0x9e, 0x9a, digest)),16)
|
||||
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
||||
assert r
|
||||
|
||||
def test_verify_pw1_2(card):
|
||||
v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1)
|
||||
assert v
|
||||
|
||||
def test_decryption(card):
|
||||
msg = b"encrypt me please"
|
||||
pk = card.cmd_get_public_key(2)
|
||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
||||
ciphertext = rsa_keys.encrypt_with_pubkey(pk_info, msg)
|
||||
r = card.cmd_pso(0x80, 0x86, ciphertext)
|
||||
assert r == msg
|
||||
|
||||
def test_signature_authkey(card):
|
||||
msg = b"Sign me please to authenticate"
|
||||
pk = card.cmd_get_public_key(3)
|
||||
pk_info = (pk[9:9+256], pk[9+256+2:9+256+2+3])
|
||||
digest = rsa_keys.compute_digestinfo(msg)
|
||||
sig = int(hexlify(card.cmd_internal_authenticate(digest)),16)
|
||||
r = rsa_keys.verify_signature(pk_info, digest, sig)
|
||||
assert r
|
||||
from skip_if_emulation import *
|
||||
from card_test_keygen import *
|
||||
from card_test_remove_keys import *
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
test_003_remove_keys.py
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_007_kdf_full.py - test KDF data object
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -20,15 +20,10 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
from skip_gnuk_only_tests import *
|
||||
|
||||
def test_verify_pw3(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_kdf_put_full(card):
|
||||
r = card.cmd_put_data(0x00, 0xf9, KDF_FULL)
|
||||
if r:
|
||||
card.configure_with_kdf()
|
||||
assert r
|
||||
from card_test_kdf_full import *
|
||||
from card_test_personalize_card import *
|
||||
from card_test_personalize_reset import *
|
||||
from card_test_remove_keys import *
|
||||
from card_test_reset_pw3 import *
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
test_001_personalize_card.py
|
||||
@@ -1 +0,0 @@
|
||||
test_002_personalize_reset.py
|
||||
@@ -1 +0,0 @@
|
||||
test_003_remove_keys.py
|
||||
@@ -1 +0,0 @@
|
||||
test_004_reset_pw3.py
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
test_012_kdf_single.py - test KDF data object
|
||||
|
||||
Copyright (C) 2018 g10 Code GmbH
|
||||
Copyright (C) 2018, 2019 g10 Code GmbH
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -20,15 +20,10 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
from skip_gnuk_only_tests import *
|
||||
|
||||
def test_verify_pw3(card):
|
||||
v = card.verify(3, FACTORY_PASSPHRASE_PW3)
|
||||
assert v
|
||||
|
||||
def test_kdf_put_single(card):
|
||||
r = card.cmd_put_data(0x00, 0xf9, KDF_SINGLE)
|
||||
if r:
|
||||
card.configure_with_kdf()
|
||||
assert r
|
||||
from card_test_kdf_single import *
|
||||
from card_test_personalize_card import *
|
||||
from card_test_personalize_reset import *
|
||||
from card_test_remove_keys import *
|
||||
from card_test_reset_pw3 import *
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
test_001_personalize_card.py
|
||||
@@ -1 +0,0 @@
|
||||
test_002_personalize_reset.py
|
||||
@@ -1 +0,0 @@
|
||||
test_003_remove_keys.py
|
||||
@@ -1 +0,0 @@
|
||||
test_004_reset_pw3.py
|
||||
@@ -1 +0,0 @@
|
||||
test_005_personalize_admin_less.py
|
||||
5
tests/test_021_personalize_admin_less.py
Normal file
5
tests/test_021_personalize_admin_less.py
Normal file
@@ -0,0 +1,5 @@
|
||||
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 *
|
||||
@@ -1 +0,0 @@
|
||||
test_002_personalize_reset.py
|
||||
@@ -1 +0,0 @@
|
||||
test_003_remove_keys.py
|
||||
@@ -1 +0,0 @@
|
||||
test_004_reset_pw3.py
|
||||
@@ -20,6 +20,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from skip_gnuk_only_tests import *
|
||||
|
||||
from card_const import *
|
||||
from constants_for_test import *
|
||||
|
||||
|
||||
@@ -109,15 +109,15 @@ def build_rsakey_from_ssh_key_under_gpg_agent(g, timestamp=None):
|
||||
# The information is in SEXP format, extract N and E
|
||||
s = sexp(pubkey_info_str)
|
||||
if s[0] != 'public-key':
|
||||
print s
|
||||
print(s)
|
||||
exit(1)
|
||||
rsa = s[1]
|
||||
if rsa[0] != 'rsa':
|
||||
print rsa
|
||||
print(rsa)
|
||||
exit(1)
|
||||
n_x = rsa[1]
|
||||
if n_x[0] != 'n':
|
||||
print n_x
|
||||
print(n_x)
|
||||
exit(1)
|
||||
n_byte_str = n_x[1]
|
||||
while n_byte_str[0] == '\x00':
|
||||
@@ -125,7 +125,7 @@ def build_rsakey_from_ssh_key_under_gpg_agent(g, timestamp=None):
|
||||
n = n_byte_str
|
||||
e_x = rsa[2]
|
||||
if e_x[0] != 'e':
|
||||
print e_x
|
||||
print(e_x)
|
||||
exit(1)
|
||||
e = e_x[1]
|
||||
if not timestamp:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user