Compare commits
183 Commits
release/0.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f39380d3aa | ||
|
|
0d36a58804 | ||
|
|
eb0e913eee | ||
|
|
7575dda42a | ||
|
|
61ec9b7ed7 | ||
|
|
b49390de7a | ||
|
|
71eaffc0ee | ||
|
|
5e9a35c881 | ||
|
|
df5b7f31a3 | ||
|
|
add6fa8b67 | ||
|
|
c488bed215 | ||
|
|
63979416f6 | ||
|
|
92be182e8a | ||
|
|
9ffa68355d | ||
|
|
814f6b6329 | ||
|
|
1927f8a1ec | ||
|
|
d3fb62b437 | ||
|
|
5d3e6c2b29 | ||
|
|
8be278be17 | ||
|
|
6de9c11329 | ||
|
|
63df97a2e0 | ||
|
|
144dd88a07 | ||
|
|
e80c8f1e8e | ||
|
|
99d7e8d396 | ||
|
|
f38f33dade | ||
|
|
cbed6b49c7 | ||
|
|
51435e7dba | ||
|
|
29b68186bf | ||
|
|
a5fddc691d | ||
|
|
965dace0a4 | ||
|
|
ee4f3806c2 | ||
|
|
9ad6c6461d | ||
|
|
a796e9f145 | ||
|
|
f88e7af3ce | ||
|
|
fe31219d94 | ||
|
|
6f97e8a7c4 | ||
|
|
e78206e1cd | ||
|
|
ffba0e0158 | ||
|
|
324b648de8 | ||
|
|
9ef97836c9 | ||
|
|
628c03634b | ||
|
|
315bef4639 | ||
|
|
610573256e | ||
|
|
976e123413 | ||
|
|
6f4c868336 | ||
|
|
33c3980e46 | ||
|
|
6d8580f67a | ||
|
|
506761d823 | ||
|
|
09f22b114c | ||
|
|
9f0b8ff4c3 | ||
|
|
2764bbb5a9 | ||
|
|
3202b7d45c | ||
|
|
19e677ae74 | ||
|
|
9cc6de9e65 | ||
|
|
0988474d87 | ||
|
|
d564e4a3c1 | ||
|
|
839b0156a9 | ||
|
|
92d500d4b5 | ||
|
|
1944a78443 | ||
|
|
e11d81376c | ||
|
|
3c7a5bff61 | ||
|
|
a41476ab32 | ||
|
|
1118cd030a | ||
|
|
e6e11ddcb0 | ||
|
|
5c5074c5c7 | ||
|
|
d3f092a736 | ||
|
|
70efd3a1cd | ||
|
|
fd9f46bcc7 | ||
|
|
6f203bc4ea | ||
|
|
c25d98bc58 | ||
|
|
4290a2cc10 | ||
|
|
b3c15ce93c | ||
|
|
cb8ee10292 | ||
|
|
3df59ca6f9 | ||
|
|
6a4d7fa108 | ||
|
|
de51fc2fd4 | ||
|
|
c61a63dbb6 | ||
|
|
e0282629e3 | ||
|
|
fe58e86c6c | ||
|
|
abd64bc495 | ||
|
|
2d5246e7fa | ||
|
|
94a65f0d99 | ||
|
|
2e5973e7cc | ||
|
|
a5d77ec5af | ||
|
|
a2855c9442 | ||
|
|
670e9058f1 | ||
|
|
81f8f94dd4 | ||
|
|
956e89d10a | ||
|
|
ec0297050a | ||
|
|
258552e544 | ||
|
|
17fd82ffa1 | ||
|
|
3fa01ef7a9 | ||
|
|
ee743ca042 | ||
|
|
39a3cb8b09 | ||
|
|
2db7875da7 | ||
|
|
3da8a3b326 | ||
|
|
808cb61b9a | ||
|
|
75bfa6068a | ||
|
|
37b1992f10 | ||
|
|
bfa4952f31 | ||
|
|
1164ac4d28 | ||
|
|
f73634d17c | ||
|
|
07b1266727 | ||
|
|
961b808adb | ||
|
|
879b8b9966 | ||
|
|
78d9a56277 | ||
|
|
75b480f2c2 | ||
|
|
19d9e55613 | ||
|
|
441051a485 | ||
|
|
42f9c16fd8 | ||
|
|
7860f1e729 | ||
|
|
5cafb8a84f | ||
|
|
41633871fe | ||
|
|
fa2ae42e69 | ||
|
|
2215a6dd2c | ||
|
|
95f328f94f | ||
|
|
34bd069743 | ||
|
|
c5762e7891 | ||
|
|
ab51c5421d | ||
|
|
093c98bb0f | ||
|
|
6ba65c8d8b | ||
|
|
f8bb88227a | ||
|
|
cc95fff074 | ||
|
|
7ae467f874 | ||
|
|
01de6a74c5 | ||
|
|
08563d5a65 | ||
|
|
e2ab8c9183 | ||
|
|
8d8e67f1ad | ||
|
|
1576b8303e | ||
|
|
ba8609be41 | ||
|
|
3588fbd97a | ||
|
|
54f52838ef | ||
|
|
f072de436b | ||
|
|
cb1dc21b61 | ||
|
|
4e8af02ac0 | ||
|
|
95fd3711d8 | ||
|
|
0bda48c985 | ||
|
|
ded02a6808 | ||
|
|
8538ac19d0 | ||
|
|
cdc9d441a6 | ||
|
|
7dd703c28b | ||
|
|
1e9b73de49 | ||
|
|
2113d5b751 | ||
|
|
6b47ee56b8 | ||
|
|
8c6ffaa167 | ||
|
|
37f82b6026 | ||
|
|
1c910fc3e2 | ||
|
|
e99d129c97 | ||
|
|
94e38ae1bc | ||
|
|
0c721d6e10 | ||
|
|
21053abc51 | ||
|
|
4a59c73bc3 | ||
|
|
b02c6a480d | ||
|
|
dec12d4b15 | ||
|
|
b1cc1ec6f6 | ||
|
|
d31b2211c6 | ||
|
|
365b59cd56 | ||
|
|
80e2d33a51 | ||
|
|
8e4775ab4a | ||
|
|
d3af289b3c | ||
|
|
84e3a5c1a6 | ||
|
|
6c205c3111 | ||
|
|
244cdbff3f | ||
|
|
b202f95376 | ||
|
|
86b1c1848a | ||
|
|
ab4e0c2167 | ||
|
|
cc80c3e433 | ||
|
|
11be169187 | ||
|
|
abfe779728 | ||
|
|
12c94c1f22 | ||
|
|
449b3c35ba | ||
|
|
dc85bcfb92 | ||
|
|
f95cf8942b | ||
|
|
810b0d9a5b | ||
|
|
b7599feb4f | ||
|
|
48f143aa31 | ||
|
|
0c4fb96c1a | ||
|
|
c723df0841 | ||
|
|
87d36deeb9 | ||
|
|
ce338a9727 | ||
|
|
e2e2e1a045 | ||
|
|
f2afeacdcb | ||
|
|
429c6f3d8b |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,14 +1,17 @@
|
||||
# generated files by 'configure'
|
||||
src/Makefile
|
||||
src/config.h
|
||||
src/gnuk.ld
|
||||
*.lst
|
||||
*.o
|
||||
*.pyc
|
||||
src/.dep
|
||||
src/Makefile
|
||||
src/config.h
|
||||
src/gnuk.ld
|
||||
src/gnuk.bin
|
||||
src/gnuk.dmp
|
||||
src/gnuk.elf
|
||||
src/gnuk.hex
|
||||
src/gnuk.map
|
||||
src/*.inc
|
||||
regnual/regnual.bin
|
||||
regnual/regnual.hex
|
||||
regnual/regnual.elf
|
||||
doc/_build
|
||||
|
||||
43
AUTHORS
43
AUTHORS
@@ -37,32 +37,39 @@ NIIBE Yutaka:
|
||||
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:
|
||||
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/main.c
|
||||
src/usb_lld.h
|
||||
src/gnuk.h
|
||||
src/usb_lld.c
|
||||
src/usb-icc.c
|
||||
src/openpgp-do.c
|
||||
src/flash.c
|
||||
src/debug.c
|
||||
src/usb_desc.c
|
||||
src/usb-cdc-vport.c
|
||||
src/hardclock.c
|
||||
src/openpgp.h
|
||||
src/openpgp.c
|
||||
src/call-rsa.c
|
||||
src/random.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/usb_msc.c
|
||||
src/usb_msc.h
|
||||
src/neug.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.
|
||||
|
||||
669
ChangeLog
669
ChangeLog
@@ -1,3 +1,672 @@
|
||||
2012-08-03 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 1.0.1.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
* src/main.c (ID_OFFSET): Fix.
|
||||
|
||||
2012-08-02 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/gnuk.py (gnuk_token.get_string): New.
|
||||
* test/features/991_version_string.feature: New.
|
||||
|
||||
2012-07-21 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 1.0.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
Documentation by Sphinx.
|
||||
* doc/Makefile: New.
|
||||
* doc/note: Old notes are moved here.
|
||||
|
||||
2012-07-20 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/002_get_data_static.feature: Support CERTDO enabled
|
||||
Gnuk for the test of extended capabilities.
|
||||
* test/features/802_get_data_static.feature: Ditto.
|
||||
* test/features/402_get_data_static.feature: Ditto.
|
||||
|
||||
2012-07-10 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/*: Add test cases for PW1/PW3 of factory settings.
|
||||
|
||||
* test/features/202_keygen.feature: Add PSO signature test after
|
||||
keygen.
|
||||
* test/features/602_keygen.feature: Ditto.
|
||||
|
||||
Bug fix.
|
||||
* src/openpgp-do.c (gpg_do_write_prvkey): Don't call ac_reset_*
|
||||
here.
|
||||
(proc_key_import): But call ac_reset_* here.
|
||||
(gpg_do_keygen): Load private key for signing.
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.usb_disconnect): New.
|
||||
|
||||
2012-07-09 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_pso): For decryption, return error sooner for
|
||||
invalid data.
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.setup_gpio): Fix GPIOB_CRL.
|
||||
|
||||
* test/rsa_keys.py (integer_to_bytes_256): Rename from
|
||||
integer_to_bytes and it should be exactly 256-byte long.
|
||||
|
||||
2012-07-06 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.21.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
* boards/FST_01/board.h (VAL_GPIOACRL): Change for SPI flash.
|
||||
* tool/stlinkv2.py (stlinkv2.setup_gpio): Likewise.
|
||||
(stlinkv2.spi_flash_init, stlinkv2.spi_flash_select)
|
||||
(stlinkv2.spi_flash_sendbyte, stlinkv2.spi_flash_read_id): New.
|
||||
(main): Add SPI flash ROM id check.
|
||||
|
||||
2012-07-05 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/call-rsa.c (rsa_sign, rsa_decrypt): Don't need to setup N.
|
||||
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_check_pubkey)
|
||||
(rsa_check_privkey): Ifdef-out.
|
||||
|
||||
More tests.
|
||||
* test/*: Add tests for admin-less mode.
|
||||
* test/features/990_reset_passphrase.feature: This is now for
|
||||
admin-less mode.
|
||||
* test/features/970_key_removal.feature: Ditto.
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Call ac_reset_admin when
|
||||
admin-less mode.
|
||||
(cmd_reset_user_password): Likewise.
|
||||
|
||||
* src/ac.c (ac_reset_admin, ac_fini): Clear ADMIN_AUTHORIZED.
|
||||
|
||||
Bug fix.
|
||||
* src/ac.c (verify_admin): Call s2k with ADMIN_AUTHORIZED.
|
||||
|
||||
2012-07-04 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Bug fixes.
|
||||
* src/ac.c (verify_admin_0): Compare PW_LEN and BUF_LEN.
|
||||
|
||||
* src/openpgp-do.c (gpg_do_chks_prvkey): Set do_ptr to NULL before
|
||||
calling flash_do_write (which might cause GC).
|
||||
(gpg_do_put_data, gpg_do_write_simple): Likewise.
|
||||
|
||||
* src/openpgp.c (cmd_reset_user_password): Write to
|
||||
DO_KEYSTRING_PW1.
|
||||
|
||||
2012-07-03 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/040_passphrase_change.feature: New.
|
||||
* test/features/203_passphrase_change.feature: New.
|
||||
* test/features/210_compute_signature.feature: Rename (was:
|
||||
203_compute_signature.feature)
|
||||
* test/features/211_decryption.feature: Rename (was:
|
||||
204_decryption.feature)
|
||||
|
||||
2012-07-02 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.__init__): Don't call setAltInterface.
|
||||
|
||||
2012-06-30 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (s2k): New.
|
||||
(resetcode_s2k): Remove.
|
||||
(cmd_reset_user_password, cmd_change_password): Use s2k (was:
|
||||
sha256 directly or resetcode_s2k).
|
||||
* src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey):
|
||||
Likewise.
|
||||
* src/ac.c (verify_user_0, verify_admin): Likewise.
|
||||
|
||||
2012-06-29 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* regnual/Makefile: Don't copy usb_lld.c.
|
||||
|
||||
2012-06-28 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/204_decryption.feature: New.
|
||||
* test/features/203_compute_signature.feature: New.
|
||||
* test/features/202_keygen.feature: New.
|
||||
* test/features/201_setup_passphrase.feature: New.
|
||||
* test/features/200_key_removal.feature: New.
|
||||
|
||||
* test/rsa_keys.py (verify_signature): New.
|
||||
(encrypt_with_pubkey): New.
|
||||
|
||||
* test/gnuk.py (gnuk_token): New method: increment_seq.
|
||||
(gnuk_token.icc_send_cmd): Handle timeout.
|
||||
(gnuk_token.cmd_genkey): New.
|
||||
(gnuk_token.cmd_get_public_key): New.
|
||||
|
||||
2012-06-27 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test/features/101_decryption.feature: New.
|
||||
* test/features/100_compute_signature.feature: New.
|
||||
|
||||
* src/openpgp-do.c (gpg_do_chks_prvkey): Call flash_do_release before
|
||||
flash_do_write.
|
||||
(gpg_do_write_prvkey): Bug fix when GC occurs.
|
||||
|
||||
* src/openpgp.c (cmd_change_password): Support resetting to
|
||||
factory setting of PW3.
|
||||
|
||||
* src/openpgp-do.c (gpg_do_write_prvkey): Don't reset signagure
|
||||
counter here.
|
||||
(proc_key_import): But reset here.
|
||||
Call ac_reset_* when key is imported.
|
||||
|
||||
2012-06-26 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* test: New.
|
||||
|
||||
2012-06-25 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/usb_strings.py: New.
|
||||
|
||||
2012-06-22 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/stlinkv2.py (stlinkv2.blank_check): Add blank check of
|
||||
Flash ROM.
|
||||
|
||||
2012-06-21 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/asm-thumb/blank_check.S: New.
|
||||
|
||||
2012-06-20 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
ST-Link/V2 flash ROM writer.
|
||||
* tool/stlinkv2.py: New.
|
||||
* tool/asm-thumb/opt_bytes_write.S: New.
|
||||
* tool/asm-thumb/flash_write.S: New.
|
||||
|
||||
2012-06-19 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.20.
|
||||
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
2012-06-18 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
LED display output change.
|
||||
* src/main.c (MAIN_TIMEOUT_INTERVAL): New.
|
||||
(LED_TIMEOUT_INTERVAL, etc.): New values.
|
||||
(main_mode, display_interaction): Remove.
|
||||
(led_inverted, emit_led): New.
|
||||
(display_status_code): Use emit_led.
|
||||
(led_blink): Use LED_* for SPEC.
|
||||
(main, fatal): New LED display output.
|
||||
* src/gnuk.h (LED_ONESHOT, LED_TWOSHOTS, LED_SHOW_STATUS)
|
||||
(LED_START_COMMAND, LED_FINISH_COMMAND, LED_FATAL): New semantics.
|
||||
(main_thread): Remove.
|
||||
* src/openpgp-do.c (gpg_do_keygen): Don't touch LED here.
|
||||
* src/openpgp.c (get_pinpad_input): Call led_blink.
|
||||
(cmd_pso, cmd_internal_authenticate): Don't touch LED here.
|
||||
(GPGthread): Call led_blink.
|
||||
* src/pin-cir.c (pinpad_getline): Change arg of led_blink.
|
||||
* src/pin-dnd.c (pinpad_getline): Ditto.
|
||||
* src/usb-icc.c (icc_handle_timeout): Ditto.
|
||||
(icc_send_status): Call led_blink.
|
||||
* src/usb_ctrl.c (gnuk_usb_event): Don't touch LED here.
|
||||
|
||||
2012-06-16 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Use SHA256 format for "external authenticate".
|
||||
* tool/gnuk_upgrade.py (gpg_sign): SHA256 sign by "SCD PKAUTH".
|
||||
(main): Not specify keygrip, but always use key for authentication.
|
||||
* src/call-rsa.c (rsa_verify): It is SHA256 format (was: SHA1).
|
||||
* src/openpgp.c (cmd_get_challenge): Don't add chip-id prefix.
|
||||
(cmd_external_authenticate): Likewise.
|
||||
|
||||
2012-06-15 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/random.c (random_bytes_free): Clear out random bytes.
|
||||
|
||||
More protection improvements.
|
||||
* src/random.c (RANDOM_BYTES_LENGTH): It's 32 now (was: 16).
|
||||
* src/gnuk.h (struct key_data_internal): Remove check, random,
|
||||
magic. Add checksum.
|
||||
(struct prvkey_data): Remove crm_encrypted. Add iv and
|
||||
checksum_encrypted.
|
||||
* src/openpgp-do.c (encrypt, decrypt): Add IV argument.
|
||||
(encrypt_dek, decrypt_dek): New. It's in ECB mode.
|
||||
(compute_key_data_checksum): New.
|
||||
(gpg_do_load_prvkey): Handle initial vector and checksum.
|
||||
Use decrypt_dek to decrypt DEK. Clear DEK after use.
|
||||
(calc_check32):Remove.
|
||||
(gpg_do_write_prvkey): Use encrypt_dek to encrypt DEK.
|
||||
(gpg_do_chks_prvkey): Likewise.
|
||||
|
||||
* polarssl-0.14.0/include/polarssl/aes.h (aes_crypt_cbc)
|
||||
* polarssl-0.14.0/library/aes.c (aes_crypt_cbc): ifdef-out.
|
||||
|
||||
* src/configure (--enable-pinpad): Deprecate DND.
|
||||
|
||||
2012-06-14 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Protection improvement.
|
||||
* src/openpgp.c (resetcode_s2k): New.
|
||||
(cmd_reset_user_password): Use resetcode_s2k.
|
||||
* src/openpgp-do.c (proc_resetting_code): Likewise.
|
||||
|
||||
* src/sha256.c (sha256_finish): Clear out CTX at the end.
|
||||
|
||||
* src/call-rsa.c (rsa_sign, rsa_decrypt, rsa_verify): Use
|
||||
mpi_lset (was: mpi_read_string).
|
||||
* polarssl-0.14.0/library/bignum.c (mpi_get_digit)
|
||||
(mpi_read_string): ifdef-out.
|
||||
|
||||
KDF is now SHA-256 (was: SHA1).
|
||||
* src/sha256.c: New file. Based on the implementation by Dr Brian
|
||||
Gladman.
|
||||
* src/openpgp.c (cmd_change_password, cmd_reset_user_password):
|
||||
Use sha256.
|
||||
* src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey): Likewise.
|
||||
* src/ac.c (verify_user_0, calc_md, verify_admin): Likewise.
|
||||
* src/crypt.mk (CRYPTSRC): Add sha256.c, removing sha1.c.
|
||||
* src/gnuk.h (KEYSTRING_MD_SIZE): It's 32 for SHA-256.
|
||||
|
||||
2012-06-13 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Bug fixes.
|
||||
* src/main.c (display_interaction): Assign to main_mode.
|
||||
* src/openpgp.c (cmd_change_password): Bug fix for admin less mode
|
||||
to admin full mode. Variable who_old should be admin_authorized.
|
||||
|
||||
Key generation is configure option.
|
||||
* src/configure (keygen): Add --enable-keygen option.
|
||||
* src/Makefile.in (UDEFS): Add definition of KEYGEN_SUPPORT.
|
||||
* src/call-rsa.c [KEYGEN_SUPPORT] (rsa_genkey): Conditionalize.
|
||||
* src/random.c [KEYGEN_SUPPORT] (random_byte): Ditto.
|
||||
* src/openpgp.c [KEYGEN_SUPPORT] (cmd_pgp_gakp): Ditto.
|
||||
* src/openpgp-do.c [KEYGEN_SUPPORT] (gpg_do_keygen): Ditto.
|
||||
* polarssl-0.14.0/include/polarssl/config.h: Ditto.
|
||||
* polarssl-0.14.0/library/bignum.c [POLARSSL_GENPRIME]
|
||||
(mpi_inv_mod): Unconditionalize.
|
||||
|
||||
2012-06-08 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* polarssl-0.14.0/library/bignum.c (mpi_cmp_mpi): Bug fix.
|
||||
Though it doesn't matter for Gnuk usage.
|
||||
|
||||
Emit LED light while computation (or asking user input).
|
||||
* src/usb-icc.c (icc_handle_timeout): Call led_blink.
|
||||
* src/openpgp.c (cmd_pso, cmd_internal_authenticate): Call
|
||||
LED_WAIT_MODE, LED_STATUS_MODE to show "it's under computation".
|
||||
* src/openpgp-do.c (gpg_do_keygen): Ditto.
|
||||
* src/gnuk.h (LED_WAIT_MODE): Rename (was: LED_INPUT_MODE).
|
||||
* src/main.c (display_interaction): Change the behavior of LED,
|
||||
now, it's mostly ON (was: mostly OFF).
|
||||
|
||||
2012-06-07 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (cmd_internal_authenticate): Add check for input
|
||||
length.
|
||||
|
||||
Implement key generation.
|
||||
* src/openpgp.c (cmd_pgp_gakp): Call gpg_do_keygen.
|
||||
* src/openpgp-do.c (proc_key_import): Call with modulus = NULL.
|
||||
(gpg_do_keygen): New function.
|
||||
(gpg_reset_digital_signature_counter): New function.
|
||||
(gpg_do_write_prvkey): New argument MODULUS. Call
|
||||
gpg_reset_digital_signature_counter.
|
||||
* src/call-rsa.c (rsa_genkey): New function.
|
||||
* src/random.c (random_byte): New function.
|
||||
|
||||
PolarSSL modification.
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_gen_key): Don't set D, DP,
|
||||
DQ, and QP. It's only for key generation.
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_gen_key, rsa_pkcs1_encrypt):
|
||||
Change f_rng function return type.
|
||||
* polarssl-0.14.0/include/polarssl/rsa.h: Likewise.
|
||||
* polarssl-0.14.0/library/bignum.c (mpi_is_prime, mpi_gen_prime):
|
||||
Change f_rng function return type.
|
||||
* polarssl-0.14.0/include/polarssl/bignum.h: Likewise.
|
||||
|
||||
2012-06-06 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.19.
|
||||
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
* regnual/regnual.c (fetch): Better implementation.
|
||||
|
||||
2012-06-05 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Firmware update key handling.
|
||||
* tool/gnuk_put_binary.py (GnukToken.cmd_get_response): Handle
|
||||
larger data such as card holder certificate.
|
||||
(GnukToken.cmd_write_binary): Bug fix for cert do write.
|
||||
(GnukToken.cmd_read_binary): New.
|
||||
(main): Support firmware update key.
|
||||
|
||||
Take advantage of the Thumb-2 "rbit" instruction.
|
||||
* regnual/regnual.c (fetch): Reverse bits.
|
||||
* src/usb_ctrl.c (rbit): New. Deleted reverse32.
|
||||
(download_check_crc32): Use rbit.
|
||||
* tool/gnuk_upgrade.py (crc32): Just use binascii.crc32.
|
||||
(crctab): Remove.
|
||||
|
||||
2012-06-04 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Card holder certificate data object bug fixes.
|
||||
* tool/gnuk_put_binary_libusb.py (gnuk_token.cmd_get_response):
|
||||
Handle larger data such as card holder certificate.
|
||||
* src/flash.c (flash_write_binary): Bug fix. Call
|
||||
flash_check_blank with p + offset.
|
||||
* src/gnuk.h (FLASH_CH_CERTIFICATE_SIZE): Define here (was: flash.c).
|
||||
|
||||
Implement CRC32 check for firmware update.
|
||||
* src/usb_ctrl.c (download_check_crc32): New.
|
||||
* regnual/regnual.c (calc_crc32): New.
|
||||
(regnual_ctrl_write_finish): Call calc_crc32.
|
||||
* tool/gnuk_upgrade.py (crc32): New.
|
||||
(regnual.download): Check crc32code.
|
||||
|
||||
* regnual/regnual.c (regnual_ctrl_write_finish): Bug fix.
|
||||
|
||||
2012-06-01 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Support firmware update with public key authentication.
|
||||
* tool/gnuk_upgrade.py (gpg_sign): New.
|
||||
* tool/gnuk_put_binary_libusb.py (main): Support firmware update
|
||||
key registration.
|
||||
|
||||
Update of reGNUal.
|
||||
* regnual/regnual.c (main): Follow the change of usb_lld_init.
|
||||
(regnual_config_desc): Include interface descriptor.
|
||||
(usb-strings.c.inc): Change the file name.
|
||||
* regnual/Makefile (regnual.o): Depend on sys.h.
|
||||
* src/configure (usb-strings.c.inc): ifdef-out
|
||||
gnuk_revision_detail and gnuk_config_options (for reGNUal).
|
||||
* src/usb_desc.c (USB_STRINGS_FOR_GNUK): Define.
|
||||
|
||||
USB bug fixes.
|
||||
* src/usb_ctrl.c (gnuk_usb_event): Bug fix for handling
|
||||
USB_EVENT_CONFIG. Do nothing when current_conf == value.
|
||||
* src/usb_lld.c (std_clear_feature): Bug fix. Always clear DTOG.
|
||||
(usb_lld_init): New argument for FEATURE.
|
||||
|
||||
2012-05-31 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_pkcs1_verify): BUF size is
|
||||
256 (was: 1024).
|
||||
* src/call-rsa.c (rsa_verify): It's SIG_RSA_SHA1.
|
||||
* src/openpgp.c (cmd_external_authenticate): Follow the change of
|
||||
rsa_verify.
|
||||
|
||||
Support "firmware update" keys.
|
||||
* src/flash.c (flash_write_binary): Support update keys.
|
||||
* src/gnuk.h (FILEID_UPDATE_KEY_0, FILEID_UPDATE_KEY_1)
|
||||
(FILEID_UPDATE_KEY_2,FILEID_UPDATE_KEY_3): New.
|
||||
* src/gnuk.ld.in (_updatekey_store): New.
|
||||
* src/openpgp.c (FILE_EF_UPDATE_KEY_0, FILE_EF_UPDATE_KEY_1)
|
||||
(FILE_EF_UPDATE_KEY_2, FILE_EF_UPDATE_KEY_3): New.
|
||||
(gpg_get_firmware_update_key): New.
|
||||
(cmd_read_binary): Support update keys and certificate.
|
||||
(modify_binary): New.
|
||||
(cmd_update_binary, cmd_write_binary): Use modify_binary.
|
||||
(cmd_external_authenticate): Support up to four keys.
|
||||
|
||||
Version string of system service is now USB string.
|
||||
* src/sys.h (unique_device_id): Define here, not as system
|
||||
service.
|
||||
* src/sys.c (sys_version): Version string for system service.
|
||||
* src/usb_desc.c (String_Descriptors): Add sys_version.
|
||||
* src/usb_conf.h (NUM_STRING_DESC): 7 (was: 6).
|
||||
* src/gnuk.ld.in (.sys.version): New section.
|
||||
|
||||
2012-05-30 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/openpgp.c (CHALLENGE_LEN): New.
|
||||
(cmd_external_authenticate): Authentication by response with
|
||||
public key.
|
||||
(cmd_get_challenge): 16-byte is enough for challenge.
|
||||
|
||||
2012-05-29 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/call-rsa.c (rsa_verify): New function.
|
||||
|
||||
* polarssl-0.14.0/include/polarssl/rsa.h (rsa_pkcs1_verify)
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_pkcs1_verify): Fix API.
|
||||
|
||||
* src/usb_conf.h (NUM_STRING_DESC): Incremented to 6 (was: 4).
|
||||
* src/configure: Generate strings for revision detail and config
|
||||
options.
|
||||
* src/usb_desc.c (gnuk_revision_detail, gnuk_config_options): New.
|
||||
|
||||
* src/main.c (main) [DFU_SUPPORT]: Kill DFU and install .sys.
|
||||
|
||||
* src/config.h.in (FLASH_PAGE_SIZE): New.
|
||||
* src/configure: Support FLASH_PAGE_SIZE for config.h
|
||||
* boards/*/board.h (FLASH_PAGE_SIZE): Remove.
|
||||
* src/flash.c (FLASH_PAGE_SIZE): Remove.
|
||||
|
||||
* src/sys.c (reset): Don't depend if DFU_SUPPORT or not.
|
||||
(flash_erase_all_and_exec): Rename and change the argument.
|
||||
* src/gnuk.ld.in (__flash_start__): Real flash ROM address,
|
||||
regardless of DFU_SUPPORT.
|
||||
* src/main.c (main): Call flash_erase_all_and_exec with SRAM
|
||||
address.
|
||||
|
||||
* polarssl-0.14.0/library/aes.c (FT0, FT1, FT2): Specify sections
|
||||
in detail, so that addresses won't be affected by compiler.
|
||||
* src/gnuk.ld.in (.sys): Define sections in detail.
|
||||
|
||||
* boards/STBEE_MINI/board.h (SET_USB_CONDITION, GPIO_USB)
|
||||
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
|
||||
(FLASH_PAGE_SIZE): New.
|
||||
* boards/STBEE_MINI/board.c (USB_Cable_Config, set_led): Remove.
|
||||
|
||||
* boards/STBEE/board.h (SET_USB_CONDITION, GPIO_USB, IOPORT_USB)
|
||||
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
|
||||
* boards/STBEE/board.c (USB_Cable_Config, set_led): Remove.
|
||||
|
||||
* boards/CQ_STARM/board.h (SET_USB_CONDITION)
|
||||
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
|
||||
* boards/CQ_STARM/board.c (USB_Cable_Config, set_led): Remove.
|
||||
|
||||
2012-05-28 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* boards/*/board.c (hwinit0): Removed...
|
||||
* boards/common/hwinit.c (hwinit0): ... and define here.
|
||||
(hwinit0) [DFU_SUPPORT]: Don't set SCB->VTOR here.
|
||||
* src/sys.c (reset) [DFU_SUPPORT]: Set SCB->VTOR here.
|
||||
(flash_write): Range check.
|
||||
|
||||
* polarssl-0.14.0/library/aes.c (FT0, FT1, FT2): Specify the
|
||||
section ".sys", so that we will have more room for flash ROM.
|
||||
* src/gnuk.ld.in (.sys): Add alignment settings.
|
||||
|
||||
* tool/gnuk_upgrade.py (main): First 4096-byte of Gnuk is system
|
||||
block. Don't send it to reGNUal.
|
||||
|
||||
* regnual/sys.c (entry): Fix clearing BSS. It is called with all
|
||||
interrupts disabled.
|
||||
|
||||
* regnual/regnual.ld (_flash_start): It's 0x08001000 now, because
|
||||
there is system block now (was: 0x08000000).
|
||||
|
||||
2012-05-26 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/sys.c (reset): Set SCR->VCR here.
|
||||
|
||||
2012-05-25 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/gnuk.ld.in (.sys): New section.
|
||||
|
||||
* boards/OLIMEX_STM32_H103/board.h (SET_USB_CONDITION, GPIO_USB)
|
||||
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
|
||||
(FLASH_PAGE_SIZE): New.
|
||||
* boards/OLIMEX_STM32_H103/board.c (USB_Cable_Config, set_led):
|
||||
Remove.
|
||||
|
||||
* boards/STM32_PRIMER2/board.h (SET_USB_CONDITION, GPIO_USB)
|
||||
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
|
||||
(FLASH_PAGE_SIZE): New.
|
||||
* boards/STM32_PRIMER2/board.c (USB_Cable_Config, set_led):
|
||||
Remove.
|
||||
|
||||
* boards/FST_01_00/board.h (SET_USB_CONDITION, GPIO_USB)
|
||||
(IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED)
|
||||
(FLASH_PAGE_SIZE): New.
|
||||
* boards/FST_01_00/board.c (USB_Cable_Config, set_led): Remove.
|
||||
|
||||
* boards/FST_01/board.h (SET_USB_CONDITION, GPIO_USB, IOPORT_USB)
|
||||
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
|
||||
* boards/FST_01/board.c (USB_Cable_Config, set_led): Remove.
|
||||
|
||||
* regnual/sys-stm8s-discovery.h, sys-stbee.h: Remove.
|
||||
|
||||
* boards/STM8S_DISCOVERY/board.h (SET_USB_CONDITION)
|
||||
(SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New.
|
||||
* boards/STM8S_DISCOVERY/board.c (USB_Cable_Config, set_led):
|
||||
Remove.
|
||||
|
||||
* regnual/Makefile: Add -I ../src to CFLAGS.
|
||||
|
||||
* regnual/regnual.ld (vector): New.
|
||||
|
||||
* regnual/sys.c: Remove implementation, but jump to vector by sys.h.
|
||||
|
||||
* src/Makefile.in: Follow change of files.
|
||||
|
||||
* src/configure: Undo changes of 2012-05-22.
|
||||
|
||||
* boards/common/hw_config.c: Remove. Mov function to sys.c.
|
||||
* src/flash.c: Move functions to sys.c.
|
||||
* src/sys.c: New.
|
||||
|
||||
* src/main.c (main): Call flash_mass_erase_and_exec.
|
||||
|
||||
* src/usb_lld.c: Include sys.h.
|
||||
|
||||
* src/usb_lld_sys.c: Remove. Move interrupt handler to...
|
||||
* src/usb_ctrl.c: ... this file.
|
||||
|
||||
* regnual/sys.c (clock_init, gpio_init, flash_unlock): Removed.
|
||||
(entry): Rename (was: reset).
|
||||
|
||||
2012-05-24 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/main.c (good_bye): Care LSB of function pointer.
|
||||
(flash_mass_erase_and_exec): Implemented in C.
|
||||
|
||||
2012-05-23 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* regnual/sys-stm8s-discovery.h: New.
|
||||
|
||||
* src/main.c (flash_mass_erase_and_exec, good_bye): New.
|
||||
(main): Call good_bye.
|
||||
|
||||
* tool/gnuk_upgrade.py (regnual.protect): New.
|
||||
(main): Call regnual.protect().
|
||||
|
||||
* regnual/regnual.c (regnual_setup): Don't call flash_write here.
|
||||
(regnual_ctrl_write_finish): But call here.
|
||||
(USB_REGNUAL_RESULT): New.
|
||||
|
||||
* regnual/sys.c (flash_protect): New.
|
||||
|
||||
2012-05-22 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/configure (../regnual/sys.h): Create symblic link.
|
||||
|
||||
* src/usb_ctrl.c: Rename (was: usb_prop.c).
|
||||
|
||||
* regnual/types.h, regnual/sys.c, regnual/regnual.ld: New.
|
||||
* regnual/regnual.c, regnual/Makefile: New.
|
||||
* regnual/sys-stbee.h: New.
|
||||
|
||||
* src/usb_lld.c: Support FREE_STANDING environment as well as
|
||||
under ChibiOS/RT.
|
||||
(usb_lld_init): Call usb_lld_sys_init. Don't call user defined
|
||||
method. Call usb_lld_set_configuration.
|
||||
(usb_lld_shutdown): Call usb_lld_sys_shutdown.
|
||||
(Vector90): Move to usb_lld_sys.c.
|
||||
(usb_interrupt_handler): Export to global.
|
||||
|
||||
* src/usb_lld_sys.c: New.
|
||||
|
||||
* src/usb_prop.c (Device_Method): Remove gnuk_device_init.
|
||||
(gnuk_device_init): Remove.
|
||||
|
||||
2012-05-19 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb_lld.c (handle_datastage_in): Bug fix, erable RX when
|
||||
sending ZLP. It will be possible to get OUT transaction soon
|
||||
after IN transaction.
|
||||
|
||||
2012-05-18 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/usb_lld.c (handle_datastage_out): Fix rx copying.
|
||||
(handle_setup0): Bug fix not stalling TX, it will be possible
|
||||
to go IN transaction, soon after OUT transaction.
|
||||
|
||||
* src/usb_lld.h (USB_SETUP_SET, USB_SETUP_GET): New.
|
||||
(usb_device_method.ctrl_write_finish): New.
|
||||
(usb_device_method.setup): Merge setup_with_data, and
|
||||
setup_with_nodata.
|
||||
|
||||
* src/usb_lld.c (usb_lld_shutdown, usb_lld_prepare_shutdown): New.
|
||||
(handle_setup0): Call ->setup.
|
||||
(handle_in0): Call ->ctrl_write_finish.
|
||||
|
||||
* src/usb_prop.c (vcom_port_data_setup): Merge
|
||||
vcom_port_setup_with_nodata.
|
||||
(download_check_crc32): New.
|
||||
(gnuk_setup): Merge gnuk_setup_with_data and
|
||||
gnuk_setup_with_nodata.
|
||||
(gnuk_ctrl_write_finish): New.
|
||||
|
||||
2012-05-17 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_upgrade.py: New tool.
|
||||
|
||||
* src/gnuk.h (ICC_STATE_EXITED, ICC_STATE_EXEC_REQUESTED): New.
|
||||
|
||||
* src/openpgp.c (INS_EXTERNAL_AUTHENTICATE)
|
||||
(cmd_external_authenticate): New.
|
||||
(INS_GET_CHALLENGE, cmd_get_challenge): New.
|
||||
|
||||
* src/usb-icc.c (USBthread): Finish the thread with
|
||||
ICC_STATE_EXITED, after EXTERNAL_AUTHENTICATE.
|
||||
|
||||
* src/usb_prop.c (gnuk_setup_endpoints_for_interface): Add STOP
|
||||
argument.
|
||||
(gnuk_usb_event): Disable all endpoints when configure(0).
|
||||
(vcom_port_data_setup): Check direction and support
|
||||
USB_CDC_REQ_SET_LINE_CODING.
|
||||
(vcom_port_setup_with_nodata): Check direction.
|
||||
(gnuk_setup_with_data): Check direction and add FSIJ_GNUK device
|
||||
requests.
|
||||
(gnuk_setup_with_nodata): Likewise.
|
||||
|
||||
* src/usb_lld.c (LAST_OUT_DATA): Remove.
|
||||
(handle_datastage_out): Cleanup and call st103_ep_set_rxtx_status.
|
||||
(handle_datastage_in): Call st103_ep_set_rxtx_status and
|
||||
st103_ep_set_tx_status.
|
||||
(handle_setup0): Likewise.
|
||||
(handle_out0): Remove LAST_OUT_DATA.
|
||||
(std_none, std_get_status, std_clear_feature, std_set_feature)
|
||||
(std_set_address, std_get_descriptor, std_get_configuration)
|
||||
(std_set_configuration, std_get_interface, std_set_interface):
|
||||
Check direction.
|
||||
(handle_setup0): Add length for setup_with_data.
|
||||
|
||||
2012-05-16 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_put_binary.py (main): Fix fileid.
|
||||
* tool/gnuk_put_binary_libusb.py: Ditto.
|
||||
|
||||
* src/openpgp.c (FILE_EF_RANDOM): Remove.
|
||||
(cmd_update_binary, cmds): ifdef CERTDO_SUPPORT.
|
||||
(cmd_write_binary): Fix fileid.
|
||||
|
||||
* src/flash.c (flash_check_blank): Always enable.
|
||||
(flash_erase_binary): ifdef CERTDO_SUPPORT.
|
||||
(flash_write_binary): Call flash_check_blank.
|
||||
|
||||
2012-05-15 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.18.
|
||||
|
||||
100
NEWS
100
NEWS
@@ -1,5 +1,103 @@
|
||||
Gnuk NEWS - User visible changes
|
||||
|
||||
* Major changes in Gnuk 1.0.1
|
||||
|
||||
Released 2012-08-03, by NIIBE Yutaka
|
||||
|
||||
** USB SerialNumber String
|
||||
In 1.0, it has a bug for USB SerialNumber String. It has been fixed
|
||||
in 1.0.1.
|
||||
|
||||
|
||||
* Major changes in Gnuk 1.0
|
||||
|
||||
Released 2012-07-21, by NIIBE Yutaka
|
||||
|
||||
This is bug fixes only release.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.21
|
||||
|
||||
Released 2012-07-06, by NIIBE Yutaka
|
||||
|
||||
** Test suite
|
||||
A functinality test suite is added under test/ directory.
|
||||
|
||||
** New tool: stlinkv2.py
|
||||
This tool is SWD flash ROM writer with ST-Link/V2.
|
||||
|
||||
** New tool: usb_strings.py
|
||||
This tool is to dump USB strings, which include revision detail and config
|
||||
options.
|
||||
|
||||
** Protection improvement (even when internal data is disclosed)
|
||||
Even if PW1 and PW3 is same, content of encrypted DEK is different
|
||||
now.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.20
|
||||
|
||||
Released 2012-06-19, by NIIBE Yutaka
|
||||
|
||||
** Key generation feature added
|
||||
Finally, key generation is supported. Note that it may be very slow.
|
||||
It may take a few minutes (or more) to generate two or three keys,
|
||||
when you are unlucky.
|
||||
|
||||
** DnD pinentry support is deprecated
|
||||
Once, DnD pinentry was considered a great feature, but it found that
|
||||
it is difficult to remember moves of folders.
|
||||
|
||||
** gnuk_upgrade.py assumes using another token for authentication
|
||||
Use of another token for authentication is assumed now. This is
|
||||
incompatible change. Note that when you upgrade a token of version
|
||||
0.19 to 0.20 (or later), you need gnuk_upgrade.py of version 0.19.
|
||||
|
||||
** KDF (Key Derivation Function) is now SHA-256
|
||||
Keystring is now computed by SHA-256 (it was SHA1 before).
|
||||
|
||||
** Protection improvements (even when internal data is disclosed)
|
||||
Three improvements. (1) Even if PW1 and Reset-code is same, content
|
||||
of encrypted DEK is different now. (2) DEK is now encrypted and
|
||||
decrypted by keystring in ECB mode (it was just a kind of xor by
|
||||
single block CFB mode). (3) Key data plus checksum are encrypted in
|
||||
CFB mode with initial vector (it will be able to switch OCB mode
|
||||
easily).
|
||||
|
||||
** LED display output change
|
||||
LED display output by Gnuk is now more reactive. It shows status code
|
||||
when it gets GET_STATUS message of CCID. When you communicate Gnuk by
|
||||
internal CCID driver of GnuPG (instead of PC/SC), and enable
|
||||
'debug-disable-ticker' option in .gnupg/scdaemon.conf, it is more
|
||||
silent now.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.19
|
||||
|
||||
Released 2012-06-06, by NIIBE Yutaka
|
||||
|
||||
** Firmware upgrade feature
|
||||
Firmware upgrade is now possible after the public key authentication
|
||||
using EXTERNAL AUTHENTICATE command of ISO 7816. Firmware upgrade is
|
||||
done together with reGNUal, the firmware upgrade program.
|
||||
|
||||
** System service blocks at the beginning of flash ROM.
|
||||
Once flash ROM is protected, first 4-KiB cannot be modified. Gnuk
|
||||
use this area for "system service". Note that this area will not
|
||||
be able to be modified by firmware upgrade (or by any method).
|
||||
|
||||
** New tool: gnuk_upgrade.py
|
||||
The tool gnuk_upgrade.py is to do public key authentication using
|
||||
gpg-agent and send reGNUal to Gnuk. Then, we put new Gnuk binary
|
||||
into the device with reGNUal.
|
||||
|
||||
** USB strings for revision detail, configure options, and system service.
|
||||
USB strings now have more information. There are revision detail
|
||||
string, configure options string, system service version string, as
|
||||
well as vendor string and product string. These strings could be
|
||||
examined to check Gnuk Token.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.18
|
||||
|
||||
Released 2012-05-15, by NIIBE Yutaka
|
||||
@@ -22,7 +120,7 @@ original implementation. Hopefully, size and quality are improved.
|
||||
Released 2012-02-02, by NIIBE Yutaka
|
||||
|
||||
** USB CCID/ICCD protocol implementation change
|
||||
Gnuk now only supports short APDU level exchange, not support.
|
||||
Gnuk now only supports short APDU level exchange, not supporting
|
||||
extended APDU level exchange. Thus, Gnuk could be compatible to older
|
||||
host side software implementation.
|
||||
|
||||
|
||||
182
README
182
README
@@ -1,26 +1,26 @@
|
||||
Gnuk - software for GnuPG USB Token
|
||||
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
|
||||
|
||||
Version 0.18
|
||||
2012-05-15
|
||||
Version 1.0.1
|
||||
2012-08-03
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
What's Gnuk?
|
||||
============
|
||||
|
||||
Gnuk is software implementation of a USB token for GNU Privacy Guard.
|
||||
Gnuk supports OpenPGP card protocol version 2, and it runs on
|
||||
Gnuk is an implementation of USB cryptographic token for GNU Privacy
|
||||
Guard. Gnuk supports OpenPGP card protocol version 2, and it runs on
|
||||
STM32F103 processor.
|
||||
|
||||
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
|
||||
to bring a card reader all the time. With Gnuk, this issue will be
|
||||
solved by a USB token which is small enough.
|
||||
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. I am with a USB
|
||||
Token by "Gnuk", always, everywhere.
|
||||
son used to be with his NUK(R), always, everywhere. Now, I am with a
|
||||
USB Cryptographic Token by "Gnuk", always, everywhere.
|
||||
|
||||
|
||||
FAQ
|
||||
@@ -30,16 +30,12 @@ Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
|
||||
card 2.0, GPF Crypto Stick, etc.) ?
|
||||
http://www.g10code.de/p-card.html
|
||||
http://www.privacyfoundation.de/crypto_stick/
|
||||
A0: IMRHO, not quite, since there is no ready-to-use out-of-box Gnuk
|
||||
product yet. (It is welcome for me that some vendor will
|
||||
manufacture Gnuk USB Token. Even I can help design of hardware,
|
||||
if needed.)
|
||||
Good points for Gnuk are:
|
||||
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 acceleration 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.),
|
||||
@@ -55,24 +51,25 @@ Q3: What's your recommendation for target board?
|
||||
A3: Orthodox choice is Olimex STM32-H103.
|
||||
If you have skill of electronics and like DIY, STM32 part of STM8S
|
||||
Discovery Kit might be the best choice.
|
||||
Currently FST-01 (Flying Stone Tiny 01) is under development,
|
||||
it will be the best choice, hopefully.
|
||||
FST-01 (Flying Stone Tiny 01) will be soon available for sale,
|
||||
and it will be the best choice, hopefully.
|
||||
|
||||
Q4: What's version of GnuPG are you using?
|
||||
A4: In Debian GNU/Linux system, I use gnupg 1.4.11-3 and gnupg-agent
|
||||
2.0.14-2 (in sid). With older versions, you can only sign with SHA1.
|
||||
2.0.18-2. With older versions, you can only sign with SHA1.
|
||||
See: http://www.fsij.org/gnuk/gnupg2-fixes-needed
|
||||
|
||||
Q5: What's version of pcscd and libccid are you using?
|
||||
A5: In Debian GNU/Linux system, I use pcscd 1.5.5-4 and libccid 1.3.11-2,
|
||||
which is in squeeze. Note that you need to edit /etc/libccid_Info.plist
|
||||
when using libccid (< 1.4.1).
|
||||
Note that pcscd and libccid are optional, you can use Gnuk without them.
|
||||
|
||||
Q6: What kinds of hardware is required for development?
|
||||
A6: You need a target board plus a JTAG 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 debugger
|
||||
to enable flash ROM protection.
|
||||
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.
|
||||
@@ -83,13 +80,18 @@ A8: STM8S Discovery Kit costs 750 JPY (< $10 USD) only. You can build
|
||||
http://www.fsij.org/gnuk/jtag_dongle_ftdi2232
|
||||
|
||||
Q9: I got an error like "gpg: selecting openpgp failed: ec=6.108", what's up?
|
||||
|
||||
A9: GnuPG's SCDaemon has problems for handling insertion/removal of
|
||||
card/reader (problems are fixed in trunk). When your newly
|
||||
inserted token is not found by GnuPG, try killing scdaemon and let
|
||||
it to be invoked again. I do:
|
||||
$ killall -9 scdaemon
|
||||
card/reader (problems are fixed in trunk, and backported to 2.0
|
||||
branch, it will be 2.0.20). 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
|
||||
|
||||
$ 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
|
||||
@@ -106,16 +108,18 @@ Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
|
||||
"GPG Password Agent" and "SSH Key Agent".
|
||||
|
||||
Qc: Do you know a good SWD debugger to connect FST-01 or something?
|
||||
Ac: Perhaps, you can use a part of STM32F4 Discovery Kit as SWD
|
||||
debugger. It seems that there is a free software tool for that.
|
||||
Ac: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
|
||||
writer program.
|
||||
|
||||
|
||||
Release notes
|
||||
=============
|
||||
|
||||
This is nineteenth release of Gnuk. In this release, the usage of USB
|
||||
device ID by FSIJ is clarified. While it works well for specific
|
||||
usages and it is considered stable, it is still somewhat experimental.
|
||||
This is a minor release in version 1.0 series of Gnuk.
|
||||
|
||||
While it is daily use for more than a year, some newly introduced
|
||||
features (including key generation and firmware upgrade) should be
|
||||
considered experimental.
|
||||
|
||||
Tested features are:
|
||||
|
||||
@@ -132,9 +136,17 @@ Tested features are:
|
||||
* Changing value of password status bytes (0x00C4): forcesig
|
||||
* Verify with pin pad
|
||||
* Modify with pin pad
|
||||
* Card holder certificate
|
||||
* Removal of keys (Overriding key import is not supported,
|
||||
* Card holder certificate (read)
|
||||
* Removal of keys
|
||||
(Overriding key import is not supported,
|
||||
but you can remove all keys to import again).
|
||||
* Key generation on device side
|
||||
|
||||
Original features of Gnuk, tested 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:
|
||||
|
||||
@@ -142,9 +154,11 @@ It is known not-working well:
|
||||
work well. Please make sure to disable DEBUG option if it
|
||||
doesn't work well.
|
||||
|
||||
Not supported feature(s):
|
||||
|
||||
* Key generation on device side
|
||||
It is known that the combination of libccid 1.4.1 (or newer) with
|
||||
libusb 1.0.8 (or older) has 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
|
||||
@@ -157,7 +171,7 @@ With DfuSe support, CQ STARM, STBee, and STBee Mini are also our
|
||||
targets. But those targets with DfuSe are basically not for normal
|
||||
use but for experiments, because it would be impossible for DfuSe to
|
||||
disable read from flash. For real use, please consider killing DfuSe
|
||||
and enable read protection using JTAG debugger.
|
||||
and enabling read protection using JTAG debugger.
|
||||
|
||||
I think that it could run on Olimex STM32-P103, or other boards with
|
||||
STM32F103. Besides, we are porting it to STM32 Primer 2.
|
||||
@@ -174,15 +188,10 @@ Another PIN-pad support is connecting rotary encoder, push switch and
|
||||
7-segment LED display. Both of PIN verification and PIN modification
|
||||
are supported for this circuit extension.
|
||||
|
||||
Recently, "DnDpinentry" support is added. This is using usual file
|
||||
manager for pinentry. User does "drag and drop" folders and it will
|
||||
be pin entry. This feature doesn't require any additional hardware.
|
||||
See doc/settings-for-DnDpinentry for your desktop configuration.
|
||||
|
||||
Note that you need pinpad support for GnuPG, it's currently in the
|
||||
master branch of GnuPG git repository at git.gnupg.org, and it's under
|
||||
evaluation. When it will be considered stable, it will be put onto
|
||||
stable branch.
|
||||
Note that you need pinpad support for GnuPG to use PIN-pad enabled
|
||||
Gnuk. The pinpad support for GnuPG is currently in the master branch
|
||||
of GnuPG git repository at git.gnupg.org, and it's under evaluation.
|
||||
When it will be considered stable, it will be put onto stable branch.
|
||||
|
||||
|
||||
Souce code
|
||||
@@ -190,6 +199,11 @@ Souce 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://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
@@ -198,12 +212,12 @@ 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, 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 USB Token by Gnuk
|
||||
should be able to acess everything on the Token, regardless of its
|
||||
should be able to access everything on the Token, regardless of its
|
||||
protections. Private keys, and other information should be protected
|
||||
properly.
|
||||
|
||||
@@ -222,12 +236,21 @@ Gnuk is distributed with external source code.
|
||||
* polarssl-0.14.0/ -- PolarSSL 0.14.0
|
||||
|
||||
Taken from http://polarssl.org/
|
||||
We use PolarSSL for RSA computation, AES encryption/decryption
|
||||
and SHA-1 computation.
|
||||
We use PolarSSL for RSA computation, AES encryption/decryption.
|
||||
|
||||
The file include/polarssl/bn_mul.h is heavily modified for ARM
|
||||
Cortex-M3.
|
||||
|
||||
The files include/polarssl/rsa.h, library/rsa.c,
|
||||
include/polarssl/bignum.h, and library/bignum.c are modified so that
|
||||
f_rng function returns unsigned char.
|
||||
|
||||
The file library/rsa.c is modified so that it only computes things
|
||||
needed for Gnuk.
|
||||
|
||||
The file library/aes.c is modified so that some constants can
|
||||
go to .sys section.
|
||||
|
||||
|
||||
USB vendor ID and product ID (USB device ID)
|
||||
============================================
|
||||
@@ -235,7 +258,7 @@ USB vendor ID and product ID (USB device ID)
|
||||
When you have a vender 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 source code.
|
||||
release of the source code.
|
||||
|
||||
When you are modifing Gnuk and installing the binary to device, you
|
||||
should replace "FSIJ" in the string gnukStringSerial (usb_desc.c) to
|
||||
@@ -264,20 +287,23 @@ with Gnuk under one of following conditions:
|
||||
please use that number for your device.
|
||||
(There a file 'GNUK_SERIAL_NUMBER' in the official release.)
|
||||
|
||||
FSIJ could permit companies or business entities 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 permission.
|
||||
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. When you modify Gnuk, please
|
||||
replace "FSIJ" in the string gnukStringSerial (usb_desc.c) to yours.
|
||||
your own USB vendor ID and product ID. Please replace "FSIJ" in the
|
||||
string gnukStringSerial (usb_desc.c) to yours, when you modify Gnuk.
|
||||
|
||||
|
||||
Host Requirements
|
||||
=================
|
||||
|
||||
For GNU/Linux, libccid version >= 1.3.11 is recommended.
|
||||
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.
|
||||
|
||||
I think that it should not be requirment but the kernel version of my use is:
|
||||
Linux version 2.6.32-5-686 (Debian 2.6.32-18) (ben@decadent.org.uk) (gcc version 4.3.5 (Debian 4.3.5-2) ) #1 SMP Sat Jul 24 02:27:10 UTC 2010
|
||||
@@ -293,7 +319,7 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
||||
|
||||
See http://github.com/esden/summon-arm-toolchain/ (which includes fix
|
||||
of binutils-2.21.1) for preparation of GNU Toolchain for
|
||||
'arm-none-eabi' target.
|
||||
'arm-none-eabi' target. This is for GCC 4.5.
|
||||
|
||||
# Note that we need to link correct C library (for string functions).
|
||||
# For this purpose, Makefile.in contains following line:
|
||||
@@ -309,6 +335,13 @@ of binutils-2.21.1) for preparation of GNU Toolchain for
|
||||
# -mno-thumb-interwork option. This means that you should not
|
||||
# link C library which contains ARM (not Thumb) code.
|
||||
|
||||
Recently, there is "gcc-arm-embedded" project. See:
|
||||
|
||||
https://launchpad.net/gcc-arm-embedded/
|
||||
|
||||
It is based on GCC 4.6. For version 4.6-2012-q2-update, you'd
|
||||
need "-O3 -Os" instead of "-O2" and it will be slightly better.
|
||||
|
||||
|
||||
Change directory to `src':
|
||||
|
||||
@@ -456,7 +489,7 @@ PyUSB (python-usb package in Debian).
|
||||
If scdaemon is running, please kill it, or you will get "Smartcard
|
||||
Exception" by "Sharing violation".
|
||||
|
||||
$ killall -9 scdaemon
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
In case of PyUSB tool, you need to stop pcscd.
|
||||
|
||||
@@ -535,11 +568,15 @@ This entry has been added into libccid 1.4.1 already ([r5425]).
|
||||
Testing Gnuk
|
||||
------------
|
||||
|
||||
Try following to see Gnuk runs:
|
||||
Type following command to see Gnuk runs:
|
||||
|
||||
$ gpg --card-status
|
||||
|
||||
|
||||
Besides, there is a functinality test under test/ directory. See
|
||||
test/README.
|
||||
|
||||
|
||||
Personalize the Token and import keys
|
||||
-------------------------------------
|
||||
|
||||
@@ -552,18 +589,21 @@ command is:
|
||||
Note that the factory setting of user password is "123456" and admin
|
||||
password is "12345678" as the specification.
|
||||
|
||||
No, Gnuk doesn't support key generation. You need 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.
|
||||
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.
|
||||
|
||||
For detail, please see doc/DEMO and doc/DEMO-2.
|
||||
Gnuk supports key generation, but this feature is young and should be
|
||||
considered experimental.
|
||||
|
||||
For detail, please see doc/note/DEMO and doc/note/DEMO-2.
|
||||
|
||||
Note that it make sense to preserve your keys on your computer so that
|
||||
you can import the keys (again) to (possibly another) Gnuk Token. In
|
||||
this case, you can use GnuPG's option to specify the home directory by
|
||||
--homedir.
|
||||
|
||||
After creating keys by:
|
||||
After creating keys on your computer by:
|
||||
|
||||
$ gpg --gen-key
|
||||
...
|
||||
@@ -615,6 +655,12 @@ You can observe the traffic of USB using "usbmon". See the file:
|
||||
linux/Documentation/usb/usbmon.txt
|
||||
|
||||
|
||||
Firmware update
|
||||
===============
|
||||
|
||||
See doc/note/firmware-update.
|
||||
|
||||
|
||||
Read-only Git Repository
|
||||
========================
|
||||
|
||||
|
||||
@@ -4,34 +4,8 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
}
|
||||
|
||||
void
|
||||
USB_Cable_Config (FunctionalState NewState)
|
||||
{
|
||||
/* CQ STARM has no functionality to stop USB. */
|
||||
/*
|
||||
* It seems that users can add the functionality with USB_DC (PD9)
|
||||
* though
|
||||
*/
|
||||
(void)NewState;
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palSetPad (IOPORT3, GPIOC_LED);
|
||||
else
|
||||
palClearPad (IOPORT3, GPIOC_LED);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
/*
|
||||
* Setup for the CQ STARM board.
|
||||
*/
|
||||
#undef SET_USB_CONDITION /* No functionality to disconnect USB */
|
||||
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
|
||||
#define GPIO_LED GPIOC_LED
|
||||
#define IOPORT_LED GPIOC
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1 (void)
|
||||
{
|
||||
@@ -48,24 +42,6 @@ hwinit1 (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
USB_Cable_Config (int NewState)
|
||||
{
|
||||
if (NewState != DISABLE)
|
||||
palSetPad (IOPORT1, GPIOA_USB_ENABLE);
|
||||
else
|
||||
palClearPad (IOPORT1, GPIOA_USB_ENABLE);
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palSetPad (IOPORT2, GPIOB_LED);
|
||||
else
|
||||
palClearPad (IOPORT2, GPIOB_LED);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
/*
|
||||
* Setup for the FST-01 board.
|
||||
*/
|
||||
#define SET_USB_CONDITION(en) en /* To connect USB, call palSetPad */
|
||||
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
|
||||
#define GPIO_USB GPIOA_USB_ENABLE
|
||||
#define IOPORT_USB GPIOA
|
||||
#define GPIO_LED GPIOB_LED
|
||||
#define IOPORT_LED GPIOB
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
@@ -91,12 +97,15 @@
|
||||
* PA0 - input with pull-up (TIM2_CH1)
|
||||
* PA1 - input with pull-down (TIM2_CH2)
|
||||
* PA2 - input with pull-up (TIM2_CH3)
|
||||
* PA4 - Push pull output (SPI1_NSS)
|
||||
* PA5 - Alternate Push pull output (SPI1_SCK)
|
||||
* PA6 - Alternate Push pull output (SPI1_MISO)
|
||||
* PA7 - Alternate Push pull output (SPI1_MOSI)
|
||||
* PA10 - Push pull output (USB 1:ON 0:OFF)
|
||||
* PA11 - input with pull-up (USBDM)
|
||||
* PA12 - input with pull-up (USBDP)
|
||||
* Everything input with pull-up except:
|
||||
* PA10 - Push pull output (USB 1:ON 0:OFF)
|
||||
*/
|
||||
#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */
|
||||
#define VAL_GPIOACRL 0xBBB38888 /* PA7...PA0 */
|
||||
#define VAL_GPIOACRH 0x88888388 /* PA15...PA8 */
|
||||
#define VAL_GPIOAODR 0xFFFFFFFD
|
||||
|
||||
|
||||
@@ -4,33 +4,8 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
USB_Cable_Config (int NewState)
|
||||
{
|
||||
if (NewState != DISABLE)
|
||||
palSetPad (IOPORT1, GPIOA_USB_ENABLE);
|
||||
else
|
||||
palClearPad (IOPORT1, GPIOA_USB_ENABLE);
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palSetPad (IOPORT1, GPIOA_LED);
|
||||
else
|
||||
palClearPad (IOPORT1, GPIOA_LED);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
/*
|
||||
* Setup for the FST-01 board (experimental version 00).
|
||||
*/
|
||||
#define SET_USB_CONDITION(en) en /* To connect USB, call palSetPad */
|
||||
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
|
||||
#define GPIO_USB GPIOA_USB_ENABLE
|
||||
#define IOPORT_USB GPIOA
|
||||
#define GPIO_LED GPIOA_LED
|
||||
#define IOPORT_LED GPIOA
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
|
||||
@@ -4,32 +4,8 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1 (void)
|
||||
{
|
||||
hwinit1_common ();
|
||||
}
|
||||
|
||||
void
|
||||
USB_Cable_Config (FunctionalState NewState)
|
||||
{
|
||||
if (NewState != DISABLE)
|
||||
palClearPad (IOPORT3, GPIOC_DISC);
|
||||
else
|
||||
palSetPad (IOPORT3, GPIOC_DISC);
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palClearPad (IOPORT3, GPIOC_LED);
|
||||
else
|
||||
palSetPad (IOPORT3, GPIOC_LED);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
/*
|
||||
* Setup for the Olimex STM32-H103 proto board.
|
||||
*/
|
||||
#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */
|
||||
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
|
||||
#define GPIO_USB GPIOC_DISC
|
||||
#define IOPORT_USB GPIOC
|
||||
#define GPIO_LED GPIOC_LED
|
||||
#define IOPORT_LED GPIOC
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1 (void)
|
||||
{
|
||||
@@ -70,24 +64,6 @@ hwinit1 (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
USB_Cable_Config (FunctionalState NewState)
|
||||
{
|
||||
if (NewState != DISABLE)
|
||||
palClearPad (IOPORT4, GPIOD_USB_ENABLE);
|
||||
else
|
||||
palSetPad (IOPORT4, GPIOD_USB_ENABLE);
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palClearPad (IOPORT4, GPIOD_LED1);
|
||||
else
|
||||
palSetPad (IOPORT4, GPIOD_LED1);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
/*
|
||||
* Setup for the STBee board.
|
||||
*/
|
||||
#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */
|
||||
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
|
||||
#define GPIO_USB GPIOD_USB_ENABLE
|
||||
#define IOPORT_USB GPIOD
|
||||
#define GPIO_LED GPIOD_LED1
|
||||
#define IOPORT_LED GPIOD
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1 (void)
|
||||
{
|
||||
@@ -83,24 +77,6 @@ hwinit1 (void)
|
||||
palSetPad (IOPORT1, GPIOA_LED2);
|
||||
}
|
||||
|
||||
void
|
||||
USB_Cable_Config (FunctionalState NewState)
|
||||
{
|
||||
if (NewState != DISABLE)
|
||||
palSetPad (IOPORT1, GPIOA_USB_ENABLE);
|
||||
else
|
||||
palClearPad (IOPORT1, GPIOA_USB_ENABLE);
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palClearPad (IOPORT1, GPIOA_LED1);
|
||||
else
|
||||
palSetPad (IOPORT1, GPIOA_LED1);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
/*
|
||||
* Setup for the STBee Mini board.
|
||||
*/
|
||||
#define SET_USB_CONDITION(en) (en) /* To connect USB, call palSetPad */
|
||||
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
|
||||
#define GPIO_USB GPIOA_USB_ENABLE
|
||||
#define IOPORT_USB GPIOA
|
||||
#define GPIO_LED GPIOA_LED1
|
||||
#define IOPORT_LED GPIOA
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0(void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1(void)
|
||||
{
|
||||
@@ -21,21 +15,3 @@ hwinit1(void)
|
||||
palClearPad (IOPORT5, GPIOE_LED);
|
||||
palClearPad (IOPORT3, GPIOC_SHUTDOWN);
|
||||
}
|
||||
|
||||
void
|
||||
USB_Cable_Config (FunctionalState NewState)
|
||||
{
|
||||
if (NewState != DISABLE)
|
||||
palClearPad (IOPORT4, GPIOD_DISC);
|
||||
else
|
||||
palSetPad (IOPORT4, GPIOD_DISC);
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palClearPad (IOPORT5, GPIOE_LEDR);
|
||||
else
|
||||
palSetPad (IOPORT5, GPIOE_LEDR);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
/*
|
||||
* Setup for the STM32 Primer2.
|
||||
*/
|
||||
#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */
|
||||
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
|
||||
#define GPIO_USB GPIOD_DISC
|
||||
#define IOPORT_USB GPIOD
|
||||
#define GPIO_LED GPIOE_LEDR
|
||||
#define IOPORT_LED GPIOE
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
|
||||
#include "../common/hwinit.c"
|
||||
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
hwinit0_common ();
|
||||
}
|
||||
|
||||
void
|
||||
hwinit1 (void)
|
||||
{
|
||||
@@ -46,22 +40,6 @@ hwinit1 (void)
|
||||
AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_PARTIALREMAP;
|
||||
}
|
||||
|
||||
void
|
||||
USB_Cable_Config (FunctionalState NewState)
|
||||
{
|
||||
/* No functionality to stop USB. */
|
||||
(void)NewState;
|
||||
}
|
||||
|
||||
void
|
||||
set_led (int value)
|
||||
{
|
||||
if (value)
|
||||
palSetPad (IOPORT1, GPIOA_LED);
|
||||
else
|
||||
palClearPad (IOPORT1, GPIOA_LED);
|
||||
}
|
||||
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
void
|
||||
cir_ext_disable (void)
|
||||
|
||||
@@ -32,11 +32,16 @@
|
||||
* Setup for the ST-Link part of STM8S-Discovery board.
|
||||
*/
|
||||
|
||||
#undef SET_USB_CONDITION /* No functionality to disconnect USB */
|
||||
#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */
|
||||
#define GPIO_LED GPIOA_LED
|
||||
#define IOPORT_LED GPIOA
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
*/
|
||||
#define BOARD_ST_DISCOVERY
|
||||
#define BOARD_NAME "ST-Link"
|
||||
#define BOARD_NAME "STM8S Discovery"
|
||||
#define CPU_WITH_NO_GPIOE 1
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/* Hardware specific function */
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "board.h"
|
||||
|
||||
const uint8_t *
|
||||
unique_device_id (void)
|
||||
{
|
||||
/* STM32F103 has 96-bit unique device identifier */
|
||||
const uint8_t *addr = (const uint8_t *)0x1ffff7e8;
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -29,15 +29,9 @@
|
||||
* This initialization is performed just after reset before BSS and DATA
|
||||
* segments initialization.
|
||||
*/
|
||||
/*
|
||||
* Common code for hwinit0
|
||||
*/
|
||||
static void hwinit0_common (void)
|
||||
void
|
||||
hwinit0 (void)
|
||||
{
|
||||
#ifdef DFU_SUPPORT
|
||||
SCB->VTOR = 0x08003000;
|
||||
#endif
|
||||
|
||||
stm32_clock_init();
|
||||
}
|
||||
|
||||
|
||||
153
doc/Makefile
Normal file
153
doc/Makefile
Normal file
@@ -0,0 +1,153 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER = a4
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GnukDocumentation.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GnukDocumentation.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/GnukDocumentation"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GnukDocumentation"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
246
doc/conf.py
Normal file
246
doc/conf.py
Normal file
@@ -0,0 +1,246 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Gnuk Documentation documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Jul 4 15:29:05 2012.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Gnuk Documentation'
|
||||
copyright = u'2012, NIIBE Yutaka'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'GnukDocumentationdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'GnukDocumentation.tex', u'Gnuk Documentation Documentation',
|
||||
u'NIIBE Yutaka', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'gnukdocumentation', u'Gnuk Documentation Documentation',
|
||||
[u'NIIBE Yutaka'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'GnukDocumentation', u'Gnuk Documentation Documentation',
|
||||
u'NIIBE Yutaka', 'GnukDocumentation', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'http://docs.python.org/': None}
|
||||
82
doc/development.rst
Normal file
82
doc/development.rst
Normal file
@@ -0,0 +1,82 @@
|
||||
Development Environment
|
||||
=======================
|
||||
|
||||
|
||||
Hardware
|
||||
--------
|
||||
|
||||
For development, it is highly recommended to have JTAG debugger or SWD
|
||||
debugger.
|
||||
|
||||
For boards with DFU (Device Firmware Upgrade) feature, such as DfuSe,
|
||||
it is possible to develop with that. But it should be considered
|
||||
*experimental* environment, and it should not be used for usual
|
||||
purpose. That's because it is basically impossible for DfuSe
|
||||
implementations to disable reading-out from flash ROM. It means
|
||||
that your secret will be readily extracted by DfuSe.
|
||||
|
||||
For JTAG debugger, Olimex JTAG-Tiny is good and supported well. For
|
||||
SWD debugger, ST-Link/V2 would be good, and it is supported by
|
||||
the tool of tool/stlinkv2.py.
|
||||
|
||||
|
||||
OpenOCD
|
||||
-------
|
||||
|
||||
For JTAG debugger or SWD debugger, we can use OpenOCD.
|
||||
|
||||
Note that ST-Link/V2 is *not* supported by OpenOCD 0.5.0. It will be
|
||||
supported by version 0.6 or later, as current development version
|
||||
supports it.
|
||||
|
||||
|
||||
GNU Toolchain
|
||||
-------------
|
||||
|
||||
You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
||||
|
||||
See http://github.com/esden/summon-arm-toolchain/ (which includes fix
|
||||
of binutils-2.21.1) for preparation of GNU Toolchain for
|
||||
'arm-none-eabi' target. This is for GCC 4.5.
|
||||
|
||||
Note that we need to link correct C library (for string functions).
|
||||
For this purpose, our src/Makefile.in contains following line:
|
||||
|
||||
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
|
||||
|
||||
This should not be needed (as -mcpu=cortex-m3 means
|
||||
-mfix-cortex-m3-ldrd), but it is needed for the configuration of
|
||||
patch-gcc-config-arm-t-arm-elf.diff in summon-arm-toolchain in practice.
|
||||
|
||||
In ChibiOS_2.0.8/os/ports/GCC/ARM/rules.mk, it specifies
|
||||
-mno-thumb-interwork option. This means that you should not link C
|
||||
library which contains ARM (not Thumb) code.
|
||||
|
||||
Recently, there is "gcc-arm-embedded" project. See:
|
||||
https://launchpad.net/gcc-arm-embedded/
|
||||
|
||||
It is based on GCC 4.6. For version 4.6-2012-q2-update, you'd
|
||||
need "-O3 -s" instead of "-O2" and it will be slightly better.
|
||||
|
||||
|
||||
|
||||
Building Gnuk
|
||||
-------------
|
||||
|
||||
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.
|
||||
|
||||
Type:
|
||||
|
||||
$ make
|
||||
|
||||
Then, we will have "gnuk.elf".
|
||||
228
doc/generating-2048-RSA-key.rst
Normal file
228
doc/generating-2048-RSA-key.rst
Normal file
@@ -0,0 +1,228 @@
|
||||
============================
|
||||
Generating 2048-bit RSA keys
|
||||
============================
|
||||
|
||||
This document describes how I generate 2048-bit RSA keys.
|
||||
|
||||
.. BREAK
|
||||
|
||||
Here is the log to generate signature key and encryption subkey.
|
||||
|
||||
I invoke GnuPG with ``--gen-key`` option. ::
|
||||
|
||||
$ gpg --gen-key
|
||||
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
and GnuPG asks kind of key. Select ``RSA and RSA``. ::
|
||||
|
||||
Please select what kind of key you want:
|
||||
(1) RSA and RSA (default)
|
||||
(2) DSA and Elgamal
|
||||
(3) DSA (sign only)
|
||||
(4) RSA (sign only)
|
||||
Your selection? 1
|
||||
RSA keys may be between 1024 and 4096 bits long.
|
||||
|
||||
and select 2048-bit (as Gnuk Token only suppurt this). ::
|
||||
|
||||
What keysize do you want? (2048)
|
||||
Requested keysize is 2048 bits
|
||||
|
||||
and select expiration of the key. ::
|
||||
|
||||
Please specify how long the key should be valid.
|
||||
0 = key does not expire
|
||||
<n> = key expires in n days
|
||||
<n>w = key expires in n weeks
|
||||
<n>m = key expires in n months
|
||||
<n>y = key expires in n years
|
||||
Key is valid for? (0) 0
|
||||
Key does not expire at all
|
||||
|
||||
Confirm key types, bitsize and expiration. ::
|
||||
|
||||
Is this correct? (y/N) y
|
||||
|
||||
Then enter user ID. ::
|
||||
|
||||
You need a user ID to identify your key; the software constructs the user ID
|
||||
from the Real Name, Comment and Email Address in this form:
|
||||
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
|
||||
|
||||
Real name: Niibe Yutaka
|
||||
Email address: gniibe@fsij.org
|
||||
Comment:
|
||||
You selected this USER-ID:
|
||||
"Niibe Yutaka <gniibe@fsij.org>"
|
||||
|
||||
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
|
||||
|
||||
and enter passphrase for this **key on PC**. ::
|
||||
|
||||
You need a Passphrase to protect your secret key.
|
||||
<PASSWORD-KEY-ON-PC>
|
||||
|
||||
Then, GnuPG generate keys. It takes some time. ::
|
||||
|
||||
We need to generate a lot of random bytes. It is a good idea to perform
|
||||
some other action (type on the keyboard, move the mouse, utilize the
|
||||
disks) during the prime generation; this gives the random number
|
||||
generator a better chance to gain enough entropy.
|
||||
...+++++
|
||||
+++++
|
||||
We need to generate a lot of random bytes. It is a good idea to perform
|
||||
some other action (type on the keyboard, move the mouse, utilize the
|
||||
disks) during the prime generation; this gives the random number
|
||||
generator a better chance to gain enough entropy.
|
||||
..+++++
|
||||
|
||||
Not enough random bytes available. Please do some other work to give
|
||||
the OS a chance to collect more entropy! (Need 15 more bytes)
|
||||
...+++++
|
||||
gpg: key 28C0CD7C marked as ultimately trusted
|
||||
public and secret key created and signed.
|
||||
|
||||
gpg: checking the trustdb
|
||||
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
|
||||
gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u
|
||||
pub 2048R/28C0CD7C 2011-05-24
|
||||
Key fingerprint = 0B4D C763 D57B ADBB 1870 A978 BDEE 4A35 28C0 CD7C
|
||||
uid Niibe Yutaka <gniibe@fsij.org>
|
||||
sub 2048R/F01E19B7 2011-05-24
|
||||
$
|
||||
|
||||
Done.
|
||||
|
||||
Then, I create authentication subkey. Authentication subkey is not that common, but very useful (say, for SSH authentication). As it is not that common, we need ``--expert`` option for GnuPG. ::
|
||||
|
||||
$ gpg --expert --edit-key 28C0CD7C
|
||||
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
Secret key is available.
|
||||
|
||||
pub 2048R/28C0CD7C created: 2011-05-24 expires: never usage: SC
|
||||
trust: ultimate validity: ultimate
|
||||
sub 2048R/F01E19B7 created: 2011-05-24 expires: never usage: E
|
||||
[ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
gpg>
|
||||
|
||||
Here, I enter ``addkey`` command. Then, I enter the passphrase of **key on PC**, I specified above. ::
|
||||
|
||||
gpg> addkey
|
||||
Key is protected.
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "Niibe Yutaka <gniibe@fsij.org>"
|
||||
2048-bit RSA key, ID 28C0CD7C, created 2011-05-24
|
||||
<PASSWORD-KEY-ON-PC>
|
||||
gpg: gpg-agent is not available in this session
|
||||
|
||||
GnuPG askes kind of key. I select ``RSA (set your own capabilities)``. ::
|
||||
|
||||
Please select what kind of key you want:
|
||||
(3) DSA (sign only)
|
||||
(4) RSA (sign only)
|
||||
(5) Elgamal (encrypt only)
|
||||
(6) RSA (encrypt only)
|
||||
(7) DSA (set your own capabilities)
|
||||
(8) RSA (set your own capabilities)
|
||||
Your selection? 8
|
||||
|
||||
And select ``Authenticate`` for the capabilities for this key. Initially, it's ``Sign`` and ``Encrypt``. I need to deselect ``Sign`` and ``Encryp``, and select ``Authenticate``. To do that, I enter ``s``, ``a``, and ``e``. ::
|
||||
|
||||
Possible actions for a RSA key: Sign Encrypt Authenticate
|
||||
Current allowed actions: Sign Encrypt
|
||||
|
||||
(S) Toggle the sign capability
|
||||
(E) Toggle the encrypt capability
|
||||
(A) Toggle the authenticate capability
|
||||
(Q) Finished
|
||||
|
||||
Your selection? s
|
||||
|
||||
Possible actions for a RSA key: Sign Encrypt Authenticate
|
||||
Current allowed actions: Encrypt
|
||||
|
||||
(S) Toggle the sign capability
|
||||
(E) Toggle the encrypt capability
|
||||
(A) Toggle the authenticate capability
|
||||
(Q) Finished
|
||||
|
||||
Your selection? a
|
||||
|
||||
Possible actions for a RSA key: Sign Encrypt Authenticate
|
||||
Current allowed actions: Encrypt Authenticate
|
||||
|
||||
(S) Toggle the sign capability
|
||||
(E) Toggle the encrypt capability
|
||||
(A) Toggle the authenticate capability
|
||||
(Q) Finished
|
||||
|
||||
Your selection? e
|
||||
|
||||
Possible actions for a RSA key: Sign Encrypt Authenticate
|
||||
Current allowed actions: Authenticate
|
||||
|
||||
(S) Toggle the sign capability
|
||||
(E) Toggle the encrypt capability
|
||||
(A) Toggle the authenticate capability
|
||||
(Q) Finished
|
||||
|
||||
OK, I set the capability of ``Authenticate``. I enter ``q`` to finish setting capabilities. ::
|
||||
|
||||
Your selection? q
|
||||
|
||||
GnuPG asks bitsize and expiration, I enter 2048 for bitsize and no expiration. Then, I confirm that I really create the key. ::
|
||||
|
||||
RSA keys may be between 1024 and 4096 bits long.
|
||||
What keysize do you want? (2048)
|
||||
Requested keysize is 2048 bits
|
||||
Please specify how long the key should be valid.
|
||||
0 = key does not expire
|
||||
<n> = key expires in n days
|
||||
<n>w = key expires in n weeks
|
||||
<n>m = key expires in n months
|
||||
<n>y = key expires in n years
|
||||
Key is valid for? (0) 0
|
||||
Key does not expire at all
|
||||
Is this correct? (y/N) y
|
||||
Really create? (y/N) y
|
||||
|
||||
Then, GnuPG generate the key. ::
|
||||
|
||||
We need to generate a lot of random bytes. It is a good idea to perform
|
||||
some other action (type on the keyboard, move the mouse, utilize the
|
||||
disks) during the prime generation; this gives the random number
|
||||
generator a better chance to gain enough entropy.
|
||||
.......+++++
|
||||
+++++
|
||||
|
||||
pub 2048R/28C0CD7C created: 2011-05-24 expires: never usage: SC
|
||||
trust: ultimate validity: ultimate
|
||||
sub 2048R/F01E19B7 created: 2011-05-24 expires: never usage: E
|
||||
sub 2048R/B8929606 created: 2011-05-24 expires: never usage: A
|
||||
[ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
gpg>
|
||||
|
||||
I save the key. ::
|
||||
|
||||
gpg> save
|
||||
$
|
||||
|
||||
Now, we have three keys (one primary key for signature and certification, subkey for encryption, and another subkey for authentication).
|
||||
|
||||
|
||||
Publishing public key
|
||||
=====================
|
||||
|
||||
I make a file for my public key by ``--export`` option of GnuPG. ::
|
||||
|
||||
$ gpg --armor --output gniibe.asc --export 4CA7BABE
|
||||
|
||||
and put it at: http://www.gniibe.org/gniibe.asc
|
||||
30
doc/gnome3-gpg-settings.rst
Normal file
30
doc/gnome3-gpg-settings.rst
Normal file
@@ -0,0 +1,30 @@
|
||||
==========================
|
||||
GnuPG settings for GNOME 3
|
||||
==========================
|
||||
|
||||
In the article `GnuPG settings`_, I wrote how I disable GNOME-keyrings for SSH.
|
||||
|
||||
It was for GNOME 2. The old days was good, we just disabled GNOME-keyrings interference to SSH and customizing our desktop was easy for GNU and UNIX users.
|
||||
|
||||
.. _GnuPG settings: gpg-settings
|
||||
|
||||
|
||||
GNOME keyrings in GNOME 3
|
||||
=========================
|
||||
|
||||
It seems that it is more integrated into the desktop. It is difficult to kill it. It would be possible to kill it simply, but then, I can't use, say, wi-fi access (which needs to access "secrets") any more.
|
||||
|
||||
We can't use GNOME configuration tool to disable interference by GNOME keyrings any more. It seems that desktop should not have customization these days.
|
||||
|
||||
|
||||
GNOME-SESSION-PROPERTIES
|
||||
========================
|
||||
|
||||
After struggling some ours, I figured out it is GNOME-SESSION-PROPERTIES to disable the interference. Invoking::
|
||||
|
||||
$ gnome-session-properties
|
||||
|
||||
and at the tab of "Startup Programs", I removed radio check buttons for "GPG Password Agent" and "SSH Key Agent".
|
||||
|
||||
|
||||
Now, I use gpg-agent for GnuPG Agent and SSH agent with Gnuk Token.
|
||||
177
doc/gnuk-keytocard-noremoval.rst
Normal file
177
doc/gnuk-keytocard-noremoval.rst
Normal file
@@ -0,0 +1,177 @@
|
||||
=============================================
|
||||
Key import from PC to Gnuk Token (no removal)
|
||||
=============================================
|
||||
|
||||
This document describes how I put my **keys on PC** to the Token without removing keys from PC.
|
||||
|
||||
The difference is just not-to-save changes after key imports.
|
||||
|
||||
.. BREAK
|
||||
|
||||
After personalization, I put my keys into the Token.
|
||||
|
||||
Here is the log.
|
||||
|
||||
I invoke GnuPG with my key (4ca7babe) and with ``--homedir`` option to specify the directory which contains my secret keys. ::
|
||||
|
||||
$ gpg --homedir=/home/gniibe/tmp/gnuk-testing-dir --edit-key 4ca7babe
|
||||
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
Secret key is available.
|
||||
|
||||
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
|
||||
trust: ultimate validity: ultimate
|
||||
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
|
||||
Then, GnuPG enters its own command interaction mode. The prompt is ``gpg>``.
|
||||
To enable ``keytocard`` command, I type ``toggle`` command. ::
|
||||
|
||||
gpg> toggle
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Firstly, I import my primary key into Gnuk Token.
|
||||
I type ``keytocard`` command, answer ``y`` to confirm keyimport,
|
||||
and type ``1`` to say it's signature key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Really move the primary key? (y/N) y
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00'
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
|
||||
Please select where to store the key:
|
||||
(1) Signature key
|
||||
(3) Authentication key
|
||||
Your selection? 1
|
||||
|
||||
Then, GnuPG asks two passwords. One is the passphrase of **keys on PC** and another is the password of **Gnuk Token**. Note that the password of the token and the password of the keys on PC are different things, although they can be same.
|
||||
|
||||
I enter these passwords. ::
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "NIIBE Yutaka <gniibe@fsij.org>"
|
||||
2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
|
||||
<PASSWORD-KEY-4CA7BABE>
|
||||
gpg: writing new key
|
||||
gpg: 3 Admin PIN attempts remaining before card is permanently locked
|
||||
|
||||
Please enter the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-GNUK>
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
The primary key is now on the Token and GnuPG says its card-no (F517 00000001) , where F517 is the vendor ID of FSIJ.
|
||||
|
||||
Secondly, I import my subkey of encryption. I select key number '1'. ::
|
||||
|
||||
gpg> key 1
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/084239CF created: 2010-10-15 expires: never
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
You can see that the subkey is marked by '*'.
|
||||
I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``2`` as it's encryption key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
|
||||
Please select where to store the key:
|
||||
(2) Encryption key
|
||||
Your selection? 2
|
||||
|
||||
Then, GnuPG asks the passphrase of **keys on PC** again. I enter. ::
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "NIIBE Yutaka <gniibe@fsij.org>"
|
||||
2048-bit RSA key, ID 084239CF, created 2010-10-15
|
||||
<PASSWORD-KEY-4CA7BABE>
|
||||
gpg: writing new key
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
The sub key is now on the Token and GnuPG says its card-no for it.
|
||||
|
||||
I type ``key 1`` to deselect key number '1'. ::
|
||||
|
||||
gpg> key 1
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Thirdly, I select sub key of suthentication which has key number '2'. ::
|
||||
|
||||
gpg> key 2
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
You can see that the subkey number '2' is marked by '*'.
|
||||
I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``3`` as it's authentication key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
|
||||
Please select where to store the key:
|
||||
(3) Authentication key
|
||||
Your selection? 3
|
||||
|
||||
Then, GnuPG asks the passphrase of **keys on PC** again. I enter. ::
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "NIIBE Yutaka <gniibe@fsij.org>"
|
||||
2048-bit RSA key, ID 5BB065DC, created 2010-10-22
|
||||
<PASSWORD-KEY-4CA7BABE>
|
||||
gpg: writing new key
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
card-no: F517 00000001
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
The sub key is now on the Token and GnuPG says its card-no for it.
|
||||
|
||||
Lastly, I quit GnuPG. Note that I **don't** save changes. ::
|
||||
|
||||
gpg> quit
|
||||
Save changes? (y/N) n
|
||||
Quit without saving? (y/N) y
|
||||
$
|
||||
|
||||
All keys are imported to Gnuk Token now.
|
||||
183
doc/gnuk-keytocard.rst
Normal file
183
doc/gnuk-keytocard.rst
Normal file
@@ -0,0 +1,183 @@
|
||||
================================
|
||||
Key import from PC to Gnuk Token
|
||||
================================
|
||||
|
||||
This document describes how I put my **keys on PC** to the Token, and remove keys from PC.
|
||||
|
||||
Note that there is **no ways** to export keys from the Token, so please be careful.
|
||||
|
||||
.. BREAK
|
||||
|
||||
If you want to import same keys to multiple Tokens, please copy ``.gnupg`` directory before. In my case, I do something like following: ::
|
||||
|
||||
$ cp -a .gnupg tmp/gnuk-testing-dir
|
||||
|
||||
See `another document`_ to import keys to the Token from copied directory.
|
||||
|
||||
.. _another document: gnuk-keytocard-noremoval
|
||||
|
||||
After personalization, I put my keys into the Token.
|
||||
|
||||
Here is the log.
|
||||
|
||||
I invoke GnuPG with my key (4ca7babe). ::
|
||||
|
||||
$ gpg --edit-key 4ca7babe
|
||||
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
Secret key is available.
|
||||
|
||||
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
|
||||
trust: ultimate validity: ultimate
|
||||
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
|
||||
Then, GnuPG enters its own command interaction mode. The prompt is ``gpg>``.
|
||||
To enable ``keytocard`` command, I type ``toggle`` command. ::
|
||||
|
||||
gpg> toggle
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Firstly, I import my primary key into Gnuk Token.
|
||||
I type ``keytocard`` command, answer ``y`` to confirm keyimport,
|
||||
and type ``1`` to say it's signature key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Really move the primary key? (y/N) y
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00'
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
|
||||
Please select where to store the key:
|
||||
(1) Signature key
|
||||
(3) Authentication key
|
||||
Your selection? 1
|
||||
|
||||
Then, GnuPG asks two passwords. One is the passphrase of **keys on PC** and another is the password of **Gnuk Token**. Note that the password of the token and the password of the keys on PC are different things, although they can be same.
|
||||
|
||||
I enter these passwords. ::
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "NIIBE Yutaka <gniibe@fsij.org>"
|
||||
2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
|
||||
<PASSWORD-KEY-4CA7BABE>
|
||||
gpg: writing new key
|
||||
gpg: 3 Admin PIN attempts remaining before card is permanently locked
|
||||
|
||||
Please enter the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-GNUK>
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
The primary key is now on the Token and GnuPG says its card-no (F517 00000001) , where F517 is the vendor ID of FSIJ.
|
||||
|
||||
Secondly, I import my subkey of encryption. I select key number '1'. ::
|
||||
|
||||
gpg> key 1
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/084239CF created: 2010-10-15 expires: never
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
You can see that the subkey is marked by '*'.
|
||||
I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``2`` as it's encryption key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
|
||||
Please select where to store the key:
|
||||
(2) Encryption key
|
||||
Your selection? 2
|
||||
|
||||
Then, GnuPG asks the passphrase of **keys on PC** again. I enter. ::
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "NIIBE Yutaka <gniibe@fsij.org>"
|
||||
2048-bit RSA key, ID 084239CF, created 2010-10-15
|
||||
<PASSWORD-KEY-4CA7BABE>
|
||||
gpg: writing new key
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
The sub key is now on the Token and GnuPG says its card-no for it.
|
||||
|
||||
I type ``key 1`` to deselect key number '1'. ::
|
||||
|
||||
gpg> key 1
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Thirdly, I select sub key of suthentication which has key number '2'. ::
|
||||
|
||||
gpg> key 2
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
You can see that the subkey number '2' is marked by '*'.
|
||||
I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``3`` as it's authentication key. ::
|
||||
|
||||
gpg> keytocard
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
|
||||
Please select where to store the key:
|
||||
(3) Authentication key
|
||||
Your selection? 3
|
||||
|
||||
Then, GnuPG asks the passphrase of **keys on PC** again. I enter. ::
|
||||
|
||||
You need a passphrase to unlock the secret key for
|
||||
user: "NIIBE Yutaka <gniibe@fsij.org>"
|
||||
2048-bit RSA key, ID 5BB065DC, created 2010-10-22
|
||||
<PASSWORD-KEY-4CA7BABE>
|
||||
gpg: writing new key
|
||||
|
||||
sec 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb* 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
card-no: F517 00000001
|
||||
(1) NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
The sub key is now on the Token and GnuPG says its card-no for it.
|
||||
|
||||
Lastly, I save changes of **keys on PC** and quit GnuPG. ::
|
||||
|
||||
gpg> save
|
||||
$
|
||||
|
||||
All secret keys are imported to Gnuk Token now. On PC, only references (card-no) to the Token remain.
|
||||
118
doc/gnuk-personalization.rst
Normal file
118
doc/gnuk-personalization.rst
Normal file
@@ -0,0 +1,118 @@
|
||||
=============================
|
||||
Personalization of Gnuk Token
|
||||
=============================
|
||||
|
||||
|
||||
Personalize your Gnuk Token
|
||||
===========================
|
||||
|
||||
Invoke GnuPG with the option ``--card-edit``. ::
|
||||
|
||||
$ gpg --card-edit
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-34006E06) 00 00'
|
||||
Application ID ...: D276000124010200F517000000010000
|
||||
Version ..........: 2.0
|
||||
Manufacturer .....: FSIJ
|
||||
Serial number ....: 00000001
|
||||
Name of cardholder: [not set]
|
||||
Language prefs ...: [not set]
|
||||
Sex ..............: unspecified
|
||||
URL of public key : [not set]
|
||||
Login data .......: [not set]
|
||||
Signature PIN ....: forced
|
||||
Key attributes ...: 2048R 2048R 2048R
|
||||
Max. PIN lengths .: 127 127 127
|
||||
PIN retry counter : 3 3 3
|
||||
Signature counter : 0
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
General key info..: [none]
|
||||
|
||||
It shows the status of the card (as same as the output of ``gpg --card-status``). It shows token's name and its USB serial string (0.12-34006E06) from PC/SC-lite.
|
||||
|
||||
Then, GnuPG enters its own command interaction mode. The prompt is ``gpg/card>``.
|
||||
|
||||
Firstly, I change PIN of card user from factory setting (of "123456"). Note that, only changing PIN of user enables "admin less mode" of Gnuk. Admin password will become same one of user's. ::
|
||||
|
||||
gpg/card> passwd
|
||||
gpg: OpenPGP card no. D276000124010200F517000000010000 detected
|
||||
|
||||
Please enter the PIN
|
||||
Enter PIN: 123456
|
||||
|
||||
New PIN
|
||||
Enter New PIN: <PASSWORD-OF-GNUK>
|
||||
|
||||
New PIN
|
||||
Repeat this PIN: <PASSWORD-OF-GNUK>
|
||||
PIN changed.
|
||||
|
||||
Secondly, enabling admin command, I put name of mine. Note that I input user's PIN (which I set above) here, because it is "admin less mode". ::
|
||||
|
||||
gpg/card> admin
|
||||
Admin commands are allowed
|
||||
|
||||
gpg/card> name
|
||||
Cardholder's surname: Niibe
|
||||
Cardholder's given name: Yutaka
|
||||
gpg: 3 Admin PIN attempts remaining before card is permanently locked
|
||||
|
||||
Please enter the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-OF-GNUK>
|
||||
|
||||
Thirdly, I put some other informations, such as language, sex, login, and URL. URL specifies the place where I put my public keys. ::
|
||||
|
||||
gpg/card> lang
|
||||
Language preferences: ja
|
||||
|
||||
gpg/card> sex
|
||||
Sex ((M)ale, (F)emale or space): m
|
||||
|
||||
gpg/card> url
|
||||
URL to retrieve public key: http://www.gniibe.org/gniibe.asc
|
||||
|
||||
gpg/card> login
|
||||
Login data (account name): gniibe
|
||||
|
||||
Since I don't force PIN input everytime, toggle it to non-force-pin-for-signature. ::
|
||||
|
||||
gpg/card> forcesig
|
||||
|
||||
Lastly, I setup reset code. This is optional. ::
|
||||
|
||||
gpg/card> passwd
|
||||
gpg: OpenPGP card no. D276000124010200F517000000010000 detected
|
||||
|
||||
1 - change PIN
|
||||
2 - unblock PIN
|
||||
3 - change Admin PIN
|
||||
4 - set the Reset Code
|
||||
Q - quit
|
||||
|
||||
Your selection? 4
|
||||
gpg: 3 Admin PIN attempts remaining before card is permanently locked
|
||||
|
||||
Please enter the Admin PIN
|
||||
Enter Admin PIN: <PASSWORD-OF-GNUK>
|
||||
|
||||
New Reset Code
|
||||
Enter New PIN: <RESETCODE-OF-GNUK>
|
||||
|
||||
New Reset Code
|
||||
Repeat this PIN: <RESETCODE-OF-GNUK>
|
||||
Reset Code set.
|
||||
|
||||
1 - change PIN
|
||||
2 - unblock PIN
|
||||
3 - change Admin PIN
|
||||
4 - set the Reset Code
|
||||
Q - quit
|
||||
|
||||
Your selection? q
|
||||
|
||||
Then, I quit. ::
|
||||
|
||||
gpg/card> quit
|
||||
|
||||
That's all.
|
||||
34
doc/gnuk-token-initial-configuration.rst
Normal file
34
doc/gnuk-token-initial-configuration.rst
Normal file
@@ -0,0 +1,34 @@
|
||||
===================================
|
||||
Initial Configuration of Gnuk Token
|
||||
===================================
|
||||
|
||||
Conditions
|
||||
==========
|
||||
|
||||
I assume you are using GNU/Linux.
|
||||
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
We need to kill ``scdaemon`` before configuring Gnuk Token. ::
|
||||
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
|
||||
Serial Number (optional)
|
||||
========================
|
||||
|
||||
In the file ``GNUK_SERIAL_NUMBER``, each line has email and 6-byte serial number.
|
||||
|
||||
The tool ``../tool/gnuk_put_binary.py`` examines environment variable of ``EMAIL``, and writes serial number to Gnuk Token. ::
|
||||
|
||||
$ ../tool/gnuk_put_binary.py -s ../GNUK_SERIAL_NUMBER
|
||||
Writing serial number
|
||||
Token: FSIJ Gnuk (0.12-38FF6A06) 00 00
|
||||
ATR: 3B DA 11 FF 81 B1 FE 55 1F 03 00 31 84 73 80 01 40 00 90 00 24
|
||||
|
||||
|
||||
The tool ``../tool/gnuk_put_binary.py`` is for PC/SC Lite. Use
|
||||
``../tool/gnuk_put_binary_libusb.py`` instead, if you don't use
|
||||
PC/SC Lite but use libusb directly.
|
||||
41
doc/gpg-settings.rst
Normal file
41
doc/gpg-settings.rst
Normal file
@@ -0,0 +1,41 @@
|
||||
.. -*- coding: utf-8 -*-
|
||||
|
||||
==============
|
||||
GnuPG settings
|
||||
==============
|
||||
|
||||
Here is my GnuPG settings.
|
||||
|
||||
.gnupg/gpg.conf
|
||||
===============
|
||||
|
||||
I create ``.gnupg/gpg.conf`` file with the following content. ::
|
||||
|
||||
use-agent
|
||||
personal-digest-preferences SHA256
|
||||
cert-digest-algo SHA256
|
||||
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
|
||||
|
||||
default-key 0x4ca7babe
|
||||
|
||||
|
||||
Let gpg-agent manage SSH key
|
||||
============================
|
||||
|
||||
I deactivate seahose-agent. Also, I deactivate gnome-keyring managing SSH key. ::
|
||||
|
||||
$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
|
||||
|
||||
Then, I create ``.gnupg/gpg-agent.conf`` file with the following content. ::
|
||||
|
||||
enable-ssh-support
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
* `Creating a new GPG key`_
|
||||
* `Use OpenPGP Keys for OpenSSH, how to use gpg with ssh`_
|
||||
|
||||
.. _Creating a new GPG key: http://keyring.debian.org/creating-key.html
|
||||
.. _Use OpenPGP Keys for OpenSSH, how to use gpg with ssh: http://www.programmierecke.net/howto/gpg-ssh.html
|
||||
BIN
doc/images/gnuk-sticker.png
Normal file
BIN
doc/images/gnuk-sticker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
37
doc/index.rst
Normal file
37
doc/index.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
.. Gnuk Documentation documentation master file, created by
|
||||
sphinx-quickstart on Wed Jul 4 15:29:05 2012.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
Copyright (C) 2012 NIIBE Yutaka
|
||||
Copyright (C) 2012 Free Software Initiative of Japan
|
||||
This document is licensed under a CC-BY-SA 3.0 Unported License
|
||||
|
||||
Gnuk Documentation
|
||||
==================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro.rst
|
||||
development.rst
|
||||
stop-scdaemon.rst
|
||||
udev-rules.rst
|
||||
generating-2048-RSA-key.rst
|
||||
gnuk-token-initial-configuration.rst
|
||||
gnuk-personalization.rst
|
||||
gnuk-keytocard.rst
|
||||
gnuk-keytocard-noremoval.rst
|
||||
using-gnuk-token-with-another-computer.rst
|
||||
gpg-settings.rst
|
||||
gnome3-gpg-settings.rst
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
69
doc/intro.rst
Normal file
69
doc/intro.rst
Normal file
@@ -0,0 +1,69 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
|
||||
What's Gnuk?
|
||||
------------
|
||||
|
||||
Gnuk is an implementation of USB cryptographic token for GNU Privacy
|
||||
Guard. Gnuk supports OpenPGP card protocol version 2, and it runs on
|
||||
STM32F103 processor.
|
||||
|
||||
|
||||
Cryptographic token and feature of Gnuk
|
||||
---------------------------------------
|
||||
|
||||
Cryptographic token is a store of private keys and it computes cryptographic
|
||||
functions on the device.
|
||||
|
||||
The idea is to separate important secrets to independent device,
|
||||
from where nobody can extract them.
|
||||
|
||||
|
||||
Development Environment
|
||||
-----------------------
|
||||
|
||||
See :doc:`development` for development environment for Gnuk.
|
||||
Gnuk is developed on the environment where there are only Free Software.
|
||||
|
||||
|
||||
Target boards for running Gnuk
|
||||
------------------------------
|
||||
|
||||
Hardware requirement for Gnuk is the micro controller STM32F103.
|
||||
In version 1.0, Gnuk supports following boards.
|
||||
|
||||
* FST-01 (Flying Stone Tiny ZERO-ONE)
|
||||
|
||||
* Olimex STM32-H103
|
||||
|
||||
* CQ STARM
|
||||
|
||||
* STBee
|
||||
|
||||
* STBee Mini
|
||||
|
||||
* STM32 part of STM8S Discovery Kit
|
||||
|
||||
|
||||
Host prerequisites for using Gnuk Token
|
||||
---------------------------------------
|
||||
|
||||
* GNU Privacy Guard (GnuPG)
|
||||
|
||||
* libusb
|
||||
|
||||
* [Optional] PC/SC lite (pcscd, libccid)
|
||||
|
||||
* SSH: openssh
|
||||
|
||||
* Web: scute, firefox
|
||||
|
||||
|
||||
Usages
|
||||
------
|
||||
|
||||
* Sign with GnuPG
|
||||
* Decrypt with GnuPG
|
||||
* Use with OpenSSH
|
||||
* Use with Firefox for X.509 client certificate authentication
|
||||
@@ -1,4 +1,4 @@
|
||||
* Random Number Generator
|
||||
* [DONE] Random Number Generator
|
||||
|
||||
RNG is needed for Data Encryption Key to encrypt private key (P and Q).
|
||||
It is important to collect enough entropy. Perhaps, it would
|
||||
@@ -77,7 +77,8 @@ KEYPTR
|
||||
<---encrypted----><--- plain ---->
|
||||
|
||||
key_addr 4-byte
|
||||
additional_data_encrypted 16-byte
|
||||
initial_vector (random) 16-byte
|
||||
checksum_encrypted 16-byte
|
||||
dek_encrypted_by_keystring_pw1 16-byte
|
||||
dek_encrypted_by_keystring_rc 16-byte
|
||||
dek_encrypted_by_keystring_pw3 16-byte
|
||||
@@ -85,6 +86,4 @@ dek_encrypted_by_keystring_pw3 16-byte
|
||||
... decrypted to
|
||||
|
||||
[ P ][ Q ]
|
||||
check 4-byte
|
||||
random 4-byte
|
||||
magic[] 8-byte
|
||||
checksum 16-byte
|
||||
132
doc/note/firmware-update
Normal file
132
doc/note/firmware-update
Normal file
@@ -0,0 +1,132 @@
|
||||
Firmware update feature
|
||||
=======================
|
||||
|
||||
The firmware update feature of Gnuk is experimental. Please be
|
||||
careful using that.
|
||||
|
||||
Note that updating firmware, all data objects and keys will be
|
||||
removed. There is _no way_ to preserve those data.
|
||||
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
In addition to settings of Gnuk, I create a file
|
||||
/etc/udev/rules.d/92-gnuk.rules::
|
||||
|
||||
# For updating firmware, permission settings are needed.
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
||||
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
|
||||
|
||||
|
||||
While I am a member of group "pcscd" in /etc/group.
|
||||
|
||||
This is needed for reGNUal, the firmware update program.
|
||||
|
||||
|
||||
Registering a public key for firmware update
|
||||
============================================
|
||||
|
||||
You need to register a public key to update the firmware. It should
|
||||
be RSA 2048-bit.
|
||||
|
||||
One way to extract public key data is by using "gpg-connect-agent"
|
||||
command connecting gpg-agent.
|
||||
|
||||
We can examine key information of gpg-agent by "KEYINFO" command.
|
||||
Here is my example::
|
||||
|
||||
$ gpg-connect-agent "KEYINFO --list" /bye
|
||||
S KEYINFO 4970A0D537CA2EF7CE6A106E47AD89B0EFB684C8 D - - - - -
|
||||
S KEYINFO 65F67E742101C7FE6D5B33FCEFCF4F65EAF0688C T D276000124010200F517000000010000 OPENPGP.2 - - -
|
||||
S KEYINFO 5D6C89682D07CCFC034AF508420BF2276D8018ED T D276000124010200F517000000010000 OPENPGP.3 - - -
|
||||
S KEYINFO 7D180C0C2A991B25204110A92F5F92A5A509845B D - - - - -
|
||||
S KEYINFO 101DE7B639FE29F4636BDEECF442A9273AFA6565 T D276000124010200F517000000010000 OPENPGP.1 - - -
|
||||
OK
|
||||
|
||||
I have two local keys (in my PC) and three keys in my token.
|
||||
|
||||
With the script below, I extract public key of the keygrip
|
||||
5D6C89682D07CCFC034AF508420BF2276D8018ED into the file: 5D6C8968.bin::
|
||||
|
||||
$ ./get_public_key.py 5D6C89682D07CCFC034AF508420BF2276D8018ED
|
||||
|
||||
Here is the script, get_public_key.py::
|
||||
|
||||
#! /usr/bin/python
|
||||
|
||||
import sys, binascii
|
||||
from subprocess import check_output
|
||||
|
||||
def get_gpg_public_key(keygrip):
|
||||
result = check_output(["gpg-connect-agent", "READKEY %s" % keygrip, "/bye"])
|
||||
key = ""
|
||||
while True:
|
||||
i = result.find('%')
|
||||
if i < 0:
|
||||
key += result
|
||||
break
|
||||
hex_str = result[i+1:i+3]
|
||||
key += result[0:i]
|
||||
key += chr(int(hex_str,16))
|
||||
result = result[i+3:]
|
||||
|
||||
pos = key.index("D (10:public-key(3:rsa(1:n257:") + 31 # skip NUL too
|
||||
key = key[pos:-17] # )(1:e3:XYZ)))\nOK\n
|
||||
if len(key) != 256:
|
||||
raise ValueError, binascii.hexlify(key)
|
||||
return key
|
||||
|
||||
if __name__ == '__main__':
|
||||
keygrip = sys.argv[1]
|
||||
k = get_gpg_public_key(keygrip)
|
||||
shorthand = keygrip[0:8] + ".bin"
|
||||
f = open(shorthand,"w")
|
||||
f.write(k)
|
||||
f.close()
|
||||
|
||||
|
||||
Then, we can put the data of public key into token by::
|
||||
|
||||
$ tool/gnuk_put_binary_libusb.py -k 0 5D6C8968.bin
|
||||
|
||||
|
||||
Invoking firmware update
|
||||
========================
|
||||
|
||||
We specify reGNUal binary and Gnuk binary.
|
||||
|
||||
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk.bin
|
||||
|
||||
|
||||
Two or more tokens
|
||||
==================
|
||||
|
||||
Currently, GnuPG doesn't support multiple devices connected to the
|
||||
host.
|
||||
|
||||
In order to update the firmware of a TARGET token, we use GnuPG to
|
||||
authenticate with public key. It is assumed that you have another
|
||||
AUTH token for this. This situation is somewhat complicated.
|
||||
|
||||
What I do is:
|
||||
(1) Don't run PC/SC daemon::
|
||||
|
||||
# /etc/init.d/pcscd stop
|
||||
|
||||
(2) To make sure, kill scdaemon::
|
||||
|
||||
$ killall -9 scdaemon
|
||||
|
||||
(3) Insert the AUTH token to USB, and use it::
|
||||
|
||||
$ gpg --card-status
|
||||
|
||||
(4) Insert the TARGET token to USB (after scdaemon communicates AUTH
|
||||
token), and invoke gnuk_upgrade.py.
|
||||
In this situation, gnuk_upgrade.py tries to connect one of tokens,
|
||||
but a connection to the AUTH token will fail because scdaemon is
|
||||
connecting to that device, and will be expected to connect to the
|
||||
TARGET token succesufully, instead.
|
||||
--
|
||||
37
doc/stop-scdaemon.rst
Normal file
37
doc/stop-scdaemon.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
===========================
|
||||
Stopping/Resetting SCDAEMON
|
||||
===========================
|
||||
|
||||
There is a daemon named ``scdaemon`` behind gpg-agent, which handles
|
||||
communication to smartcard/token.
|
||||
|
||||
Ideally, we don't need to care about ``scdaemon``, and it should
|
||||
everything automatically. But, there are some cases (because of
|
||||
bugs), where we need to talk to the daemon directly, in practice.
|
||||
|
||||
|
||||
How to communicate SCDAEMON
|
||||
===========================
|
||||
|
||||
We have a utility to communicate with a running gpg-agent, that's
|
||||
gpg-connect-agent. We can use it to communicate with scdaemon,
|
||||
as it supports sub-command "SCD", exactly for this purpose.
|
||||
|
||||
|
||||
Stopping SCDAEMON
|
||||
=================
|
||||
|
||||
To stop SCDAEMON and let it exit, type::
|
||||
|
||||
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
|
||||
|
||||
Then, you can confirm that there is no SCDAEMON any more by ``ps``
|
||||
command.
|
||||
|
||||
|
||||
Let GPG-AGENT/SCDAEMON learn
|
||||
============================
|
||||
|
||||
To let gpg-agent/scdaemon learn, type::
|
||||
|
||||
$ gpg-connect-agent learn /bye
|
||||
48
doc/udev-rules.rst
Normal file
48
doc/udev-rules.rst
Normal file
@@ -0,0 +1,48 @@
|
||||
===============================================
|
||||
Device Configuration for Gnuk Token with libusb
|
||||
===============================================
|
||||
|
||||
In order to use Gnuk Token with libusb, configuration of device is
|
||||
needed for permissions. Note that this is not needed for the case of
|
||||
PC/SC Lite, as it has its own device configuration.
|
||||
|
||||
|
||||
Patching 60-gnupg.rules
|
||||
=======================
|
||||
|
||||
In case of Debian, there is a file /lib/udev/rules.d/60-gnupg.rules.
|
||||
This would be the place we need to change::
|
||||
|
||||
--- /lib/udev/rules.d/60-gnupg.rules.orig 2012-06-24 21:51:26.000000000 +0900
|
||||
+++ /lib/udev/rules.d/60-gnupg.rules 2012-07-13 17:18:55.149587687 +0900
|
||||
@@ -10,4 +10,7 @@
|
||||
ATTR{idVendor}=="04e6", ATTR{idProduct}=="5115", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
|
||||
+# Gnuk
|
||||
+ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
|
||||
+
|
||||
LABEL="gnupg_rules_end"
|
||||
|
||||
|
||||
|
||||
Have a another configuration for reGNUal
|
||||
========================================
|
||||
|
||||
For reGNUal (upgrade feature of Gnuk),
|
||||
I also have a file /etc/udev/rules.d/92-gnuk.rules::
|
||||
|
||||
# For updating firmware, permission settings are needed.
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
|
||||
ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd"
|
||||
|
||||
|
||||
Configuration for ST-Link/V2
|
||||
============================
|
||||
|
||||
This is for development, but I also have a file
|
||||
/etc/udev/rules.d/10-stlink.rules::
|
||||
|
||||
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", GROUP="tape", MODE="664", SYMLINK+="stlink"
|
||||
|
||||
173
doc/using-gnuk-token-with-another-computer.rst
Normal file
173
doc/using-gnuk-token-with-another-computer.rst
Normal file
@@ -0,0 +1,173 @@
|
||||
======================================
|
||||
Using Gnuk Token with another computer
|
||||
======================================
|
||||
|
||||
This document describes how you can use Gnuk Token on another PC (which is not the one you generate your keys).
|
||||
|
||||
Note that the Token only brings your secret keys, while ``.gnupg`` directory contains keyrings and trustdb, too.
|
||||
|
||||
.. BREAK
|
||||
|
||||
Fetch the public key and connect it to the Token
|
||||
================================================
|
||||
|
||||
Using the Token, we need to put the public key and the secret key reference (to the token) in ``.gnupg``.
|
||||
|
||||
To do that, invoke GnuPG with ``--card-edit`` option. ::
|
||||
|
||||
$ gpg --card-edit
|
||||
gpg: detected reader `FSIJ Gnuk (0.12-37006A06) 00 00'
|
||||
Application ID ...: D276000124010200F517000000010000
|
||||
Version ..........: 2.0
|
||||
Manufacturer .....: FSIJ
|
||||
Serial number ....: 00000001
|
||||
Name of cardholder: Yutaka Niibe
|
||||
Language prefs ...: ja
|
||||
Sex ..............: male
|
||||
URL of public key : http://www.gniibe.org/gniibe.asc
|
||||
Login data .......: gniibe
|
||||
Signature PIN ....: not forced
|
||||
Key attributes ...: 2048R 2048R 2048R
|
||||
Max. PIN lengths .: 127 127 127
|
||||
PIN retry counter : 3 3 3
|
||||
Signature counter : 6
|
||||
Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE
|
||||
created ....: 2010-10-15 06:46:33
|
||||
Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF
|
||||
created ....: 2010-10-15 06:46:33
|
||||
Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC
|
||||
created ....: 2010-10-22 06:06:36
|
||||
General key info..: [none]
|
||||
|
||||
gpg/card>
|
||||
|
||||
It says, there is no key info related to this token on your PC (``[none]``).
|
||||
|
||||
Fetch the public key from URL specified in the Token. ::
|
||||
|
||||
gpg/card> fetch
|
||||
gpg: requesting key 4CA7BABE from http server www.gniibe.org
|
||||
gpg: key 4CA7BABE: public key "NIIBE Yutaka <gniibe@fsij.org>" imported
|
||||
gpg: no ultimately trusted keys found
|
||||
gpg: Total number processed: 1
|
||||
gpg: imported: 1 (RSA: 1)
|
||||
|
||||
gpg/card>
|
||||
|
||||
Good. The public key is now in ``.gnupg``. We can examine by ``gpg --list-keys``.
|
||||
|
||||
However, the secret key reference (to the token) is not in ``.gnupg`` yet.
|
||||
|
||||
It will be generated when I do ``--card-status`` by GnuPG with correspoinding public key in ``.gnupg``, or just type return at the ``gpg/card>`` prompt. ::
|
||||
|
||||
gpg/card>
|
||||
|
||||
Application ID ...: D276000124010200F517000000010000
|
||||
Version ..........: 2.0
|
||||
Manufacturer .....: FSIJ
|
||||
Serial number ....: 00000001
|
||||
Name of cardholder: Yutaka Niibe
|
||||
Language prefs ...: ja
|
||||
Sex ..............: male
|
||||
URL of public key : http://www.gniibe.org/gniibe.asc
|
||||
Login data .......: gniibe
|
||||
Signature PIN ....: not forced
|
||||
Key attributes ...: 2048R 2048R 2048R
|
||||
Max. PIN lengths .: 127 127 127
|
||||
PIN retry counter : 3 3 3
|
||||
Signature counter : 6
|
||||
Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE
|
||||
created ....: 2010-10-15 06:46:33
|
||||
Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF
|
||||
created ....: 2010-10-15 06:46:33
|
||||
Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC
|
||||
created ....: 2010-10-22 06:06:36
|
||||
General key info..:
|
||||
pub 2048R/4CA7BABE 2010-10-15 NIIBE Yutaka <gniibe@fsij.org>
|
||||
sec> 2048R/4CA7BABE created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb> 2048R/084239CF created: 2010-10-15 expires: never
|
||||
card-no: F517 00000001
|
||||
ssb> 2048R/5BB065DC created: 2010-10-22 expires: never
|
||||
card-no: F517 00000001
|
||||
|
||||
gpg/card>
|
||||
|
||||
OK, now I can use the Token on this computer.
|
||||
|
||||
|
||||
Update trustdb for the key on Gnuk Token
|
||||
========================================
|
||||
|
||||
Yes, I can use the Token by the public key and the secret key reference to the card. More, I need to update the trustdb.
|
||||
|
||||
To do that I do: ::
|
||||
|
||||
$ gpg --edit-key 4ca7babe
|
||||
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
Secret key is available.
|
||||
|
||||
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
|
||||
trust: unknown validity: unknown
|
||||
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
|
||||
|
||||
gpg>
|
||||
|
||||
See, the key is ``unknown`` state. Add trust for that. ::
|
||||
|
||||
gpg> trust
|
||||
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
|
||||
trust: unknown validity: unknown
|
||||
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
|
||||
|
||||
Please decide how far you trust this user to correctly verify other users' keys
|
||||
(by looking at passports, checking fingerprints from different sources, etc.)
|
||||
|
||||
1 = I don't know or won't say
|
||||
2 = I do NOT trust
|
||||
3 = I trust marginally
|
||||
4 = I trust fully
|
||||
5 = I trust ultimately
|
||||
m = back to the main menu
|
||||
|
||||
Your decision? 5
|
||||
Do you really want to set this key to ultimate trust? (y/N) y
|
||||
|
||||
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
|
||||
trust: ultimate validity: unknown
|
||||
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
|
||||
Please note that the shown key validity is not necessarily correct
|
||||
unless you restart the program.
|
||||
|
||||
$
|
||||
|
||||
Next time I invoke GnuPG, it will be ``ultimate`` key. Let's see: ::
|
||||
|
||||
$ gpg --edit-key 4ca7babe
|
||||
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
Secret key is available.
|
||||
|
||||
pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC
|
||||
trust: ultimate validity: ultimate
|
||||
sub 2048R/084239CF created: 2010-10-15 expires: never usage: E
|
||||
sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A
|
||||
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
|
||||
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
|
||||
|
||||
gpg> quit
|
||||
$
|
||||
@@ -83,6 +83,7 @@ int aes_crypt_ecb( aes_context *ctx,
|
||||
const unsigned char input[16],
|
||||
unsigned char output[16] );
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* \brief AES-CBC buffer encryption/decryption
|
||||
* Length should be a multiple of the block
|
||||
@@ -103,6 +104,7 @@ int aes_crypt_cbc( aes_context *ctx,
|
||||
unsigned char iv[16],
|
||||
const unsigned char *input,
|
||||
unsigned char *output );
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief AES-CFB128 buffer encryption/decryption.
|
||||
|
||||
@@ -501,7 +501,7 @@ int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
|
||||
* 1 if memory allocation failed,
|
||||
* POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
|
||||
*/
|
||||
int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
|
||||
int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng );
|
||||
|
||||
/**
|
||||
* \brief Prime number generation
|
||||
@@ -517,7 +517,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
|
||||
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
|
||||
*/
|
||||
int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
|
||||
int (*f_rng)(void *), void *p_rng );
|
||||
unsigned char (*f_rng)(void *), void *p_rng );
|
||||
|
||||
/**
|
||||
* \brief Checkup routine
|
||||
|
||||
@@ -86,10 +86,12 @@
|
||||
*/
|
||||
#define POLARSSL_VERSION_C
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
/*
|
||||
* Enable the prime-number generation code.
|
||||
*/
|
||||
#define POLARSSL_GENPRIME
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Uncomment this macro to store the AES tables in ROM.
|
||||
|
||||
@@ -183,7 +183,7 @@ void rsa_init( rsa_context *ctx,
|
||||
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||
*/
|
||||
int rsa_gen_key( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int nbits, int exponent );
|
||||
|
||||
@@ -258,7 +258,7 @@ int rsa_private( rsa_context *ctx,
|
||||
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||
*/
|
||||
int rsa_pkcs1_encrypt( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int mode, int ilen,
|
||||
const unsigned char *input,
|
||||
@@ -330,7 +330,7 @@ int rsa_pkcs1_verify( rsa_context *ctx,
|
||||
int hash_id,
|
||||
int hashlen,
|
||||
const unsigned char *hash,
|
||||
unsigned char *sig );
|
||||
const unsigned char *sig );
|
||||
|
||||
/**
|
||||
* \brief Free the components of an RSA key
|
||||
|
||||
@@ -172,15 +172,15 @@ static const unsigned char FSb[256] =
|
||||
V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
|
||||
|
||||
#define V(a,b,c,d) 0x##a##b##c##d
|
||||
static const unsigned long FT0[256] = { FT };
|
||||
static const unsigned long FT0[256] __attribute__((section(".sys.0"))) = { FT };
|
||||
#undef V
|
||||
|
||||
#define V(a,b,c,d) 0x##b##c##d##a
|
||||
static const unsigned long FT1[256] = { FT };
|
||||
static const unsigned long FT1[256] __attribute__((section(".sys.1"))) = { FT };
|
||||
#undef V
|
||||
|
||||
#define V(a,b,c,d) 0x##c##d##a##b
|
||||
static const unsigned long FT2[256] = { FT };
|
||||
static const unsigned long FT2[256] __attribute__((section(".sys.2"))) = { FT };
|
||||
#undef V
|
||||
|
||||
#define V(a,b,c,d) 0x##d##a##b##c
|
||||
@@ -753,6 +753,7 @@ int aes_crypt_ecb( aes_context *ctx,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* AES-CBC buffer encryption/decryption
|
||||
*/
|
||||
@@ -816,6 +817,7 @@ int aes_crypt_cbc( aes_context *ctx,
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AES-CFB128 buffer encryption/decryption
|
||||
|
||||
@@ -225,6 +225,7 @@ int mpi_size( const mpi *X )
|
||||
return( ( mpi_msb( X ) + 7 ) >> 3 );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Convert an ASCII character to digit value
|
||||
*/
|
||||
@@ -310,7 +311,6 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Helper to write the digits high-order first
|
||||
*/
|
||||
@@ -649,7 +649,7 @@ int mpi_cmp_mpi( const mpi *X, const mpi *Y )
|
||||
return( 0 );
|
||||
|
||||
if( i > j ) return( X->s );
|
||||
if( j > i ) return( -X->s );
|
||||
if( j > i ) return( -Y->s );
|
||||
|
||||
if( X->s > 0 && Y->s < 0 ) return( 1 );
|
||||
if( Y->s > 0 && X->s < 0 ) return( -1 );
|
||||
@@ -1570,8 +1570,6 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_GENPRIME)
|
||||
|
||||
/*
|
||||
* Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
|
||||
*/
|
||||
@@ -1665,6 +1663,8 @@ cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_GENPRIME)
|
||||
|
||||
static const int small_prime[] =
|
||||
{
|
||||
3, 5, 7, 11, 13, 17, 19, 23,
|
||||
@@ -1693,7 +1693,7 @@ static const int small_prime[] =
|
||||
/*
|
||||
* Miller-Rabin primality test (HAC 4.24)
|
||||
*/
|
||||
int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
|
||||
int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng )
|
||||
{
|
||||
int ret, i, j, n, s, xs;
|
||||
mpi W, R, T, A, RR;
|
||||
@@ -1755,7 +1755,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
|
||||
|
||||
p = (unsigned char *) A.p;
|
||||
for( j = 0; j < A.n * ciL; j++ )
|
||||
*p++ = (unsigned char) f_rng( p_rng );
|
||||
*p++ = f_rng( p_rng );
|
||||
|
||||
j = mpi_msb( &A ) - mpi_msb( &W );
|
||||
MPI_CHK( mpi_shift_r( &A, j + 1 ) );
|
||||
@@ -1809,7 +1809,7 @@ cleanup:
|
||||
* Prime number generation
|
||||
*/
|
||||
int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
|
||||
int (*f_rng)(void *), void *p_rng )
|
||||
unsigned char (*f_rng)(void *), void *p_rng )
|
||||
{
|
||||
int ret, k, n;
|
||||
unsigned char *p;
|
||||
@@ -1827,7 +1827,7 @@ int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
|
||||
|
||||
p = (unsigned char *) X->p;
|
||||
for( k = 0; k < X->n * ciL; k++ )
|
||||
*p++ = (unsigned char) f_rng( p_rng );
|
||||
*p++ = f_rng( p_rng );
|
||||
|
||||
k = mpi_msb( X );
|
||||
if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );
|
||||
|
||||
@@ -58,7 +58,7 @@ void rsa_init( rsa_context *ctx,
|
||||
* Generate an RSA keypair
|
||||
*/
|
||||
int rsa_gen_key( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int nbits, int exponent )
|
||||
{
|
||||
@@ -101,6 +101,7 @@ int rsa_gen_key( rsa_context *ctx,
|
||||
}
|
||||
while( mpi_cmp_int( &G, 1 ) != 0 );
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* D = E^-1 mod ((P-1)*(Q-1))
|
||||
* DP = D mod (P - 1)
|
||||
@@ -111,6 +112,7 @@ int rsa_gen_key( rsa_context *ctx,
|
||||
MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
|
||||
MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
|
||||
MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
|
||||
#endif
|
||||
|
||||
ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
|
||||
|
||||
@@ -129,6 +131,7 @@ cleanup:
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Check a public RSA key
|
||||
*/
|
||||
@@ -197,6 +200,7 @@ cleanup:
|
||||
mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL );
|
||||
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED | ret );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do an RSA public key operation
|
||||
@@ -295,7 +299,7 @@ cleanup:
|
||||
* Add the message padding, then do an RSA operation
|
||||
*/
|
||||
int rsa_pkcs1_encrypt( rsa_context *ctx,
|
||||
int (*f_rng)(void *),
|
||||
unsigned char (*f_rng)(void *),
|
||||
void *p_rng,
|
||||
int mode, int ilen,
|
||||
const unsigned char *input,
|
||||
@@ -323,7 +327,7 @@ int rsa_pkcs1_encrypt( rsa_context *ctx,
|
||||
int rng_dl = 100;
|
||||
|
||||
do {
|
||||
*p = (unsigned char) f_rng( p_rng );
|
||||
*p = f_rng( p_rng );
|
||||
} while( *p == 0 && --rng_dl );
|
||||
|
||||
// Check if RNG failed to generate data
|
||||
@@ -538,11 +542,11 @@ int rsa_pkcs1_verify( rsa_context *ctx,
|
||||
int hash_id,
|
||||
int hashlen,
|
||||
const unsigned char *hash,
|
||||
unsigned char *sig )
|
||||
const unsigned char *sig )
|
||||
{
|
||||
int ret, len, siglen;
|
||||
unsigned char *p, c;
|
||||
unsigned char buf[1024];
|
||||
unsigned char buf[256];
|
||||
|
||||
siglen = ctx->len;
|
||||
|
||||
|
||||
49
regnual/Makefile
Normal file
49
regnual/Makefile
Normal file
@@ -0,0 +1,49 @@
|
||||
# Makefile for reGNUal
|
||||
|
||||
PROJECT = regnual
|
||||
|
||||
OBJS = regnual.o usb_lld.o sys.o
|
||||
LDSCRIPT= regnual.ld
|
||||
|
||||
###################################
|
||||
MCU = cortex-m3
|
||||
|
||||
TRGT = arm-none-eabi-
|
||||
CC = $(TRGT)gcc
|
||||
LD = $(TRGT)ld
|
||||
OBJCOPY = $(TRGT)objcopy
|
||||
OBJDUMP = $(TRGT)objdump
|
||||
|
||||
# THUMB-specific options here
|
||||
TOPT = -mthumb -DTHUMB -mno-thumb-interwork
|
||||
# Define C warning options here
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
|
||||
DEFS = -DFREE_STANDING
|
||||
|
||||
CFLAGS = -O2 -g
|
||||
CFLAGS += $(CWARN) -I . -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
|
||||
|
||||
LDFLAGS = -T$(LDSCRIPT) -nostartfiles $(MCFLAGS) $(TOPT)
|
||||
|
||||
|
||||
####################
|
||||
|
||||
all: regnual.hex
|
||||
|
||||
regnual.o: regnual.c ../src/sys.h
|
||||
|
||||
regnual.hex: regnual.elf
|
||||
$(OBJCOPY) -Obinary regnual.elf regnual.bin
|
||||
$(OBJCOPY) -Oihex regnual.elf regnual.hex
|
||||
|
||||
usb_lld.o: ../src/usb_lld.c
|
||||
$(CC) $(CFLAGS) -c -o usb_lld.o ../src/usb_lld.c
|
||||
|
||||
regnual.elf: $(OBJS) $(LDSCRIPT)
|
||||
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS)
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin
|
||||
|
||||
distclean: clean
|
||||
355
regnual/regnual.c
Normal file
355
regnual/regnual.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* regnual.c -- Firmware installation for STM32F103 Flash ROM
|
||||
*
|
||||
* Copyright (C) 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
*
|
||||
* Gnuk is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* ReGNUal
|
||||
*/
|
||||
|
||||
#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 uint8_t _flash_start, _flash_end;
|
||||
extern int flash_write (uint32_t dst_addr, const uint8_t *src, size_t len);
|
||||
extern int flash_protect (void);
|
||||
extern void nvic_system_reset (void);
|
||||
|
||||
|
||||
#define ENDP0_RXADDR (0x40)
|
||||
#define ENDP0_TXADDR (0x80)
|
||||
|
||||
/* USB Standard Device Descriptor */
|
||||
static const uint8_t regnual_device_desc[] = {
|
||||
18, /* bLength */
|
||||
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0xFF, /* bDeviceClass: VENDOR */
|
||||
0x00, /* bDeviceSubClass */
|
||||
0x00, /* bDeviceProtocol */
|
||||
0x40, /* bMaxPacketSize0 */
|
||||
#include "../src/usb-vid-pid-ver.c.inc"
|
||||
1, /* Index of string descriptor describing manufacturer */
|
||||
2, /* Index of string descriptor describing product */
|
||||
3, /* Index of string descriptor describing the device's serial number */
|
||||
0x01 /* bNumConfigurations */
|
||||
};
|
||||
|
||||
static const uint8_t regnual_config_desc[] = {
|
||||
9,
|
||||
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
|
||||
18, 0, /* wTotalLength: no of returned bytes */
|
||||
1, /* bNumInterfaces: single vender interface */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: None */
|
||||
#if defined(USB_SELF_POWERED)
|
||||
0xC0, /* bmAttributes: self powered */
|
||||
#else
|
||||
0x80, /* bmAttributes: bus powered */
|
||||
#endif
|
||||
50, /* MaxPower 100 mA */
|
||||
|
||||
/* Interface Descriptor */
|
||||
9,
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
0, /* bInterfaceNumber: Index of this interface */
|
||||
0, /* Alternate setting for this interface */
|
||||
0, /* bNumEndpoints: None */
|
||||
0xFF,
|
||||
0,
|
||||
0,
|
||||
0, /* string index for interface */
|
||||
};
|
||||
|
||||
static const uint8_t regnual_string_lang_id[] = {
|
||||
4, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE,
|
||||
0x09, 0x04 /* LangID = 0x0409: US-English */
|
||||
};
|
||||
|
||||
#include "../src/usb-strings.c.inc"
|
||||
|
||||
static const uint8_t regnual_string_serial[] = {
|
||||
8*2+2,
|
||||
USB_STRING_DESCRIPTOR_TYPE,
|
||||
/* FSIJ-0.0 */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
|
||||
'0', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
const struct Descriptor device_desc = {
|
||||
regnual_device_desc,
|
||||
sizeof (regnual_device_desc)
|
||||
};
|
||||
|
||||
const struct Descriptor config_desc = {
|
||||
regnual_config_desc,
|
||||
sizeof (regnual_config_desc)
|
||||
};
|
||||
|
||||
const struct Descriptor string_descs[] = {
|
||||
{regnual_string_lang_id, sizeof (regnual_string_lang_id)},
|
||||
{gnukStringVendor, sizeof (gnukStringVendor)},
|
||||
{gnukStringProduct, sizeof (gnukStringProduct)},
|
||||
{regnual_string_serial, sizeof (regnual_string_serial)},
|
||||
};
|
||||
|
||||
#define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
|
||||
|
||||
static void
|
||||
regnual_device_reset (void)
|
||||
{
|
||||
/* Set DEVICE as not configured */
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (config_desc.Descriptor[7]);
|
||||
|
||||
usb_lld_reset ();
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
|
||||
64);
|
||||
}
|
||||
|
||||
#define USB_REGNUAL_MEMINFO 0
|
||||
#define USB_REGNUAL_SEND 1
|
||||
#define USB_REGNUAL_RESULT 2
|
||||
#define USB_REGNUAL_FLASH 3
|
||||
#define USB_REGNUAL_PROTECT 4
|
||||
#define USB_REGNUAL_FINISH 5
|
||||
|
||||
static uint8_t mem[256];
|
||||
static uint32_t result;
|
||||
|
||||
static const uint8_t *const mem_info[] = { &_flash_start, &_flash_end, };
|
||||
|
||||
|
||||
static uint32_t rbit (uint32_t v)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
|
||||
return r;
|
||||
}
|
||||
|
||||
static uint32_t fetch (int i)
|
||||
{
|
||||
uint32_t v;
|
||||
|
||||
v = *(uint32_t *)(&mem[i*4]);
|
||||
return rbit (v);
|
||||
}
|
||||
|
||||
struct CRC {
|
||||
__IO uint32_t DR;
|
||||
__IO uint8_t IDR;
|
||||
uint8_t RESERVED0;
|
||||
uint16_t RESERVED1;
|
||||
__IO uint32_t CR;
|
||||
};
|
||||
|
||||
#define CRC_CR_RESET 0x01
|
||||
static uint32_t calc_crc32 (void)
|
||||
{
|
||||
struct CRC *CRC = (struct CRC *)0x40023000;
|
||||
int i;
|
||||
|
||||
CRC->CR = CRC_CR_RESET;
|
||||
|
||||
for (i = 0; i < 256/4; i++)
|
||||
CRC->DR = fetch (i);
|
||||
|
||||
return rbit (CRC->DR);
|
||||
}
|
||||
|
||||
|
||||
static void regnual_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index,
|
||||
uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
|
||||
{
|
||||
if (req_no == USB_REGNUAL_SEND && value == 0)
|
||||
result = calc_crc32 ();
|
||||
else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
|
||||
{
|
||||
uint32_t dst_addr = (0x08000000 + value * 0x100);
|
||||
|
||||
result = flash_write (dst_addr, mem, 256);
|
||||
}
|
||||
else if (req_no == USB_REGNUAL_PROTECT && len == 0
|
||||
&& value == 0 && index == 0)
|
||||
result = flash_protect ();
|
||||
else if (req_no == USB_REGNUAL_FINISH && len == 0
|
||||
&& value == 0 && index == 0)
|
||||
nvic_system_reset ();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
regnual_setup (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == USB_REGNUAL_MEMINFO)
|
||||
{
|
||||
usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_REGNUAL_RESULT)
|
||||
{
|
||||
usb_lld_set_data_to_send (&result, sizeof (uint32_t));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else /* SETUP_SET */
|
||||
{
|
||||
if (req_no == USB_REGNUAL_SEND)
|
||||
{
|
||||
if (value != 0 || index + len > 256)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (index + len < 256)
|
||||
memset (mem + index + len, 0xff, 256 - (index + len));
|
||||
|
||||
usb_lld_set_data_to_recv (mem + index, len);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
|
||||
{
|
||||
uint32_t dst_addr = (0x08000000 + value * 0x100);
|
||||
|
||||
if (dst_addr + 256 <= (uint32_t)&_flash_end)
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_REGNUAL_PROTECT && len == 0
|
||||
&& value == 0 && index == 0)
|
||||
return USB_SUCCESS;
|
||||
else if (req_no == USB_REGNUAL_FINISH && len == 0
|
||||
&& value == 0 && index == 0)
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int
|
||||
regnual_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
{
|
||||
(void)index;
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (device_desc.Descriptor,
|
||||
device_desc.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (config_desc.Descriptor,
|
||||
config_desc.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
uint8_t desc_index = value & 0xff;
|
||||
|
||||
if (desc_index < NUM_STRING_DESC)
|
||||
{
|
||||
usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
|
||||
string_descs[desc_index].Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int regnual_usb_event (uint8_t event_type, uint16_t value)
|
||||
{
|
||||
(void)value;
|
||||
|
||||
switch (event_type)
|
||||
{
|
||||
case USB_EVENT_ADDRESS:
|
||||
case USB_EVENT_CONFIG:
|
||||
return USB_SUCCESS;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int regnual_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
{
|
||||
(void)cmd; (void)interface; (void)alt;
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
const struct usb_device_method Device_Method = {
|
||||
regnual_device_reset,
|
||||
regnual_ctrl_write_finish,
|
||||
regnual_setup,
|
||||
regnual_get_descriptor,
|
||||
regnual_usb_event,
|
||||
regnual_interface,
|
||||
};
|
||||
|
||||
static void wait (int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
}
|
||||
|
||||
#define WAIT 2400000
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
|
||||
set_led (0);
|
||||
|
||||
usb_lld_init (regnual_config_desc[7]);
|
||||
|
||||
while (1)
|
||||
{
|
||||
set_led (1);
|
||||
wait (WAIT);
|
||||
set_led (0);
|
||||
wait (WAIT);
|
||||
}
|
||||
}
|
||||
98
regnual/regnual.ld
Normal file
98
regnual/regnual.ld
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* ST32F103 memory setup.
|
||||
*/
|
||||
__main_stack_size__ = 0x0400;
|
||||
__process_stack_size__ = 0x0200;
|
||||
__stacks_total_size__ = __main_stack_size__ + __process_stack_size__;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram0 : org = 0x20000000, len = 0x1400
|
||||
ram1 : org = 0x20001400, len = 20k - 0x1400
|
||||
}
|
||||
|
||||
vector = 0x08000000;
|
||||
_flash_start = 0x08001000;
|
||||
_flash_end = 0x08020000;
|
||||
|
||||
__ram_start__ = ORIGIN(ram0);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
.bss :
|
||||
{
|
||||
_bss_start = .;
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_bss_end = .;
|
||||
} > ram0
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
_text = .;
|
||||
KEEP(*(.vectors))
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.gcc*)
|
||||
} > ram1
|
||||
|
||||
.ctors :
|
||||
{
|
||||
PROVIDE(_ctors_start_ = .);
|
||||
KEEP(*(SORT(.ctors.*)))
|
||||
KEEP(*(.ctors))
|
||||
PROVIDE(_ctors_end_ = .);
|
||||
} > ram1
|
||||
|
||||
.dtors :
|
||||
{
|
||||
PROVIDE(_dtors_start_ = .);
|
||||
KEEP(*(SORT(.dtors.*)))
|
||||
KEEP(*(.dtors))
|
||||
PROVIDE(_dtors_end_ = .);
|
||||
} > ram1
|
||||
|
||||
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)}
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > ram1
|
||||
__exidx_end = .;
|
||||
|
||||
.eh_frame_hdr : {*(.eh_frame_hdr)}
|
||||
|
||||
.eh_frame : ONLY_IF_RO {*(.eh_frame)}
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
_textdata = _etext;
|
||||
|
||||
.data :
|
||||
{
|
||||
_data = .;
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
*(.data.*)
|
||||
. = ALIGN(4);
|
||||
*(.ramtext)
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} > ram1
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
__heap_base__ = _end;
|
||||
__heap_end__ = __ram_end__ - __stacks_total_size__;
|
||||
60
regnual/sys.c
Normal file
60
regnual/sys.c
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "types.h"
|
||||
|
||||
static void fatal (void)
|
||||
{
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static void none (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Note: it is not reset */
|
||||
static __attribute__ ((naked))
|
||||
void entry (void)
|
||||
{
|
||||
asm volatile ("ldr r0, =__ram_end__\n\t"
|
||||
"ldr r1, =__main_stack_size__\n\t"
|
||||
"sub r0, r0, r1\n\t"
|
||||
"mov sp, r0\n\t"
|
||||
"mov r0, #0\n\t"
|
||||
"ldr r1, =_bss_start\n\t"
|
||||
"ldr r2, =_bss_end\n"
|
||||
"0:\n\t"
|
||||
"str r0, [r1], #4\n\t"
|
||||
"cmp r2, r1\n\t"
|
||||
"bhi 0b\n\t"
|
||||
"cpsie i\n\t" /* Enable interrupts */
|
||||
"mov r0, #0\n\t"
|
||||
"mov r1, r0\n\t"
|
||||
"bl main\n"
|
||||
"1:\n\t"
|
||||
"b 1b\n"
|
||||
: /* no output */ : /* no input */ : "memory");
|
||||
}
|
||||
|
||||
typedef void (*handler)(void);
|
||||
extern uint8_t __ram_end__;
|
||||
extern void usb_interrupt_handler (void);
|
||||
|
||||
handler vector_table[] __attribute__ ((section(".vectors"))) = {
|
||||
(handler)&__ram_end__,
|
||||
entry,
|
||||
fatal, /* nmi */
|
||||
fatal, /* hard fault */
|
||||
/* 10 */
|
||||
fatal, /* mem manage */
|
||||
fatal, /* bus fault */
|
||||
fatal, /* usage fault */
|
||||
none,
|
||||
/* 20 */
|
||||
none, none, none, none, none, none, none, none,
|
||||
/* 40 */
|
||||
none, none, none, none, none, none, none, none,
|
||||
/* 60 */
|
||||
none, none, none, none, none, none, none, none,
|
||||
/* 80 */
|
||||
none, none, none, none,
|
||||
/* 90 */
|
||||
usb_interrupt_handler,
|
||||
};
|
||||
12
regnual/types.h
Normal file
12
regnual/types.h
Normal file
@@ -0,0 +1,12 @@
|
||||
typedef unsigned long size_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define NULL 0
|
||||
|
||||
#define __IO volatile
|
||||
@@ -76,16 +76,14 @@ CSRC = $(PORTSRC) \
|
||||
$(HALSRC) \
|
||||
$(PLATFORMSRC) \
|
||||
$(BOARDSRC) \
|
||||
../boards/common/hw_config.c \
|
||||
$(BOARD_DIR)/board.c \
|
||||
$(CHIBIOS)/os/various/evtimer.c \
|
||||
$(CHIBIOS)/os/various/syscalls.c \
|
||||
$(VCOMSRC) \
|
||||
$(CRYPTSRC) \
|
||||
main.c usb_lld.c \
|
||||
usb_desc.c usb_prop.c \
|
||||
usb_desc.c usb_ctrl.c \
|
||||
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c \
|
||||
random.c neug.c
|
||||
random.c neug.c sys.c
|
||||
|
||||
ifneq ($(ENABLE_DEBUG),)
|
||||
CSRC += debug.c
|
||||
@@ -177,7 +175,7 @@ DLIBS =
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
UDEFS =
|
||||
UDEFS = @KEYGEN_SUPPORT@
|
||||
|
||||
# Define ASM defines here
|
||||
UADEFS =
|
||||
@@ -195,13 +193,6 @@ ULIBS =
|
||||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
ifeq ($(USE_FWLIB),yes)
|
||||
include $(CHIBIOS)/ext/stm32lib/stm32lib.mk
|
||||
CSRC += $(STM32SRC)
|
||||
INCDIR += $(STM32INC)
|
||||
USE_OPT += -DUSE_STDPERIPH_DRIVER
|
||||
endif
|
||||
|
||||
include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk
|
||||
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
|
||||
|
||||
|
||||
31
src/ac.c
31
src/ac.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ac.c -- Check access condition
|
||||
*
|
||||
* Copyright (C) 2010 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -24,9 +24,7 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/sha1.h"
|
||||
#include "sha256.h"
|
||||
|
||||
uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */
|
||||
|
||||
@@ -89,7 +87,7 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
}
|
||||
|
||||
success_one_step:
|
||||
sha1 (pw, pw_len, keystring);
|
||||
s2k (BY_USER, pw, pw_len, keystring);
|
||||
if (access == AC_PSO_CDS_AUTHORIZED)
|
||||
{
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
@@ -161,28 +159,27 @@ static void
|
||||
calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
|
||||
uint8_t md[KEYSTRING_MD_SIZE])
|
||||
{
|
||||
sha1_context sha1_ctx;
|
||||
sha256_context sha256_ctx;
|
||||
|
||||
sha1_starts (&sha1_ctx);
|
||||
sha256_start (&sha256_ctx);
|
||||
|
||||
while (count > pw_len + 8)
|
||||
{
|
||||
sha1_update (&sha1_ctx, salt, 8);
|
||||
sha1_update (&sha1_ctx, pw, pw_len);
|
||||
sha256_update (&sha256_ctx, salt, 8);
|
||||
sha256_update (&sha256_ctx, pw, pw_len);
|
||||
count -= pw_len + 8;
|
||||
}
|
||||
|
||||
if (count <= 8)
|
||||
sha1_update (&sha1_ctx, salt, count);
|
||||
sha256_update (&sha256_ctx, salt, count);
|
||||
else
|
||||
{
|
||||
sha1_update (&sha1_ctx, salt, 8);
|
||||
sha256_update (&sha256_ctx, salt, 8);
|
||||
count -= 8;
|
||||
sha1_update (&sha1_ctx, pw, count);
|
||||
sha256_update (&sha256_ctx, pw, count);
|
||||
}
|
||||
|
||||
sha1_finish (&sha1_ctx, md);
|
||||
memset (&sha1_ctx, 0, sizeof (sha1_ctx));
|
||||
sha256_finish (&sha256_ctx, md);
|
||||
}
|
||||
|
||||
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
|
||||
@@ -205,7 +202,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
|
||||
return 0;
|
||||
|
||||
pw_len = pw3_keystring[0];
|
||||
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len)
|
||||
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len > buf_len)
|
||||
goto failure;
|
||||
|
||||
salt = &pw3_keystring[1];
|
||||
@@ -283,7 +280,7 @@ verify_admin (const uint8_t *pw, int pw_len)
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
sha1 (pw, pw_len, keystring_md_pw3);
|
||||
s2k (admin_authorized, pw, pw_len, keystring_md_pw3);
|
||||
auth_status |= AC_ADMIN_AUTHORIZED;
|
||||
return 1;
|
||||
}
|
||||
@@ -293,6 +290,7 @@ ac_reset_admin (void)
|
||||
{
|
||||
memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE);
|
||||
auth_status &= ~AC_ADMIN_AUTHORIZED;
|
||||
admin_authorized = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -303,4 +301,5 @@ ac_fini (void)
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
|
||||
auth_status = AC_NONE_AUTHORIZED;
|
||||
admin_authorized = 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -47,10 +47,12 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
|
||||
rsa_ctx.len = KEY_CONTENT_LEN;
|
||||
mpi_read_string (&rsa_ctx.E, 16, "10001");
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2], rsa_ctx.len / 2);
|
||||
#if 0 /* Using CRT, we don't use N */
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
#endif
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
mpi_mul_mpi (&H, &P1, &Q1);
|
||||
@@ -61,17 +63,6 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
mpi_free (&P1, &Q1, &H, NULL);
|
||||
|
||||
DEBUG_INFO ("RSA sign...");
|
||||
#if 0
|
||||
if ((r = rsa_check_privkey (&rsa_ctx)) == 0)
|
||||
DEBUG_INFO ("ok...");
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("failed.\r\n");
|
||||
DEBUG_SHORT (r);
|
||||
rsa_free (&rsa_ctx);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = rsa_pkcs1_sign (&rsa_ctx, RSA_PRIVATE, SIG_RSA_RAW,
|
||||
msg_len, raw_message, temp);
|
||||
@@ -138,11 +129,13 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
rsa_ctx.len = msg_len;
|
||||
DEBUG_WORD (msg_len);
|
||||
|
||||
mpi_read_string (&rsa_ctx.E, 16, "10001");
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.P, &kd->data[0], KEY_CONTENT_LEN / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2],
|
||||
KEY_CONTENT_LEN / 2);
|
||||
#if 0 /* Using CRT, we don't use N */
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
#endif
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
mpi_mul_mpi (&H, &P1, &Q1);
|
||||
@@ -153,18 +146,6 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
mpi_free (&P1, &Q1, &H, NULL);
|
||||
|
||||
DEBUG_INFO ("RSA decrypt ...");
|
||||
#if 0
|
||||
/* This consume some memory */
|
||||
if ((r = rsa_check_privkey (&rsa_ctx)) == 0)
|
||||
DEBUG_INFO ("ok...");
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("failed.\r\n");
|
||||
DEBUG_SHORT (r);
|
||||
rsa_free (&rsa_ctx);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = rsa_pkcs1_decrypt (&rsa_ctx, RSA_PRIVATE, &output_len,
|
||||
input, output, MAX_RES_APDU_DATA_SIZE);
|
||||
@@ -183,3 +164,65 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
|
||||
{
|
||||
int r;
|
||||
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
rsa_ctx.len = KEY_CONTENT_LEN;
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.N, pubkey, KEY_CONTENT_LEN);
|
||||
|
||||
DEBUG_INFO ("RSA verify...");
|
||||
|
||||
r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA256, 32, hash, sig);
|
||||
|
||||
rsa_free (&rsa_ctx);
|
||||
if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("fail:");
|
||||
DEBUG_SHORT (r);
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("verified.\r\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define RSA_EXPONENT 0x10001
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
const uint8_t *
|
||||
rsa_genkey (void)
|
||||
{
|
||||
int r;
|
||||
uint8_t index = 0;
|
||||
uint8_t *p_q_modulus = (uint8_t *)malloc (KEY_CONTENT_LEN*2);
|
||||
uint8_t *p = p_q_modulus;
|
||||
uint8_t *q = p_q_modulus + KEY_CONTENT_LEN/2;
|
||||
uint8_t *modulus = p_q_modulus + KEY_CONTENT_LEN;
|
||||
|
||||
if (p_q_modulus == NULL)
|
||||
return NULL;
|
||||
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
r = rsa_gen_key (&rsa_ctx, random_byte, &index,
|
||||
KEY_CONTENT_LEN * 8, RSA_EXPONENT);
|
||||
if (r < 0)
|
||||
{
|
||||
free (p_q_modulus);
|
||||
rsa_free (&rsa_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mpi_write_binary (&rsa_ctx.P, p, KEY_CONTENT_LEN/2);
|
||||
mpi_write_binary (&rsa_ctx.Q, q, KEY_CONTENT_LEN/2);
|
||||
mpi_write_binary (&rsa_ctx.N, modulus, KEY_CONTENT_LEN);
|
||||
rsa_free (&rsa_ctx);
|
||||
return p_q_modulus;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,3 +6,4 @@
|
||||
@PINPAD_DEFINE@
|
||||
@PINPAD_MORE_DEFINE@
|
||||
@CERTDO_DEFINE@
|
||||
#define FLASH_PAGE_SIZE @FLASH_PAGE_SIZE@
|
||||
|
||||
106
src/configure
vendored
106
src/configure
vendored
@@ -28,6 +28,7 @@ with_dfu=default
|
||||
debug=no
|
||||
pinpad=no
|
||||
certdo=no
|
||||
keygen=no
|
||||
|
||||
# Process each option
|
||||
for option; do
|
||||
@@ -49,8 +50,6 @@ for option; do
|
||||
debug=yes ;;
|
||||
--disable-debug)
|
||||
debug=no ;;
|
||||
--enable-pinpad)
|
||||
pinpad=yes ;;
|
||||
--enable-pinpad=*)
|
||||
pinpad=$optarg ;;
|
||||
--disable-pinpad)
|
||||
@@ -59,6 +58,10 @@ for option; do
|
||||
certdo=yes ;;
|
||||
--disable-certdo)
|
||||
certdo=no ;;
|
||||
--enable-keygen)
|
||||
keygen=yes ;;
|
||||
--disable-keygen)
|
||||
keygen=no ;;
|
||||
--with-dfu)
|
||||
with_dfu=yes ;;
|
||||
--without-dfu)
|
||||
@@ -90,9 +93,10 @@ Configuration:
|
||||
STBEE
|
||||
FST_01
|
||||
--enable-debug debug with virtual COM port [no]
|
||||
--enable-pinpad={dnd,cir,dial}
|
||||
--enable-pinpad={cir,dial}
|
||||
PIN entry support [no]
|
||||
--enable-certdo support CERT.3 data object [no]
|
||||
--enable-keygen support key generation [no]
|
||||
--with-dfu build image for DFU [<target specific>]
|
||||
EOF
|
||||
exit 0
|
||||
@@ -103,35 +107,6 @@ if test "$vidpid" = "none"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if !(IFS=" "
|
||||
while read VIDPID VERSION PRODUCT VENDOR; do
|
||||
if test "$vidpid" = "$VIDPID"; then
|
||||
(echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\n 0x\4, 0x\3, /* idProduct */%p"
|
||||
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
|
||||
) > usb-vid-pid-ver.c.inc
|
||||
(echo 'static const uint8_t gnukStringVendor[] = {'
|
||||
echo " ${#VENDOR}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* Manufacturer: \"$VENDOR\" */"
|
||||
echo $VENDOR | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo 'static const uint8_t gnukStringProduct[] = {'
|
||||
echo " ${#PRODUCT}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* Product name: \"$PRODUCT\" */"
|
||||
echo $PRODUCT | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
) >usb-string-vendor-product.c.inc
|
||||
exit 0
|
||||
fi
|
||||
done; exit 1) < ../GNUK_USB_DEVICE_ID
|
||||
then
|
||||
echo "Please specify valid Vendor ID and Product ID."
|
||||
echo "Check ../GNUK_USB_DEVICE_ID."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BOARD_DIR=../boards/$target
|
||||
if test -d $BOARD_DIR; then
|
||||
echo "Configured for target: $target"
|
||||
@@ -186,6 +161,7 @@ if test "$with_dfu" = "yes"; then
|
||||
FLASH_SIZE=`expr $FLASH_SIZE - 12`
|
||||
DFU_DEFINE="#define DFU_SUPPORT 1"
|
||||
else
|
||||
with_dfu=no
|
||||
echo "Configured for bare system (no-DFU)"
|
||||
ORIGIN=0x08000000
|
||||
DFU_DEFINE="#undef DFU_SUPPORT"
|
||||
@@ -197,11 +173,6 @@ if test "$pinpad" = "no"; then
|
||||
PINPAD_DEFINE="#undef PINPAD_SUPPORT"
|
||||
PINPAD_MORE_DEFINE=""
|
||||
echo "PIN pad option disabled"
|
||||
elif test "$pinpad" = "yes"; then
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=dnd"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
PINPAD_MORE_DEFINE="#define PINPAD_DND_SUPPORT 1"
|
||||
echo "PIN pad option enabled (dnd)"
|
||||
else
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
@@ -215,12 +186,70 @@ if test "$certdo" = "yes"; then
|
||||
echo "CERT.3 Data Object is supported"
|
||||
else
|
||||
CERTDO_DEFINE="#undef CERTDO_SUPPORT"
|
||||
echo "CERT.3 Data Object is not supported"
|
||||
echo "CERT.3 Data Object is NOT supported"
|
||||
fi
|
||||
|
||||
# --enable-keygen option
|
||||
if test "$keygen" = "yes"; then
|
||||
KEYGEN_SUPPORT="-DKEYGEN_SUPPORT"
|
||||
echo "Key generation on device is supported"
|
||||
else
|
||||
KEYGEN_SUPPORT=""
|
||||
echo "Key generation on device is NOT supported"
|
||||
fi
|
||||
|
||||
REVISION=`git describe --dirty="-modified"`
|
||||
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:keygen=$keygen"
|
||||
|
||||
if !(IFS=" "
|
||||
while read VIDPID VERSION PRODUCT VENDOR; do
|
||||
if test "$vidpid" = "$VIDPID"; then
|
||||
(echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\n 0x\4, 0x\3, /* idProduct */%p"
|
||||
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
|
||||
) > usb-vid-pid-ver.c.inc
|
||||
(echo 'static const uint8_t gnukStringVendor[] = {'
|
||||
echo " ${#VENDOR}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* Manufacturer: \"$VENDOR\" */"
|
||||
echo $VENDOR | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo 'static const uint8_t gnukStringProduct[] = {'
|
||||
echo " ${#PRODUCT}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* Product name: \"$PRODUCT\" */"
|
||||
echo $PRODUCT | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo '#ifdef USB_STRINGS_FOR_GNUK'
|
||||
echo 'static const uint8_t gnuk_revision_detail[] = {'
|
||||
echo " ${#REVISION}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* revision detail: \"$REVISION\" */"
|
||||
echo $REVISION | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo 'static const uint8_t gnuk_config_options[] = {'
|
||||
echo " ${#CONFIG}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* configure options: \"$CONFIG\" */"
|
||||
echo $CONFIG | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo '#endif'
|
||||
) >usb-strings.c.inc
|
||||
exit 0
|
||||
fi
|
||||
done; exit 1) < ../GNUK_USB_DEVICE_ID
|
||||
then
|
||||
echo "Please specify valid Vendor ID and Product ID."
|
||||
echo "Check ../GNUK_USB_DEVICE_ID."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \
|
||||
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
|
||||
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
|
||||
-e "s%@KEYGEN_SUPPORT@%$KEYGEN_SUPPORT%" \
|
||||
< Makefile.in > Makefile
|
||||
if test "$certdo" = "yes"; then
|
||||
sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \
|
||||
@@ -238,5 +267,6 @@ sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
|
||||
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
|
||||
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
|
||||
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
< config.h.in > config.h
|
||||
exit 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CRYPTDIR = ../polarssl-0.14.0
|
||||
CRYPTSRCDIR = $(CRYPTDIR)/library
|
||||
CRYPTINCDIR = $(CRYPTDIR)/include
|
||||
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/sha1.c \
|
||||
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c \
|
||||
$(CRYPTSRCDIR)/aes.c \
|
||||
call-rsa.c
|
||||
sha256.c call-rsa.c
|
||||
|
||||
180
src/flash.c
180
src/flash.c
@@ -32,108 +32,9 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "sys.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
#define FLASH_KEY2 0xCDEF89ABUL
|
||||
|
||||
enum flash_status
|
||||
{
|
||||
FLASH_BUSY = 1,
|
||||
FLASH_ERROR_PG,
|
||||
FLASH_ERROR_WRP,
|
||||
FLASH_COMPLETE,
|
||||
FLASH_TIMEOUT
|
||||
};
|
||||
|
||||
void
|
||||
flash_unlock (void)
|
||||
{
|
||||
FLASH->KEYR = FLASH_KEY1;
|
||||
FLASH->KEYR = FLASH_KEY2;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_get_status (void)
|
||||
{
|
||||
int status;
|
||||
|
||||
if ((FLASH->SR & FLASH_SR_BSY) != 0)
|
||||
status = FLASH_BUSY;
|
||||
else if ((FLASH->SR & FLASH_SR_PGERR) != 0)
|
||||
status = FLASH_ERROR_PG;
|
||||
else if((FLASH->SR & FLASH_SR_WRPRTERR) != 0 )
|
||||
status = FLASH_ERROR_WRP;
|
||||
else
|
||||
status = FLASH_COMPLETE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_wait_for_last_operation (uint32_t timeout)
|
||||
{
|
||||
int status;
|
||||
|
||||
do
|
||||
if (--timeout == 0)
|
||||
return FLASH_TIMEOUT;
|
||||
else
|
||||
status = flash_get_status ();
|
||||
while (status == FLASH_BUSY);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#define FLASH_PROGRAM_TIMEOUT 0x00010000
|
||||
#define FLASH_ERASE_TIMEOUT 0x01000000
|
||||
|
||||
static int
|
||||
flash_program_halfword (uint32_t addr, uint16_t data)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
|
||||
|
||||
chSysLock ();
|
||||
if (status == FLASH_COMPLETE)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PG;
|
||||
|
||||
*(volatile uint16_t *)addr = data;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
|
||||
if (status != FLASH_TIMEOUT)
|
||||
FLASH->CR &= ~FLASH_CR_PG;
|
||||
}
|
||||
chSysUnlock ();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_erase_page (uint32_t addr)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
|
||||
chSysLock ();
|
||||
if (status == FLASH_COMPLETE)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PER;
|
||||
FLASH->AR = addr;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
if (status != FLASH_TIMEOUT)
|
||||
FLASH->CR &= ~FLASH_CR_PER;
|
||||
}
|
||||
chSysUnlock ()
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flash memory map
|
||||
*
|
||||
@@ -145,7 +46,7 @@ flash_erase_page (uint32_t addr)
|
||||
* .data
|
||||
* _bss_start
|
||||
* .bss
|
||||
* _end
|
||||
* _end
|
||||
* <alignment to page>
|
||||
* ch_certificate_startp
|
||||
* <2048 bytes>
|
||||
@@ -154,14 +55,11 @@ flash_erase_page (uint32_t addr)
|
||||
* _keystore_pool
|
||||
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3)
|
||||
*/
|
||||
#define KEY_SIZE 512 /* P, Q and N */
|
||||
|
||||
#define FLASH_DATA_POOL_HEADER_SIZE 2
|
||||
#if defined(STM32F10X_HD)
|
||||
#define FLASH_PAGE_SIZE 2048
|
||||
#else
|
||||
#define FLASH_PAGE_SIZE 1024
|
||||
#endif
|
||||
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
|
||||
#define FLASH_KEYSTORE_SIZE (512*3)
|
||||
#define FLASH_KEYSTORE_SIZE (KEY_SIZE*3)
|
||||
|
||||
static const uint8_t *data_pool;
|
||||
extern uint8_t _keystore_pool;
|
||||
@@ -200,7 +98,7 @@ flash_init (void)
|
||||
/* Seek empty keystore */
|
||||
p = &_keystore_pool;
|
||||
while (*p != 0xff || *(p+1) != 0xff)
|
||||
p += 512;
|
||||
p += KEY_SIZE;
|
||||
|
||||
keystore = p;
|
||||
|
||||
@@ -294,14 +192,14 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
|
||||
|
||||
addr = (uint32_t)p;
|
||||
hw = nr | (len << 8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
addr += 2;
|
||||
|
||||
for (i = 0; i < len/2; i++)
|
||||
{
|
||||
hw = data[i*2] | (data[i*2+1]<<8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
addr += 2;
|
||||
}
|
||||
@@ -309,7 +207,7 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
|
||||
if ((len & 1))
|
||||
{
|
||||
hw = data[i*2] | 0xff00;
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
}
|
||||
}
|
||||
@@ -359,19 +257,19 @@ flash_do_release (const uint8_t *do_data)
|
||||
/* Fill zero for content and pad */
|
||||
for (i = 0; i < len/2; i ++)
|
||||
{
|
||||
if (flash_program_halfword (addr, 0) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, 0) != 0)
|
||||
flash_warning ("fill-zero failure");
|
||||
addr += 2;
|
||||
}
|
||||
|
||||
if ((len & 1))
|
||||
{
|
||||
if (flash_program_halfword (addr, 0) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, 0) != 0)
|
||||
flash_warning ("fill-zero pad failure");
|
||||
}
|
||||
|
||||
/* Fill 0x0000 for "tag_number and length" word */
|
||||
if (flash_program_halfword (addr_tag, 0) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr_tag, 0) != 0)
|
||||
flash_warning ("fill-zero tag_nr failure");
|
||||
}
|
||||
|
||||
@@ -383,7 +281,7 @@ flash_key_alloc (void)
|
||||
if ((k - &_keystore_pool) >= FLASH_KEYSTORE_SIZE)
|
||||
return NULL;
|
||||
|
||||
keystore += 512;
|
||||
keystore += KEY_SIZE;
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -399,7 +297,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
|
||||
for (i = 0; i < KEY_CONTENT_LEN/2; i ++)
|
||||
{
|
||||
hw = key_data[i*2] | (key_data[i*2+1]<<8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
return -1;
|
||||
addr += 2;
|
||||
}
|
||||
@@ -407,7 +305,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
|
||||
for (i = 0; i < KEY_CONTENT_LEN/2; i ++)
|
||||
{
|
||||
hw = modulus[i*2] | (modulus[i*2+1]<<8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
return -1;
|
||||
addr += 2;
|
||||
}
|
||||
@@ -580,24 +478,9 @@ flash_cnt123_clear (const uint8_t **addr_p)
|
||||
|
||||
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
static int
|
||||
flash_check_blank (const uint8_t *page, int size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
for (p = page; p < page + size; p++)
|
||||
if (*p != 0xff)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define FLASH_CH_CERTIFICATE_SIZE 2048
|
||||
int
|
||||
flash_erase_binary (uint8_t file_id)
|
||||
{
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
const uint8_t *p = &ch_certificate_start;
|
||||
@@ -611,12 +494,10 @@ flash_erase_binary (uint8_t file_id)
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
#else
|
||||
(void)file_id;
|
||||
#endif
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
@@ -626,19 +507,23 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
|
||||
uint16_t maxsize;
|
||||
const uint8_t *p;
|
||||
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
maxsize = FLASH_CH_CERTIFICATE_SIZE;
|
||||
p = &ch_certificate_start;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (file_id == FILEID_SERIAL_NO)
|
||||
{
|
||||
maxsize = 6;
|
||||
p = &openpgpcard_aid[8];
|
||||
}
|
||||
else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
|
||||
{
|
||||
maxsize = KEY_CONTENT_LEN;
|
||||
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
|
||||
}
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
else if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
maxsize = FLASH_CH_CERTIFICATE_SIZE;
|
||||
p = &ch_certificate_start;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -650,11 +535,14 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
|
||||
uint32_t addr;
|
||||
int i;
|
||||
|
||||
if (flash_check_blank (p + offset, len) == 0)
|
||||
return -1;
|
||||
|
||||
addr = (uint32_t)p + offset;
|
||||
for (i = 0; i < len/2; i++)
|
||||
{
|
||||
hw = data[i*2] | (data[i*2+1]<<8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
addr += 2;
|
||||
}
|
||||
|
||||
73
src/gnuk.h
73
src/gnuk.h
@@ -76,6 +76,9 @@ enum icc_state
|
||||
ICC_STATE_EXECUTE, /* Busy4 */
|
||||
ICC_STATE_RECEIVE, /* APDU Received Partially */
|
||||
ICC_STATE_SEND, /* APDU Sent Partially */
|
||||
|
||||
ICC_STATE_EXITED, /* ICC Thread Terminated */
|
||||
ICC_STATE_EXEC_REQUESTED, /* Exec requested */
|
||||
};
|
||||
|
||||
extern enum icc_state *icc_state_p;
|
||||
@@ -117,7 +120,9 @@ extern void gpg_data_copy (const uint8_t *p);
|
||||
extern void gpg_do_get_data (uint16_t tag, int with_tag);
|
||||
extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
|
||||
extern void gpg_do_public_key (uint8_t kk_byte);
|
||||
extern void gpg_do_keygen (uint8_t kk_byte);
|
||||
|
||||
extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
|
||||
|
||||
|
||||
enum kind_of_key {
|
||||
@@ -126,30 +131,36 @@ enum kind_of_key {
|
||||
GPG_KEY_FOR_AUTHENTICATION,
|
||||
};
|
||||
|
||||
extern void flash_unlock (void);
|
||||
extern const uint8_t *flash_init (void);
|
||||
extern void flash_do_release (const uint8_t *);
|
||||
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
|
||||
extern uint8_t *flash_key_alloc (void);
|
||||
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
|
||||
const uint8_t *modulus);
|
||||
extern void flash_keystore_release (void);
|
||||
extern void flash_set_data_pool_last (const uint8_t *p);
|
||||
extern void flash_clear_halfword (uint32_t addr);
|
||||
extern void flash_increment_counter (uint8_t counter_tag_nr);
|
||||
extern void flash_reset_counter (uint8_t counter_tag_nr);
|
||||
|
||||
#define FILEID_CH_CERTIFICATE 0
|
||||
#define FILEID_RANDOM 1
|
||||
#define FILEID_SERIAL_NO 2
|
||||
#define FILEID_SERIAL_NO 0
|
||||
#define FILEID_UPDATE_KEY_0 1
|
||||
#define FILEID_UPDATE_KEY_1 2
|
||||
#define FILEID_UPDATE_KEY_2 3
|
||||
#define FILEID_UPDATE_KEY_3 4
|
||||
#define FILEID_CH_CERTIFICATE 5
|
||||
extern int flash_erase_binary (uint8_t file_id);
|
||||
extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t len, uint16_t offset);
|
||||
|
||||
#define FLASH_CH_CERTIFICATE_SIZE 2048
|
||||
|
||||
/* Linker set these two symbols */
|
||||
extern uint8_t ch_certificate_start;
|
||||
extern uint8_t random_bits_start;
|
||||
|
||||
#define KEY_MAGIC_LEN 8
|
||||
#define KEY_CONTENT_LEN 256 /* p and q */
|
||||
#define GNUK_MAGIC "Gnuk KEY"
|
||||
#define INITIAL_VECTOR_SIZE 16
|
||||
#define DATA_ENCRYPTION_KEY_SIZE 16
|
||||
|
||||
/* encrypted data content */
|
||||
struct key_data {
|
||||
@@ -158,22 +169,21 @@ struct key_data {
|
||||
|
||||
struct key_data_internal {
|
||||
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
|
||||
uint32_t check;
|
||||
uint32_t random;
|
||||
char magic[KEY_MAGIC_LEN];
|
||||
uint8_t checksum[DATA_ENCRYPTION_KEY_SIZE];
|
||||
};
|
||||
|
||||
#define ADDITIONAL_DATA_SIZE 16
|
||||
#define DATA_ENCRYPTION_KEY_SIZE 16
|
||||
struct prvkey_data {
|
||||
const uint8_t *key_addr;
|
||||
/*
|
||||
* CRM: [C]heck, [R]andom, and [M]agic in struct key_data_internal
|
||||
*
|
||||
* IV: Initial Vector
|
||||
*/
|
||||
uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE];
|
||||
uint8_t iv[INITIAL_VECTOR_SIZE];
|
||||
/*
|
||||
* DEK: Data Encryption Key
|
||||
* Checksum
|
||||
*/
|
||||
uint8_t checksum_encrypted[DATA_ENCRYPTION_KEY_SIZE];
|
||||
/*
|
||||
* DEK (Data Encryption Key) encrypted
|
||||
*/
|
||||
uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */
|
||||
uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */
|
||||
@@ -184,12 +194,14 @@ struct prvkey_data {
|
||||
#define BY_RESETCODE 2
|
||||
#define BY_ADMIN 3
|
||||
|
||||
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus);
|
||||
extern void s2k (int who, const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32]);
|
||||
|
||||
|
||||
#define KEYSTRING_PASSLEN_SIZE 1
|
||||
#define KEYSTRING_SALT_SIZE 8 /* optional */
|
||||
#define KEYSTRING_ITER_SIZE 1 /* optional */
|
||||
#define KEYSTRING_MD_SIZE 20
|
||||
#define KEYSTRING_MD_SIZE 32
|
||||
#define KEYSTRING_SIZE_PW1 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
|
||||
#define KEYSTRING_SIZE_RC (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
|
||||
#define KEYSTRING_SIZE_PW3 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_SALT_SIZE \
|
||||
@@ -224,6 +236,9 @@ extern int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *);
|
||||
extern const uint8_t *modulus_calc (const uint8_t *, int);
|
||||
extern void modulus_free (const uint8_t *);
|
||||
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
|
||||
extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
|
||||
const uint8_t *signature);
|
||||
extern const uint8_t *rsa_genkey (void);
|
||||
|
||||
extern const uint8_t *gpg_do_read_simple (uint8_t);
|
||||
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);
|
||||
@@ -291,7 +306,7 @@ extern uint8_t admin_authorized;
|
||||
/*
|
||||
* Representation of Boolean object:
|
||||
* 0: No record in flash memory
|
||||
* 1: 0xc?00
|
||||
* 1: 0xf000
|
||||
*/
|
||||
#define NR_BOOL_PW1_LIFETIME 0xf0
|
||||
/*
|
||||
@@ -300,7 +315,7 @@ extern uint8_t admin_authorized;
|
||||
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
||||
/*
|
||||
* Representation of 123-counters:
|
||||
* 0: No record in flash memory
|
||||
* 0: No record in flash memory
|
||||
* 1: 0xfe?? 0xffff
|
||||
* 2: 0xfe?? 0xc3c3
|
||||
* 3: 0xfe?? 0x0000
|
||||
@@ -317,11 +332,11 @@ extern const uint8_t *random_bytes_get (void);
|
||||
extern void random_bytes_free (const uint8_t *);
|
||||
/* 4-byte salt */
|
||||
extern uint32_t get_salt (void);
|
||||
/* iterator returning a byta at a time */
|
||||
extern uint8_t random_byte (void *arg);
|
||||
|
||||
extern uint32_t hardclock (void);
|
||||
|
||||
extern void set_led (int);
|
||||
|
||||
#define NUM_ALL_PRV_KEYS 3 /* SIG, DEC and AUT */
|
||||
|
||||
extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
|
||||
@@ -349,16 +364,14 @@ extern void flash_bool_write_internal (const uint8_t *p, int nr);
|
||||
extern void flash_cnt123_write_internal (const uint8_t *p, int which, int v);
|
||||
extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len);
|
||||
|
||||
extern const unsigned char *unique_device_id (void);
|
||||
extern const uint8_t gnukStringSerial[];
|
||||
|
||||
#define LED_ONESHOT_SHORT ((eventmask_t)1)
|
||||
#define LED_ONESHOT_LONG ((eventmask_t)2)
|
||||
#define LED_TWOSHOT ((eventmask_t)4)
|
||||
#define LED_STATUS_MODE ((eventmask_t)8)
|
||||
#define LED_INPUT_MODE ((eventmask_t)16)
|
||||
#define LED_FATAL_MODE ((eventmask_t)32)
|
||||
extern Thread *main_thread;
|
||||
#define LED_ONESHOT ((eventmask_t)1)
|
||||
#define LED_TWOSHOTS ((eventmask_t)2)
|
||||
#define LED_SHOW_STATUS ((eventmask_t)4)
|
||||
#define LED_START_COMMAND ((eventmask_t)8)
|
||||
#define LED_FINISH_COMMAND ((eventmask_t)16)
|
||||
#define LED_FATAL ((eventmask_t)32)
|
||||
extern void led_blink (int spec);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
@@ -386,3 +399,5 @@ extern uint8_t pin_input_len;
|
||||
extern int pinpad_getline (int msg_code, systime_t timeout);
|
||||
|
||||
#endif
|
||||
|
||||
extern uint8_t _regnual_start, __heap_end__;
|
||||
|
||||
@@ -33,10 +33,15 @@ __stacks_total_size__ = __main_stack_size__ + __process_stack_size__;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash : org = @ORIGIN@, len = @FLASH_SIZE@k
|
||||
flash0 : org = @ORIGIN@, len = 4k
|
||||
flash : org = @ORIGIN@+0x1000, len = @FLASH_SIZE@k - 4k
|
||||
ram : org = 0x20000000, len = 20k
|
||||
}
|
||||
|
||||
/* __flash_start__: flash ROM start address regardless of DFU_SUPPORT */
|
||||
__flash_start__ = 0x08001000;
|
||||
__flash_end__ = ORIGIN(flash) + LENGTH(flash);
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = LENGTH(ram);
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
@@ -45,6 +50,22 @@ SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
.sys : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
_sys = .;
|
||||
KEEP(*(.vectors))
|
||||
. = ALIGN(16);
|
||||
*(.sys.version)
|
||||
sys.o(.text)
|
||||
sys.o(.text.*)
|
||||
sys.o(.rodata)
|
||||
sys.o(.rodata.*)
|
||||
. = ALIGN(1024);
|
||||
*(.sys.0)
|
||||
*(.sys.1)
|
||||
*(.sys.2)
|
||||
} > flash0
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
_text = .;
|
||||
@@ -114,6 +135,8 @@ SECTIONS
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
. = ALIGN(512);
|
||||
_regnual_start = .;
|
||||
|
||||
@CERTDO_SUPPORT_START@
|
||||
.gnuk_ch_certificate :
|
||||
@@ -136,6 +159,9 @@ SECTIONS
|
||||
_keystore_pool = .;
|
||||
. += 512*3;
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
_updatekey_store = .;
|
||||
. += 1024;
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
} > flash =0xffffffff
|
||||
}
|
||||
|
||||
|
||||
320
src/main.c
320
src/main.c
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "sys.h"
|
||||
#include "gnuk.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb-cdc.h"
|
||||
@@ -168,13 +170,15 @@ extern msg_t USBthread (void *arg);
|
||||
/*
|
||||
* main thread does 1-bit LED display output
|
||||
*/
|
||||
#define LED_TIMEOUT_INTERVAL MS2ST(100)
|
||||
#define LED_TIMEOUT_ZERO MS2ST(50)
|
||||
#define LED_TIMEOUT_ONE MS2ST(200)
|
||||
#define LED_TIMEOUT_STOP MS2ST(500)
|
||||
#define MAIN_TIMEOUT_INTERVAL MS2ST(5000)
|
||||
|
||||
#define LED_TIMEOUT_INTERVAL MS2ST(75)
|
||||
#define LED_TIMEOUT_ZERO MS2ST(25)
|
||||
#define LED_TIMEOUT_ONE MS2ST(100)
|
||||
#define LED_TIMEOUT_STOP MS2ST(200)
|
||||
|
||||
|
||||
#define ID_OFFSET 22
|
||||
#define ID_OFFSET 24
|
||||
static void
|
||||
device_initialize_once (void)
|
||||
{
|
||||
@@ -192,7 +196,7 @@ device_initialize_once (void)
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
uint8_t b = u[i];
|
||||
uint8_t nibble;
|
||||
uint8_t nibble;
|
||||
|
||||
nibble = (b >> 4);
|
||||
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
||||
@@ -206,95 +210,64 @@ device_initialize_once (void)
|
||||
|
||||
static volatile uint8_t fatal_code;
|
||||
|
||||
Thread *main_thread;
|
||||
|
||||
#define GNUK_INIT 0
|
||||
#define GNUK_RUNNING 1
|
||||
#define GNUK_INPUT_WAIT 2
|
||||
#define GNUK_FATAL 255
|
||||
/*
|
||||
* 0 for initializing
|
||||
* 1 for normal mode
|
||||
* 2 for input waiting
|
||||
* 255 for fatal
|
||||
*/
|
||||
static uint8_t main_mode;
|
||||
|
||||
static void display_interaction (void)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
while (1)
|
||||
{
|
||||
m = chEvtWaitOne (ALL_EVENTS);
|
||||
set_led (1);
|
||||
switch (m)
|
||||
{
|
||||
case LED_ONESHOT_SHORT:
|
||||
chThdSleep (MS2ST (100));
|
||||
break;
|
||||
case LED_ONESHOT_LONG:
|
||||
chThdSleep (MS2ST (400));
|
||||
break;
|
||||
case LED_TWOSHOT:
|
||||
chThdSleep (MS2ST (50));
|
||||
set_led (0);
|
||||
chThdSleep (MS2ST (50));
|
||||
set_led (1);
|
||||
chThdSleep (MS2ST (50));
|
||||
break;
|
||||
case LED_STATUS_MODE:
|
||||
chThdSleep (MS2ST (400));
|
||||
set_led (0);
|
||||
return;
|
||||
case LED_FATAL_MODE:
|
||||
main_mode = GNUK_FATAL;
|
||||
set_led (0);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
set_led (0);
|
||||
}
|
||||
}
|
||||
static Thread *main_thread;
|
||||
|
||||
static void display_fatal_code (void)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (1);
|
||||
if (fatal_code & 1)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if (fatal_code & 2)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
while (1)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (1);
|
||||
if (fatal_code & 1)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if (fatal_code & 2)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL*10);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_status_code (void)
|
||||
static uint8_t led_inverted;
|
||||
|
||||
static eventmask_t emit_led (int on_time, int off_time)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
set_led (!led_inverted);
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, on_time);
|
||||
set_led (led_inverted);
|
||||
if (m) return m;
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, off_time)))
|
||||
return m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static eventmask_t display_status_code (void)
|
||||
{
|
||||
enum icc_state icc_state;
|
||||
eventmask_t m;
|
||||
|
||||
if (icc_state_p == NULL)
|
||||
icc_state = ICC_STATE_START;
|
||||
@@ -302,72 +275,50 @@ static void display_status_code (void)
|
||||
icc_state = *icc_state_p;
|
||||
|
||||
if (icc_state == ICC_STATE_START)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 3);
|
||||
}
|
||||
return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
|
||||
else
|
||||
/* GPGthread running */
|
||||
{
|
||||
set_led (1);
|
||||
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
|
||||
if (icc_state == ICC_STATE_WAIT)
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 2);
|
||||
}
|
||||
else if (icc_state == ICC_STATE_RECEIVE)
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP * 2)))
|
||||
return m;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
|
||||
if ((m = emit_led (icc_state == ICC_STATE_RECEIVE?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_STOP)))
|
||||
return m;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
led_blink (int spec)
|
||||
{
|
||||
if (spec == 0)
|
||||
chEvtSignal (main_thread, LED_ONESHOT_SHORT);
|
||||
else if (spec == 1)
|
||||
chEvtSignal (main_thread, LED_ONESHOT_LONG);
|
||||
else
|
||||
chEvtSignal (main_thread, LED_TWOSHOT);
|
||||
chEvtSignal (main_thread, spec);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Entry point.
|
||||
*
|
||||
@@ -375,9 +326,9 @@ led_blink (int spec)
|
||||
* See the hwinit1_common function.
|
||||
*/
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int count = 0;
|
||||
unsigned int count = 0;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
@@ -386,7 +337,7 @@ main (int argc, char **argv)
|
||||
|
||||
flash_unlock ();
|
||||
device_initialize_once ();
|
||||
usb_lld_init ();
|
||||
usb_lld_init (Config_Descriptor.Descriptor[7]);
|
||||
random_init ();
|
||||
|
||||
while (1)
|
||||
@@ -414,49 +365,49 @@ main (int argc, char **argv)
|
||||
msc_init ();
|
||||
#endif
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED)
|
||||
break;
|
||||
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, MAIN_TIMEOUT_INTERVAL);
|
||||
got_it:
|
||||
count++;
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL);
|
||||
switch (m)
|
||||
{
|
||||
case LED_STATUS_MODE:
|
||||
main_mode = GNUK_RUNNING;
|
||||
case LED_ONESHOT:
|
||||
if ((m = emit_led (MS2ST (100), MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
break;
|
||||
case LED_FATAL_MODE:
|
||||
main_mode = GNUK_FATAL;
|
||||
case LED_TWOSHOTS:
|
||||
if ((m = emit_led (MS2ST (50), MS2ST (50)))) goto got_it;
|
||||
if ((m = emit_led (MS2ST (50), MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
break;
|
||||
case LED_INPUT_MODE:
|
||||
main_mode = GNUK_INPUT_WAIT;
|
||||
case LED_SHOW_STATUS:
|
||||
if ((count & 0x07) != 0) continue; /* Display once for eight times */
|
||||
if ((m = display_status_code ())) goto got_it;
|
||||
break;
|
||||
case LED_START_COMMAND:
|
||||
set_led (1);
|
||||
chThdSleep (MS2ST (400));
|
||||
led_inverted = 1;
|
||||
break;
|
||||
case LED_FINISH_COMMAND:
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP);
|
||||
led_inverted = 0;
|
||||
set_led (0);
|
||||
if (m)
|
||||
goto got_it;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (main_mode)
|
||||
{
|
||||
case GNUK_FATAL:
|
||||
case LED_FATAL:
|
||||
display_fatal_code ();
|
||||
break;
|
||||
case GNUK_INIT:
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 3);
|
||||
break;
|
||||
case GNUK_INPUT_WAIT:
|
||||
display_interaction ();
|
||||
break;
|
||||
case GNUK_RUNNING:
|
||||
default:
|
||||
display_status_code ();
|
||||
if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
|
||||
goto got_it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MORE
|
||||
if (bDeviceState == CONFIGURED && (count % 10) == 0)
|
||||
@@ -469,6 +420,41 @@ main (int argc, char **argv)
|
||||
#endif
|
||||
}
|
||||
|
||||
set_led (1);
|
||||
usb_lld_shutdown ();
|
||||
/* Disable SysTick */
|
||||
SysTick->CTRL = 0;
|
||||
/* Disable all interrupts */
|
||||
port_disable ();
|
||||
/* Set vector */
|
||||
SCB->VTOR = (uint32_t)&_regnual_start;
|
||||
#ifdef DFU_SUPPORT
|
||||
#define FLASH_SYS_START_ADDR 0x08000000
|
||||
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
|
||||
{
|
||||
extern uint8_t _sys;
|
||||
uint32_t addr;
|
||||
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
|
||||
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10];
|
||||
|
||||
/* Kill DFU */
|
||||
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
|
||||
addr += FLASH_PAGE_SIZE)
|
||||
flash_erase_page (addr);
|
||||
|
||||
/* copy system service routines */
|
||||
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
|
||||
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
(*func) (*((void (**)(void))(&_regnual_start+4)));
|
||||
for (;;);
|
||||
}
|
||||
#else
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
|
||||
#endif
|
||||
|
||||
/* Never reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -476,7 +462,7 @@ void
|
||||
fatal (uint8_t code)
|
||||
{
|
||||
fatal_code = code;
|
||||
chEvtSignal (main_thread, LED_FATAL_MODE);
|
||||
chEvtSignal (main_thread, LED_FATAL);
|
||||
_write ("fatal\r\n", 7);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
@@ -32,15 +32,15 @@ static Thread *rng_thread;
|
||||
|
||||
/* Total number of channels to be sampled by a single ADC operation.*/
|
||||
#define ADC_GRP1_NUM_CHANNELS 2
|
||||
|
||||
|
||||
/* Depth of the conversion buffer, channels are sampled one time each.*/
|
||||
#define ADC_GRP1_BUF_DEPTH 4
|
||||
|
||||
|
||||
/*
|
||||
* ADC samples buffer.
|
||||
*/
|
||||
static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
|
||||
|
||||
|
||||
static void adccb (adcsample_t *buffer, size_t n);
|
||||
|
||||
/*
|
||||
|
||||
334
src/openpgp-do.c
334
src/openpgp-do.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -25,12 +25,12 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "sys.h"
|
||||
#include "gnuk.h"
|
||||
#include "openpgp.h"
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/aes.h"
|
||||
#include "polarssl/sha1.h"
|
||||
|
||||
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
|
||||
static const uint8_t *pw_err_counter_p[3];
|
||||
@@ -162,6 +162,17 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gpg_reset_digital_signature_counter (void)
|
||||
{
|
||||
if (digital_signature_counter != 0)
|
||||
{
|
||||
flash_put_data (NR_COUNTER_DS);
|
||||
flash_put_data (NR_COUNTER_DS_LSB);
|
||||
digital_signature_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gpg_increment_digital_signature_counter (void)
|
||||
{
|
||||
@@ -531,7 +542,7 @@ proc_resetting_code (const uint8_t *data, int len)
|
||||
|
||||
newpw_len = len;
|
||||
newpw = data;
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (BY_RESETCODE, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
|
||||
if (r <= -2)
|
||||
@@ -560,40 +571,58 @@ proc_resetting_code (const uint8_t *data, int len)
|
||||
}
|
||||
|
||||
static void
|
||||
encrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
aes_context aes;
|
||||
uint8_t iv[16];
|
||||
uint8_t iv0[INITIAL_VECTOR_SIZE];
|
||||
int iv_offset;
|
||||
|
||||
DEBUG_INFO ("ENC\r\n");
|
||||
DEBUG_BINARY (data, len);
|
||||
|
||||
aes_setkey_enc (&aes, key_str, 128);
|
||||
memset (iv, 0, 16);
|
||||
aes_setkey_enc (&aes, key, 128);
|
||||
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
|
||||
iv_offset = 0;
|
||||
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data);
|
||||
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv0, data, data);
|
||||
}
|
||||
|
||||
/* Signing, Decryption, and Authentication */
|
||||
struct key_data kd[3];
|
||||
|
||||
static void
|
||||
decrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
decrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
aes_context aes;
|
||||
uint8_t iv[16];
|
||||
uint8_t iv0[INITIAL_VECTOR_SIZE];
|
||||
int iv_offset;
|
||||
|
||||
aes_setkey_enc (&aes, key_str, 128);
|
||||
memset (iv, 0, 16);
|
||||
aes_setkey_enc (&aes, key, 128); /* This is setkey_enc, because of CFB. */
|
||||
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
|
||||
iv_offset = 0;
|
||||
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv, data, data);
|
||||
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv0, data, data);
|
||||
|
||||
DEBUG_INFO ("DEC\r\n");
|
||||
DEBUG_BINARY (data, len);
|
||||
}
|
||||
|
||||
static void
|
||||
encrypt_dek (const uint8_t *key_string, uint8_t *dek)
|
||||
{
|
||||
aes_context aes;
|
||||
|
||||
aes_setkey_enc (&aes, key_string, 128);
|
||||
aes_crypt_ecb (&aes, AES_ENCRYPT, dek, dek);
|
||||
}
|
||||
|
||||
static void
|
||||
decrypt_dek (const uint8_t *key_string, uint8_t *dek)
|
||||
{
|
||||
aes_context aes;
|
||||
|
||||
aes_setkey_dec (&aes, key_string, 128);
|
||||
aes_crypt_ecb (&aes, AES_DECRYPT, dek, dek);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
get_do_ptr_nr_for_kk (enum kind_of_key kk)
|
||||
{
|
||||
@@ -615,6 +644,25 @@ gpg_do_clear_prvkey (enum kind_of_key kk)
|
||||
memset ((void *)&kd[kk], 0, sizeof (struct key_data));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
compute_key_data_checksum (struct key_data_internal *kdi, int check_or_calc)
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t d[4] = { 0, 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < KEY_CONTENT_LEN / sizeof (uint32_t); i++)
|
||||
d[i&3] ^= *(uint32_t *)(&kdi->data[i*4]);
|
||||
|
||||
if (check_or_calc == 0) /* store */
|
||||
{
|
||||
memcpy (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
else /* check */
|
||||
return memcmp (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 on success,
|
||||
* 0 if none,
|
||||
@@ -625,8 +673,9 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
|
||||
{
|
||||
uint8_t nr = get_do_ptr_nr_for_kk (kk);
|
||||
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
|
||||
uint8_t *key_addr;
|
||||
const uint8_t *key_addr;
|
||||
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
|
||||
const uint8_t *iv;
|
||||
struct key_data_internal kdi;
|
||||
|
||||
DEBUG_INFO ("Loading private key: ");
|
||||
@@ -635,60 +684,47 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
|
||||
if (do_data == NULL)
|
||||
return 0;
|
||||
|
||||
key_addr = *(uint8_t **)&(do_data)[1];
|
||||
key_addr = *(const uint8_t **)&(do_data)[1]; /* Possible unaligned access */
|
||||
memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
|
||||
memcpy (((uint8_t *)&kdi.check), do_data+5, ADDITIONAL_DATA_SIZE);
|
||||
iv = do_data+5;
|
||||
memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (dek, do_data+5+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt_dek (keystring, dek);
|
||||
|
||||
decrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
if (memcmp (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
|
||||
decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
memset (dek, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
if (!compute_key_data_checksum (&kdi, 1))
|
||||
{
|
||||
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
|
||||
return -1;
|
||||
}
|
||||
/* more sanity check??? */
|
||||
|
||||
memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
|
||||
DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
calc_check32 (const uint8_t *p, int len)
|
||||
{
|
||||
uint32_t check = 0;
|
||||
uint32_t *data = (uint32_t *)p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len/4; i++)
|
||||
check += data[i];
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
static int8_t num_prv_keys;
|
||||
|
||||
static int
|
||||
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
const uint8_t *keystring_admin)
|
||||
const uint8_t *keystring_admin, const uint8_t *modulus)
|
||||
{
|
||||
uint8_t nr = get_do_ptr_nr_for_kk (kk);
|
||||
const uint8_t *p;
|
||||
int r;
|
||||
const uint8_t *modulus;
|
||||
struct prvkey_data *pd;
|
||||
uint8_t *key_addr;
|
||||
const uint8_t *dek;
|
||||
const uint8_t *dek, *iv;
|
||||
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
|
||||
const uint8_t *ks_pw1;
|
||||
const uint8_t *ks_rc;
|
||||
struct key_data_internal kdi;
|
||||
|
||||
#if 0
|
||||
assert (key_len == KEY_CONTENT_LEN);
|
||||
#endif
|
||||
int modulus_allocated_here = 0;
|
||||
uint8_t ks_pw1_len = 0;
|
||||
uint8_t ks_rc_len = 0;
|
||||
|
||||
DEBUG_INFO ("Key import\r\n");
|
||||
DEBUG_SHORT (key_len);
|
||||
@@ -697,15 +733,23 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
/* No replace support, you need to remove it first. */
|
||||
return -1;
|
||||
|
||||
if (key_len != KEY_CONTENT_LEN)
|
||||
return -1;
|
||||
|
||||
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
|
||||
if (pd == NULL)
|
||||
return -1;
|
||||
|
||||
modulus = modulus_calc (key_data, key_len);
|
||||
if (modulus == NULL)
|
||||
{
|
||||
free (pd);
|
||||
return -1;
|
||||
modulus = modulus_calc (key_data, key_len);
|
||||
if (modulus == NULL)
|
||||
{
|
||||
free (pd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
modulus_allocated_here = 1;
|
||||
}
|
||||
|
||||
DEBUG_INFO ("Getting keystore address...\r\n");
|
||||
@@ -713,7 +757,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
if (key_addr == NULL)
|
||||
{
|
||||
free (pd);
|
||||
modulus_free (modulus);
|
||||
if (modulus_allocated_here)
|
||||
modulus_free (modulus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -721,21 +766,21 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
DEBUG_WORD ((uint32_t)key_addr);
|
||||
|
||||
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
|
||||
kdi.check = calc_check32 (key_data, KEY_CONTENT_LEN);
|
||||
kdi.random = get_salt ();
|
||||
memcpy (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
|
||||
compute_key_data_checksum (&kdi, 0);
|
||||
|
||||
dek = random_bytes_get (); /* 16-byte random bytes */
|
||||
dek = random_bytes_get (); /* 32-byte random bytes */
|
||||
iv = dek + DATA_ENCRYPTION_KEY_SIZE;
|
||||
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
|
||||
|
||||
encrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
|
||||
r = flash_key_write (key_addr, kdi.data, modulus);
|
||||
modulus_free (modulus);
|
||||
if (modulus_allocated_here)
|
||||
modulus_free (modulus);
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
@@ -745,32 +790,33 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
}
|
||||
|
||||
pd->key_addr = key_addr;
|
||||
memcpy (pd->crm_encrypted, (uint8_t *)&kdi.check, ADDITIONAL_DATA_SIZE);
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
ac_reset_pso_cds ();
|
||||
else
|
||||
ac_reset_other ();
|
||||
memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE);
|
||||
memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
if (ks_pw1)
|
||||
encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
|
||||
{
|
||||
ks_pw1_len = ks_pw1[0];
|
||||
encrypt_dek (ks_pw1+1, pd->dek_encrypted_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t ks123_pw1[KEYSTRING_SIZE_PW1];
|
||||
uint8_t ks[KEYSTRING_MD_SIZE];
|
||||
|
||||
ks123_pw1[0] = strlen (OPENPGP_CARD_INITIAL_PW1);
|
||||
sha1 ((uint8_t *)OPENPGP_CARD_INITIAL_PW1,
|
||||
strlen (OPENPGP_CARD_INITIAL_PW1), ks123_pw1+1);
|
||||
encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
|
||||
s2k (BY_USER, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1,
|
||||
strlen (OPENPGP_CARD_INITIAL_PW1), ks);
|
||||
encrypt_dek (ks, pd->dek_encrypted_1);
|
||||
}
|
||||
|
||||
if (ks_rc)
|
||||
encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
|
||||
{
|
||||
ks_rc_len = ks_rc[0];
|
||||
encrypt_dek (ks_rc+1, pd->dek_encrypted_2);
|
||||
}
|
||||
else
|
||||
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
if (keystring_admin)
|
||||
encrypt (keystring_admin, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
|
||||
encrypt_dek (keystring_admin, pd->dek_encrypted_3);
|
||||
else
|
||||
memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
@@ -785,17 +831,11 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
if (++num_prv_keys == NUM_ALL_PRV_KEYS) /* All keys are registered. */
|
||||
{
|
||||
/* Remove contents of keystrings from DO, but length */
|
||||
if (ks_pw1)
|
||||
{
|
||||
uint8_t ks_pw1_len = ks_pw1[0];
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
|
||||
}
|
||||
if (ks_pw1_len)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
|
||||
|
||||
if (ks_rc)
|
||||
{
|
||||
uint8_t ks_rc_len = ks_rc[0];
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
|
||||
}
|
||||
if (ks_rc_len)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -820,19 +860,21 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
|
||||
if (pd == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy (pd, &(do_data)[1], sizeof (struct prvkey_data));
|
||||
dek_p = ((uint8_t *)pd) + 4 + ADDITIONAL_DATA_SIZE
|
||||
+ DATA_ENCRYPTION_KEY_SIZE * (who_old - 1);
|
||||
memcpy (pd, &do_data[1], sizeof (struct prvkey_data));
|
||||
flash_do_release (do_data);
|
||||
|
||||
dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE
|
||||
+ DATA_ENCRYPTION_KEY_SIZE * who_old;
|
||||
memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt (old_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
encrypt (new_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt_dek (old_ks, dek);
|
||||
encrypt_dek (new_ks, dek);
|
||||
dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old);
|
||||
memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
do_ptr[nr - NR_DO__FIRST__] = NULL;
|
||||
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
|
||||
do_ptr[nr - NR_DO__FIRST__] = p;
|
||||
|
||||
flash_do_release (do_data);
|
||||
free (pd);
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
@@ -876,11 +918,19 @@ proc_key_import (const uint8_t *data, int len)
|
||||
p += 1;
|
||||
|
||||
if (*p == 0xb6)
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
else if (*p == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
{
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
ac_reset_pso_cds ();
|
||||
gpg_reset_digital_signature_counter ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*p == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
ac_reset_other ();
|
||||
}
|
||||
|
||||
if (len <= 22)
|
||||
{ /* Deletion of the key */
|
||||
@@ -900,6 +950,11 @@ proc_key_import (const uint8_t *data, int len)
|
||||
/* Delete PW1 and RC if any */
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
|
||||
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -907,7 +962,7 @@ proc_key_import (const uint8_t *data, int len)
|
||||
|
||||
/* It should starts with 00 01 00 01 (E) */
|
||||
/* Skip E, 4-byte */
|
||||
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin);
|
||||
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
else
|
||||
@@ -988,7 +1043,7 @@ gpg_do_table[] = {
|
||||
/ sizeof (struct do_table_entry))
|
||||
|
||||
/*
|
||||
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
|
||||
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
|
||||
*/
|
||||
void
|
||||
gpg_data_scan (const uint8_t *p_start)
|
||||
@@ -1038,18 +1093,18 @@ gpg_data_scan (const uint8_t *p_start)
|
||||
}
|
||||
else
|
||||
switch (nr)
|
||||
{
|
||||
case NR_BOOL_PW1_LIFETIME:
|
||||
pw1_lifetime_p = p - 1;
|
||||
p++;
|
||||
continue;
|
||||
case NR_COUNTER_123:
|
||||
p++;
|
||||
if (second_byte <= PW_ERR_PW3)
|
||||
pw_err_counter_p[second_byte] = p;
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
{
|
||||
case NR_BOOL_PW1_LIFETIME:
|
||||
pw1_lifetime_p = p - 1;
|
||||
p++;
|
||||
continue;
|
||||
case NR_COUNTER_123:
|
||||
p++;
|
||||
if (second_byte <= PW_ERR_PW3)
|
||||
pw_err_counter_p[second_byte] = p;
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,8 +1291,8 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
|
||||
}
|
||||
case DO_PROC_READWRITE:
|
||||
{
|
||||
int (*rw_func)(uint16_t, int, uint8_t *, int, int)
|
||||
= (int (*)(uint16_t, int, uint8_t *, int, int))do_p->obj;
|
||||
int (*rw_func)(uint16_t, int, const uint8_t *, int, int)
|
||||
= (int (*)(uint16_t, int, const uint8_t *, int, int))do_p->obj;
|
||||
|
||||
return rw_func (do_p->tag, with_tag, NULL, 0, 0);
|
||||
}
|
||||
@@ -1338,6 +1393,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
|
||||
GPG_MEMORY_FAILURE ();
|
||||
else
|
||||
{
|
||||
*do_data_p = NULL;
|
||||
*do_data_p = flash_do_write (nr, data, len);
|
||||
if (*do_data_p)
|
||||
GPG_SUCCESS ();
|
||||
@@ -1452,6 +1508,7 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
*do_data_p = NULL;
|
||||
*do_data_p = flash_do_write (nr, data, size);
|
||||
if (*do_data_p == NULL)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
@@ -1459,3 +1516,78 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
|
||||
else
|
||||
*do_data_p = NULL;
|
||||
}
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
void
|
||||
gpg_do_keygen (uint8_t kk_byte)
|
||||
{
|
||||
enum kind_of_key kk;
|
||||
const uint8_t *keystring_admin;
|
||||
const uint8_t *p_q_modulus;
|
||||
const uint8_t *p_q;
|
||||
const uint8_t *modulus;
|
||||
int r;
|
||||
|
||||
DEBUG_INFO ("Keygen\r\n");
|
||||
DEBUG_BYTE (kk_byte);
|
||||
|
||||
if (kk_byte == 0xb6)
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
else if (kk_byte == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
|
||||
if (admin_authorized == BY_ADMIN)
|
||||
keystring_admin = keystring_md_pw3;
|
||||
else
|
||||
keystring_admin = NULL;
|
||||
|
||||
p_q_modulus = rsa_genkey ();
|
||||
if (p_q_modulus == NULL)
|
||||
{
|
||||
GPG_MEMORY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
p_q = p_q_modulus;
|
||||
modulus = p_q_modulus + KEY_CONTENT_LEN;
|
||||
|
||||
r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN,
|
||||
keystring_admin, modulus);
|
||||
free ((uint8_t *)p_q_modulus);
|
||||
if (r < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_INFO ("Calling gpg_do_public_key...\r\n");
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
{
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *ks;
|
||||
|
||||
/* GnuPG expects it's ready for signing. */
|
||||
/* Don't call ac_reset_pso_cds here, but load the private key */
|
||||
|
||||
if (ks_pw1)
|
||||
ks = ks_pw1+1;
|
||||
else
|
||||
{
|
||||
const uint8_t * pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
|
||||
|
||||
s2k (BY_USER, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
|
||||
ks = keystring;
|
||||
}
|
||||
|
||||
gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, ks);
|
||||
}
|
||||
else
|
||||
ac_reset_other ();
|
||||
|
||||
gpg_do_public_key (kk_byte);
|
||||
}
|
||||
#endif
|
||||
|
||||
416
src/openpgp.c
416
src/openpgp.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* openpgp.c -- OpenPGP card protocol support
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -25,9 +25,9 @@
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "gnuk.h"
|
||||
#include "sys.h"
|
||||
#include "openpgp.h"
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/sha1.h"
|
||||
#include "sha256.h"
|
||||
|
||||
#define CLS(a) a.cmd_apdu_head[0]
|
||||
#define INS(a) a.cmd_apdu_head[1]
|
||||
@@ -39,6 +39,8 @@
|
||||
#define INS_PSO 0x2a
|
||||
#define INS_RESET_RETRY_COUNTER 0x2c
|
||||
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47
|
||||
#define INS_EXTERNAL_AUTHENTICATE 0x82
|
||||
#define INS_GET_CHALLENGE 0x84
|
||||
#define INS_INTERNAL_AUTHENTICATE 0x88
|
||||
#define INS_SELECT_FILE 0xa4
|
||||
#define INS_READ_BINARY 0xb0
|
||||
@@ -48,6 +50,9 @@
|
||||
#define INS_PUT_DATA 0xda
|
||||
#define INS_PUT_DATA_ODD 0xdb /* For key import */
|
||||
|
||||
#define CHALLENGE_LEN 32
|
||||
static const uint8_t *challenge; /* Random bytes */
|
||||
|
||||
static const uint8_t
|
||||
select_file_TOP_result[] __attribute__ ((aligned (1))) = {
|
||||
0x00, 0x00, /* unused */
|
||||
@@ -76,9 +81,12 @@ set_res_sw (uint8_t sw1, uint8_t sw2)
|
||||
#define FILE_DF_OPENPGP 1
|
||||
#define FILE_MF 2
|
||||
#define FILE_EF_DIR 3
|
||||
#define FILE_EF_SERIAL 4
|
||||
#define FILE_EF_CH_CERTIFICATE 5
|
||||
#define FILE_EF_RANDOM 6
|
||||
#define FILE_EF_SERIAL_NO 4
|
||||
#define FILE_EF_UPDATE_KEY_0 5
|
||||
#define FILE_EF_UPDATE_KEY_1 6
|
||||
#define FILE_EF_UPDATE_KEY_2 7
|
||||
#define FILE_EF_UPDATE_KEY_3 8
|
||||
#define FILE_EF_CH_CERTIFICATE 9
|
||||
|
||||
static uint8_t file_selection;
|
||||
|
||||
@@ -99,7 +107,7 @@ gpg_fini (void)
|
||||
}
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
/*
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
@@ -109,9 +117,9 @@ get_pinpad_input (int msg_code)
|
||||
{
|
||||
int r;
|
||||
|
||||
chEvtSignal (main_thread, LED_INPUT_MODE);
|
||||
led_blink (LED_START_COMMAND);
|
||||
r = pinpad_getline (msg_code, MS2ST (8000));
|
||||
chEvtSignal (main_thread, LED_STATUS_MODE);
|
||||
led_blink (LED_FINISH_COMMAND);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
@@ -212,10 +220,10 @@ cmd_change_password (void)
|
||||
uint8_t p1 = P1 (apdu); /* 0: change (old+new), 1: exchange (new) */
|
||||
uint8_t p2 = P2 (apdu);
|
||||
int len;
|
||||
const uint8_t *pw;
|
||||
const uint8_t *newpw;
|
||||
uint8_t *pw, *newpw;
|
||||
int pw_len, newpw_len;
|
||||
int who = p2 - 0x80;
|
||||
int who_old;
|
||||
int r;
|
||||
|
||||
DEBUG_INFO ("Change PW\r\n");
|
||||
@@ -235,6 +243,7 @@ cmd_change_password (void)
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
|
||||
pw_len = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, len, -1, ks_pw1);
|
||||
who_old = who;
|
||||
|
||||
if (pw_len < 0)
|
||||
{
|
||||
@@ -274,15 +283,23 @@ cmd_change_password (void)
|
||||
{
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = len - pw_len;
|
||||
gpg_set_pw3 (newpw, newpw_len);
|
||||
if (newpw_len == 0 && admin_authorized == BY_ADMIN)
|
||||
{
|
||||
newpw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
|
||||
memcpy (newpw, OPENPGP_CARD_INITIAL_PW3, newpw_len);
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW3, NULL, 0);
|
||||
}
|
||||
else
|
||||
gpg_set_pw3 (newpw, newpw_len);
|
||||
who_old = admin_authorized;
|
||||
}
|
||||
}
|
||||
|
||||
sha1 (pw, pw_len, old_ks);
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (who_old, pw, pw_len, old_ks);
|
||||
s2k (who, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
|
||||
r = gpg_change_keystring (who, old_ks, who, new_ks);
|
||||
r = gpg_change_keystring (who_old, old_ks, who, new_ks);
|
||||
if (r <= -2)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
@@ -298,6 +315,8 @@ cmd_change_password (void)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -306,6 +325,8 @@ cmd_change_password (void)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -317,6 +338,29 @@ cmd_change_password (void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define USER_S2K_MAGIC "\xffUSER\r\n"
|
||||
#define RESETCODE_S2K_MAGIC "\xffRESET\r\n"
|
||||
|
||||
void
|
||||
s2k (int who, const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32])
|
||||
{
|
||||
sha256_context ctx;
|
||||
|
||||
sha256_start (&ctx);
|
||||
sha256_update (&ctx, input, ilen);
|
||||
if (who == BY_USER)
|
||||
sha256_update (&ctx, (unsigned char *)USER_S2K_MAGIC,
|
||||
sizeof (USER_S2K_MAGIC));
|
||||
else if (who == BY_RESETCODE)
|
||||
sha256_update (&ctx, (unsigned char *)RESETCODE_S2K_MAGIC,
|
||||
sizeof (RESETCODE_S2K_MAGIC));
|
||||
/* Not add any for BY_ADMIN */
|
||||
sha256_finish (&ctx, output);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmd_reset_user_password (void)
|
||||
{
|
||||
@@ -357,8 +401,8 @@ cmd_reset_user_password (void)
|
||||
pw_len = ks_rc[0];
|
||||
newpw = pw + pw_len;
|
||||
newpw_len = len - pw_len;
|
||||
sha1 (pw, pw_len, old_ks);
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (BY_RESETCODE, pw, pw_len, old_ks);
|
||||
s2k (BY_USER, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks);
|
||||
if (r <= -2)
|
||||
@@ -382,6 +426,8 @@ cmd_reset_user_password (void)
|
||||
KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_RC);
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
@@ -389,8 +435,11 @@ cmd_reset_user_password (void)
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_RC);
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
@@ -409,7 +458,7 @@ cmd_reset_user_password (void)
|
||||
|
||||
newpw_len = len;
|
||||
newpw = pw;
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (BY_USER, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
r = gpg_change_keystring (admin_authorized, old_ks, BY_USER, new_ks);
|
||||
if (r <= -2)
|
||||
@@ -429,14 +478,19 @@ cmd_reset_user_password (void)
|
||||
KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -471,32 +525,107 @@ cmd_pgp_gakp (void)
|
||||
/* Get public key */
|
||||
gpg_do_public_key (apdu.cmd_apdu_data[0]);
|
||||
else
|
||||
{ /* Generate key pair */
|
||||
{
|
||||
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
|
||||
GPG_SECURITY_FAILURE ();
|
||||
|
||||
/* XXX: Not yet supported */
|
||||
GPG_ERROR ();
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
/* Generate key pair */
|
||||
gpg_do_keygen (apdu.cmd_apdu_data[0]);
|
||||
#else
|
||||
GPG_FUNCTION_NOT_SUPPORTED ();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t *
|
||||
gpg_get_firmware_update_key (uint8_t keyno)
|
||||
{
|
||||
extern uint8_t _updatekey_store;
|
||||
const uint8_t *p;
|
||||
|
||||
p = &_updatekey_store + keyno * KEY_CONTENT_LEN;
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef CERTDO_SUPPORT
|
||||
#define FILEID_CH_CERTIFICATE_IS_VALID 1
|
||||
#else
|
||||
#define FILEID_CH_CERTIFICATE_IS_VALID 0
|
||||
#endif
|
||||
|
||||
static void
|
||||
cmd_read_binary (void)
|
||||
{
|
||||
int is_short_EF = (P1 (apdu) & 0x80) != 0;
|
||||
uint8_t file_id;
|
||||
const uint8_t *p;
|
||||
uint16_t offset;
|
||||
|
||||
DEBUG_INFO (" - Read binary\r\n");
|
||||
|
||||
if (file_selection == FILE_EF_SERIAL)
|
||||
if (is_short_EF)
|
||||
file_id = (P1 (apdu) & 0x1f);
|
||||
else
|
||||
file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO;
|
||||
|
||||
if ((!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE)
|
||||
|| file_id > FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
if (P2 (apdu) >= 6)
|
||||
GPG_BAD_P0_P1 ();
|
||||
else
|
||||
{
|
||||
gpg_do_get_data (0x004f, 1); /* AID */
|
||||
res_APDU[0] = 0x5a;
|
||||
}
|
||||
GPG_NO_FILE ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_short_EF)
|
||||
{
|
||||
file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
|
||||
offset = P2 (apdu);
|
||||
}
|
||||
else
|
||||
GPG_NO_RECORD();
|
||||
offset = (P1 (apdu) << 8) | P2 (apdu);
|
||||
|
||||
if (file_id == FILEID_SERIAL_NO)
|
||||
{
|
||||
if (offset != 0)
|
||||
GPG_BAD_P1_P2 ();
|
||||
else
|
||||
{
|
||||
gpg_do_get_data (0x004f, 1); /* Get AID... */
|
||||
res_APDU[0] = 0x5a; /* ... and overwrite the first byte of data. */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
|
||||
{
|
||||
if (offset != 0)
|
||||
GPG_MEMORY_FAILURE ();
|
||||
else
|
||||
{
|
||||
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
|
||||
res_APDU_size = KEY_CONTENT_LEN;
|
||||
memcpy (res_APDU, p, KEY_CONTENT_LEN);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
}
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
else /* file_id == FILEID_CH_CERTIFICATE */
|
||||
{
|
||||
uint16_t len = 256;
|
||||
|
||||
p = &ch_certificate_start;
|
||||
if (offset >= FLASH_CH_CERTIFICATE_SIZE)
|
||||
GPG_MEMORY_FAILURE ();
|
||||
else
|
||||
{
|
||||
if (offset + len >= FLASH_CH_CERTIFICATE_SIZE)
|
||||
len = FLASH_CH_CERTIFICATE_SIZE - offset;
|
||||
|
||||
res_APDU_size = len;
|
||||
memcpy (res_APDU, p + offset, len);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -539,7 +668,7 @@ cmd_select_file (void)
|
||||
* MF.EF-GDO -- Serial number of the card and name of the owner
|
||||
*/
|
||||
GPG_SUCCESS ();
|
||||
file_selection = FILE_EF_SERIAL;
|
||||
file_selection = FILE_EF_SERIAL_NO;
|
||||
}
|
||||
else if (apdu.cmd_apdu_data_len == 2
|
||||
&& apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00)
|
||||
@@ -647,10 +776,15 @@ cmd_pso (void)
|
||||
|
||||
/* Skip padding 0x00 */
|
||||
len--;
|
||||
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_DECRYPTION]);
|
||||
if (r < 0)
|
||||
GPG_ERROR ();
|
||||
if (len != KEY_CONTENT_LEN)
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
else
|
||||
{
|
||||
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_DECRYPTION]);
|
||||
if (r < 0)
|
||||
GPG_ERROR ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -664,6 +798,8 @@ cmd_pso (void)
|
||||
DEBUG_INFO ("PSO done.\r\n");
|
||||
}
|
||||
|
||||
|
||||
#define MAX_DIGEST_INFO_LEN 102 /* 40% */
|
||||
static void
|
||||
cmd_internal_authenticate (void)
|
||||
{
|
||||
@@ -683,6 +819,13 @@ cmd_internal_authenticate (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (len > MAX_DIGEST_INFO_LEN)
|
||||
{
|
||||
DEBUG_INFO ("input is too long.");
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_AUTHENTICATION]);
|
||||
if (r < 0)
|
||||
@@ -700,16 +843,17 @@ cmd_internal_authenticate (void)
|
||||
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
|
||||
}
|
||||
|
||||
#define MBD_OPRATION_WRITE 0
|
||||
#define MBD_OPRATION_UPDATE 1
|
||||
|
||||
static void
|
||||
cmd_update_binary (void)
|
||||
modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
|
||||
{
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
uint8_t file_id;
|
||||
uint16_t offset;
|
||||
int is_short_EF = (p1 & 0x80) != 0;
|
||||
int r;
|
||||
|
||||
DEBUG_INFO (" - UPDATE BINARY\r\n");
|
||||
|
||||
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
|
||||
{
|
||||
DEBUG_INFO ("security error.");
|
||||
@@ -717,42 +861,52 @@ cmd_update_binary (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((P1 (apdu) & 0x80))
|
||||
if ((P1 (apdu) & 0x7f) <= FILEID_RANDOM)
|
||||
{
|
||||
file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f);
|
||||
r = flash_erase_binary (file_selection - FILE_EF_CH_CERTIFICATE);
|
||||
if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
GPG_MEMORY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPG_NO_FILE ();
|
||||
return;
|
||||
}
|
||||
if (is_short_EF)
|
||||
file_id = (p1 & 0x1f);
|
||||
else
|
||||
{
|
||||
if (file_selection != FILE_EF_CH_CERTIFICATE
|
||||
&& file_selection != FILE_EF_RANDOM)
|
||||
{
|
||||
GPG_COMMAND_NOT_ALLOWED ();
|
||||
return;
|
||||
}
|
||||
file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO;
|
||||
|
||||
offset = (P1 (apdu) << 8) | P2 (apdu);
|
||||
if (!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
GPG_NO_FILE ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (op == MBD_OPRATION_UPDATE && file_id != FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_id > FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
GPG_NO_FILE ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_short_EF)
|
||||
{
|
||||
file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
|
||||
offset = p2;
|
||||
|
||||
if (op == MBD_OPRATION_UPDATE)
|
||||
{
|
||||
r = flash_erase_binary (file_id);
|
||||
if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
GPG_MEMORY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
offset = (p1 << 8) | p2;
|
||||
|
||||
DEBUG_SHORT (len);
|
||||
DEBUG_SHORT (offset);
|
||||
|
||||
r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
|
||||
apdu.cmd_apdu_data, len, offset);
|
||||
r = flash_write_binary (file_id, apdu.cmd_apdu_data, len, offset);
|
||||
if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
@@ -761,64 +915,103 @@ cmd_update_binary (void)
|
||||
}
|
||||
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
|
||||
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
static void
|
||||
cmd_update_binary (void)
|
||||
{
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
|
||||
DEBUG_INFO (" - UPDATE BINARY\r\n");
|
||||
modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
|
||||
DEBUG_INFO ("UPDATE BINARY done.\r\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
cmd_write_binary (void)
|
||||
{
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
uint16_t offset;
|
||||
int r;
|
||||
int i;
|
||||
const uint8_t *p;
|
||||
|
||||
DEBUG_INFO (" - WRITE BINARY\r\n");
|
||||
modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
|
||||
|
||||
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p = gpg_get_firmware_update_key (i);
|
||||
if (p[0] != 0x00 || p[1] != 0x00) /* still valid */
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 4) /* all update keys are removed */
|
||||
{
|
||||
p = gpg_get_firmware_update_key (0);
|
||||
flash_erase_page ((uint32_t)p);
|
||||
}
|
||||
|
||||
DEBUG_INFO ("WRITE BINARY done.\r\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmd_external_authenticate (void)
|
||||
{
|
||||
const uint8_t *pubkey;
|
||||
const uint8_t *signature = apdu.cmd_apdu_data;
|
||||
int len = apdu.cmd_apdu_data_len;
|
||||
uint8_t keyno = P2 (apdu);
|
||||
int r;
|
||||
|
||||
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
|
||||
|
||||
if (keyno > 4)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
pubkey = gpg_get_firmware_update_key (keyno);
|
||||
if (len != 256
|
||||
|| (pubkey[0] == 0xff && pubkey[1] == 0xff) /* not registered */
|
||||
|| (pubkey[0] == 0x00 && pubkey[1] == 0x00) /* removed */)
|
||||
{
|
||||
GPG_CONDITION_NOT_SATISFIED ();
|
||||
return;
|
||||
}
|
||||
|
||||
r = rsa_verify (pubkey, challenge, signature);
|
||||
random_bytes_free (challenge);
|
||||
challenge = NULL;
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("security error.");
|
||||
GPG_SECURITY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((P1 (apdu) & 0x80))
|
||||
if ((P1 (apdu) & 0x7f) <= FILEID_SERIAL_NO)
|
||||
{
|
||||
file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f);
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPG_NO_FILE ();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file_selection != FILE_EF_CH_CERTIFICATE
|
||||
&& file_selection != FILE_EF_RANDOM
|
||||
&& file_selection != FILE_EF_SERIAL)
|
||||
{
|
||||
GPG_COMMAND_NOT_ALLOWED ();
|
||||
return;
|
||||
}
|
||||
chThdTerminate (chThdSelf ());
|
||||
set_res_sw (0xff, 0xff);
|
||||
DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n");
|
||||
}
|
||||
|
||||
offset = (P1 (apdu) << 8) | P2 (apdu);
|
||||
}
|
||||
static void
|
||||
cmd_get_challenge (void)
|
||||
{
|
||||
DEBUG_INFO (" - GET CHALLENGE\r\n");
|
||||
|
||||
DEBUG_SHORT (len);
|
||||
DEBUG_SHORT (offset);
|
||||
|
||||
r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
|
||||
apdu.cmd_apdu_data, len, offset);
|
||||
if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("memory error.\r\n");
|
||||
GPG_MEMORY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
if (challenge)
|
||||
random_bytes_free (challenge);
|
||||
|
||||
challenge = random_bytes_get ();
|
||||
memcpy (res_APDU, challenge, CHALLENGE_LEN);
|
||||
res_APDU_size = CHALLENGE_LEN;
|
||||
GPG_SUCCESS ();
|
||||
DEBUG_INFO ("WRITE BINARY done.\r\n");
|
||||
DEBUG_INFO ("GET CHALLENGE done.\r\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -834,12 +1027,17 @@ const struct command cmds[] = {
|
||||
{ INS_PSO, cmd_pso },
|
||||
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
|
||||
{ INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
|
||||
{ INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */
|
||||
cmd_external_authenticate },
|
||||
{ INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */
|
||||
{ INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
|
||||
{ INS_SELECT_FILE, cmd_select_file },
|
||||
{ INS_READ_BINARY, cmd_read_binary },
|
||||
{ INS_GET_DATA, cmd_get_data },
|
||||
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
|
||||
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
{ INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */
|
||||
#endif
|
||||
{ INS_PUT_DATA, cmd_put_data },
|
||||
{ INS_PUT_DATA_ODD, cmd_put_data },
|
||||
};
|
||||
@@ -966,7 +1164,9 @@ GPGthread (void *arg)
|
||||
else if (m == EV_NOP)
|
||||
continue;
|
||||
|
||||
led_blink (LED_START_COMMAND);
|
||||
process_command_apdu ();
|
||||
led_blink (LED_FINISH_COMMAND);
|
||||
done:
|
||||
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81)
|
||||
#define GPG_NO_FILE() set_res_sw (0x6a, 0x82)
|
||||
#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88)
|
||||
#define GPG_BAD_P0_P1() set_res_sw (0x6b, 0x00)
|
||||
#define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00)
|
||||
#define GPG_NO_INS() set_res_sw (0x6d, 0x00)
|
||||
#define GPG_ERROR() set_res_sw (0x6f, 0x00)
|
||||
#define GPG_SUCCESS() set_res_sw (0x90, 0x00)
|
||||
|
||||
@@ -595,7 +595,7 @@ cir_getchar (systime_t timeout)
|
||||
|
||||
static Thread *pin_thread;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
@@ -620,7 +620,7 @@ pinpad_getline (int msg_code, systime_t timeout)
|
||||
|
||||
if (ch_is_backspace (ch))
|
||||
{
|
||||
led_blink (2);
|
||||
led_blink (LED_TWOSHOTS);
|
||||
if (pin_input_len > 0)
|
||||
pin_input_len--;
|
||||
}
|
||||
@@ -628,7 +628,7 @@ pinpad_getline (int msg_code, systime_t timeout)
|
||||
break;
|
||||
else if (pin_input_len < MAX_PIN_CHARS)
|
||||
{
|
||||
led_blink (0);
|
||||
led_blink (LED_ONESHOT);
|
||||
pin_input_buffer[pin_input_len++] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ uint8_t pin_input_len;
|
||||
|
||||
#define OFF '\x00'
|
||||
#define ENTER '\x0a'
|
||||
static struct led_pattern { uint8_t c, v; } led_pattern[] =
|
||||
static struct led_pattern { uint8_t c, v; } led_pattern[] =
|
||||
{
|
||||
/* char : dp a b c d e f g */
|
||||
{ ENTER, 0xf8 }, /* |- : 1 1 1 1 1 0 0 0 (enter) */
|
||||
|
||||
@@ -41,7 +41,7 @@ uint8_t pin_input_len;
|
||||
|
||||
static Thread *pin_thread;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
@@ -71,7 +71,7 @@ pinpad_getline (int msg_code, systime_t timeout)
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
|
||||
led_blink (0);
|
||||
led_blink (LED_ONESHOT);
|
||||
if (msg != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
38
src/random.c
38
src/random.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* random.c -- get random bytes
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "gnuk.h"
|
||||
#include "neug.h"
|
||||
|
||||
#define RANDOM_BYTES_LENGTH 16
|
||||
#define RANDOM_BYTES_LENGTH 32
|
||||
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
|
||||
|
||||
void
|
||||
@@ -43,7 +43,7 @@ random_init (void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointer to random 16-byte
|
||||
* Return pointer to random 32-byte
|
||||
*/
|
||||
const uint8_t *
|
||||
random_bytes_get (void)
|
||||
@@ -53,12 +53,13 @@ random_bytes_get (void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Free pointer to random 16-byte
|
||||
* Free pointer to random 32-byte
|
||||
*/
|
||||
void
|
||||
random_bytes_free (const uint8_t *p)
|
||||
{
|
||||
(void)p;
|
||||
memset (random_word, 0, RANDOM_BYTES_LENGTH);
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
@@ -70,3 +71,32 @@ get_salt (void)
|
||||
{
|
||||
return neug_get (NEUG_KICK_FILLING);
|
||||
}
|
||||
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
/*
|
||||
* Random byte iterator
|
||||
*/
|
||||
uint8_t
|
||||
random_byte (void *arg)
|
||||
{
|
||||
uint8_t *index_p = (uint8_t *)arg;
|
||||
uint8_t index = *index_p;
|
||||
uint8_t *p = ((uint8_t *)random_word) + index;
|
||||
uint8_t v;
|
||||
|
||||
neug_wait_full ();
|
||||
|
||||
v = *p;
|
||||
|
||||
if (++index >= RANDOM_BYTES_LENGTH)
|
||||
{
|
||||
index = 0;
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
*index_p = index;
|
||||
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
222
src/sha256.c
Normal file
222
src/sha256.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* sha256.c -- Compute SHA-256 hash
|
||||
*
|
||||
* Just for little endian architecture.
|
||||
*
|
||||
* Code taken from:
|
||||
* http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
|
||||
*
|
||||
* File names are sha2.c, sha2.h, brg_types.h, brg_endian.h
|
||||
* in the archive sha2-07-01-07.zip.
|
||||
*
|
||||
* Code is modified in the style of PolarSSL API.
|
||||
*
|
||||
* See original copyright notice below.
|
||||
*/
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "sha256.h"
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#define SHA256_BLOCK_SIZE 64
|
||||
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
|
||||
|
||||
static void bswap32_buf (uint32_t *p, int n)
|
||||
{
|
||||
while (n--)
|
||||
p[n] = __builtin_bswap32 (p[n]); /* bswap32 is GCC extention */
|
||||
}
|
||||
|
||||
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
|
||||
|
||||
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
|
||||
|
||||
/* round transforms for SHA256 compression functions */
|
||||
#define vf(n,i) v[(n - i) & 7]
|
||||
|
||||
#define hf(i) (p[i & 15] += \
|
||||
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
|
||||
|
||||
#define v_cycle(i,j) \
|
||||
vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \
|
||||
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
|
||||
vf(3,i) += vf(7,i); \
|
||||
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
|
||||
|
||||
#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
|
||||
#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
|
||||
#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
|
||||
#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
|
||||
#define k_0 k256
|
||||
|
||||
const uint32_t k256[64] = {
|
||||
0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5,
|
||||
0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5,
|
||||
0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3,
|
||||
0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174,
|
||||
0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC,
|
||||
0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA,
|
||||
0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7,
|
||||
0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967,
|
||||
0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13,
|
||||
0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85,
|
||||
0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3,
|
||||
0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070,
|
||||
0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5,
|
||||
0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3,
|
||||
0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208,
|
||||
0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2,
|
||||
};
|
||||
|
||||
void
|
||||
sha256_process (sha256_context *ctx)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t *p = ctx->wbuf;
|
||||
uint32_t v[8];
|
||||
|
||||
memcpy (v, ctx->state, 8 * sizeof (uint32_t));
|
||||
|
||||
for (i = 0; i < 64; i += 16)
|
||||
{
|
||||
v_cycle ( 0, i);
|
||||
v_cycle ( 1, i);
|
||||
v_cycle ( 2, i);
|
||||
v_cycle ( 3, i);
|
||||
v_cycle ( 4, i);
|
||||
v_cycle ( 5, i);
|
||||
v_cycle ( 6, i);
|
||||
v_cycle ( 7, i);
|
||||
v_cycle ( 8, i);
|
||||
v_cycle ( 9, i);
|
||||
v_cycle (10, i);
|
||||
v_cycle (11, i);
|
||||
v_cycle (12, i);
|
||||
v_cycle (13, i);
|
||||
v_cycle (14, i);
|
||||
v_cycle (15, i);
|
||||
}
|
||||
|
||||
ctx->state[0] += v[0];
|
||||
ctx->state[1] += v[1];
|
||||
ctx->state[2] += v[2];
|
||||
ctx->state[3] += v[3];
|
||||
ctx->state[4] += v[4];
|
||||
ctx->state[5] += v[5];
|
||||
ctx->state[6] += v[6];
|
||||
ctx->state[7] += v[7];
|
||||
}
|
||||
|
||||
void
|
||||
sha256_update (sha256_context *ctx, const unsigned char *input,
|
||||
unsigned int ilen)
|
||||
{
|
||||
uint32_t left = (ctx->total[0] & SHA256_MASK);
|
||||
uint32_t fill = SHA256_BLOCK_SIZE - left;
|
||||
|
||||
ctx->total[0] += ilen;
|
||||
if (ctx->total[0] < ilen)
|
||||
ctx->total[1]++;
|
||||
|
||||
while (ilen >= fill)
|
||||
{
|
||||
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
|
||||
bswap32_buf (ctx->wbuf, SHA256_BLOCK_SIZE >> 2);
|
||||
sha256_process (ctx);
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
fill = SHA256_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
|
||||
}
|
||||
|
||||
void
|
||||
sha256_finish (sha256_context *ctx, unsigned char output[32])
|
||||
{
|
||||
uint32_t last = (ctx->total[0] & SHA256_MASK);
|
||||
|
||||
bswap32_buf (ctx->wbuf, (last + 3) >> 2);
|
||||
|
||||
ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3));
|
||||
ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3));
|
||||
|
||||
if (last > SHA256_BLOCK_SIZE - 9)
|
||||
{
|
||||
if (last < 60)
|
||||
ctx->wbuf[15] = 0;
|
||||
sha256_process (ctx);
|
||||
last = 0;
|
||||
}
|
||||
else
|
||||
last = (last >> 2) + 1;
|
||||
|
||||
while (last < 14)
|
||||
ctx->wbuf[last++] = 0;
|
||||
|
||||
ctx->wbuf[14] = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
|
||||
ctx->wbuf[15] = ctx->total[0] << 3;
|
||||
sha256_process (ctx);
|
||||
|
||||
bswap32_buf (ctx->state, SHA256_DIGEST_SIZE >> 2);
|
||||
memcpy (output, ctx->state, SHA256_DIGEST_SIZE);
|
||||
memset (ctx, 0, sizeof (sha256_context));
|
||||
}
|
||||
|
||||
const uint32_t initial_state[8] =
|
||||
{
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
void
|
||||
sha256_start (sha256_context *ctx)
|
||||
{
|
||||
ctx->total[0] = ctx->total[1] = 0;
|
||||
memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void
|
||||
sha256 (const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32])
|
||||
{
|
||||
sha256_context ctx;
|
||||
|
||||
sha256_start (&ctx);
|
||||
sha256_update (&ctx, input, ilen);
|
||||
sha256_finish (&ctx, output);
|
||||
}
|
||||
14
src/sha256.h
Normal file
14
src/sha256.h
Normal file
@@ -0,0 +1,14 @@
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total[2];
|
||||
uint32_t state[8];
|
||||
uint32_t wbuf[16];
|
||||
} sha256_context;
|
||||
|
||||
extern void sha256 (const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32]);
|
||||
extern void sha256_start (sha256_context *ctx);
|
||||
extern void sha256_finish (sha256_context *ctx, unsigned char output[32]);
|
||||
extern void sha256_update (sha256_context *ctx, const unsigned char *input,
|
||||
unsigned int ilen);
|
||||
extern void sha256_process (sha256_context *ctx);
|
||||
307
src/sys.c
Normal file
307
src/sys.c
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* sys.c - system services at the first flash ROM blocks
|
||||
*
|
||||
* Copyright (C) 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
*
|
||||
* Gnuk is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "board.h"
|
||||
#include "usb_lld.h"
|
||||
|
||||
extern uint8_t __flash_start__, __flash_end__;
|
||||
|
||||
|
||||
static void
|
||||
usb_cable_config (int enable)
|
||||
{
|
||||
#if defined(SET_USB_CONDITION)
|
||||
if (SET_USB_CONDITION (enable))
|
||||
palSetPad (IOPORT_USB, GPIO_USB);
|
||||
else
|
||||
palClearPad (IOPORT_USB, GPIO_USB);
|
||||
#else
|
||||
(void)enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
set_led (int on)
|
||||
{
|
||||
if (SET_LED_CONDITION (on))
|
||||
palSetPad (IOPORT_LED, GPIO_LED);
|
||||
else
|
||||
palClearPad (IOPORT_LED, GPIO_LED);
|
||||
}
|
||||
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
#define FLASH_KEY2 0xCDEF89ABUL
|
||||
|
||||
static void
|
||||
flash_unlock (void)
|
||||
{
|
||||
FLASH->KEYR = FLASH_KEY1;
|
||||
FLASH->KEYR = FLASH_KEY2;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
flash_wait_for_last_operation (uint32_t timeout)
|
||||
{
|
||||
int status;
|
||||
|
||||
do
|
||||
{
|
||||
status = FLASH->SR;
|
||||
if (--timeout == 0)
|
||||
break;
|
||||
}
|
||||
while ((status & FLASH_SR_BSY) != 0);
|
||||
|
||||
return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR);
|
||||
}
|
||||
|
||||
#define FLASH_PROGRAM_TIMEOUT 0x00010000
|
||||
#define FLASH_ERASE_TIMEOUT 0x01000000
|
||||
|
||||
static int
|
||||
flash_program_halfword (uint32_t addr, uint16_t data)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
|
||||
|
||||
port_disable ();
|
||||
if (status == 0)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PG;
|
||||
|
||||
*(volatile uint16_t *)addr = data;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
|
||||
FLASH->CR &= ~FLASH_CR_PG;
|
||||
}
|
||||
port_enable ();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_erase_page (uint32_t addr)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
|
||||
port_disable ();
|
||||
if (status == 0)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PER;
|
||||
FLASH->AR = addr;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
FLASH->CR &= ~FLASH_CR_PER;
|
||||
}
|
||||
port_enable ();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_check_blank (const uint8_t *p_start, size_t size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
for (p = p_start; p < p_start + size; p++)
|
||||
if (*p != 0xff)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
int status;
|
||||
uint32_t flash_start = (uint32_t)&__flash_start__;
|
||||
uint32_t flash_end = (uint32_t)&__flash_end__;
|
||||
|
||||
if (dst_addr < flash_start || dst_addr + len > flash_end)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#define OPTION_BYTES_ADDR 0x1ffff800
|
||||
|
||||
static int
|
||||
flash_protect (void)
|
||||
{
|
||||
int status;
|
||||
uint32_t option_bytes_value;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
|
||||
port_disable ();
|
||||
if (status == 0)
|
||||
{
|
||||
FLASH->OPTKEYR = FLASH_KEY1;
|
||||
FLASH->OPTKEYR = FLASH_KEY2;
|
||||
|
||||
FLASH->CR |= FLASH_CR_OPTER;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
FLASH->CR &= ~FLASH_CR_OPTER;
|
||||
}
|
||||
port_enable ();
|
||||
|
||||
if (status != 0)
|
||||
return 0;
|
||||
|
||||
option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR;
|
||||
return (option_bytes_value & 0xff) == 0xff ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((naked))
|
||||
flash_erase_all_and_exec (void (*entry)(void))
|
||||
{
|
||||
uint32_t addr = (uint32_t)&__flash_start__;
|
||||
uint32_t end = (uint32_t)&__flash_end__;
|
||||
int r;
|
||||
|
||||
while (addr < end)
|
||||
{
|
||||
r = flash_erase_page (addr);
|
||||
if (r != 0)
|
||||
break;
|
||||
|
||||
addr += FLASH_PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (addr >= end)
|
||||
(*entry) ();
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static void
|
||||
nvic_enable_vector (uint32_t n, uint32_t prio)
|
||||
{
|
||||
unsigned int sh = (n & 3) << 3;
|
||||
|
||||
NVIC_IPR (n >> 2) = (NVIC_IPR(n >> 2) & ~(0xFF << sh)) | (prio << sh);
|
||||
NVIC_ICPR (n >> 5) = 1 << (n & 0x1F);
|
||||
NVIC_ISER (n >> 5) = 1 << (n & 0x1F);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
|
||||
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
|
||||
/*
|
||||
* Note that we also have other IRQ(s):
|
||||
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
|
||||
* USBWakeUp_IRQn (suspend/resume)
|
||||
*/
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
|
||||
usb_cable_config (1);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
|
||||
usb_cable_config (0);
|
||||
}
|
||||
|
||||
#define SYSRESETREQ 0x04
|
||||
static void
|
||||
nvic_system_reset (void)
|
||||
{
|
||||
SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ);
|
||||
asm volatile ("dsb");
|
||||
}
|
||||
|
||||
static void __attribute__ ((naked))
|
||||
reset (void)
|
||||
{
|
||||
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
|
||||
"mov.w r0, #0xed00\n\t" /* r0 = SCR */
|
||||
"movt r0, #0xe000\n\t"
|
||||
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
|
||||
"mov r2, #0x1000\n\t"
|
||||
"add r1, r1, r2\n\t"
|
||||
"sub r2, r2, #1\n\t"
|
||||
"bic r1, r1, r2\n\t"
|
||||
"str r1, [r0, #8]\n\t" /* Set SCR->VCR */
|
||||
"ldr r0, [r1], #4\n\t"
|
||||
"msr MSP, r0\n\t" /* Main (exception handler) stack. */
|
||||
"ldr r0, [r1]\n\t" /* Reset handler. */
|
||||
"bx r0\n"
|
||||
: /* no output */ : /* no input */ : "memory");
|
||||
}
|
||||
|
||||
typedef void (*handler)(void);
|
||||
extern uint8_t __ram_end__;
|
||||
|
||||
handler vector[] __attribute__ ((section(".vectors"))) = {
|
||||
(handler)&__ram_end__,
|
||||
reset,
|
||||
(handler)set_led,
|
||||
flash_unlock,
|
||||
(handler)flash_program_halfword,
|
||||
(handler)flash_erase_page,
|
||||
(handler)flash_check_blank,
|
||||
(handler)flash_write,
|
||||
(handler)flash_protect,
|
||||
(handler)flash_erase_all_and_exec,
|
||||
usb_lld_sys_init,
|
||||
usb_lld_sys_shutdown,
|
||||
nvic_system_reset,
|
||||
};
|
||||
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/
|
||||
/* sys version: "1.0" */
|
||||
'1', 0, '.', 0, '0', 0,
|
||||
};
|
||||
95
src/sys.h
Normal file
95
src/sys.h
Normal file
@@ -0,0 +1,95 @@
|
||||
extern const uint8_t sys_version[8];
|
||||
|
||||
typedef void (*handler)(void);
|
||||
extern handler vector[14];
|
||||
|
||||
static inline const uint8_t *
|
||||
unique_device_id (void)
|
||||
{
|
||||
/* STM32F103 has 96-bit unique device identifier */
|
||||
const uint8_t *addr = (const uint8_t *)0x1ffff7e8;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_led (int on)
|
||||
{
|
||||
void (*func) (int) = (void (*)(int))vector[2];
|
||||
|
||||
return (*func) (on);
|
||||
}
|
||||
|
||||
static inline void
|
||||
flash_unlock (void)
|
||||
{
|
||||
(*vector[3]) ();
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_program_halfword (uint32_t addr, uint16_t data)
|
||||
{
|
||||
int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4];
|
||||
|
||||
return (*func) (addr, data);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_erase_page (uint32_t addr)
|
||||
{
|
||||
int (*func) (uint32_t) = (int (*)(uint32_t))vector[5];
|
||||
|
||||
return (*func) (addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_check_blank (const uint8_t *p_start, size_t size)
|
||||
{
|
||||
int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6];
|
||||
|
||||
return (*func) (p_start, size);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
int (*func) (uint32_t, const uint8_t *, size_t)
|
||||
= (int (*)(uint32_t, const uint8_t *, size_t))vector[7];
|
||||
|
||||
return (*func) (dst_addr, src, len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_protect (void)
|
||||
{
|
||||
int (*func) (void) = (int (*)(void))vector[8];
|
||||
|
||||
return (*func) ();
|
||||
}
|
||||
|
||||
static inline void __attribute__((noreturn))
|
||||
flash_erase_all_and_exec (void (*entry)(void))
|
||||
{
|
||||
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9];
|
||||
|
||||
(*func) (entry);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static inline void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
(*vector[10]) ();
|
||||
}
|
||||
|
||||
static inline void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
(*vector[11]) ();
|
||||
}
|
||||
|
||||
static inline void
|
||||
nvic_system_reset (void)
|
||||
{
|
||||
(*vector[12]) ();
|
||||
}
|
||||
@@ -803,6 +803,7 @@ icc_send_status (struct ccid *c)
|
||||
c->epi->tx_done = 1;
|
||||
usb_lld_write (c->epi->ep_num, icc_reply, ICC_MSG_HEADER_SIZE);
|
||||
|
||||
led_blink (LED_SHOW_STATUS);
|
||||
#ifdef DEBUG_MORE
|
||||
DEBUG_INFO ("St\r\n");
|
||||
#endif
|
||||
@@ -1260,6 +1261,7 @@ icc_handle_timeout (struct ccid *c)
|
||||
{
|
||||
case ICC_STATE_EXECUTE:
|
||||
icc_send_data_block (c, ICC_CMD_STATUS_TIMEEXT);
|
||||
led_blink (LED_ONESHOT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1273,6 +1275,7 @@ icc_handle_timeout (struct ccid *c)
|
||||
|
||||
static struct ccid ccid;
|
||||
|
||||
#define GPG_THREAD_TERMINATED 0xffff
|
||||
|
||||
msg_t
|
||||
USBthread (void *arg)
|
||||
@@ -1303,6 +1306,16 @@ USBthread (void *arg)
|
||||
else if (m == EV_EXEC_FINISHED)
|
||||
if (c->icc_state == ICC_STATE_EXECUTE)
|
||||
{
|
||||
if (c->a->sw == GPG_THREAD_TERMINATED)
|
||||
{
|
||||
c->sw1sw2[0] = 0x90;
|
||||
c->sw1sw2[1] = 0x00;
|
||||
c->state = APDU_STATE_RESULT;
|
||||
icc_send_data_block (c, 0);
|
||||
c->icc_state = ICC_STATE_EXITED;
|
||||
break;
|
||||
}
|
||||
|
||||
c->a->cmd_apdu_data_len = 0;
|
||||
c->sw1sw2[0] = c->a->sw >> 8;
|
||||
c->sw1sw2[1] = c->a->sw & 0xff;
|
||||
|
||||
@@ -372,7 +372,7 @@ void msc_handle_command (void)
|
||||
msc_send_result (buf, 12);
|
||||
return;
|
||||
case SCSI_START_STOP_UNIT:
|
||||
if (CBW.CBWCB[4] == 0x00 /* stop */
|
||||
if (CBW.CBWCB[4] == 0x00 /* stop */
|
||||
|| CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
|
||||
{
|
||||
msc_scsi_stop (CBW.CBWCB[4]);
|
||||
@@ -380,7 +380,7 @@ void msc_handle_command (void)
|
||||
contingent_allegiance = 1;
|
||||
keep_contingent_allegiance = 1;
|
||||
}
|
||||
/* CBW.CBWCB[4] == 0x01 *//* start */
|
||||
/* CBW.CBWCB[4] == 0x01 *//* start */
|
||||
goto success;
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
if (contingent_allegiance)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef __USB_CONF_H
|
||||
#define __USB_CONF_H
|
||||
|
||||
#define NUM_STRING_DESC 4
|
||||
#define NUM_STRING_DESC 7
|
||||
|
||||
/* Control pipe */
|
||||
/* EP0 */
|
||||
|
||||
454
src/usb_ctrl.c
Normal file
454
src/usb_ctrl.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
*
|
||||
* Gnuk is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Packet size of USB Bulk transfer for full speed */
|
||||
#define GNUK_MAX_PACKET_SIZE 64
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb_conf.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#include "usb-cdc.h"
|
||||
|
||||
struct line_coding
|
||||
{
|
||||
uint32_t bitrate;
|
||||
uint8_t format;
|
||||
uint8_t paritytype;
|
||||
uint8_t datatype;
|
||||
};
|
||||
|
||||
static struct line_coding line_coding = {
|
||||
115200, /* baud rate: 115200 */
|
||||
0x00, /* stop bits: 1 */
|
||||
0x00, /* parity: none */
|
||||
0x08 /* bits: 8 */
|
||||
};
|
||||
|
||||
static int
|
||||
vcom_port_data_setup (uint8_t req, uint8_t req_no)
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
|
||||
{
|
||||
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else /* USB_SETUP_SET (req) */
|
||||
{
|
||||
if (req_no == USB_CDC_REQ_SET_LINE_CODING)
|
||||
{
|
||||
usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||
/* Do nothing and success */
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
#define VCOM_NUM_INTERFACES 2
|
||||
#else
|
||||
#define VCOM_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
#include "usb-msc.h"
|
||||
#define MSC_NUM_INTERFACES 1
|
||||
#else
|
||||
#define MSC_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#define NUM_INTERFACES (1+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
||||
#define MSC_INTERFACE_NO (1+VCOM_NUM_INTERFACES)
|
||||
|
||||
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
|
||||
|
||||
static void
|
||||
gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
|
||||
{
|
||||
if (interface == 0)
|
||||
{
|
||||
if (!stop)
|
||||
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, ENDP1_TXADDR,
|
||||
GNUK_MAX_PACKET_SIZE);
|
||||
else
|
||||
{
|
||||
usb_lld_stall_rx (ENDP1);
|
||||
usb_lld_stall_tx (ENDP1);
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (interface == 1)
|
||||
{
|
||||
if (!stop)
|
||||
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
|
||||
else
|
||||
usb_lld_stall_tx (ENDP4);
|
||||
}
|
||||
else if (interface == 2)
|
||||
{
|
||||
if (!stop)
|
||||
{
|
||||
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
|
||||
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
|
||||
VIRTUAL_COM_PORT_DATA_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_lld_stall_tx (ENDP3);
|
||||
usb_lld_stall_rx (ENDP5);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (interface == MSC_INTERFACE_NO)
|
||||
{
|
||||
if (!stop)
|
||||
{
|
||||
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
|
||||
ENDP6_RXADDR, ENDP6_TXADDR, 64);
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_lld_stall_tx (ENDP6);
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_reset (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Set DEVICE as not configured */
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (Config_Descriptor.Descriptor[7]);
|
||||
|
||||
usb_lld_reset ();
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
|
||||
GNUK_MAX_PACKET_SIZE);
|
||||
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i, 0);
|
||||
|
||||
bDeviceState = ATTACHED;
|
||||
}
|
||||
|
||||
#define USB_CCID_REQ_ABORT 0x01
|
||||
#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02
|
||||
#define USB_CCID_REQ_GET_DATA_RATES 0x03
|
||||
|
||||
static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
|
||||
|
||||
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
|
||||
|
||||
#if defined(PINPAD_DND_SUPPORT)
|
||||
static const uint8_t lun_table[] = { 0, 0, 0, 0, };
|
||||
#endif
|
||||
|
||||
static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, };
|
||||
|
||||
#define USB_FSIJ_GNUK_MEMINFO 0
|
||||
#define USB_FSIJ_GNUK_DOWNLOAD 1
|
||||
#define USB_FSIJ_GNUK_EXEC 2
|
||||
|
||||
static uint32_t rbit (uint32_t v)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
|
||||
return r;
|
||||
}
|
||||
|
||||
/* After calling this function, CRC module remain enabled. */
|
||||
static int download_check_crc32 (const uint32_t *end_p)
|
||||
{
|
||||
uint32_t crc32 = *end_p;
|
||||
const uint32_t *p;
|
||||
|
||||
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
||||
CRC->CR = CRC_CR_RESET;
|
||||
|
||||
for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
|
||||
CRC->DR = rbit (*p);
|
||||
|
||||
if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
|
||||
return USB_SUCCESS;
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int
|
||||
gnuk_setup (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == USB_FSIJ_GNUK_MEMINFO)
|
||||
{
|
||||
usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else /* SETUP_SET */
|
||||
{
|
||||
uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
|
||||
|
||||
if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
|
||||
{
|
||||
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (addr < &_regnual_start || addr + len > &__heap_end__)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (index + len < 256)
|
||||
memset (addr + index + len, 0, 256 - (index + len));
|
||||
|
||||
usb_lld_set_data_to_recv (addr, len);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
|
||||
{
|
||||
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (((uint32_t)addr & 0x03))
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
return download_check_crc32 ((uint32_t *)addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
||||
if (index == 0)
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
|
||||
{
|
||||
usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
|
||||
{
|
||||
usb_lld_set_data_to_send (data_rate_table,
|
||||
sizeof (data_rate_table));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (req_no == USB_CCID_REQ_ABORT)
|
||||
/* wValue: bSeq, bSlot */
|
||||
/* Abortion is not supported in Gnuk */
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (index == 1)
|
||||
return vcom_port_data_setup (req, req_no);
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (index == MSC_INTERFACE_NO)
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == MSC_GET_MAX_LUN_COMMAND)
|
||||
{
|
||||
usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
|
||||
/* Should call resetting MSC thread, something like msc_reset() */
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static void gnuk_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index,
|
||||
uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
|
||||
&& USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
|
||||
{
|
||||
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
||||
return;
|
||||
|
||||
(void)value; (void)index;
|
||||
usb_lld_prepare_shutdown (); /* No further USB communication */
|
||||
*icc_state_p = ICC_STATE_EXEC_REQUESTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
{
|
||||
(void)index;
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
|
||||
Device_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
|
||||
Config_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
uint8_t desc_index = value & 0xff;
|
||||
|
||||
if (desc_index < NUM_STRING_DESC)
|
||||
{
|
||||
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
|
||||
String_Descriptors[desc_index].Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_usb_event (uint8_t event_type, uint16_t value)
|
||||
{
|
||||
int i;
|
||||
uint8_t current_conf;
|
||||
|
||||
switch (event_type)
|
||||
{
|
||||
case USB_EVENT_ADDRESS:
|
||||
bDeviceState = ADDRESSED;
|
||||
return USB_SUCCESS;
|
||||
case USB_EVENT_CONFIG:
|
||||
current_conf = usb_lld_current_configuration ();
|
||||
if (current_conf == 0)
|
||||
{
|
||||
if (value != 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
usb_lld_set_configuration (value);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i, 0);
|
||||
bDeviceState = CONFIGURED;
|
||||
}
|
||||
else if (current_conf != value)
|
||||
{
|
||||
if (value != 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
usb_lld_set_configuration (0);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i, 1);
|
||||
bDeviceState = ADDRESSED;
|
||||
}
|
||||
/* Do nothing when current_conf == value */
|
||||
return USB_SUCCESS;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
{
|
||||
static uint8_t zero = 0;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case USB_SET_INTERFACE:
|
||||
if (alt != 0)
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
{
|
||||
gnuk_setup_endpoints_for_interface (interface, 0);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
case USB_GET_INTERFACE:
|
||||
usb_lld_set_data_to_send (&zero, 1);
|
||||
return USB_SUCCESS;
|
||||
|
||||
default:
|
||||
case USB_QUERY_INTERFACE:
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to USB core
|
||||
*/
|
||||
|
||||
const struct usb_device_method Device_Method = {
|
||||
gnuk_device_reset,
|
||||
gnuk_ctrl_write_finish,
|
||||
gnuk_setup,
|
||||
gnuk_get_descriptor,
|
||||
gnuk_usb_event,
|
||||
gnuk_interface,
|
||||
};
|
||||
|
||||
CH_IRQ_HANDLER (Vector90)
|
||||
{
|
||||
CH_IRQ_PROLOGUE();
|
||||
chSysLockFromIsr();
|
||||
|
||||
usb_interrupt_handler ();
|
||||
|
||||
chSysUnlockFromIsr();
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "sys.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb_conf.h"
|
||||
#include "usb-cdc.h"
|
||||
@@ -253,20 +254,20 @@ static const uint8_t gnukStringLangID[] = {
|
||||
0x09, 0x04 /* LangID = 0x0409: US-English */
|
||||
};
|
||||
|
||||
#include "usb-string-vendor-product.c.inc"
|
||||
#define USB_STRINGS_FOR_GNUK 1
|
||||
#include "usb-strings.c.inc"
|
||||
|
||||
const uint8_t gnukStringSerial[] = {
|
||||
18*2+2, /* bLength */
|
||||
19*2+2, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
/* FSIJ-0.18 */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
|
||||
'0', 0, '.', 0, '1', 0, '8', 0, /* Version number of Gnuk */
|
||||
/* FSIJ-1.0 */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
|
||||
'1', 0, '.', 0, '0', 0, '.', 0, '1', 0, /* Version number of Gnuk */
|
||||
'-', 0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
|
||||
const struct Descriptor Device_Descriptor = {
|
||||
gnukDeviceDescriptor,
|
||||
sizeof (gnukDeviceDescriptor)
|
||||
@@ -282,4 +283,7 @@ const struct Descriptor String_Descriptors[NUM_STRING_DESC] = {
|
||||
{gnukStringVendor, sizeof (gnukStringVendor)},
|
||||
{gnukStringProduct, sizeof (gnukStringProduct)},
|
||||
{gnukStringSerial, sizeof (gnukStringSerial)},
|
||||
{gnuk_revision_detail, sizeof (gnuk_revision_detail)},
|
||||
{gnuk_config_options, sizeof (gnuk_config_options)},
|
||||
{sys_version, sizeof (sys_version)},
|
||||
};
|
||||
|
||||
308
src/usb_lld.c
308
src/usb_lld.c
@@ -1,11 +1,14 @@
|
||||
#ifdef FREE_STANDING
|
||||
#include "types.h"
|
||||
#else
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#endif
|
||||
#include "sys.h"
|
||||
#include "usb_lld.h"
|
||||
|
||||
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
|
||||
|
||||
#define RECIPIENT 0x1F /* Mask to get recipient */
|
||||
|
||||
enum STANDARD_REQUESTS
|
||||
{
|
||||
GET_STATUS = 0,
|
||||
@@ -27,16 +30,15 @@ enum STANDARD_REQUESTS
|
||||
/* The state machine states of a control pipe */
|
||||
enum CONTROL_STATE
|
||||
{
|
||||
WAIT_SETUP, /* 0 */
|
||||
SETTING_UP, /* 1 */
|
||||
IN_DATA, /* 2 */
|
||||
OUT_DATA, /* 3 */
|
||||
LAST_IN_DATA, /* 4 */
|
||||
LAST_OUT_DATA, /* 5 */
|
||||
WAIT_STATUS_IN, /* 7 */
|
||||
WAIT_STATUS_OUT, /* 8 */
|
||||
STALLED, /* 9 */
|
||||
PAUSE /* 10 */
|
||||
WAIT_SETUP,
|
||||
SETTING_UP,
|
||||
IN_DATA,
|
||||
OUT_DATA,
|
||||
LAST_IN_DATA,
|
||||
WAIT_STATUS_IN,
|
||||
WAIT_STATUS_OUT,
|
||||
STALLED,
|
||||
PAUSE
|
||||
};
|
||||
|
||||
enum FEATURE_SELECTOR
|
||||
@@ -69,9 +71,15 @@ struct DEVICE_INFO
|
||||
uint8_t state;
|
||||
};
|
||||
|
||||
static struct CONTROL_INFO *ctrl_p;
|
||||
static struct DEVICE_INFO *dev_p;
|
||||
static struct DATA_INFO *data_p;
|
||||
static struct CONTROL_INFO control_info;
|
||||
static struct DEVICE_INFO device_info;
|
||||
static struct DATA_INFO data_info;
|
||||
extern const struct usb_device_method Device_Method;
|
||||
|
||||
static struct CONTROL_INFO *const ctrl_p = &control_info;
|
||||
static struct DEVICE_INFO *const dev_p = &device_info;
|
||||
static struct DATA_INFO *const data_p = &data_info;
|
||||
static const struct usb_device_method *const method_p = &Device_Method;
|
||||
|
||||
#define REG_BASE (0x40005C00UL) /* USB_IP Peripheral Registers base address */
|
||||
#define PMA_ADDR (0x40006000UL) /* USB_IP Packet Memory Area base address */
|
||||
@@ -350,9 +358,37 @@ static void st103_ep_clear_dtog_tx (uint8_t ep_num)
|
||||
}
|
||||
}
|
||||
|
||||
static const struct usb_device_method* method_p;
|
||||
void usb_lld_init (uint8_t feature)
|
||||
{
|
||||
usb_lld_sys_init ();
|
||||
|
||||
static void
|
||||
dev_p->state = IN_DATA;
|
||||
|
||||
usb_lld_set_configuration (0);
|
||||
usb_lld_set_feature (feature);
|
||||
|
||||
/* Reset USB */
|
||||
st103_set_cntr (CNTR_FRES);
|
||||
st103_set_cntr (0);
|
||||
|
||||
/* Clear Interrupt Status Register, and enable interrupt for USB */
|
||||
st103_set_istr (0);
|
||||
st103_set_cntr (CNTR_CTRM | CNTR_RESETM);
|
||||
}
|
||||
|
||||
void usb_lld_prepare_shutdown (void)
|
||||
{
|
||||
st103_set_istr (0);
|
||||
st103_set_cntr (0);
|
||||
}
|
||||
|
||||
void usb_lld_shutdown (void)
|
||||
{
|
||||
st103_set_cntr (CNTR_PDWN);
|
||||
usb_lld_sys_shutdown ();
|
||||
}
|
||||
|
||||
void
|
||||
usb_interrupt_handler (void)
|
||||
{
|
||||
uint16_t istr_value = st103_get_istr ();
|
||||
@@ -373,51 +409,33 @@ usb_interrupt_handler (void)
|
||||
st103_set_istr (CLR_ERR);
|
||||
}
|
||||
|
||||
CH_IRQ_HANDLER (Vector90) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
chSysLockFromIsr();
|
||||
|
||||
usb_interrupt_handler ();
|
||||
|
||||
chSysUnlockFromIsr();
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
static void handle_datastage_out (void)
|
||||
{
|
||||
if (data_p->addr && data_p->len)
|
||||
{
|
||||
uint8_t *buf;
|
||||
uint32_t len = USB_MAX_PACKET_SIZE;
|
||||
uint32_t len = st103_get_rx_count (ENDP0);
|
||||
|
||||
if (len > data_p->len)
|
||||
len = data_p->len;
|
||||
|
||||
buf = data_p->addr + data_p->offset;
|
||||
usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len);
|
||||
data_p->len -= len;
|
||||
data_p->offset += len;
|
||||
|
||||
usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len);
|
||||
}
|
||||
|
||||
if (data_p->len != 0)
|
||||
if (data_p->len == 0)
|
||||
{
|
||||
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
dev_p->state = WAIT_STATUS_IN;
|
||||
st103_set_tx_count (ENDP0, 0);
|
||||
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
|
||||
}
|
||||
|
||||
if (data_p->len >= USB_MAX_PACKET_SIZE)
|
||||
dev_p->state = OUT_DATA;
|
||||
else
|
||||
if (data_p->len > 0)
|
||||
dev_p->state = LAST_OUT_DATA;
|
||||
else if (data_p->len == 0)
|
||||
{
|
||||
dev_p->state = WAIT_STATUS_IN;
|
||||
st103_set_tx_count (ENDP0, 0);
|
||||
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
{
|
||||
dev_p->state = OUT_DATA;
|
||||
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_datastage_in (void)
|
||||
@@ -433,14 +451,15 @@ static void handle_datastage_in (void)
|
||||
|
||||
/* No more data to send. Send empty packet */
|
||||
st103_set_tx_count (ENDP0, 0);
|
||||
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No more data to send. Thus, STALL the TX Status*/
|
||||
/* No more data to send, proceed to receive OUT acknowledge.*/
|
||||
dev_p->state = WAIT_STATUS_OUT;
|
||||
st103_ep_set_tx_status (ENDP0, EP_TX_STALL);
|
||||
st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_STALL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -451,32 +470,33 @@ static void handle_datastage_in (void)
|
||||
|
||||
buf = (const uint8_t *)data_p->addr + data_p->offset;
|
||||
usb_lld_to_pmabuf (buf, st103_get_tx_addr (ENDP0), len);
|
||||
st103_set_tx_count (ENDP0, len);
|
||||
|
||||
data_p->len -= len;
|
||||
data_p->offset += len;
|
||||
st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID);
|
||||
st103_set_tx_count (ENDP0, len);
|
||||
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
|
||||
typedef int (*HANDLER) (uint8_t rcp,
|
||||
typedef int (*HANDLER) (uint8_t req,
|
||||
uint16_t value, uint16_t index, uint16_t length);
|
||||
|
||||
static int std_none (uint8_t rcp,
|
||||
static int std_none (uint8_t req,
|
||||
uint16_t value, uint16_t index, uint16_t length)
|
||||
{
|
||||
(void)rcp; (void)value; (void)index; (void)length;
|
||||
(void)req; (void)value; (void)index; (void)length;
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_get_status (uint8_t rcp,
|
||||
static int std_get_status (uint8_t req,
|
||||
uint16_t value, uint16_t index, uint16_t length)
|
||||
{
|
||||
static uint16_t status_info;
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
status_info = 0; /* Reset Status Information */
|
||||
data_p->addr = (uint8_t *)&status_info;
|
||||
|
||||
if (value != 0 || length != 2 || (index >> 8) != 0)
|
||||
if (value != 0 || length != 2 || (index >> 8) != 0
|
||||
|| (req & REQUEST_DIR) == 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
@@ -548,9 +568,14 @@ static int std_get_status (uint8_t rcp,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_clear_feature (uint8_t rcp, uint16_t value,
|
||||
static int std_clear_feature (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (length != 0 || index != 0)
|
||||
@@ -582,22 +607,10 @@ static int std_clear_feature (uint8_t rcp, uint16_t value,
|
||||
if (status == 0) /* Disabled */
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (index & 0x80)
|
||||
{ /* IN endpoint */
|
||||
if (st103_ep_get_tx_status (endpoint) == EP_TX_STALL)
|
||||
{
|
||||
st103_ep_clear_dtog_tx (endpoint);
|
||||
st103_ep_set_tx_status (endpoint, EP_TX_VALID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* OUT endpoint */
|
||||
if (st103_ep_get_rx_status (endpoint) == EP_RX_STALL)
|
||||
{
|
||||
st103_ep_clear_dtog_rx (endpoint);
|
||||
st103_ep_set_rx_status (endpoint, EP_RX_VALID);
|
||||
}
|
||||
}
|
||||
if (index & 0x80) /* IN endpoint */
|
||||
st103_ep_clear_dtog_tx (endpoint);
|
||||
else /* OUT endpoint */
|
||||
st103_ep_clear_dtog_rx (endpoint);
|
||||
|
||||
// event??
|
||||
return USB_SUCCESS;
|
||||
@@ -606,9 +619,14 @@ static int std_clear_feature (uint8_t rcp, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_set_feature (uint8_t rcp, uint16_t value,
|
||||
static int std_set_feature (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (length != 0 || index != 0)
|
||||
@@ -654,9 +672,14 @@ static int std_set_feature (uint8_t rcp, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_set_address (uint8_t rcp, uint16_t value,
|
||||
static int std_set_address (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (length == 0 && value <= 127 && index == 0
|
||||
@@ -667,9 +690,14 @@ static int std_set_address (uint8_t rcp, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_get_descriptor (uint8_t rcp, uint16_t value,
|
||||
static int std_get_descriptor (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
(void)length;
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
return (*method_p->get_descriptor) ((value >> 8), index, value);
|
||||
@@ -677,9 +705,14 @@ static int std_get_descriptor (uint8_t rcp, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_get_configuration (uint8_t rcp, uint16_t value,
|
||||
static int std_get_configuration (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
(void)value; (void)index; (void)length;
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
@@ -691,9 +724,14 @@ static int std_get_configuration (uint8_t rcp, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_set_configuration (uint8_t rcp, uint16_t value,
|
||||
static int std_set_configuration (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0)
|
||||
{
|
||||
int r;
|
||||
@@ -706,9 +744,14 @@ static int std_set_configuration (uint8_t rcp, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_get_interface (uint8_t rcp, uint16_t value,
|
||||
static int std_get_interface (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (rcp == INTERFACE_RECIPIENT)
|
||||
{
|
||||
if (value != 0 || (index >> 8) != 0 || length != 1)
|
||||
@@ -723,9 +766,14 @@ static int std_get_interface (uint8_t rcp, uint16_t value,
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int std_set_interface (uint8_t rcp, uint16_t value,
|
||||
static int std_set_interface (uint8_t req, uint16_t value,
|
||||
uint16_t index, uint16_t length)
|
||||
{
|
||||
uint8_t rcp = req & RECIPIENT;
|
||||
|
||||
if ((req & REQUEST_DIR) == 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (rcp == INTERFACE_RECIPIENT)
|
||||
{
|
||||
int r;
|
||||
@@ -767,7 +815,6 @@ static void handle_setup0 (void)
|
||||
uint8_t req;
|
||||
int r = USB_UNSUPPORT;
|
||||
HANDLER handler;
|
||||
uint8_t type_rcp;
|
||||
|
||||
pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2));
|
||||
w = *pw++;
|
||||
@@ -781,63 +828,53 @@ static void handle_setup0 (void)
|
||||
pw++;
|
||||
ctrl_p->wLength = *pw;
|
||||
|
||||
dev_p->state = STALLED;
|
||||
data_p->addr = NULL;
|
||||
data_p->len = 0;
|
||||
data_p->offset = 0;
|
||||
|
||||
type_rcp = (ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT));
|
||||
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) /* Interface */
|
||||
|| (ctrl_p->bmRequestType & REQUEST_TYPE) == VENDOR_REQUEST)
|
||||
{
|
||||
if (ctrl_p->wLength == 0)
|
||||
r = (*method_p->setup_with_nodata) (type_rcp, req, ctrl_p->wIndex);
|
||||
else
|
||||
{
|
||||
(*method_p->setup_with_data) (type_rcp, req, ctrl_p->wIndex);
|
||||
if (data_p->len != 0)
|
||||
r = USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
|
||||
if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
|
||||
{
|
||||
if (req < TOTAL_REQUEST)
|
||||
{
|
||||
handler = std_request_handler[req];
|
||||
r = (*handler) (ctrl_p->bmRequestType & RECIPIENT,
|
||||
r = (*handler) (ctrl_p->bmRequestType,
|
||||
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
r = (*method_p->setup) (ctrl_p->bmRequestType, req,
|
||||
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
|
||||
|
||||
if (r != USB_SUCCESS)
|
||||
dev_p->state = STALLED;
|
||||
else
|
||||
{
|
||||
if (ctrl_p->wLength == 0)
|
||||
{
|
||||
dev_p->state = WAIT_STATUS_IN;
|
||||
st103_set_tx_count (ENDP0, 0);
|
||||
st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
else if (ctrl_p->bmRequestType & 0x80)
|
||||
if (USB_SETUP_GET (ctrl_p->bmRequestType))
|
||||
{
|
||||
uint32_t len = ctrl_p->wLength;
|
||||
|
||||
|
||||
/* Restrict the data length to be the one host asks for */
|
||||
if (data_p->len > len)
|
||||
data_p->len = len;
|
||||
|
||||
|
||||
if ((data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = TRUE;
|
||||
else
|
||||
data_p->require_zlp = FALSE;
|
||||
|
||||
dev_p->state = IN_DATA;
|
||||
handle_datastage_in ();
|
||||
}
|
||||
else if (ctrl_p->wLength == 0)
|
||||
{
|
||||
dev_p->state = WAIT_STATUS_IN;
|
||||
st103_set_tx_count (ENDP0, 0);
|
||||
st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
dev_p->state = OUT_DATA;
|
||||
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
/* enable for next data reception */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -855,6 +892,11 @@ static void handle_in0 (void)
|
||||
st103_set_daddr (ctrl_p->wValue);
|
||||
(*method_p->event) (USB_EVENT_ADDRESS, ctrl_p->wValue);
|
||||
}
|
||||
else
|
||||
(*method_p->ctrl_write_finish) (ctrl_p->bmRequestType,
|
||||
ctrl_p->bRequest, ctrl_p->wValue,
|
||||
ctrl_p->wIndex, ctrl_p->wLength);
|
||||
|
||||
dev_p->state = STALLED;
|
||||
}
|
||||
else
|
||||
@@ -866,7 +908,7 @@ static void handle_out0 (void)
|
||||
if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
|
||||
/* host aborts the transfer before finish */
|
||||
dev_p->state = STALLED;
|
||||
else if (dev_p->state == OUT_DATA || dev_p->state == LAST_OUT_DATA)
|
||||
else if (dev_p->state == OUT_DATA)
|
||||
handle_datastage_out ();
|
||||
else if (dev_p->state == WAIT_STATUS_OUT)
|
||||
dev_p->state = STALLED;
|
||||
@@ -879,7 +921,7 @@ static void nop_proc (void)
|
||||
{
|
||||
}
|
||||
|
||||
#define WEAK __attribute__ ((weak))
|
||||
#define WEAK __attribute__ ((weak, alias ("nop_proc")))
|
||||
void WEAK EP1_IN_Callback (void);
|
||||
void WEAK EP2_IN_Callback (void);
|
||||
void WEAK EP3_IN_Callback (void);
|
||||
@@ -896,22 +938,6 @@ void WEAK EP5_OUT_Callback (void);
|
||||
void WEAK EP6_OUT_Callback (void);
|
||||
void WEAK EP7_OUT_Callback (void);
|
||||
|
||||
#pragma weak EP1_IN_Callback = nop_proc
|
||||
#pragma weak EP2_IN_Callback = nop_proc
|
||||
#pragma weak EP3_IN_Callback = nop_proc
|
||||
#pragma weak EP4_IN_Callback = nop_proc
|
||||
#pragma weak EP5_IN_Callback = nop_proc
|
||||
#pragma weak EP6_IN_Callback = nop_proc
|
||||
#pragma weak EP7_IN_Callback = nop_proc
|
||||
|
||||
#pragma weak EP1_OUT_Callback = nop_proc
|
||||
#pragma weak EP2_OUT_Callback = nop_proc
|
||||
#pragma weak EP3_OUT_Callback = nop_proc
|
||||
#pragma weak EP4_OUT_Callback = nop_proc
|
||||
#pragma weak EP5_OUT_Callback = nop_proc
|
||||
#pragma weak EP6_OUT_Callback = nop_proc
|
||||
#pragma weak EP7_OUT_Callback = nop_proc
|
||||
|
||||
void (*const ep_intr_handler_IN[7]) (void) = {
|
||||
EP1_IN_Callback,
|
||||
EP2_IN_Callback,
|
||||
@@ -994,46 +1020,12 @@ usb_handle_transfer (void)
|
||||
}
|
||||
}
|
||||
|
||||
static struct CONTROL_INFO Control_Info;
|
||||
static struct DEVICE_INFO Device_Info;
|
||||
static struct DATA_INFO Data_Info;
|
||||
|
||||
void usb_lld_reset (void)
|
||||
{
|
||||
st103_set_btable ();
|
||||
st103_set_daddr (0);
|
||||
}
|
||||
|
||||
void usb_lld_init (void)
|
||||
{
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
NVICEnableVector (USB_LP_CAN1_RX0_IRQn,
|
||||
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
|
||||
/*
|
||||
* Note that we also have other IRQ(s):
|
||||
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
|
||||
* USBWakeUp_IRQn (suspend/resume)
|
||||
*/
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
|
||||
dev_p = &Device_Info;
|
||||
ctrl_p = &Control_Info;
|
||||
data_p = &Data_Info;
|
||||
dev_p->state = IN_DATA;
|
||||
method_p = &Device_Method;
|
||||
|
||||
method_p->init();
|
||||
|
||||
/* Reset USB */
|
||||
st103_set_cntr (CNTR_FRES);
|
||||
st103_set_cntr (0);
|
||||
|
||||
/* Clear Interrupt Status Register, and enable interrupt for USB */
|
||||
st103_set_istr (0);
|
||||
st103_set_cntr (CNTR_CTRM | CNTR_RESETM);
|
||||
}
|
||||
|
||||
void usb_lld_txcpy (const void *src,
|
||||
int ep_num, int offset, size_t len)
|
||||
{
|
||||
|
||||
@@ -39,10 +39,15 @@ enum DESCRIPTOR_TYPE
|
||||
ENDPOINT_DESCRIPTOR
|
||||
};
|
||||
|
||||
#define REQUEST_DIR 0x80 /* Mask to get request dir */
|
||||
#define REQUEST_TYPE 0x60 /* Mask to get request type */
|
||||
#define STANDARD_REQUEST 0x00 /* Standard request */
|
||||
#define CLASS_REQUEST 0x20 /* Class request */
|
||||
#define VENDOR_REQUEST 0x40 /* Vendor request */
|
||||
#define RECIPIENT 0x1F /* Mask to get recipient */
|
||||
|
||||
#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0)
|
||||
#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0)
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
@@ -58,17 +63,17 @@ enum
|
||||
|
||||
struct usb_device_method
|
||||
{
|
||||
void (*init) (void);
|
||||
void (*reset) (void);
|
||||
void (*setup_with_data) (uint8_t rcp, uint8_t req_no, uint16_t index);
|
||||
int (*setup_with_nodata) (uint8_t rcp, uint8_t req_no, uint16_t index);
|
||||
void (*ctrl_write_finish) (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len);
|
||||
int (*setup) (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len);
|
||||
int (*get_descriptor) (uint8_t desc_type, uint16_t index, uint16_t value);
|
||||
int (*event) (uint8_t event_type, uint16_t value);
|
||||
int (*interface) (uint8_t cmd, uint16_t interface, uint16_t value);
|
||||
};
|
||||
|
||||
enum {
|
||||
USB_EVENT_RESET,
|
||||
USB_EVENT_ADDRESS,
|
||||
USB_EVENT_CONFIG,
|
||||
USB_EVENT_SUSPEND,
|
||||
@@ -104,7 +109,7 @@ extern uint32_t bDeviceState;
|
||||
|
||||
#define STM32_USB_IRQ_PRIORITY 11
|
||||
|
||||
extern void usb_lld_init (void);
|
||||
extern void usb_lld_init (uint8_t feature);
|
||||
|
||||
extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
|
||||
|
||||
@@ -141,3 +146,13 @@ extern uint8_t usb_lld_current_configuration (void);
|
||||
extern void usb_lld_set_feature (uint8_t feature);
|
||||
|
||||
extern void usb_lld_set_data_to_send (const void *p, size_t len);
|
||||
|
||||
extern inline void usb_lld_set_data_to_recv (void *p, size_t len)
|
||||
{
|
||||
usb_lld_set_data_to_send ((const void *)p, len);
|
||||
}
|
||||
|
||||
extern void usb_lld_prepare_shutdown (void);
|
||||
extern void usb_lld_shutdown (void);
|
||||
|
||||
extern void usb_interrupt_handler (void);
|
||||
|
||||
342
src/usb_prop.c
342
src/usb_prop.c
@@ -1,342 +0,0 @@
|
||||
/*
|
||||
* usb_prop.c - interface code between Gnuk and USB
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
*
|
||||
* Gnuk is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Packet size of USB Bulk transfer for full speed */
|
||||
#define GNUK_MAX_PACKET_SIZE 64
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb_conf.h"
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#include "usb-cdc.h"
|
||||
|
||||
struct line_coding
|
||||
{
|
||||
uint32_t bitrate;
|
||||
uint8_t format;
|
||||
uint8_t paritytype;
|
||||
uint8_t datatype;
|
||||
};
|
||||
|
||||
static const struct line_coding line_coding = {
|
||||
115200, /* baud rate: 115200 */
|
||||
0x00, /* stop bits: 1 */
|
||||
0x00, /* parity: none */
|
||||
0x08 /* bits: 8 */
|
||||
};
|
||||
|
||||
static void
|
||||
vcom_port_data_setup (uint8_t RequestNo)
|
||||
{
|
||||
if (RequestNo != USB_CDC_REQ_GET_LINE_CODING)
|
||||
return;
|
||||
|
||||
/* RequestNo == USB_CDC_REQ_SET_LINE_CODING is not supported */
|
||||
|
||||
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
|
||||
}
|
||||
|
||||
static int
|
||||
vcom_port_setup_with_nodata (uint8_t RequestNo)
|
||||
{
|
||||
if (RequestNo == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||
/* Do nothing and success */
|
||||
return USB_SUCCESS;
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
#define VCOM_NUM_INTERFACES 2
|
||||
#else
|
||||
#define VCOM_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
#include "usb-msc.h"
|
||||
#define MSC_NUM_INTERFACES 1
|
||||
#else
|
||||
#define MSC_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#define NUM_INTERFACES (1+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
||||
#define MSC_INTERFACE_NO (1+VCOM_NUM_INTERFACES)
|
||||
|
||||
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
|
||||
|
||||
static void
|
||||
gnuk_device_init (void)
|
||||
{
|
||||
usb_lld_set_configuration (0);
|
||||
USB_Cable_Config (1);
|
||||
bDeviceState = UNCONNECTED;
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_setup_endpoints_for_interface (uint16_t interface)
|
||||
{
|
||||
if (interface == 0)
|
||||
{
|
||||
/* Initialize Endpoint 1 */
|
||||
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, ENDP1_TXADDR,
|
||||
GNUK_MAX_PACKET_SIZE);
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (interface == 1)
|
||||
{
|
||||
/* Initialize Endpoint 4 */
|
||||
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
|
||||
}
|
||||
else if (interface == 2)
|
||||
{
|
||||
/* Initialize Endpoint 3 */
|
||||
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
|
||||
|
||||
/* Initialize Endpoint 5 */
|
||||
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
|
||||
VIRTUAL_COM_PORT_DATA_SIZE);
|
||||
}
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (interface == MSC_INTERFACE_NO)
|
||||
{
|
||||
/* Initialize Endpoint 6 */
|
||||
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0, ENDP6_RXADDR, ENDP6_TXADDR,
|
||||
64);
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_reset (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Set DEVICE as not configured */
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (Config_Descriptor.Descriptor[7]);
|
||||
|
||||
usb_lld_reset ();
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
|
||||
GNUK_MAX_PACKET_SIZE);
|
||||
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i);
|
||||
|
||||
bDeviceState = ATTACHED;
|
||||
}
|
||||
|
||||
#define USB_CCID_REQ_ABORT 0x01
|
||||
#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02
|
||||
#define USB_CCID_REQ_GET_DATA_RATES 0x03
|
||||
|
||||
static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
|
||||
|
||||
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
|
||||
|
||||
#if defined(PINPAD_DND_SUPPORT)
|
||||
static const uint8_t lun_table[] = { 0, 0, 0, 0, };
|
||||
#endif
|
||||
|
||||
static void
|
||||
gnuk_setup_with_data (uint8_t recipient, uint8_t RequestNo, uint16_t index)
|
||||
{
|
||||
if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
|
||||
usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
|
||||
else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES)
|
||||
usb_lld_set_data_to_send (data_rate_table, sizeof (data_rate_table));
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (index == 1)
|
||||
vcom_port_data_setup (RequestNo);
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (index == MSC_INTERFACE_NO)
|
||||
{
|
||||
if (RequestNo == MSC_GET_MAX_LUN_COMMAND)
|
||||
usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gnuk_setup_with_nodata (uint8_t recipient, uint8_t RequestNo, uint16_t index)
|
||||
{
|
||||
if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
|
||||
if (index == 0)
|
||||
{
|
||||
if (RequestNo == USB_CCID_REQ_ABORT)
|
||||
/* wValue: bSeq, bSlot */
|
||||
/* Abortion is not supported in Gnuk */
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (index == 1)
|
||||
return vcom_port_setup_with_nodata (RequestNo);
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (index == MSC_INTERFACE_NO)
|
||||
{
|
||||
if (RequestNo == MSC_MASS_STORAGE_RESET_COMMAND)
|
||||
{
|
||||
/* Should call resetting MSC thread, something like msc_reset() */
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int
|
||||
gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
{
|
||||
(void)index;
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
|
||||
Device_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
|
||||
Config_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
uint8_t desc_index = value & 0xff;
|
||||
|
||||
if (desc_index < NUM_STRING_DESC)
|
||||
{
|
||||
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
|
||||
String_Descriptors[desc_index].Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_usb_event (uint8_t event_type, uint16_t value)
|
||||
{
|
||||
switch (event_type)
|
||||
{
|
||||
case USB_EVENT_RESET:
|
||||
break;
|
||||
case USB_EVENT_ADDRESS:
|
||||
bDeviceState = ADDRESSED;
|
||||
break;
|
||||
case USB_EVENT_CONFIG:
|
||||
if (usb_lld_current_configuration () == 0)
|
||||
{
|
||||
int i;
|
||||
extern void *main_thread;
|
||||
#define LED_STATUS_MODE (8)
|
||||
|
||||
if (value != 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
usb_lld_set_configuration (value);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i);
|
||||
bDeviceState = CONFIGURED;
|
||||
chEvtSignalI (main_thread, LED_STATUS_MODE);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value != 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
usb_lld_set_configuration (0);
|
||||
// Disable all endpoints???
|
||||
bDeviceState = ADDRESSED;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
{
|
||||
static uint8_t zero = 0;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case USB_SET_INTERFACE:
|
||||
if (alt != 0)
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
{
|
||||
gnuk_setup_endpoints_for_interface (interface);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
case USB_GET_INTERFACE:
|
||||
usb_lld_set_data_to_send (&zero, 1);
|
||||
return USB_SUCCESS;
|
||||
|
||||
default:
|
||||
case USB_QUERY_INTERFACE:
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to USB core
|
||||
*/
|
||||
|
||||
const struct usb_device_method Device_Method = {
|
||||
gnuk_device_init,
|
||||
gnuk_device_reset,
|
||||
gnuk_setup_with_data,
|
||||
gnuk_setup_with_nodata,
|
||||
gnuk_get_descriptor,
|
||||
gnuk_usb_event,
|
||||
gnuk_interface,
|
||||
};
|
||||
20
test/README
Normal file
20
test/README
Normal file
@@ -0,0 +1,20 @@
|
||||
This is a functionality test suite for Gnuk.
|
||||
|
||||
You need python-nose, python-freshen as well as python-usb.
|
||||
|
||||
Besides, python-crypto is needed when you use generate_keys.py to
|
||||
update contents of *.key.
|
||||
|
||||
|
||||
Type:
|
||||
|
||||
$ nosetests --with-freshen
|
||||
|
||||
or
|
||||
|
||||
$ nosetests -v --with-freshen
|
||||
|
||||
to run the test suite.
|
||||
|
||||
To skip tests for key generation, add an option "--tag ~keygen". To
|
||||
stop running tests after the first error or failure, add "--stop" option.
|
||||
79
test/features/000_empty_check.feature
Normal file
79
test/features/000_empty_check.feature
Normal file
@@ -0,0 +1,79 @@
|
||||
Feature: confirm empty token
|
||||
In order to start tests
|
||||
A token should be empty (no data, no keys)
|
||||
|
||||
Scenario: data object Login
|
||||
When requesting login data: 5e
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Name
|
||||
When requesting name: 5b
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Language preference
|
||||
When requesting anguage preference: 5f2d
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object Sex
|
||||
When requesting sex: 5f35
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object URL
|
||||
When requesting URL: 5f50
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object ds counter
|
||||
When requesting ds counter: 93
|
||||
Then you should get: \x00\x00\x00
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
When requesting pw1 status bytes: c4
|
||||
Then you should get: \x00\x7f\x7f\x7f\x03\x03\x03
|
||||
|
||||
Scenario: data object finger print 0
|
||||
When requesting finger print: c5
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object finger print 1
|
||||
When requesting finger print: c7
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object finger print 2
|
||||
When requesting finger print: c8
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object finger print 3
|
||||
When requesting finger print: c9
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 0
|
||||
When requesting finger print: c6
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object CA finger print 1
|
||||
When requesting finger print: ca
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 2
|
||||
When requesting finger print: cb
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object CA finger print 3
|
||||
When requesting finger print: cc
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 0
|
||||
When requesting date/time of key pair: cd
|
||||
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
|
||||
|
||||
Scenario: data object date/time of key pair 1
|
||||
When requesting date/time of key pair: ce
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 2
|
||||
When requesting date/time of key pair: cf
|
||||
Then you should get NULL
|
||||
|
||||
Scenario: data object date/time of key pair 3
|
||||
When requesting date/time of key pair: d0
|
||||
Then you should get NULL
|
||||
15
test/features/001_empty_check_passphrase.feature
Normal file
15
test/features/001_empty_check_passphrase.feature
Normal file
@@ -0,0 +1,15 @@
|
||||
Feature: confirm empty token
|
||||
In order to start tests
|
||||
A token should be empty (no pass phrase)
|
||||
|
||||
Scenario: verify PW1 factory setting (1)
|
||||
Given cmd_verify with 1 and "123456"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 factory setting (2)
|
||||
Given cmd_verify with 2 and "123456"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 factory setting
|
||||
Given cmd_verify with 3 and "12345678"
|
||||
Then it should get success
|
||||
27
test/features/002_get_data_static.feature
Normal file
27
test/features/002_get_data_static.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: command GET DATA
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support all mandatory features of the specification
|
||||
|
||||
Scenario: data object historical bytes
|
||||
When requesting historical bytes: 5f52
|
||||
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00
|
||||
|
||||
Scenario: data object extended capabilities
|
||||
When requesting extended capabilities: c0
|
||||
Then data should match: \x30\x00\x00\x00[\x00\x08]\x00\x00\xff\x01\x00
|
||||
|
||||
Scenario: data object algorithm attributes 1
|
||||
When requesting algorithm attributes 1: c1
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object algorithm attributes 2
|
||||
When requesting algorithm attributes 2: c2
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object algorithm attributes 3
|
||||
When requesting algorighm attributes 3: c3
|
||||
Then you should get: \x01\x08\x00\x00\x20\x00
|
||||
|
||||
Scenario: data object AID
|
||||
When requesting AID: 4f
|
||||
Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00
|
||||
63
test/features/010_setup_passphrase.feature
Normal file
63
test/features/010_setup_passphrase.feature
Normal file
@@ -0,0 +1,63 @@
|
||||
Feature: setup pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: setup PW1 (admin-less mode)
|
||||
Given cmd_change_reference_data with 1 and "123456user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1)
|
||||
Given cmd_verify with 1 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2)
|
||||
Given cmd_verify with 2 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode)
|
||||
Given cmd_verify with 3 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-less mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-less mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-less mode) again
|
||||
Given cmd_verify with 3 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "new user pass phraseadmin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-full mode)
|
||||
Given cmd_put_data with d3 and "another reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 0 and "another reset code 000another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
27
test/features/020_personalization_write.feature
Normal file
27
test/features/020_personalization_write.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: personalize token write
|
||||
In order to use a token
|
||||
A token should be personalized with name, sex, url, etc.
|
||||
|
||||
Scenario: data object Login
|
||||
Given cmd_put_data with 5e and "gpg_user"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Name
|
||||
Given cmd_put_data with 5b and "GnuPG User"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Language preference
|
||||
Given cmd_put_data with 5f2d and "ja"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object Sex
|
||||
Given cmd_put_data with 5f35 and "1"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object URL
|
||||
Given cmd_put_data with 5f50 and "http://www.fsij.org/gnuk/"
|
||||
Then it should get success
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
Given cmd_put_data with c4 and "\x01"
|
||||
Then it should get success
|
||||
27
test/features/021_personalization_read.feature
Normal file
27
test/features/021_personalization_read.feature
Normal file
@@ -0,0 +1,27 @@
|
||||
Feature: personalize token read
|
||||
In order to use a token
|
||||
A token should be personalized with name, sex, url, etc.
|
||||
|
||||
Scenario: data object Login
|
||||
When requesting login data: 5e
|
||||
Then you should get: gpg_user
|
||||
|
||||
Scenario: data object Name
|
||||
When requesting name: 5b
|
||||
Then you should get: GnuPG User
|
||||
|
||||
Scenario: data object Language preference
|
||||
When requesting anguage preference: 5f2d
|
||||
Then you should get: ja
|
||||
|
||||
Scenario: data object Sex
|
||||
When requesting sex: 5f35
|
||||
Then you should get: 1
|
||||
|
||||
Scenario: data object URL
|
||||
When requesting URL: 5f50
|
||||
Then you should get: http://www.fsij.org/gnuk/
|
||||
|
||||
Scenario: data object pw1 status bytes
|
||||
When requesting pw1 status bytes: c4
|
||||
Then you should get: \x01\x7f\x7f\x7f\x03\x03\x03
|
||||
56
test/features/030_key_registration.feature
Normal file
56
test/features/030_key_registration.feature
Normal file
@@ -0,0 +1,56 @@
|
||||
Feature: import keys to token
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: importing OPENPGP.1 key (sign)
|
||||
Given a RSA key pair 0
|
||||
And importing it to the token as OPENPGP.1
|
||||
Then it should get success
|
||||
|
||||
Scenario: importing OPENPGP.2 key (decrypt)
|
||||
Given a RSA key pair 1
|
||||
And importing it to the token as OPENPGP.2
|
||||
Then it should get success
|
||||
|
||||
Scenario: importing OPENPGP.3 key (authentication)
|
||||
Given a RSA key pair 2
|
||||
And importing it to the token as OPENPGP.3
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print sig
|
||||
Given a fingerprint of OPENPGP.1 key
|
||||
And put the data to c7
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print dec
|
||||
Given a fingerprint of OPENPGP.2 key
|
||||
And put the data to c8
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object Finger print aut
|
||||
Given a fingerprint of OPENPGP.3 key
|
||||
And put the data to c9
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time sig
|
||||
Given a timestamp of OPENPGP.1 key
|
||||
And put the data to ce
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time dec
|
||||
Given a timestamp of OPENPGP.2 key
|
||||
And put the data to cf
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup data object keygeneration data/time aut
|
||||
Given a timestamp of OPENPGP.3 key
|
||||
And put the data to d0
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
71
test/features/040_passphrase_change.feature
Normal file
71
test/features/040_passphrase_change.feature
Normal file
@@ -0,0 +1,71 @@
|
||||
Feature: change pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
A token should support pass phrase: PW1, PW3 and reset code
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code again (in admin-full mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "admin pass phraseanother admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "another admin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by admin (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "new user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW1
|
||||
Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: change PW3 (admin-full mode)
|
||||
Given cmd_change_reference_data with 3 and "another admin pass phraseadmin pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW3 (admin-full mode)
|
||||
Given cmd_verify with 3 and "admin pass phrase"
|
||||
Then it should get success
|
||||
31
test/features/100_compute_signature.feature
Normal file
31
test/features/100_compute_signature.feature
Normal file
@@ -0,0 +1,31 @@
|
||||
Feature: compute digital signature
|
||||
In order to use a token
|
||||
A token should compute digital signature properly
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (1)
|
||||
Given a message "This is a test message."
|
||||
And let a token compute digital signature
|
||||
And compute digital signature on host with RSA key pair 0
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.1 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And let a token compute digital signature
|
||||
And compute digital signature on host with RSA key pair 0
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (1)
|
||||
Given a message "This is a test message."
|
||||
And let a token authenticate
|
||||
And compute digital signature on host with RSA key pair 2
|
||||
Then results should be same
|
||||
|
||||
Scenario: compute digital signature by OPENPGP.3 key (2)
|
||||
Given a message "This is another test message.\nMultiple lines.\n"
|
||||
And let a token authenticate
|
||||
And compute digital signature on host with RSA key pair 2
|
||||
Then results should be same
|
||||
|
||||
Scenario: data object ds counter
|
||||
When requesting ds counter: 93
|
||||
Then you should get: \x00\x00\x02
|
||||
16
test/features/101_decryption.feature
Normal file
16
test/features/101_decryption.feature
Normal file
@@ -0,0 +1,16 @@
|
||||
Feature: decryption
|
||||
In order to use a token
|
||||
A token should decrypt encrypted data
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (1)
|
||||
Given a plain text "This is a test message."
|
||||
And encrypt it on host with RSA key pair 1
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
Scenario: decrypt by OPENPGP.2 key (2)
|
||||
Given a plain text "RSA decryption is as easy as pie."
|
||||
And encrypt it on host with RSA key pair 1
|
||||
And let a token decrypt encrypted data
|
||||
Then decrypted data should be same as a plain text
|
||||
|
||||
40
test/features/200_key_removal.feature
Normal file
40
test/features/200_key_removal.feature
Normal file
@@ -0,0 +1,40 @@
|
||||
@keygen
|
||||
Feature: key removal
|
||||
In order to use a token
|
||||
A token should have keys
|
||||
|
||||
Scenario: remove OPENPGP.1 key (sign)
|
||||
When removing a key OPENPGP.1
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.2 key (decrypt)
|
||||
When removing a key OPENPGP.2
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove OPENPGP.3 key (authentication)
|
||||
When removing a key OPENPGP.3
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print sig
|
||||
Given cmd_put_data with c7 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print dec
|
||||
Given cmd_put_data with c8 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object Finger print aut
|
||||
Given cmd_put_data with c9 and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time sig
|
||||
Given cmd_put_data with ce and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time dec
|
||||
Given cmd_put_data with cf and ""
|
||||
Then it should get success
|
||||
|
||||
Scenario: remove data object keygeneration data/time aut
|
||||
Given cmd_put_data with d0 and ""
|
||||
Then it should get success
|
||||
32
test/features/201_setup_passphrase.feature
Normal file
32
test/features/201_setup_passphrase.feature
Normal file
@@ -0,0 +1,32 @@
|
||||
@keygen
|
||||
Feature: setup pass phrase
|
||||
In order to conform OpenPGP card 2.0 specification
|
||||
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"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1)
|
||||
Given cmd_verify with 1 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2)
|
||||
Given cmd_verify with 2 and "user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: setup reset code (in admin-full mode)
|
||||
Given cmd_put_data with d3 and "example reset code 000"
|
||||
Then it should get success
|
||||
|
||||
Scenario: reset pass phrase by reset code (in admin-full mode)
|
||||
Given cmd_reset_retry_counter with 0 and "example reset code 000another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (1) again
|
||||
Given cmd_verify with 1 and "another user pass phrase"
|
||||
Then it should get success
|
||||
|
||||
Scenario: verify PW1 (2) again
|
||||
Given cmd_verify with 2 and "another user pass phrase"
|
||||
Then it should get success
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user