Compare commits

...

515 Commits

Author SHA1 Message Date
434c155a25 docs: update .all-contributorsrc 2019-08-29 20:44:40 +00:00
893898c5e7 docs: update README.md 2019-08-29 20:44:39 +00:00
83dd92d9ba Update STABLE_VERSION 2019-08-29 22:05:10 +08:00
5d3914bc5e remove delays 2019-08-23 22:25:22 +08:00
abe306a649 Merge branch 'master' of github.com:solokeys/solo 2019-08-23 14:53:22 +08:00
41ceb78f6c add user presence to flags 2019-08-23 14:48:21 +08:00
8e192f2363 do not delay bootloader 2019-08-23 14:41:26 +08:00
affc256ca2 add delay to cap button improve reliability 2019-08-23 14:41:26 +08:00
b3ac739a35 make touch sensor edge based to avoid approving >1 transaction 2019-08-23 13:44:06 +08:00
3b53537077 refactor fido2 user presence handling & increase timeout to 29s 2019-08-23 13:19:28 +08:00
3fad9a7a7d add response to reset command and delete debug 2019-08-23 10:43:09 +08:00
8973608f59 docs: update .all-contributorsrc 2019-08-22 22:42:17 +02:00
8af6505f6d docs: update README.md 2019-08-22 22:42:17 +02:00
d39d7978fd small fix 2019-08-22 21:04:01 +08:00
c972a13034 fix reboot 2019-08-22 20:55:25 +08:00
a95e62e2ea reset 2019-08-22 20:55:25 +08:00
c79b7abfb6 add reset placeholder 2019-08-22 20:55:25 +08:00
dfb124dc8b refactoring 2019-08-22 20:55:12 +08:00
972760eb78 added APDU input chaining 2019-08-22 20:55:12 +08:00
0d621d13f9 fix decoding apdu 2019-08-22 20:55:12 +08:00
728acc1671 chaining not needs to go to the start 2019-08-21 12:13:16 +08:00
62b4418dac fix pck length math 2019-08-21 12:13:16 +08:00
8059a9765f was wrong buffer 2019-08-21 12:13:16 +08:00
b743d5fac5 sketch 2019-08-21 12:13:16 +08:00
dccfb0d1b3 stub pc build 2019-08-21 12:06:06 +08:00
a72f0ede05 take a lazy approach to key agreement generation to not hold up boot time for nfc 2019-08-21 12:06:06 +08:00
adcbd3aeb8 speed up public key derivation slightly for nfc 2019-08-21 12:06:06 +08:00
d931954a13 remove WTX, move debug log 2019-08-21 12:06:06 +08:00
b706cc30b0 for now, always gen key agreement 2019-08-21 12:06:06 +08:00
57fe39704b Merge pull request #282 from solokeys/update-udev-docs
Update udev docs
2019-08-21 02:48:33 +02:00
4b6619b705 Update udev docs 2019-08-21 02:37:15 +02:00
095b08e3d9 add some stability in small responses 2019-08-19 22:33:32 +08:00
89e021003a small fix for HID readers 2019-08-19 22:33:32 +08:00
4f3d4b09eb Update README.md 2019-08-16 17:22:46 -04:00
3f4843b03a Merge pull request #270 from solokeys/bump_2.4.3
Update STABLE_VERSION
2019-08-16 21:07:59 +02:00
26af0c423e Update solo-extras.md 2019-08-16 14:04:43 +08:00
19422d9daa add info for rng use 2019-08-16 14:04:43 +08:00
b7a4cf001a run through fixes 2019-08-16 14:04:43 +08:00
3927aec06d dont remove solo.hex bootloader.hex 2019-08-16 14:04:43 +08:00
f5794481ae initial draft 2019-08-16 14:04:43 +08:00
caac9d0cc1 add secure build that uses default attestation key 2019-08-16 14:04:43 +08:00
ffadab05a3 Update STABLE_VERSION 2019-08-15 19:35:54 +08:00
2423154fee fix warning 2019-08-15 18:07:40 +08:00
cf79b7865d small fix 2019-08-15 17:50:16 +08:00
6f0cf99c92 PPS implementation 2019-08-15 17:50:16 +08:00
7ef68fd5d3 Merge pull request #265 from solokeys/fix_cdc_interfaces
Fix cdc interfaces
2019-08-15 17:49:53 +08:00
3be8611fcf remove duplicate from merge 2019-08-15 17:44:09 +08:00
21489658a7 Merge branch 'master' into fix_cdc_interfaces 2019-08-15 17:38:57 +08:00
a07a3dee8d refactor user_presence handling 2019-08-15 17:36:35 +08:00
416da63a9a not for bootloader 2019-08-15 17:36:35 +08:00
027fa791a3 only 1 user presence auth per button press 2019-08-15 17:36:35 +08:00
3e52d7b42b cache button press for 2s 2019-08-15 17:36:35 +08:00
301e18c6a2 add some int0 logic to main cycle 2019-08-14 14:32:03 +08:00
44205141eb add one place for int0 2019-08-14 14:32:03 +08:00
6e1110ca9b fix bug with ams_wait_for_tx 2019-08-14 14:32:03 +08:00
9105b988e2 fix some warnings 2019-08-14 14:32:03 +08:00
14c94ea8f5 minor typo 2019-08-14 14:26:45 +08:00
435b908c17 Merge pull request #241 from Wesseldr/feature/STM32L432_documentation_update
Added OsX arm install, updated FIDO2 test site links
2019-08-14 14:23:41 +08:00
78280e570b adjust whitespace 2019-08-12 16:18:47 +08:00
36aec9f20b separate interface into two and add "IAD" descriptor 2019-08-12 16:18:30 +08:00
b5d3276df6 not for bootloader 2019-08-11 18:16:58 +08:00
ffd854a303 only 1 user presence auth per button press 2019-08-11 18:05:08 +08:00
349a84dcec cache button press for 2s 2019-08-11 17:59:31 +08:00
6c6a9bc5b6 Merge pull request #260 from solokeys/all-contributors/add-szszszsz
docs: add szszszsz as a contributor
2019-08-08 01:14:36 +02:00
e1528cb248 docs: update .all-contributorsrc 2019-08-07 23:14:18 +00:00
e0955c190e docs: update README.md 2019-08-07 23:14:17 +00:00
ef1e9bc1a1 Merge pull request #259 from solokeys/all-contributors/add-hughsie
docs: add hughsie as a contributor
2019-08-08 01:05:29 +02:00
f6c7dbdbdd docs: update .all-contributorsrc 2019-08-07 23:05:02 +00:00
ea1969ca94 docs: update README.md 2019-08-07 23:05:01 +00:00
c14bc76ddf Merge pull request #258 from solokeys/all-contributors/add-m3hm00d
docs: add m3hm00d as a contributor
2019-08-08 00:59:52 +02:00
f7fd30b9ae docs: update .all-contributorsrc 2019-08-07 22:59:27 +00:00
11763b6502 docs: update README.md 2019-08-07 22:59:26 +00:00
ae5d341c72 Merge pull request #255 from solokeys/all-contributors/add-rgerganov
docs: add rgerganov as a contributor
2019-08-08 00:57:23 +02:00
afed99bae9 Merge branch 'master' into all-contributors/add-rgerganov 2019-08-08 00:57:16 +02:00
d6078ce015 Merge pull request #257 from solokeys/all-contributors/add-esden
docs: add esden as a contributor
2019-08-08 00:55:01 +02:00
d630254224 docs: update .all-contributorsrc 2019-08-07 22:53:47 +00:00
b2ac7b5479 docs: update README.md 2019-08-07 22:53:46 +00:00
c050b82210 editing fail 2019-08-08 00:53:23 +02:00
ba8119b370 Merge pull request #256 from solokeys/all-contributors/add-manuel-domke
docs: add manuel-domke as a contributor
2019-08-08 00:51:24 +02:00
d350f9a638 Update .all-contributorsrc 2019-08-08 00:50:53 +02:00
53275e0182 docs: update .all-contributorsrc 2019-08-07 22:49:29 +00:00
2e14ac5b11 docs: update README.md 2019-08-07 22:49:28 +00:00
a760bed29f docs: update .all-contributorsrc 2019-08-07 22:45:57 +00:00
e854184a11 docs: update README.md 2019-08-07 22:45:56 +00:00
87c2076107 Merge pull request #254 from solokeys/all-contributors/add-alphathegeek
docs: add alphathegeek as a contributor
2019-08-08 00:44:46 +02:00
9be192b82f docs: update .all-contributorsrc 2019-08-07 22:44:17 +00:00
e95233bb5f docs: update README.md 2019-08-07 22:44:16 +00:00
2a2145b7f2 Merge pull request #253 from solokeys/all-contributors/add-StoyanDimitrov
docs: add StoyanDimitrov as a contributor
2019-08-08 00:43:09 +02:00
7cfd0ccb19 docs: update .all-contributorsrc 2019-08-07 22:42:57 +00:00
7d84caa754 docs: update README.md 2019-08-07 22:42:56 +00:00
f7dd595d84 Merge pull request #252 from solokeys/all-contributors/add-yparitcher
docs: add yparitcher as a contributor
2019-08-08 00:42:34 +02:00
04570aaf15 docs: update .all-contributorsrc 2019-08-07 22:42:17 +00:00
1a3aad9761 docs: update README.md 2019-08-07 22:42:16 +00:00
9545dacc5d Merge pull request #251 from solokeys/all-contributors/add-pjz
docs: add pjz as a contributor
2019-08-08 00:41:00 +02:00
b5e592adc9 docs: update .all-contributorsrc 2019-08-07 22:40:47 +00:00
1cd6692246 docs: update README.md 2019-08-07 22:40:46 +00:00
17884505b4 Merge pull request #250 from solokeys/all-contributors/add-YakBizzarro
docs: add YakBizzarro as a contributor
2019-08-08 00:38:06 +02:00
c2312fa69a docs: update .all-contributorsrc 2019-08-07 22:37:54 +00:00
832f06b6b4 docs: update README.md 2019-08-07 22:37:53 +00:00
4ab5477f96 Merge pull request #249 from solokeys/all-contributors/add-ehershey
docs: add ehershey as a contributor
2019-08-08 00:36:13 +02:00
434f2f89ec docs: update .all-contributorsrc 2019-08-07 22:35:54 +00:00
9174c00abf docs: update README.md 2019-08-07 22:35:53 +00:00
46111e27e3 Merge pull request #248 from solokeys/all-contributors/add-dschuermann
docs: add dschuermann as a contributor
2019-08-08 00:33:51 +02:00
763995763f docs: update .all-contributorsrc 2019-08-07 22:33:40 +00:00
4f317863e9 docs: update README.md 2019-08-07 22:33:39 +00:00
8f9aeebb9b Merge pull request #247 from solokeys/all-contributors/add-aseigler
docs: add aseigler as a contributor
2019-08-08 00:32:18 +02:00
86c6b3cbc8 docs: update .all-contributorsrc 2019-08-07 22:32:05 +00:00
a53dfb2812 docs: update README.md 2019-08-07 22:32:05 +00:00
04d6cffcb6 Merge pull request #246 from solokeys/all-contributors/add-agl
docs: add agl as a contributor
2019-08-08 00:29:03 +02:00
76e46605e3 Merge branch 'master' into all-contributors/add-agl 2019-08-08 00:28:36 +02:00
dc94e73c62 Merge pull request #245 from solokeys/all-contributors/add-merlokk
docs: add merlokk as a contributor
2019-08-08 00:26:09 +02:00
018311cfab docs: update .all-contributorsrc 2019-08-07 22:24:54 +00:00
c37638d4cb docs: update README.md 2019-08-07 22:24:53 +00:00
81a67eda24 docs: update .all-contributorsrc 2019-08-07 22:23:26 +00:00
70c176e9ef docs: update README.md 2019-08-07 22:23:25 +00:00
7e39425e98 Merge pull request #243 from solokeys/all-contributors/add-Wesseldr
docs: add Wesseldr as a contributor
2019-08-07 23:59:00 +02:00
25bf9d8e54 docs: update .all-contributorsrc 2019-08-07 21:58:17 +00:00
2e67a5f772 docs: update README.md 2019-08-07 21:58:16 +00:00
66befb96b8 Clarify that code contributions are assumed to be dual-licensed 2019-08-07 23:55:44 +02:00
257f6d1ed5 Merge pull request #242 from solokeys/all-contributors/add-szszszsz
docs: add szszszsz as a contributor
2019-08-07 23:54:17 +02:00
b4b59a6d4d Merge all-contributors with existing Contributors section 2019-08-07 23:52:52 +02:00
c18a08b14b docs: create .all-contributorsrc 2019-08-07 21:26:37 +00:00
c249148d80 docs: update README.md 2019-08-07 21:26:36 +00:00
02a51454b7 Added OsX arm install, updated FIDO2 test site links 2019-08-07 18:35:41 +02:00
4e3420f19f Merge pull request #236 from Wesseldr/patch-3
Cleaned nucleo32-board.md
2019-08-06 13:48:00 +02:00
6b8e575fac Merge branch 'master' into patch-3 2019-08-06 13:43:13 +02:00
28788d1eeb Merge pull request #237 from solokeys/remove_tests
Remove tests
2019-08-06 13:22:29 +02:00
1ee031ae9c Merge pull request #65 from Nitrokey/docs-nucleo32-board
Describe running Solo on the Nucleo board
2019-08-06 13:20:19 +02:00
6dfe42e486 All cleaned up now ? 2019-08-06 13:11:51 +02:00
29b2032dae fixing final-definitions and misc 2019-08-06 13:06:06 +02:00
f9f1e96c73 Update README.md 2019-08-06 18:54:57 +08:00
e2738d11d3 remove tests 2019-08-06 18:50:05 +08:00
a8c7c43e14 Cleaned nucleo32-board.md
The original pull request #65 was not completely compliant. hopefully this one is.
2019-08-06 12:40:05 +02:00
db479850a6 OsX path for STM32_Programmer_CLI
Added how to add the STM32_Programmer_CLI to your OsX path

Fixes https://github.com/Nitrokey/nitrokey-fido2-firmware/pull/20
2019-08-05 16:06:20 +02:00
09d450ed02 Little typo
Fixes https://github.com/Nitrokey/nitrokey-fido2-firmware/pull/19
2019-08-05 16:04:19 +02:00
be37ed46f7 Add instruction for manual flashing of the Nucleo board
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2019-08-05 16:00:30 +02:00
420d052ac9 Describe running Solo on the Nucleo32 board
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2019-08-05 16:00:27 +02:00
3698c942a2 Merge pull request #233 from solokeys/bump
Update STABLE_VERSION
2019-07-29 22:40:20 +02:00
17a170bb90 Update STABLE_VERSION 2019-07-29 14:58:30 -04:00
d4e61421b6 Merge pull request #232 from solokeys/windows_hello_error_codes
Windows hello response codes
2019-07-29 14:09:48 -04:00
690d7c716a move CTAPHID_STATUS_PROCESSING to after UP 2019-07-29 12:39:59 -04:00
78e3b291c2 make sure device status is set in all user presence tests 2019-07-28 22:10:56 -04:00
b47854c335 use error code PIN_AUTH_INVALID 2019-07-28 21:41:11 -04:00
2af747ddaa Merge pull request #229 from solokeys/fix-hmac-secret
Fix hmac secret
2019-07-27 12:49:30 -04:00
9ead11de8d Merge pull request #224 from solokeys/fault_tolerance
limit length of wLength
2019-07-27 12:47:28 -04:00
f17faca689 use correct size for auth_data for signature 2019-07-26 23:53:20 -04:00
ca66b6e43b verify signature for hmac-secret 2019-07-26 23:51:39 -04:00
1cd1b3c295 check attestation signature on all MC requests 2019-07-26 23:50:23 -04:00
df2cff2350 patch hmac final to use correct key 2019-07-26 23:49:55 -04:00
f5d50e001d test assertions work post reboot 2019-07-26 19:00:07 -04:00
235785b225 Bump stable version to 2.4.0 2019-07-17 23:42:56 +02:00
303c42901a limit length of wLength 2019-07-15 11:32:02 -04:00
df2f950e69 Merge pull request #217 from merlokk/extapdu
Extended length apdu, iso14443 chaining and select
2019-07-08 22:03:02 -04:00
10bf4242e1 fail with more import related info 2019-07-08 21:54:48 -04:00
9e95b0075c default no serial printing 2019-07-08 21:54:36 -04:00
ddbe31776c Merge pull request #220 from merlokk/obt_src
added text how to obtain source code
2019-07-08 21:22:48 -04:00
645ca6a5a0 add 3-space list 2019-07-08 18:12:28 +03:00
15fc39faed added text how to obtain source code 2019-07-08 17:58:57 +03:00
a1eedc0048 small fix 2019-07-06 13:09:19 +03:00
89e00482e4 some improvements 2019-07-06 12:52:23 +03:00
533ce39237 fix nfc_cc length 2019-07-06 00:15:21 +03:00
63ee003535 Merge pull request #202 from winksaville/patch-1
Update building.md
2019-07-05 10:29:40 -04:00
fa9408d5d6 fix u2f tests 2019-07-05 12:39:32 +03:00
ed9689435d APDU_FIDO_U2F_VERSION 2019-07-05 12:33:23 +03:00
24a006068d fix extended apdu decode 2019-07-05 12:25:46 +03:00
315b6564ab u2f works with extended apdu and now user presence not needs if request come from nfc and power from usb 2019-07-04 23:12:31 +03:00
4d9285085f fix tests 2019-07-04 20:42:24 +03:00
2272e69e15 fix tests 2019-07-04 20:14:24 +03:00
151e1d0e9b fix some errors in tests 2019-07-04 20:09:47 +03:00
d1df8b8b77 u2f authenticate fix 2019-07-04 19:54:00 +03:00
cb76c34ed2 fix addressing 2019-07-04 19:45:09 +03:00
f2ebaf6abe invalid cla and r-block works 2019-07-04 19:14:26 +03:00
4845d2c172 fix 14443 apdu decode and select 2019-07-04 17:52:00 +03:00
75b1d9cd01 offset calc refactoring 2019-07-04 17:38:34 +03:00
26bc8a2889 apdu decoding works 2019-07-04 17:27:03 +03:00
88a8eba424 gitignore 2019-07-04 16:32:11 +03:00
d2c85881e6 applet selection and apdu check 2019-07-04 16:29:30 +03:00
236498ee03 add make 2019-07-04 16:27:57 +03:00
a51c9192b1 add apdu_decode 2019-07-04 16:27:33 +03:00
4dc6bcf771 apdu decode sketch 2019-07-03 23:01:37 +03:00
cce81b23d9 Merge branch 'master' of https://github.com/merlokk/solo into extapdu 2019-07-03 22:59:41 +03:00
8c2e2386a9 fix NFC applet selection does not work correctly #213 2019-07-03 20:35:50 +03:00
c783a1442a Merge pull request #215 from merlokk/nfc-testing
Nfc testing
2019-07-03 11:37:19 -04:00
b61e5db736 style 2019-07-03 17:57:27 +03:00
b41cd5d5b8 add nfc test force flag 2019-07-03 17:54:53 +03:00
b42e990f67 format fix 2019-07-03 01:39:38 +03:00
ff53bb1e32 fix style 2019-07-03 01:16:55 +03:00
2d72e02051 remove unused lib 2019-07-03 01:03:34 +03:00
91c77da179 cbor.loads changed to cbor.decode_from 2019-07-03 00:43:51 +03:00
795cf5c4a1 selecting NFC key works 2019-07-02 19:55:04 +03:00
d1722b85af add library not found error 2019-07-02 19:45:46 +03:00
2c500fe25a check pyscard module first 2019-06-28 12:32:52 +03:00
751b2fd69c add nfc device search 2019-06-28 12:16:59 +03:00
c2216929a9 Create SECURITY.md 2019-06-14 00:19:14 +02:00
3f225f362f Update building.md
Adding `solo` as a prerequesite, it's required by `make build-hacker` to merge the hex files.
2019-05-29 15:11:18 -07:00
dd4ff920ad Merge pull request #200 from solokeys/persistedkey
use persisted key info
2019-05-28 18:36:50 -04:00
bddd60c080 use persisted key info 2019-05-27 13:54:29 -04:00
5f878ff022 Merge pull request #196 from solokeys/fido2-conformance
Fido2 conformance
2019-05-19 12:24:36 -04:00
14f91a6e15 add screenshots of tests passing 2019-05-19 12:24:15 -04:00
cd29a0e0fe python black 2019-05-18 21:11:22 -04:00
46b7f9a778 add UP as UV method for when PIN is not set 2019-05-18 14:35:30 -04:00
31328fe7e7 dont fail when public key type is too large 2019-05-18 14:34:54 -04:00
035b1a8632 Merge pull request #195 from solokeys/bump_2.3.0
Update STABLE_VERSION
2019-05-13 23:11:33 +02:00
b1563dbe94 Update STABLE_VERSION 2019-05-13 16:43:14 -04:00
2a9e3ac576 Merge pull request #194 from solokeys/sanitize
fix potential memory leaks
2019-05-13 16:10:42 -04:00
e1474e8e8e fix potential memory leaks 2019-05-13 15:32:04 -04:00
1564df5305 Merge pull request #192 from solokeys/cap
Capacitive touch sensing
2019-05-13 14:30:37 -04:00
1f3db3fe51 Fix image in README 2019-05-12 09:41:12 -07:00
36876e1528 fix build 2019-05-10 15:57:57 -04:00
0f50ae7d63 change u2f to return early if button not immediately pressed 2019-05-10 15:56:52 -04:00
4854192c63 decrease sensitivity slightly 2019-05-09 18:37:17 -04:00
e105afd647 fix build 2019-05-09 17:51:41 -04:00
9fb02d4da3 add UP wait HID messages to U2F for windows 2019-05-09 17:46:01 -04:00
e402d36bf1 fix user presence skipping for nfc 2019-05-09 17:26:28 -04:00
54792b345c status fix 2019-05-09 16:07:05 -04:00
84740f3d6a changes to make firmware interop on all hw models 2019-05-09 16:01:07 -04:00
4ac61f7f18 slight cleanup 2019-05-09 14:53:22 -04:00
30cfa46186 fix gpio pin reading 2019-05-09 14:17:50 -04:00
aca28fde61 add to bootloader 2019-05-09 02:44:17 -04:00
60e3d01e0d refactor 2019-05-09 02:44:04 -04:00
aff8d10432 connect to application 2019-05-09 02:26:32 -04:00
898d45f871 bugfix 2019-05-09 01:34:54 -04:00
2b2835b823 initial cap sensing boilerplate 2019-05-08 22:26:57 -04:00
f9202b2b6a Merge pull request #186 from solokeys/bump2.2.2
bump
2019-04-24 20:39:00 -04:00
1b74f6a93b bump 2019-04-24 20:38:00 -04:00
0dfda6fce2 Merge pull request #185 from solokeys/wallet-api
Fix FIDO2 get assertion issues with "custom" requests
2019-04-24 20:25:19 -04:00
09b73d694f fix build 2019-04-24 19:33:26 -04:00
9ab5e761c3 Update tinycbor 2019-04-24 19:04:33 -04:00
b3604f49ba use ctap2 instead of client 2019-04-24 19:00:32 -04:00
6ae1cd3865 remove not-useful logs 2019-04-24 18:36:36 -04:00
f9d3b9561d test that getassertions are correct for solo ext 2019-04-24 18:27:11 -04:00
ec98af115f restore button in ctap_make_auth_data 2019-04-24 16:54:26 -04:00
fecf258116 disable wallet by default 2019-04-24 16:44:25 -04:00
437f691d12 Update solo.c 2019-04-24 16:41:22 -04:00
55aadfd78e add delay implementation 2019-04-24 11:45:41 -04:00
813eb97d2f reuse memory for allow_list of creds 2019-04-24 11:45:30 -04:00
32afdccfb3 Rebump 2019-04-24 17:41:08 +02:00
41ae0e4a2c Update application.mk 2019-04-24 00:16:19 -04:00
b0baace2e7 move custom credid to different location 2019-04-24 00:15:32 -04:00
6ff4200f5d unbump 2019-04-23 21:58:26 -04:00
1fab0b8f1f add wallet api in as compile option 2019-04-23 21:57:50 -04:00
ce96fffddd add info to authData for ext reqs 2019-04-23 21:57:27 -04:00
4fb25e165a remove old web assets 2019-04-23 21:15:11 -04:00
8fc0da7934 move args to device_init 2019-04-23 21:12:40 -04:00
494e856198 Merge pull request #131 from rgerganov/hidg
Add support for hidg devices on Linux
2019-04-23 20:22:33 -04:00
472b094acb bump 2019-04-23 20:21:19 -04:00
e0ce23034f Merge pull request #180 from solokeys/test_pin_fixes
Test pin fixes
2019-04-23 19:58:44 -04:00
5f3974a4e6 Merge pull request #182 from solokeys/nfc_adjustments
Nfc adjustments
2019-04-23 19:42:14 -04:00
26adac1730 size optimize tinycbor 2019-04-23 19:17:18 -04:00
eab8b81c95 include nfc in user presence test 2019-04-23 14:05:18 -04:00
325396d518 dont change clock freq if powered 2019-04-23 13:54:23 -04:00
6d04c86018 update lowFreq flag correctly 2019-04-23 13:54:10 -04:00
56d6624e4e Test correct alg parameter #179 2019-04-22 16:26:26 -04:00
3094c87b0a Test empty pinAuth in MC and GA #179 2019-04-22 16:25:08 -04:00
212f98e384 Merge pull request #179 from agl/pinfixes
Couple of fixes for PIN support
2019-04-22 16:11:34 -04:00
73f538dd0e Fix COSE type of key-agreement keys.
The key-agreement keys in the PIN protocol use COSE type -25. I'm not
sure if that's written down anywhere, but it's what everything else does
and it's an ECDH type rather than an ECDSA type.
2019-04-20 16:45:04 -07:00
a5f794c0ff Handle empty pinAuth fields.
CTAP2 specifies that an empty pinAuth field is special: it indicates
that the device should block for touch, i.e. it's just a way of letting
a user select from multiple authenticators[1].

This change handles empty pinAuth fields in GetAssertion and
MakeCredential commands.

[1] https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorMakeCredential
2019-04-20 16:26:32 -07:00
f28cf9c6d0 new release 2019-04-18 20:41:18 -07:00
6068fb9868 Merge pull request #173 from solokeys/fix_u2f_on_fido2
Fix u2f on fido2
2019-04-17 22:42:38 -04:00
6a288243c1 Add Makefile for installing a HID gadget
The Makefile has targets for building, installing and uninstalling a HID
gadget which acts as FIDO2 authenticator.

Tested on Ubuntu 18.04 but should work on other distros as well. The
only assumption being made is that kernel source is available at
/usr/src/linux-source-$(KERNEL_VERSION).tar.bz2. A possible improvement
would be to have a configure script which finds the correct kernel
source archive.
2019-04-16 10:54:49 +03:00
955d4f76ef Add support for hidg devices on Linux
There is a HID gadget driver on Linux which provides emulation of USB
HID devices. This could be very useful for testing the Solo firmware
without actual hardware, using only a Linux box.

This patch adds a command line argument which specifies whether the
existing UDP backing should be used or the new one which reads and
writes to /dev/hidg0.

Testing done:
 1. Created HID device with configfs
 2. Started "./main -b hidg" as root
 3. Successfully executed Webauthn registration and authentication on
 the same Linux machine

Closes: #122
2019-04-16 10:54:46 +03:00
74cbe00e3b Enable debug logs for >0 2019-04-14 15:13:39 -04:00
7e490f17fc delete 2019-04-13 22:42:16 -04:00
9bb706987f solo ext bugfix 2019-04-13 22:42:05 -04:00
88a759566d Improve testing 2019-04-13 22:37:47 -04:00
44fa3bbb8e Add checks to use U2F key if necessary 2019-04-13 22:37:31 -04:00
89e9296825 Add test 2019-04-13 20:43:26 -04:00
873d65b823 Merge pull request #172 from StoyanDimitrov/patch-1
Improve readability of code filenames
2019-04-13 11:54:55 -04:00
eb8e3ed46a Improve readability of code filenames 2019-04-13 15:31:35 +00:00
8b97276e32 Merge pull request #171 from solokeys/fix_cbor
Fix cbor
2019-04-12 12:04:01 -04:00
78579c27dc Refactor and self test the CBOR sorting 2019-04-11 13:42:17 -04:00
ca80329b4c Compare string length and sort from start of string 2019-04-11 13:22:55 -04:00
7a49169492 consider major type and refactor 2019-04-11 00:04:33 -04:00
46dd4fe818 unused import 2019-04-10 13:56:23 -04:00
c71bbd8689 re-enable all tests 2019-04-10 13:42:38 -04:00
7068be9cd5 reorder options 2019-04-10 13:13:38 -04:00
f8635f1682 refactor tests 2019-04-10 13:12:33 -04:00
ffa9ad4923 refactor cbor sorting test 2019-04-10 12:47:39 -04:00
5fc8d214fd remove add_user param 2019-04-10 12:47:23 -04:00
5f49f4680e re-order items in get_assertion response 2019-04-10 12:22:35 -04:00
86393c46b4 Test it is correct 2019-04-10 12:11:43 -04:00
4cc72bcd97 rearrange cbor encoding order in make_credential and get_info 2019-04-10 12:11:31 -04:00
5e0edf3e11 Update index.md 2019-04-06 21:45:51 +02:00
bd810fff87 Merge pull request #165 from ehershey/patch-3
More docs fixups
2019-04-06 21:41:19 +02:00
d9fb508949 Merge pull request #166 from ehershey/patch-2
include markdown-include mkdocs dependency
2019-04-06 21:40:13 +02:00
c2b7acb6aa include markdown-include mkdocs dependency 2019-04-06 15:29:16 -04:00
4690a7ce65 More docs fixups 2019-04-06 13:50:51 -04:00
61f24d142d Merge pull request #163 from ehershey/patch-1
link to readme and reference TC in docs start page
2019-04-06 13:41:54 -04:00
f5c6f99423 Merge pull request #164 from ehershey/patch-2
Docs fixups
2019-04-06 13:40:51 -04:00
96de4f0850 Docs fixups
Spelling, grammar
2019-04-06 13:28:16 -04:00
331ebdfccf link to readme and reference TC in docs start page 2019-04-06 13:20:10 -04:00
a6a6d653ad Update README.md 2019-04-06 14:49:44 +02:00
928bc0216d Merge pull request #161 from solokeys/bump_2.1.0
bump to 2.1.0
2019-04-02 01:31:48 +02:00
6d52c9ede7 bump to 2.1.0 2019-03-31 23:49:29 -04:00
89769ecc18 fix u2f counter for real 2019-03-31 23:29:00 -04:00
3b3f47bfcf Merge pull request #155 from solokeys/pin_lockout_ga
Pin lockout ga
2019-03-29 17:11:48 -04:00
6fa443b0bc tests for GA without pin 2019-03-26 19:00:42 -04:00
893d4131b2 change how pin is enforced for GA 2019-03-26 19:00:12 -04:00
4e21c0bd8f Merge pull request #152 from solokeys/testing_yubikey
Testing yubikey
2019-03-26 18:33:03 -04:00
251eb6bf64 Merge branch 'master' into testing_yubikey 2019-03-26 16:36:08 -04:00
08e236df69 fix code quality issues x/2 2019-03-26 16:14:28 -04:00
d2091563ab fix code quality issues 2019-03-26 16:09:30 -04:00
54a6a82ca0 Merge pull request #153 from solokeys/rng-fix
Fix buffer overrun and use correct size for random u32
2019-03-26 15:37:51 -04:00
40b9dae38a Fix buffer overrun and use correct size for random u32 2019-03-26 01:55:42 +01:00
98a209e330 make target to flash firmware via bootloader 2019-03-23 13:54:04 +01:00
d3b5fb68ee Build debug 1/2 versions of hacker firmware and bundle 2019-03-23 13:52:47 +01:00
74a1f0e21b Merge pull request #143 from solokeys/paranoid-modemmanager
Do not signal "AT modem" for ACM-CDC serial
2019-03-23 01:48:18 -04:00
e21172fff8 Merge pull request #149 from solokeys/hmac-secret
Hmac-secret
2019-03-22 22:05:41 +01:00
9d3144e9b1 oops. black 2019-03-22 21:56:18 +01:00
a2a774125f Fix usage and display fido2-ext in it 2019-03-22 21:40:55 +01:00
349ea5343a Remove paranoid MM stuff, not signaling AT modem is enough + better 2019-03-22 20:01:31 +01:00
c851807376 Do not advertise AT modem capabilities 2019-03-22 20:00:02 +01:00
84d1629aa3 Allow toggling between strict and paranoid ModemManager filter-policy 2019-03-22 20:00:02 +01:00
8f6ae29163 Fix ModemManager udev rule for some distros 2019-03-22 20:00:02 +01:00
a0d27c2c56 add memory layout commment, undo -8 simplification 2019-03-22 19:55:25 +01:00
3a10427bd9 remove unused files 2019-03-22 19:55:25 +01:00
f3b591e570 Apply suggestions from code review
Co-Authored-By: conorpp <conorpp94@gmail.com>
2019-03-22 19:55:25 +01:00
175f59d206 paste into other linker scripts 2019-03-22 19:55:25 +01:00
f5ff6a11f0 rewrite base linker script 2019-03-22 19:55:25 +01:00
d979420324 u2f work with yubikey5 2019-03-22 01:59:19 -04:00
5076af1be4 works with yubikey5 2019-03-22 01:22:55 -04:00
0a7845459c breakup test_fido2 2019-03-22 00:45:28 -04:00
c4262b0f5b rename 2019-03-22 00:20:48 -04:00
53fb0059a7 break into separate files 2019-03-22 00:20:20 -04:00
a1a75e4ab5 check errors 2019-03-21 12:47:15 -04:00
d68011ef04 remove warnings 2019-03-21 00:01:37 -04:00
02e83073e0 add hmac-secret to reg response 2019-03-20 23:58:42 -04:00
3a48756f96 remove extra layer of map 2019-03-20 23:40:58 -04:00
946e932b1e refactor to use less ram 2019-03-20 23:28:45 -04:00
142d4002e5 remove warning, reduce memory 2019-03-20 23:14:17 -04:00
dbe5283e1f test solo commands on fido2 layer 2019-03-20 21:06:18 -04:00
2d233f164e small bug fixes 2019-03-20 21:03:03 -04:00
b62e9906c7 make new function 2019-03-20 20:13:16 -04:00
e22e636475 hmac-secret tested 2019-03-20 20:03:25 -04:00
074225d87a hmac-secret fully functional 2019-03-20 20:03:12 -04:00
bb9b2ea9d4 validate saltAuth 2019-03-20 18:10:52 -04:00
e8d5bc5829 refactor ctap_make_auth_data arguments 2019-03-20 17:43:50 -04:00
850381a633 test parsing 2019-03-20 16:52:10 -04:00
ce3ad0e56f bugfix 2019-03-20 16:51:58 -04:00
00d86379e5 parse full hmac-secret 2019-03-20 16:21:21 -04:00
6098810167 start to test hmac-secret 2019-03-20 15:45:35 -04:00
821880a8d6 parse extension info in MC 2019-03-20 15:45:10 -04:00
44f96f5843 Merge pull request #148 from solokeys/testing_refactor
Testing refactor
2019-03-20 15:06:12 -04:00
6ec9fb962a delay send_raw in test 2019-03-20 14:59:31 -04:00
c9bfe001ee refactored version, previously lost 2019-03-20 14:56:52 -04:00
5e46fd96ac Create LICENSE 2019-03-19 16:29:39 +01:00
103cc3cfb0 Some fun with shields 2019-03-19 16:28:47 +01:00
9544330dc3 delay send_raw in test 2019-03-18 04:36:02 +01:00
0964ff69b7 refactor a bit 2019-03-18 04:36:02 +01:00
e4a2b9e1ca Get udev instructions up to date 2019-03-18 02:52:34 +01:00
d29fa34da1 Update README.md 2019-03-15 22:08:07 -04:00
6ed2610a5c Merge pull request #145 from solokeys/stable-v2.0.0
Set STABLE_VERSION to 2.0.0
2019-03-14 19:39:43 -04:00
3b9d4e5023 Set STABLE_VERSION to 2.0.0 2019-03-15 00:35:50 +01:00
2da083c18a Merge pull request #138 from solokeys/fix-warning
I think this does it
2019-03-11 14:33:02 -04:00
50bfbc1eff I think this does it 2019-03-10 15:26:45 +01:00
86739df7a1 Improvements to Docker build 2019-03-10 15:19:16 +01:00
c7f0d050d7 Fix udev rule for STM bootloader 2019-03-08 14:25:29 +01:00
b79670a447 Merge pull request #133 from solokeys/more_testing
More testing
2019-03-07 21:25:53 -05:00
169ba59ed4 use alpha 2019-03-07 21:19:10 -05:00
f3003c58c9 new release 2.0.0 2019-03-07 20:33:20 -05:00
084e518018 refactor 2019-03-06 17:43:28 -05:00
6674f0a8ff add more tests 2019-03-06 16:17:12 -05:00
f704851419 add bootloader tests 2019-03-06 14:23:56 -05:00
0d5e1ee872 Test solo specific commands 2019-03-06 14:06:07 -05:00
5cb81c753d Add version/extensions to PC build 2019-03-06 14:05:44 -05:00
b0b0564df9 fix imports 2019-03-06 13:13:43 -05:00
195dc2a8ae use 0x7f as upper counter byte 2019-03-04 02:36:47 -05:00
4982b13f64 Merge pull request #129 from solokeys/testing_fido2
Testing fido2
2019-03-04 02:26:06 -05:00
63a93f6ec2 test pin lock out 2019-03-03 19:01:08 -05:00
7b8ec18e76 add reboot capability for tests 2019-03-03 18:43:14 -05:00
67faef0117 tests for client pin 2019-03-03 17:17:04 -05:00
0b9f0af3c7 spin pc less 2019-03-03 17:15:26 -05:00
880d54a4f0 more fido2 tests 2019-03-03 03:43:15 -05:00
1507758ad1 bring pc crypto impl up to date 2019-03-02 23:10:43 -05:00
e883c5aa6e add many fido2 tests 2019-03-02 22:40:51 -05:00
afc85e0d2e update log message 2019-03-02 22:40:27 -05:00
a40dcf3f17 reduce nfc detect period to 10ms 2019-03-02 20:08:28 -05:00
4b82e80d7a init device with nfc detection 2019-03-02 20:08:15 -05:00
246dea8a44 fix clock init by setting flash latency last for low freqs 2019-03-02 20:05:27 -05:00
7a98764a5b organize ECC flags 2019-03-02 19:48:09 -05:00
dc946f5b35 centralize reset key agreement 2019-03-02 19:38:27 -05:00
0232893611 increase buffer size for USB strings, check string length 2019-03-02 19:38:03 -05:00
5995f84822 buffering logs sometimes freezes, stop for now 2019-03-02 15:43:12 -05:00
1ff00895b1 init nfc, fix freeze 2019-03-02 02:02:01 -05:00
83641b3789 disable clock settings for NFC passive for now 2019-03-02 01:30:09 -05:00
9b356076c5 Merge pull request #127 from solokeys/testing
Testing
2019-03-02 01:12:48 -05:00
6c96521c7d slight cleanup 2019-03-02 00:55:46 -05:00
35707c3797 wrong size, causes RK's to be overwritten 2019-03-02 00:55:25 -05:00
e31e703afd minor improvements 2019-03-01 23:42:22 -05:00
3a8be9eef7 add more u2f tests 2019-03-01 23:16:48 -05:00
e2b30ec087 basic interface 2019-03-01 22:35:50 -05:00
495e10f3a1 add basic rk support for pc 2019-03-01 22:28:25 -05:00
11ca6bd517 fix pc testing 2019-03-01 22:11:36 -05:00
a265da09fb Update u2f.c 2019-03-01 22:00:17 -05:00
1b4d1be9ee Merge pull request #119 from solokeys/udev
Cleanup udev rules, keep 99-solo.rules as symlink
2019-03-01 21:44:45 -05:00
32f2436380 Merge pull request #120 from nickray/sha512
SHA512 (via Cifra)
2019-03-01 21:44:13 -05:00
7255c4f8db Merge pull request #121 from solokeys/nfc
Nfc
2019-03-01 21:43:12 -05:00
4e215db42a start from 0 2019-02-28 23:13:12 -05:00
a1ad641076 Merge branch 'master' of github.com:solokeys/solo 2019-02-28 22:47:25 -05:00
daf56b0cc7 Silence warning about out of date pip in Travis 2019-02-28 01:06:06 +01:00
5859073cb8 Build bundle-hacker-{version}.hex 2019-02-28 01:06:06 +01:00
ff5207ba77 First attempt 2019-02-27 21:43:20 +01:00
324b4a89cc Remove python-fido2 submodule 2019-02-27 21:43:20 +01:00
0865f2a660 do not probe bootloader 2019-02-27 03:18:12 +01:00
b1c72c9d94 for docker on windows 2019-02-26 21:11:33 -05:00
5e70c11b54 Hide onboard crypto tests behind a reserved ctaphid command 2019-02-27 02:58:56 +01:00
0eac67259d remove stm32l442 target 2019-02-26 18:24:40 -05:00
9399a5f195 Cleanup udev rules, keep 99-solo.rules as symlink 2019-02-27 00:00:49 +01:00
47aa287480 Vanilla cifra needs more includes 2019-02-26 23:50:01 +01:00
865b698bed ...and bootloader 2019-02-26 23:33:57 +01:00
14974e0ebe fix compile issues 2019-02-26 15:30:57 -05:00
1ed7833c9f fix pc build 2019-02-26 15:08:09 -05:00
e8d0ad5e7c autodetect passive nfc operation or usb operation 2019-02-26 15:04:23 -05:00
e2ca7f52db optimize ecc for arm 2019-02-26 14:19:07 -05:00
c97b9f9b8f Need includes in main Makefile too 2019-02-26 20:16:38 +01:00
ecf994b647 fix warnings and compile errors 2019-02-26 14:13:29 -05:00
347d0942b1 refactor fromNFC 2019-02-26 14:07:27 -05:00
ff0d42c8d5 refactor clock rates, fix warnings 2019-02-26 13:56:06 -05:00
a6673b0917 Use our cifra fork, rename command, keep room for sha256 2019-02-26 19:52:59 +01:00
0c296bba30 First go at using cifra for SHA512 2019-02-26 19:52:59 +01:00
57930aaa13 fix compilation errors 2019-02-26 13:27:25 -05:00
1a6895ca25 merge 2019-02-26 13:10:16 -05:00
a195408a11 scale up to 24 MHz only for register 2019-02-26 01:51:07 -05:00
54b7f42056 passive operation works as is (refactor needed) 2019-02-26 01:19:35 -05:00
6128e86da2 Merge pull request #114 from merlokk/nfc4
NFC. added hardware part of UID
2019-02-19 22:05:15 -05:00
fed9f473aa added hardware part of UID 2019-02-19 18:12:01 +02:00
3b320e0aeb initialize at 24 MHz at very start instead of 16 2019-02-12 18:34:13 -05:00
529b879c08 init in device_init 2019-02-11 22:02:41 -05:00
2893cd7ce3 move inits to device_init 2019-02-11 22:00:18 -05:00
120fb95541 compile for bootloader 2019-02-08 13:09:32 -05:00
665e84d183 delay to allow spi interface to initialize 2019-02-08 13:09:12 -05:00
13d9885da4 initialize at 16MHz, add 24 and 32 options 2019-02-08 13:08:28 -05:00
e230a9464e enable ctap from usb 2019-02-07 20:09:13 -05:00
342af18b1f initialize ctap 2019-02-07 20:09:00 -05:00
be9bd941c8 simplify ams init 2019-02-07 19:45:02 -05:00
0f6be6740b Merge pull request #101 from merlokk/nfc2
Nfc2
2019-02-07 19:14:12 -05:00
9054736e0e delete debugging code 2019-02-07 19:03:45 -05:00
c6d946136e small fix 2019-02-07 16:05:08 +02:00
32400c8d09 Merge branch 'nfc' into nfc2 2019-02-07 14:49:47 +02:00
587c9aad14 refactor 2019-02-06 18:09:53 -05:00
c624a32ef6 default 8 thread build 2019-02-06 18:07:38 -05:00
3005a63938 re-arrange some logic for better passive operation 2019-02-06 18:07:09 -05:00
f470e9a9cd dont need to init clock at first in bootloader 2019-02-06 18:05:22 -05:00
e3971a5e0f change ams init, read less regs 2019-02-06 17:56:53 -05:00
2ed8667f18 immedately change clock rate to load data sections faster 2019-02-06 17:55:27 -05:00
765d532f82 add low freq clocking options 4,8,16MHz 2019-02-06 17:54:52 -05:00
ca05385513 log fixing 2019-02-06 20:06:46 +02:00
5328610ff1 delete debug messages 2019-02-06 19:51:32 +02:00
bc1bb3509f move APDU dumps to separate log channel 2019-02-06 19:21:06 +02:00
375db69e3a fido2 works 2019-02-06 19:06:49 +02:00
771fffe329 WTX works. todo: clean debug unneeded messages 2019-02-06 17:12:22 +02:00
4611f05051 small fix in AMS3956 debug texts 2019-02-06 15:17:52 +02:00
e657e26886 check AMS product type 2019-02-06 15:15:37 +02:00
3ffcc47374 fix logger 2019-02-06 14:11:49 +02:00
1b5e230d45 merge u2f endian fix 2019-02-02 00:32:36 -05:00
81a89ed6aa go back to high freq 2019-02-02 00:29:32 -05:00
ca2074de36 Update Makefile 2019-02-02 00:25:01 -05:00
ee98340a03 temporarily remove prints at start 2019-02-02 00:24:42 -05:00
3d0d91fa5c lf param 2019-02-02 00:24:11 -05:00
38171dba06 low freq init 2019-02-02 00:23:51 -05:00
4ba57ccc85 refactor init functions 2019-02-02 00:23:01 -05:00
c3bddee814 dont do this when powered by nfc 2019-02-02 00:21:26 -05:00
b7bc50bc4f Merge pull request #96 from merlokk/nfc2
small fixes in NFC branch
2019-02-02 00:16:07 -05:00
19627a959a some TODOs 2019-02-01 21:35:45 +02:00
429e4b2a77 add WTX_clear(); 2019-02-01 21:33:57 +02:00
6e5de7bd6b read data if we sent WTX 2019-02-01 21:31:20 +02:00
c6daa4acc9 more WTX sketch 2019-02-01 21:27:43 +02:00
ab01d0c73d delete comment 2019-02-01 21:02:02 +02:00
0ef42b2df7 added WTX sending sketch 2019-02-01 20:45:36 +02:00
f6e2bfa683 yubikey answers U2F_SW_WRONG_PAYLOAD instead of U2F_SW_WRONG_DATA 2019-02-01 20:06:19 +02:00
5c8acdd666 fix u2f user presence check, added dont-enforce-user-presence-and-sign, fix counter 2019-02-01 20:00:13 +02:00
e996d470f9 small fixes 2019-02-01 19:15:48 +02:00
e2e29492e6 point to website 2019-01-29 22:39:49 -05:00
5f637992b1 implement capability container and ndef tag to work with nexus 6 2019-01-29 22:12:38 -05:00
91d092a27a tell AMS to go to sleep if deselected 2019-01-27 23:55:11 -05:00
23cbfde312 Merge pull request #88 from merlokk/nfc
merging so I can test out in my branch
2019-01-27 21:11:57 -05:00
cce25b2a1c u2f auth works 2019-01-28 00:04:17 +02:00
f24058d2e8 u2f authenticate wrong length fix 2019-01-27 23:58:35 +02:00
4c941997b4 check as3956 on startup 2019-01-27 23:35:20 +02:00
2049020b92 refactoring 2019-01-27 11:44:33 +02:00
1857482617 add some len check 2019-01-27 00:01:04 +02:00
2feef8b043 add some profiling... 2019-01-26 23:53:13 +02:00
3eddfbf8a9 u2f register works 2019-01-26 23:44:51 +02:00
a662a9a619 remove dump 2019-01-26 23:36:45 +02:00
1a656d60e4 register works. but it needs to press a button.... 2019-01-26 23:35:45 +02:00
e235402fb8 u2f register 2019-01-26 21:34:53 +02:00
6ca9f1946b I block on receive 2019-01-26 21:08:18 +02:00
df671775ba add some profiling. looks good. 2019-01-26 19:30:03 +02:00
3ba83f6407 remove debug msg 2019-01-26 19:11:51 +02:00
ffa4225827 chip have too less memory. so reusing ctap_resp buffer. 2019-01-26 19:07:12 +02:00
cde6bc107a GetVersion works. not so clean. needs additional memory.... 2019-01-25 19:54:02 +02:00
15de8dc4a6 send response from key to pc in chaining mode. partially works.
GetVersion must work with pc (proxmark have errors)
2019-01-25 19:32:42 +02:00
94fe58d020 small fix 2019-01-24 20:09:57 +02:00
e8634a2d61 add u2f errors 2019-01-24 20:04:44 +02:00
67b0abde4b some refactoring 2019-01-24 19:56:18 +02:00
d713167ec4 works. needs to add chaining 2019-01-24 19:21:31 +02:00
45888c9a25 ins check is ok 2019-01-24 18:22:58 +02:00
d02206ba09 SELECT works as expected and U2F GetVersion command done 2019-01-24 18:19:23 +02:00
ad9186c13b SELECT works 2019-01-24 17:57:42 +02:00
4e0dc15dfd add historical bytes 2019-01-24 16:56:38 +02:00
dcf7940b3d basic ndef message works 2019-01-13 17:25:32 -05:00
1874e11fba organize 2019-01-13 00:02:37 -05:00
302ce75ce6 responds to RATS correctly 2019-01-12 20:20:47 -05:00
62cd7cc728 enable energy harvesting and tunneling in eeprom 2019-01-12 16:20:11 -05:00
20f8aac768 option to boot at 4MHz with no USB 2019-01-12 16:19:44 -05:00
121070822f Update main.c 2019-01-07 21:20:07 -05:00
96f65be9c2 disable main app for now 2019-01-07 21:19:56 -05:00
78c40976c3 log interrupts and recv'd data 2019-01-07 21:19:45 -05:00
aa978abfc7 cleanup 2019-01-07 19:40:20 -05:00
b7c0e4ea92 no delays 2019-01-07 19:05:39 -05:00
6ffba7d472 move to new file 2019-01-07 18:50:01 -05:00
c330346c31 add nfc log tag 2019-01-07 18:29:38 -05:00
eda26e3c93 add ST spi LL driver 2019-01-07 18:17:33 -05:00
44077a4f2f spi interface WORKS 2019-01-06 17:12:26 -05:00
4c6f0969c1 add spi 2019-01-05 20:58:39 -05:00
117 changed files with 10261 additions and 16987 deletions

197
.all-contributorsrc Normal file
View File

@ -0,0 +1,197 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"contributors": [
{
"login": "szszszsz",
"name": "Szczepan Zalega",
"avatar_url": "https://avatars0.githubusercontent.com/u/17005426?v=4",
"profile": "https://github.com/szszszsz",
"contributions": [
"code",
"doc",
"ideas"
]
},
{
"login": "Wesseldr",
"name": "Wessel dR",
"avatar_url": "https://avatars1.githubusercontent.com/u/4012809?v=4",
"profile": "https://github.com/Wesseldr",
"contributions": [
"doc"
]
},
{
"login": "agl",
"name": "Adam Langley",
"avatar_url": "https://avatars3.githubusercontent.com/u/21203?v=4",
"profile": "https://www.imperialviolet.org",
"contributions": [
"bug",
"code"
]
},
{
"login": "merlokk",
"name": "Oleg Moiseenko",
"avatar_url": "https://avatars2.githubusercontent.com/u/807634?v=4",
"profile": "http://www.lotteam.com",
"contributions": [
"code"
]
},
{
"login": "aseigler",
"name": "Alex Seigler",
"avatar_url": "https://avatars1.githubusercontent.com/u/6605560?v=4",
"profile": "https://github.com/aseigler",
"contributions": [
"bug"
]
},
{
"login": "dschuermann",
"name": "Dominik Schürmann",
"avatar_url": "https://avatars3.githubusercontent.com/u/321888?v=4",
"profile": "https://www.cotech.de/services/",
"contributions": [
"bug"
]
},
{
"login": "ehershey",
"name": "Ernie Hershey",
"avatar_url": "https://avatars0.githubusercontent.com/u/286008?v=4",
"profile": "https://github.com/ehershey",
"contributions": [
"doc"
]
},
{
"login": "YakBizzarro",
"name": "Andrea Corna",
"avatar_url": "https://avatars1.githubusercontent.com/u/767740?v=4",
"profile": "https://github.com/YakBizzarro",
"contributions": [
"infra"
]
},
{
"login": "pjz",
"name": "Paul Jimenez",
"avatar_url": "https://avatars3.githubusercontent.com/u/11100?v=4",
"profile": "https://place.org/~pj/",
"contributions": [
"infra",
"code"
]
},
{
"login": "yparitcher",
"name": "yparitcher",
"avatar_url": "https://avatars0.githubusercontent.com/u/38916402?v=4",
"profile": "https://github.com/yparitcher",
"contributions": [
"ideas",
"maintenance"
]
},
{
"login": "StoyanDimitrov",
"name": "StoyanDimitrov",
"avatar_url": "https://avatars1.githubusercontent.com/u/10962709?v=4",
"profile": "https://github.com/StoyanDimitrov",
"contributions": [
"doc"
]
},
{
"login": "alphathegeek",
"name": "alphathegeek",
"avatar_url": "https://avatars2.githubusercontent.com/u/51253712?v=4",
"profile": "https://github.com/alphathegeek",
"contributions": [
"ideas"
]
},
{
"login": "rgerganov",
"name": "Radoslav Gerganov",
"avatar_url": "https://avatars2.githubusercontent.com/u/271616?v=4",
"profile": "https://xakcop.com",
"contributions": [
"ideas",
"code"
]
},
{
"login": "manuel-domke",
"name": "Manuel Domke",
"avatar_url": "https://avatars3.githubusercontent.com/u/10274356?v=4",
"profile": "http://13-37.org",
"contributions": [
"ideas",
"code",
"business"
]
},
{
"login": "esden",
"name": "Piotr Esden-Tempski",
"avatar_url": "https://avatars3.githubusercontent.com/u/17334?v=4",
"profile": "http://1bitsquared.com",
"contributions": [
"business"
]
},
{
"login": "m3hm00d",
"name": "f.m3hm00d",
"avatar_url": "https://avatars1.githubusercontent.com/u/42179593?v=4",
"profile": "https://github.com/m3hm00d",
"contributions": [
"doc"
]
},
{
"login": "hughsie",
"name": "Richard Hughes",
"avatar_url": "https://avatars0.githubusercontent.com/u/151380?v=4",
"profile": "http://blogs.gnome.org/hughsie/",
"contributions": [
"ideas",
"code",
"infra",
"tool"
]
},
{
"login": "kimusan",
"name": "Kim Schulz",
"avatar_url": "https://avatars1.githubusercontent.com/u/1150049?v=4",
"profile": "http://www.schulz.dk",
"contributions": [
"business",
"ideas"
]
},
{
"login": "oplik0",
"name": "Jakub",
"avatar_url": "https://avatars2.githubusercontent.com/u/25460763?v=4",
"profile": "https://github.com/oplik0",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,
"projectName": "solo",
"projectOwner": "solokeys",
"repoType": "github",
"repoHost": "https://github.com"
}

12
.gitignore vendored
View File

@ -81,15 +81,7 @@ env3/
.tags* .tags*
targets/*/docs/ targets/*/docs/
main main
targets/efm32/.project
targets/efm32/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs
targets/efm32/.settings/org.eclipse.cdt.codan.core.prefs
targets/efm32/CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.s
targets/efm32/CMSIS/EFM32PG1B/system_efm32pg1b.c
targets/efm32/EFM32.hwconf
targets/efm32/EFM32_EFM32JG1B200F128GM32.hwconf
targets/efm32/emlib/em_adc.c
targets/efm32/emlib/em_assert.c
targets/efm32/emlib/em_cmu.c
builds/* builds/*
tools/testing/.idea/*
tools/testing/tests/__pycache__/*

6
.gitmodules vendored
View File

@ -1,9 +1,6 @@
[submodule "tinycbor"] [submodule "tinycbor"]
path = tinycbor path = tinycbor
url = https://github.com/intel/tinycbor url = https://github.com/intel/tinycbor
[submodule "python-fido2"]
path = python-fido2
url = https://github.com/solokeys/python-fido2
[submodule "crypto/micro-ecc"] [submodule "crypto/micro-ecc"]
path = crypto/micro-ecc path = crypto/micro-ecc
url = https://github.com/kmackay/micro-ecc.git url = https://github.com/kmackay/micro-ecc.git
@ -13,3 +10,6 @@
[submodule "targets/stm32l442/dfuse-tool"] [submodule "targets/stm32l442/dfuse-tool"]
path = targets/stm32l442/dfuse-tool path = targets/stm32l442/dfuse-tool
url = https://github.com/solokeys/dfuse-tool url = https://github.com/solokeys/dfuse-tool
[submodule "crypto/cifra"]
path = crypto/cifra
url = https://github.com/solokeys/cifra.git

View File

@ -1,28 +0,0 @@
# Notify ModemManager this device should be ignored
ACTION!="add|change|move", GOTO="mm_usb_device_blacklist_end"
SUBSYSTEM!="usb", GOTO="mm_usb_device_blacklist_end"
ENV{DEVTYPE}!="usb_device", GOTO="mm_usb_device_blacklist_end"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ENV{ID_MM_DEVICE_IGNORE}="1"
LABEL="mm_usb_device_blacklist_end"
# Solo
## bootloader + firmware access
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev"
## DFU access
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess", GROUP="plugdev"
## Solo Secure symlink
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo [1-9]*", SYMLINK+="solokey"
## Solo Hacker symlink
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo Hacker [1-9]*", SYMLINK+="solohacker"
## Solo Serial access + symlink
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", SYMLINK+="soloserial"
# U2F Zero
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", SYMLINK+="u2fzero"

1
99-solo.rules Symbolic link
View File

@ -0,0 +1 @@
udev/70-solokeys-access.rules

1
ALPHA_VERSION Normal file
View File

@ -0,0 +1 @@
2.0.0

View File

@ -1,17 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.1.0] - 2019-02-17
### Added
- Code cleanup
- Buffer over-read bug fix
- U2F counter endianness bug fix
- More testing
- Extension interface to U2F and FIDO2
- Read firmware version
- Read RNG bytes

View File

@ -14,7 +14,7 @@ RUN echo "fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.
RUN sha256sum -c gcc.sha256 RUN sha256sum -c gcc.sha256
RUN tar -C /opt -xf gcc.tar.bz2 RUN tar -C /opt -xf gcc.tar.bz2
# 2. Python3.7: for solotool (merging etc.) # 2. Python3.7: for solo-python (merging etc.)
RUN wget -q -O miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh RUN wget -q -O miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh
# from website # from website
RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5 RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5
@ -24,8 +24,10 @@ RUN echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a mini
RUN sha256sum -c miniconda.sha256 RUN sha256sum -c miniconda.sha256
RUN bash ./miniconda.sh -b -p /opt/conda RUN bash ./miniconda.sh -b -p /opt/conda
RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python3 RUN ln -s /opt/conda/bin/python /usr/local/bin/python3
RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python RUN ln -s /opt/conda/bin/python /usr/local/bin/python
RUN ln -s /opt/conda/bin/pip /usr/local/bin/pip3
RUN ln -s /opt/conda/bin/pip /usr/local/bin/pip
# 3. Source code # 3. Source code
RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input

1
LICENSE Normal file
View File

@ -0,0 +1 @@
Apache-2.0 OR MIT

View File

@ -9,7 +9,9 @@
ecc_platform=2 ecc_platform=2
src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard crypto/sha256/*.c) crypto/tiny-AES-c/aes.c src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard fido2/extensions/*.c) \
$(wildcard crypto/sha256/*.c) crypto/tiny-AES-c/aes.c
obj = $(src:.c=.o) crypto/micro-ecc/uECC.o obj = $(src:.c=.o) crypto/micro-ecc/uECC.o
LIBCBOR = tinycbor/lib/libtinycbor.a LIBCBOR = tinycbor/lib/libtinycbor.a
@ -20,9 +22,20 @@ else
export LDFLAGS = -Wl,--gc-sections export LDFLAGS = -Wl,--gc-sections
endif endif
LDFLAGS += $(LIBCBOR) LDFLAGS += $(LIBCBOR)
CFLAGS = -O2 -fdata-sections -ffunction-sections
VERSION:=$(shell git describe --abbrev=0 )
VERSION_FULL:=$(shell git describe)
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
CFLAGS = -O2 -fdata-sections -ffunction-sections $(VERSION_FLAGS) -g
INCLUDES = -I./tinycbor/src -I./crypto/sha256 -I./crypto/micro-ecc/ -Icrypto/tiny-AES-c/ -I./fido2/ -I./pc -I./fido2/extensions INCLUDES = -I./tinycbor/src -I./crypto/sha256 -I./crypto/micro-ecc/ -Icrypto/tiny-AES-c/ -I./fido2/ -I./pc -I./fido2/extensions
INCLUDES += -I./crypto/cifra/src
CFLAGS += $(INCLUDES) CFLAGS += $(INCLUDES)
# for crypto/tiny-AES-c # for crypto/tiny-AES-c
@ -40,7 +53,7 @@ tinycbor/Makefile crypto/tiny-AES-c/aes.c:
cbor: $(LIBCBOR) cbor: $(LIBCBOR)
$(LIBCBOR): $(LIBCBOR):
cd tinycbor/ && $(MAKE) clean && $(MAKE) -j8 cd tinycbor/ && $(MAKE) clean && $(MAKE) LDFLAGS='' -j8
version: version:
@git describe @git describe
@ -61,6 +74,7 @@ crypto/micro-ecc/uECC.o: ./crypto/micro-ecc/uECC.c
venv: venv:
python3 -m venv venv python3 -m venv venv
venv/bin/pip -q install --upgrade pip
venv/bin/pip -q install --upgrade -r tools/requirements.txt venv/bin/pip -q install --upgrade -r tools/requirements.txt
venv/bin/pip -q install --upgrade black venv/bin/pip -q install --upgrade black
@ -69,7 +83,7 @@ black: venv
venv/bin/black --skip-string-normalization --check tools/ venv/bin/black --skip-string-normalization --check tools/
wink: venv wink: venv
venv/bin/python tools/solotool.py solo --wink venv/bin/solo key wink
fido2-test: venv fido2-test: venv
venv/bin/python tools/ctap_test.py venv/bin/python tools/ctap_test.py
@ -81,6 +95,11 @@ docker-build:
docker run --rm -v "$(CURDIR)/builds:/builds" \ docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \ -v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH) $(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
uncached-docker-build:
docker build --no-cache -t $(DOCKER_IMAGE) .
docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
CPPCHECK_FLAGS=--quiet --error-exitcode=2 CPPCHECK_FLAGS=--quiet --error-exitcode=2

121
README.md
View File

@ -1,19 +1,20 @@
[![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE) **NEW!** We launched a new tiny security key called Somu, it's live on Crowd Supply and you can [pre-order it now](https://solokeys.com/somu)!
[![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo)
[![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com) [<img src="https://miro.medium.com/max/1400/1*PnzCPLqq_5nt1gjgSEY2LQ.png" width="600">](https://solokeys.com/somu)
Somu is the micro version of Solo. We were inspired to make a secure Tomu, so we took its tiny form factor, we added the secure microcontroller and firmware of Solo, et voilà! Here we have Somu.
[![latest release](https://img.shields.io/github/release/solokeys/solo.svg)](https://update.solokeys.com/)
[![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public) [![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_shield) [![Build Status](https://travis-ci.com/solokeys/solo.svg?style=flat-square&branch=master)](https://travis-ci.com/solokeys/solo)
# Solo
Solo is an open source security key, and you can get one at [solokeys.com](https://solokeys.com). Solo is an open source security key, and you can get one at [solokeys.com](https://solokeys.com).
[<img src="https://static.solokeys.com/images/photos/hero-on-white-cropped.png" width="600">](https://solokeys.com)
Solo supports FIDO2 and U2F standards for strong two-factor authentication and password-less login, and it will protect you against phishing and other online attacks. With colored cases and multilingual guides we want to make secure login more personable and accessible to everyone around the globe. Solo supports FIDO2 and U2F standards for strong two-factor authentication and password-less login, and it will protect you against phishing and other online attacks. With colored cases and multilingual guides we want to make secure login more personable and accessible to everyone around the globe.
<img src="https://solokeys.com/images/photos/hero-on-white-cropped.png" width="600"> This repo contains the Solo firmware, including implementations of FIDO2 and U2F (CTAP2 and CTAP) over USB and NFC. The main implementation is for STM32L432, but it is easily portable.
This repo contains the Solo firmware, including implementations of FIDO2 and U2F (CTAP2 and CTAP) over USB and NFC. The main implementation is for STM32L432, and it's ported to NRF52840 and EFM32J.
For development no hardware is needed, Solo also runs as a standalone application for Windows, Linux, and Mac OSX. If you like (or want to learn) hardware instead, you can run Solo on the NUCLEO-L432KC development board, or we make Solo for Hacker, an unlocked version of Solo that lets you customize its firmware. For development no hardware is needed, Solo also runs as a standalone application for Windows, Linux, and Mac OSX. If you like (or want to learn) hardware instead, you can run Solo on the NUCLEO-L432KC development board, or we make Solo for Hacker, an unlocked version of Solo that lets you customize its firmware.
@ -33,9 +34,9 @@ Solo is based on the STM32L432 microcontroller. It offers the following security
Solo for Hacker is a special version of Solo that let you customize its firmware, for example you can change the LED color, and even build advanced applications. Solo for Hacker is a special version of Solo that let you customize its firmware, for example you can change the LED color, and even build advanced applications.
You can only buy Solo for Hacker at [solokeys.com](https://solokeys.com), as we don't sell it on Amazon and other places to avoid confusing customers. If you buy a Hacker, you can permanently lock it into a regular Solo, but viceversa you can NOT take a regular Solo and turn it a Hacker. Check out [solokeys.com](https://solokeys.com), for options on where to buy Solo. Solo Hacker can be converted to a secure version, but normal Solo cannot be converted to a Hacker version.
If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We only support Python3. If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We support Python3.
```bash ```bash
git clone --recurse-submodules https://github.com/solokeys/solo git clone --recurse-submodules https://github.com/solokeys/solo
@ -48,24 +49,22 @@ cd ../..
make venv make venv
source venv/bin/activate source venv/bin/activate
python tools/solotool.py program targets/stm32l432/solo.hex solo program aux enter-bootloader
solo program bootloader targets/stm32l432/solo.hex
``` ```
Alternatively, run `make docker-build` and use the firmware generated in `/tmp`. Alternatively, run `make docker-build` and use the firmware generated in `/tmp`.
If you forgot the `--recurse-submodules` when cloning, simply `git submodule update --init --recursive`. If you forgot the `--recurse-submodules` when cloning, simply `git submodule update --init --recursive`.
For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/led.c#L15) and force: For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/app.h#L48) and change `LED_INIT_VALUE`
``` to be a different hex color.
uint32_t b = 0;
```
Then recompile, load your new firmware, and enjoy a blue-light-free version of Solo. Then recompile, load your new firmware, and enjoy a different LED color Solo.
In the Hacker version, hardware is the same and firmware is unlocked, in the sense that you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently. In the Hacker version, hardware is the same but the firmware is unlocked, so you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently.
A frequently asked question is whether Solo for Hacker is less secure than regular Solo. The answer is certainly yes, and therefore we only recommend to use Solo for Hacker for development, experimentation, and fun. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
Hacker Solo isn't really secure so you should only use it for development. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
# Developing Solo (No Hardware Needed) # Developing Solo (No Hardware Needed)
@ -82,7 +81,7 @@ This builds Solo as a standalone application. Solo application is set up to send
Testing can be done using our fork of Yubico's client software, python-fido2. Our fork of python-fido2 has small changes to make it send USB HID over UDP to the authenticator application. You can install our fork by running the following: Testing can be done using our fork of Yubico's client software, python-fido2. Our fork of python-fido2 has small changes to make it send USB HID over UDP to the authenticator application. You can install our fork by running the following:
```bash ```bash
cd python-fido2 && python setup.py install pip install -r tools/requirements.txt
``` ```
Run the Solo application: Run the Solo application:
@ -90,15 +89,7 @@ Run the Solo application:
./main ./main
``` ```
In another shell, you can run client software, for example our tests: In another shell, you can run our [test suite](https://github.com/solokeys/fido2-tests).
```bash
python tools/ctap_test.py
```
Or any client example such as:
```bash
python python-fido2/examples/credential.py
```
You can find more details in our [documentation](https://docs.solokeys.io/solo/), including how to build on the the NUCLEO-L432KC development board. You can find more details in our [documentation](https://docs.solokeys.io/solo/), including how to build on the the NUCLEO-L432KC development board.
@ -108,20 +99,63 @@ You can find more details in our [documentation](https://docs.solokeys.io/solo/)
Check out our [official documentation](https://docs.solokeys.io/solo/). Check out our [official documentation](https://docs.solokeys.io/solo/).
# Contributors # Contributors
Solo is an upgrade to [U2F Zero](https://github.com/conorpp/u2f-zero). It was born from Conor's passion for making secure hardware, and from our shared belief that security should be open to be trustworthy, in hardware like in software. Solo is an upgrade to [U2F Zero](https://github.com/conorpp/u2f-zero). It was born from Conor's passion for making secure hardware, and from our shared belief that security should be open to be trustworthy, in hardware like in software.
Contributors are welcome. The ultimate goal is to have a FIDO2 security key supporting USB, NFC, and BLE interfaces, that can run on a variety of MCUs. This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
The ultimate goal is to have a FIDO2 security key supporting USB, NFC, and BLE interfaces, that can run on a variety of MCUs.
Look at the issues to see what is currently being worked on. Feel free to add issues as well. Look at the issues to see what is currently being worked on. Feel free to add issues as well.
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
<table>
<tr>
<td align="center"><a href="https://github.com/szszszsz"><img src="https://avatars0.githubusercontent.com/u/17005426?v=4" width="100px;" alt="Szczepan Zalega"/><br /><sub><b>Szczepan Zalega</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=szszszsz" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=szszszsz" title="Documentation">📖</a> <a href="#ideas-szszszsz" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/Wesseldr"><img src="https://avatars1.githubusercontent.com/u/4012809?v=4" width="100px;" alt="Wessel dR"/><br /><sub><b>Wessel dR</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=Wesseldr" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.imperialviolet.org"><img src="https://avatars3.githubusercontent.com/u/21203?v=4" width="100px;" alt="Adam Langley"/><br /><sub><b>Adam Langley</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aagl" title="Bug reports">🐛</a> <a href="https://github.com/solokeys/solo/commits?author=agl" title="Code">💻</a></td>
<td align="center"><a href="http://www.lotteam.com"><img src="https://avatars2.githubusercontent.com/u/807634?v=4" width="100px;" alt="Oleg Moiseenko"/><br /><sub><b>Oleg Moiseenko</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=merlokk" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/aseigler"><img src="https://avatars1.githubusercontent.com/u/6605560?v=4" width="100px;" alt="Alex Seigler"/><br /><sub><b>Alex Seigler</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aaseigler" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://www.cotech.de/services/"><img src="https://avatars3.githubusercontent.com/u/321888?v=4" width="100px;" alt="Dominik Schürmann"/><br /><sub><b>Dominik Schürmann</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Adschuermann" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/ehershey"><img src="https://avatars0.githubusercontent.com/u/286008?v=4" width="100px;" alt="Ernie Hershey"/><br /><sub><b>Ernie Hershey</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=ehershey" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/YakBizzarro"><img src="https://avatars1.githubusercontent.com/u/767740?v=4" width="100px;" alt="Andrea Corna"/><br /><sub><b>Andrea Corna</b></sub></a><br /><a href="#infra-YakBizzarro" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center"><a href="https://place.org/~pj/"><img src="https://avatars3.githubusercontent.com/u/11100?v=4" width="100px;" alt="Paul Jimenez"/><br /><sub><b>Paul Jimenez</b></sub></a><br /><a href="#infra-pjz" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/solokeys/solo/commits?author=pjz" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/yparitcher"><img src="https://avatars0.githubusercontent.com/u/38916402?v=4" width="100px;" alt="yparitcher"/><br /><sub><b>yparitcher</b></sub></a><br /><a href="#ideas-yparitcher" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-yparitcher" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/StoyanDimitrov"><img src="https://avatars1.githubusercontent.com/u/10962709?v=4" width="100px;" alt="StoyanDimitrov"/><br /><sub><b>StoyanDimitrov</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=StoyanDimitrov" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/alphathegeek"><img src="https://avatars2.githubusercontent.com/u/51253712?v=4" width="100px;" alt="alphathegeek"/><br /><sub><b>alphathegeek</b></sub></a><br /><a href="#ideas-alphathegeek" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://xakcop.com"><img src="https://avatars2.githubusercontent.com/u/271616?v=4" width="100px;" alt="Radoslav Gerganov"/><br /><sub><b>Radoslav Gerganov</b></sub></a><br /><a href="#ideas-rgerganov" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=rgerganov" title="Code">💻</a></td>
<td align="center"><a href="http://13-37.org"><img src="https://avatars3.githubusercontent.com/u/10274356?v=4" width="100px;" alt="Manuel Domke"/><br /><sub><b>Manuel Domke</b></sub></a><br /><a href="#ideas-manuel-domke" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=manuel-domke" title="Code">💻</a> <a href="#business-manuel-domke" title="Business development">💼</a></td>
</tr>
<tr>
<td align="center"><a href="http://1bitsquared.com"><img src="https://avatars3.githubusercontent.com/u/17334?v=4" width="100px;" alt="Piotr Esden-Tempski"/><br /><sub><b>Piotr Esden-Tempski</b></sub></a><br /><a href="#business-esden" title="Business development">💼</a></td>
<td align="center"><a href="https://github.com/m3hm00d"><img src="https://avatars1.githubusercontent.com/u/42179593?v=4" width="100px;" alt="f.m3hm00d"/><br /><sub><b>f.m3hm00d</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=m3hm00d" title="Documentation">📖</a></td>
<td align="center"><a href="http://blogs.gnome.org/hughsie/"><img src="https://avatars0.githubusercontent.com/u/151380?v=4" width="100px;" alt="Richard Hughes"/><br /><sub><b>Richard Hughes</b></sub></a><br /><a href="#ideas-hughsie" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=hughsie" title="Code">💻</a> <a href="#infra-hughsie" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#tool-hughsie" title="Tools">🔧</a></td>
<td align="center"><a href="http://www.schulz.dk"><img src="https://avatars1.githubusercontent.com/u/1150049?v=4" width="100px;" alt="Kim Schulz"/><br /><sub><b>Kim Schulz</b></sub></a><br /><a href="#business-kimusan" title="Business development">💼</a> <a href="#ideas-kimusan" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/oplik0"><img src="https://avatars2.githubusercontent.com/u/25460763?v=4" width="100px;" alt="Jakub"/><br /><sub><b>Jakub</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aoplik0" title="Bug reports">🐛</a></td>
</tr>
</table>
<!-- ALL-CONTRIBUTORS-LIST:END -->
# License # License
Solo is fully open source. Solo is fully open source.
All software, unless otherwise noted, is dual licensed under Apache 2.0 and MIT. All software, unless otherwise noted, is dual licensed under Apache 2.0 and MIT.
You may use Solo under the terms of either the Apache 2.0 license or MIT license. You may use Solo software under the terms of either the Apache 2.0 license or MIT license.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
All hardware, unless otherwise noted, is dual licensed under CERN and CC-BY-SA.
You may use Solo hardware under the terms of either the CERN 2.1 license or CC-BY-SA 4.0 license.
All documentation, unless otherwise noted, is licensed under CC-BY-SA.
You may use Solo documentation under the terms of the CC-BY-SA 4.0 license
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_large) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_large)
@ -129,3 +163,20 @@ You may use Solo under the terms of either the Apache 2.0 license or MIT license
# Where To Buy Solo # Where To Buy Solo
You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solokeys.com). You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solokeys.com).
<br/>
<hr/>
<br/>
[![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE)
[![All Contributors](https://img.shields.io/badge/all_contributors-19-orange.svg?style=flat-square)](#contributors)
[![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo)
[![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com)
[![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_shield)
[![latest release](https://img.shields.io/github/release/solokeys/solo.svg)](https://github.com/solokeys/solo/releases)
[![commits since last release](https://img.shields.io/github/commits-since/solokeys/solo/latest.svg)](https://github.com/solokeys/solo/commits/master)
[![last commit](https://img.shields.io/github/last-commit/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![commit activity](https://img.shields.io/github/commit-activity/m/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![contributors](https://img.shields.io/github/contributors/solokeys/solo.svg)](https://github.com/solokeys/solo/graphs/contributors)

32
SECURITY.md Normal file
View File

@ -0,0 +1,32 @@
# Security Policy
## Supported Versions
We fix security issues as soon as they are found, and release firmware updates.
Each such release is accompanied by release notes, see <https://github.com/solokeys/solo/releases>.
The latest version can be determined using the file <https://github.com/solokeys/solo/blob/master/STABLE_VERSION>.
To update your key:
- either visit <https://update.solokeys.com>, or
- use our commandline tool <https://github.com/solokeys/solo-python>:
```
solo key update [--secure|--hacker]
```
## Reporting a Vulnerability
To report vulnerabilities you have found:
- preferably contact [@conor1](https://keybase.io/conor1), [@0x0ece](https://keybase.io/0x0ece) or [@nickray](https://keybase.io/nickray) via Keybase, or
- send us e-mail using OpenPGP to [security@solokeys.com](mailto:security@solokeys.com).
<https://keys.openpgp.org/vks/v1/by-fingerprint/85AFA2769F4381E5712C36A04DDFC46FEF1F7F3F>
We do not currently run a paid bug bounty program, but are happy to provide you with a bunch of Solo keys in recognition of your findings.
## Mailing List
Join our release notification mailing list to be informed about each release:
https://sendy.solokeys.com/subscription?f=9MLIqMDmox1Ucz89C892Kq09IqYMM7OB8UrBrkvtTkDI763QF3L5PMYlRhlVNo2AI892mO

View File

@ -1 +1 @@
1.1.1 2.5.1

1
crypto/cifra Submodule

Submodule crypto/cifra added at d04dd31860

View File

@ -0,0 +1,51 @@
# Booting into bootloader mode
You can put Solo into bootloader mode by holding down the button, and plugging in Solo. After 2 seconds, bootloader mode will activate.
You'll see a yellowish flashing light and you can let go of the button.
Now Solo is ready to [accept firmware updates](/solo/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format.
If Solo is running a hacker build, it can be put into bootloader mode on command. This makes it easier for development.
```bash
solo program aux enter-bootloader
```
# The boot stages of Solo
Solo has 3 boot stages.
## DFU
The first stage is the DFU (Device Firmware Update) which is in a ROM on Solo. It is baked into the chip and is not implemented by us.
This is what allows the entire firmware of Solo to be programmed. **It's not recommended to develop for Solo using the DFU because
if you program broken firmware, you could brick your device**.
On hacker devices, you can boot into the DFU by holding down the button for 5 seconds, when Solo is already in bootloader mode.
You can also run this command when Solo is in bootloader mode to put it in DFU mode.
```bash
solo program aux enter-dfu
```
Note it will stay in DFU mode until to tell it to boot again. You can boot it again by running the following.
```bash
solo program aux leave-dfu
```
*Warning*: If you change the firmware to something broken, and you tell the DFU to boot it, you could brick your device.
## Solo Bootloader
The next boot stage is the "Solo bootloader". So when we say to put your Solo into bootloader mode, it is this stage.
This bootloader is written by us and allows signed firmware updates to be written. On Solo Hackers, there is no signature checking
and will allow any firmware updates.
It is safe to develop for Solo using our Solo bootloader. If broken firmware is uploaded to the device, then the Solo
bootloader can always be booted again by holding down the button when plugging in.
## Solo application
This is what contains all the important functionality of Solo. FIDO2, U2F, etc. This is what Solo will boot to by default.

View File

@ -1,22 +1,34 @@
# Building solo
To build, develop and debug the firmware for the STM32L432. This will work To build, develop and debug the firmware for the STM32L432. This will work
for Solo Hacker, the Nucleo development board, or you own homemade Solo. for Solo Hacker, the Nucleo development board, or your own homemade Solo.
There exists a development board [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) you can use; The board does contain a debugger, so all you need is a USB cable (and some [udev](/udev) [rules](https://rust-embedded.github.io/book/intro/install/linux.html#udev-rules)). There exists a development board [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) you can use; The board does contain a debugger, so all you need is a USB cable (and some [udev](/udev) [rules](https://rust-embedded.github.io/book/intro/install/linux.html#udev-rules)).
# Prerequisites ## Prerequisites
Install the [latest ARM compiler toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) for your system. We recommend getting the latest compilers from ARM. Install the [latest ARM compiler toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) for your system. We recommend getting the latest compilers from ARM.
You can also install the ARM toolchain using a package manage like `apt-get` or `pacman`, You can also install the ARM toolchain using a package manager like `apt-get` or `pacman`,
but be warned they might be out of date. Typically it will be called `gcc-arm-none-eabi binutils-arm-none-eabi`. but be warned they might be out of date. Typically it will be called `gcc-arm-none-eabi binutils-arm-none-eabi`.
To program your build, you'll need one of the following programs. Install `solo-python` usually with `pip3 install solo-python`. The `solo` python application may also be used for [programming](#programming).
- [openocd](http://openocd.org) ## Obtain source code and solo tool
- [stlink](https://github.com/texane/stlink)
- [STM32CubeProg](https://www.st.com/en/development-tools/stm32cubeprog.html)
# Compilation Source code can be downloaded from:
- [github releases list](https://github.com/solokeys/solo/releases)
- [github repository](https://github.com/solokeys/solo)
**solo** tool can be downloaded from:
- from python programs [repository](https://pypi.org/project/solo-python/) `pip install solo-python`
- from installing prerequisites `pip3 install -r tools/requirements.txt`
- github repository: [repository](https://github.com/solokeys/solo-python)
- installation python enviroment with command `make venv` from root directory of source code
## Compilation
Enter the `stm32l4xx` target directory. Enter the `stm32l4xx` target directory.
@ -36,7 +48,7 @@ enabled, like being able to jump to the bootloader on command. It then merges b
and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex` and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex`
into `all.hex`. into `all.hex`.
If you're just planning to do development, please don't try to reprogram the bootloader, If you're just planning to do development, **please don't try to reprogram the bootloader**,
as this can be risky if done often. Just use `solo.hex`. as this can be risky if done often. Just use `solo.hex`.
### Building with debug messages ### Building with debug messages
@ -52,14 +64,14 @@ make build-hacker DEBUG=1
``` ```
If you use `DEBUG=2`, that means Solo will not boot until something starts reading If you use `DEBUG=2`, that means Solo will not boot until something starts reading
it's debug messages. So it basically it waits to tether to a serial terminal so that you don't its debug messages. So it basically waits to tether to a serial terminal so that you don't
miss any debug messages. miss any debug messages.
We recommend using our `solotool.py` as a serial emulator since it will automatically We recommend using our `solo` tool as a serial emulator since it will automatically
reconnect each time you program Solo. reconnect each time you program Solo.
``` ```
python tools/solotool.py monitor <serial-port> solo monitor <serial-port>
``` ```
#### Linux Users: #### Linux Users:
@ -68,6 +80,8 @@ python tools/solotool.py monitor <serial-port>
### Building a Solo release ### Building a Solo release
To build Solo
If you want to build a release of Solo, we recommend trying a Hacker build first If you want to build a release of Solo, we recommend trying a Hacker build first
just to make sure that it's working. Otherwise it may not be as easy or possible to just to make sure that it's working. Otherwise it may not be as easy or possible to
fix any mistakes. fix any mistakes.
@ -78,102 +92,13 @@ If you're ready to program a full release, run this recipe to build.
make build-release-locked make build-release-locked
``` ```
Programming `all.hex` will cause the device to permanently lock itself. This outputs bootloader.hex, solo.hex, and the combined all.hex.
Programming `all.hex` will cause the device to permanently lock itself. This means debuggers cannot be used and signature checking
will be enforced on all future updates.
# Programming Note if you program a secured `solo.hex` file onto a Solo Hacker, it will lock the flash, but the bootloader
will still accept unsigned firmware updates. So you can switch it back to being a hacker, but you will
not be able to replace the unlocked bootloader anymore, since the permanently locked flash also disables the DFU.
[Read more on Solo's boot stages](/solo/bootloader-mode).
It's recommended to test a debug/hacker build first to make sure Solo is working as expected.
Then you can switch to a locked down build, which cannot be reprogrammed as easily (or not at all!).
We recommend using our `solotool.py` to manage programming. It is cross platform. First you must
install the prerequisites:
```
pip3 install -r tools/requirements.txt
```
If you're on Windows, you must also install [libusb](https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/).
## Pre-programmed Solo Hacker
If your Solo device is already programmed (it flashes green when powered), we recommend
programming it using the Solo bootloader.
```
python tools/solotool.py program solo.hex
```
Make sure to program `solo.hex` and not `all.hex`. Nothing bad would happen, but you'd
see errors.
If something bad happens, you can always boot the Solo bootloader by doing the following.
1. Unplug device.
2. Hold down button.
3. Plug in device while holding down button.
4. Wait about 2 seconds for flashing yellow light. Release button.
If you hold the button for an additional 5 seconds, it will boot to the ST DFU (device firmware update).
Don't use the ST DFU unless you know what you're doing.
## ST USB DFU
If your Solo has never been programmed, it will boot the ST USB DFU. The LED is turned
off and it enumerates as "STM BOOTLOADER".
You can program it by running the following.
```
python tools/solotool.py program all.hex --use-dfu --detach
```
Make sure to program `all.hex`, as this contains both the bootloader and the Solo application.
If all goes well, you should see a slow-flashing green light.
## Solo Hacker vs Solo
A Solo hacker device doesn't need to be in bootloader mode to be programmed, it will automatically switch.
Solo (locked) needs the button to be held down when plugged in to boot to the bootloader.
A locked Solo will only accept signed updates.
## Signed updates
If this is not a device with a hacker build, you can only program signed updates.
```
python tools/solotool.py program /path/to/firmware.json
```
If you've provisioned the Solo bootloader with your own secp256r1 public key, you can sign your
firmware by running the following command.
```
python tools/solotool.py sign /path/to/signing-key.pem /path/to/solo.hex /output-path/to/firmware.json
```
If your Solo isn't locked, you can always reprogram it using a debugger connected directly
to the token.
# Permanently locking the device
If you plan to be using your Solo for real, you should lock it permanently. This prevents
someone from connecting a debugger to your token and stealing credentials.
To do this, build the locked release firmware.
```
make build-release-locked
```
Now when you program `all.hex`, the device will lock itself when it first boots. You can only update it
with signed updates.
If you'd like to also permanently disable signed updates, plug in your programmed Solo and run the following:
```
# WARNING: No more signed updates.
python tools/programmer.py --disable
```

View File

@ -5,22 +5,22 @@ and easy to understand, especially when paired with a high level overview.
## FIDO2 codebase ## FIDO2 codebase
* main.c - calls high level functions and implements event loop. * `main.c` - calls high level functions and implements event loop.
* ctaphid.c - implements [USBHID protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb) for FIDO. * `ctaphid.c` - implements [USBHID protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb) for FIDO.
* u2f.c - implements [U2F protocol](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html). * `u2f.c` - implements [U2F protocol](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html).
* ctap.c - implements [CTAP2 protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html). * `ctap.c` - implements [CTAP2 protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html).
* ctap_parse.c - implements parsing for CTAP protocol. * `ctap_parse.c` - implements parsing for CTAP protocol.
* this could use some work minimizing. * this could use some work minimizing.
* log.c - embedded friendly debug logging. * `log.c` - embedded friendly debug logging.
* crypto.c - software implementation of the crypto needs of the application. Generally this will be copied and edited for different platforms. API defined in crypto.h should be the same. * `crypto.c` - software implementation of the crypto needs of the application. Generally this will be copied and edited for different platforms. API defined in `crypto.h` should be the same.
* device.h - definitions of functions that are platform specific and should be implemented separately. See device.c in any of the implementations to see examples. * `device.h` - definitions of functions that are platform specific and should be implemented separately. See `device.c` in any of the implementations to see examples.
## Data flow ## Data flow

141
docs/solo/customization.md Normal file
View File

@ -0,0 +1,141 @@
# Customization
If you are interested in customizing parts of your Solo, and you have a Solo Hacker, this page is for you.
## Custom Attestation key
The attestation key is used in the FIDO2 *makeCredential* or U2F *register* requests. It signs
newly generated credentials. The certificate associated with the attestation key is output with newly created credentials.
Platforms or services can use the attestation feature to enforce specific authenticators to be used.
This is typically a use case for organizations and isn't seen in the wild for consumer use cases.
Attestation keys are typically the same for at least 100K units of a particular authenticator model.
This is so they don't contribute a significant fingerprint that platforms could use to identify the user.
If you don't want to use the default attestation key that Solo builds with, you can create your own
and program it.
### Creating your attestation key pair
Since we are generating keys, it's important to use a good entropy source.
You can use the [True RNG on your Solo](/solo/solo-extras) to generate some good random numbers.
```
# Run for 1 second, then hit control-c
solo key rng raw > seed.bin
```
First we will create a self signed key pair that acts as the root of trust. This
won't go on the authenticator, but will sign the keypair that does.
Please change the root certification information as needed. You may change the ECC curve.
```
curve=prime256v1
country=US
state=Maine
organization=OpenSourceSecurity
unit="Root CA"
CN=example.com
email=example@example.com
# generate EC private key
openssl ecparam -genkey -name "$curve" -out root_key.pem -rand seed.bin
# generate a "signing request"
openssl req -new -key root_key.pem -out root_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=example.com/emailAddress=$email"
# self sign the request
openssl x509 -trustout -req -days 18250 -in root_key.pem.csr -signkey root_key.pem -out root_cert.pem -sha256
# convert to smaller size format DER
openssl x509 -in root_cert.pem -outform der -out root_cert.der
# print out information and verify
openssl x509 -in root_cert.pem -text -noout
```
You need to create a extended certificate for the device certificate to work with FIDO2. You need to create this
file, `v3.ext`, and add these options to it.
```
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
```
Now to generate & sign the attestation key pair that will go on your device, or maybe 100,000 devices :).
Note you must use a prime256v1 curve for this step, and you must leave the unit/OU as "Authenticator Attestation".
```
country=US
state=Maine
organization=OpenSourceSecurity
unit="Authenticator Attestation"
CN=example.com
email=example@example.com
# generate EC private key
openssl ecparam -genkey -name "$curve" -out device_key.pem -rand seed.bin
# generate a "signing request"
openssl req -new -key device_key.pem -out device_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=example.com/emailAddress=$email"
# sign the request
openssl x509 -req -days 18250 -in device_key.pem.csr -extfile v3.ext -CA root_cert.pem -CAkey root_key.pem -set_serial 01 -out device_cert.pem -sha256
# convert to smaller size format DER
openssl x509 -in device_cert.pem -outform der -out device_cert.der
# Verify the device certificate details
openssl x509 -in device_cert.pem -text -noout
```
Let's verify that the attestation key and certificate are valid, and that they can be verified with the root key pair.
```
echo 'challenge $RANDOM' > chal.txt
# check that they are valid key pairs
openssl dgst -sha256 -sign device_key.pem -out sig.txt chal.txt
openssl dgst -sha256 -verify <(openssl x509 -in device_cert.pem -pubkey -noout) -signature sig.txt chal.txt
openssl dgst -sha256 -sign "root_key.pem" -out sig.txt chal.txt
openssl dgst -sha256 -verify <(openssl x509 -in root_cert.pem -pubkey -noout) -signature sig.txt chal.txt
# Check they are a chain
openssl verify -verbose -CAfile "root_cert.pem" "device_cert.pem"
```
If the checks succeed, you are ready to program the device attestation key and certificate.
### Programming an attestation key and certificate
Convert the DER format of the device attestation certificate to "C" bytes using our utility script. You may first need to
first install prerequisite python modules (pip install -r tools/requirements.txt).
```
python tools/gencert/cbytes.py device_cert.der
```
Copy the byte string portion into the [`attestation.c` source file of Solo](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/attestation.c). Overwrite the development or "default" certificate that is already there.
Now [build the Solo firmware](/solo/building), either a secure or hacker build. You will need to produce a bootloader.hex file and a solo.hex file.
Print your attestation key in a hex string format.
```
python tools/print_x_y.py device_key.pem
```
Merge the bootloader.hex, solo.hex, and attestion key into one firmware file.
```
solo mergehex --attestation-key <attestation-key-hex-string> bootloader.hex solo.hex all.hex
```
Now you have a newly create `all.hex` file with a custom attestation key. You can [program this all.hex file
with Solo in DFU mode](/solo/programming#procedure).

View File

@ -3,7 +3,7 @@ Documentation of the `master` branch is deployed to Netlify automatically.
To host or develop locally: To host or develop locally:
``` ```
pip install mkdocs mkdocs-material pip install mkdocs mkdocs-material markdown-include
``` ```
`mkdocs serve` and visit [localhost:8000](http://localhost:8000). `mkdocs serve` and visit [localhost:8000](http://localhost:8000).

View File

@ -22,8 +22,8 @@ for FIDO2 operation.
When you register a service with a FIDO2 or U2F authenticator, the When you register a service with a FIDO2 or U2F authenticator, the
authenticator must generate a new keypair unique to that service. This keypair authenticator must generate a new keypair unique to that service. This keypair
could be stored on the authenticator to be used in subsequent authentications, could be stored on the authenticator to be used in subsequent authentications,
but now a certain amount of memory needs to be allocated for this. On embedded but a certain amount of memory would need to be allocated for this. On embedded
devices, there isn't much memory to spare and users will allows frustratingly devices, there isn't much memory to spare and users would frustratingly
hit the limit of this memory. hit the limit of this memory.
The answer to this problem is to do key wrapping. The authenticator just The answer to this problem is to do key wrapping. The authenticator just
@ -39,7 +39,7 @@ In essence, the following happens at registration.
3. Return `P` and `R` to service. (`R` is in `KEYID` parameter) 3. Return `P` and `R` to service. (`R` is in `KEYID` parameter)
4. Service stores `P` and `R`. 4. Service stores `P` and `R`.
Now on authenication. Now on authentication.
1. Service issues authentication request with `R` in `KEYID` parameter. 1. Service issues authentication request with `R` in `KEYID` parameter.
2. \* Authenticator generates `K` by calculating `HMAC(M,R)`. 2. \* Authenticator generates `K` by calculating `HMAC(M,R)`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File

@ -1,4 +1,4 @@
Welcome to the technical documentation for [solokeys/solo](https://github.com/solokeys/solo). Welcome to the technical documentation for [solokeys/solo](https://github.com/solokeys/solo).
For now, you can read the repository `README.md`, more documentation to come! Use the table of contents on the left to browse this documentation.

258
docs/solo/nucleo32-board.md Normal file
View File

@ -0,0 +1,258 @@
# Nucleo32 board preparation
Additional steps are required to run the firmware on the Nucleo32 board.
## USB-A cable
Board does not provide an USB cable / socket for the target MCU communication.
Own provided USB plug has to be connected in the following way:
| PIN / Arduino PIN | MCU leg | USB wire color | Signal |
| ----------------- | ------- | -------------- | ------ |
| D10 / PA11 | 21 | white | D- |
| D2 / PA12 | 22 | green | D+ |
| GND (near D2) | ------- | black | GND |
| **not connected** | ------- | red | 5V |
Each USB plug pin should be connected via the wire in a color defined by the standard. It might be confirmed with a
multimeter for additional safety. USB plug description:
| PIN | USB wire color | Signal |
| --- | -------------- | ------ |
| 4 | black | GND |
| 3 | green | D+ |
| 2 | white | D- |
| 1 | red | 5V |
See this [USB plug] image, and Wikipedia's [USB plug description].
Plug in [USB-A_schematic.pdf] has wrong wire order, registered as [solo-hw#1].
The power is taken from the debugger / board (unless the board is configured in another way).
Make sure 5V is not connected, and is covered from contacting with the board elements.
Based on [USB-A_schematic.pdf].
## Firmware modification
Following patch has to be applied to skip the user presence confirmation, for tests. Might be applied at a later stage.
```text
diff --git a/targets/stm32l432/src/app.h b/targets/stm32l432/src/app.h
index c14a7ed..c89c3b5 100644
--- a/targets/stm32l432/src/app.h
+++ b/targets/stm32l432/src/app.h
@@ -71,6 +71,6 @@ void hw_init(void);
#define SOLO_BUTTON_PIN LL_GPIO_PIN_0
#define SKIP_BUTTON_CHECK_WITH_DELAY 0
-#define SKIP_BUTTON_CHECK_FAST 0
+#define SKIP_BUTTON_CHECK_FAST 1
#endif
```
It is possible to provide a button and connect it to the MCU pins, as instructed in [USB-A_schematic.pdf]&#x3A;
```text
PA0 / pin 6 --> button --> GND
```
In that case the mentioned patch would not be required.
## Development environment setup
Environment: Fedora 29 x64, Linux 4.19.9
See <https://docs.solokeys.io/solo/building/> for the original guide. Here details not included there will be covered.
### Install ARM tools Linux
1. Download current [ARM tools] package: [gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2].
2. Extract the archive.
3. Add full path to the `./bin` directory as first entry to the `$PATH` variable,
as in `~/gcc-arm/gcc-arm-none-eabi-8-2018-q4-major/bin/:$PATH`.
### Install ARM tools OsX using brew package manager
```bash
brew tap ArmMbed/homebrew-formulae
brew install arm-none-eabi-gcc
```
### Install flashing software
ST provides a CLI flashing tool - `STM32_Programmer_CLI`. It can be downloaded directly from the vendor's site:
1\. Go to [download site URL](https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stm32cubeprog.html),
go to bottom page and from STM32CubeProg row select Download button.
2\. Unzip contents of the archive.
3\. Run \*Linux setup
4\. In installation directory go to ./bin - there the ./STM32_Programmer_CLI is located
5\. Add symlink to the STM32 CLI binary to .local/bin. Make sure the latter it is in $PATH.
If you're on OsX and installed the STM32CubeProg, you need to add the following to your path:
```bash
# ~/.bash_profile
export PATH="/Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/bin/":$PATH
```
## Building and flashing
### Building
Please follow <https://docs.solokeys.io/solo/building/>, as the build way changes rapidly.
Currently (8.1.19) to build the firmware, following lines should be executed
```bash
# while in the main project directory
cd targets/stm32l432
make cbor
make build-hacker DEBUG=1
```
Note: `DEBUG=2` stops the device initialization, until a serial client will be attached to its virtual port.
Do not use it, if you do not plan to do so.
### Flashing via the Makefile command
```bash
# while in the main project directory
# create Python virtual environment with required packages, and activate
make venv
. venv/bin/activate
# Run flashing
cd ./targets/stm32l432
make flash
# which runs:
# flash: solo.hex bootloader.hex
# python merge_hex.py solo.hex bootloader.hex all.hex (intelhex library required)
# STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
# STM32_Programmer_CLI -c port=SWD -halt -d all.hex -rst
```
### Manual flashing
In case you already have a firmware to flash (named `all.hex`), please run the following:
```bash
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d all.hex -rst
```
## Testing
### Internal
Project-provided tests.
#### Simulated device
A simulated device is provided to test the HID layer.
##### Build
```bash
make clean
cd tinycbor
make
cd ..
make env2
```
##### Execution
```bash
# run simulated device (will create a network UDP server)
./main
# run test 1
./env2/bin/python tools/ctap_test.py
# run test 2 (or other files in the examples directory)
./env2/bin/python python-fido2/examples/credential.py
```
#### Real device
```bash
# while in the main project directory
# not passing as of 8.1.19, due to test solution issues
make fido2-test
```
### External
#### FIDO2 test sites
1. <https://www.passwordless.dev/overview>
2. <https://webauthn.bin.coffee/>
3. <https://webauthn.org/>
#### U2F test sites
1. <https://u2f.bin.coffee/>
2. <https://demo.yubico.com/u2f>
#### FIDO2 standalone clients
1. <https://github.com/Nitrokey/u2f-ref-code>
2. <https://github.com/Yubico/libfido2>
3. <https://github.com/Yubico/python-fido2>
4. <https://github.com/google/pyu2f>
## USB serial console reading
Device opens an USB-emulated serial port to output its messages. While Nucleo board offers such already,
the Solo device provides its own.
- Provided Python tool
```bash
python3 ../../tools/solotool.py monitor /dev/solokey-serial
```
- External application
```bash
sudo picocom -b 115200 /dev/solokey-serial
```
where `/dev/solokey-serial` is an udev symlink to `/dev/ttyACM1`.
## Other
### Dumping firmware
Size is calculated using bash arithmetic.
```bash
STM32_Programmer_CLI -c port=SWD -halt -u 0x0 $((256*1024)) current.hex
```
### Software reset
```bash
STM32_Programmer_CLI -c port=SWD -rst
```
### Installing required Python packages
Client script requires some Python packages, which could be easily installed locally to the project
via the Makefile command. It is sufficient to run:
```bash
make env3
```
[solo-hw#1]: https://github.com/solokeys/solo-hw/issues/1
[usb plug]: https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/USB.svg/1200px-USB.svg.png
[usb plug description]: https://en.wikipedia.org/wiki/USB#Receptacle_(socket)_identification
[usb-a_schematic.pdf]: https://github.com/solokeys/solo-hw/releases/download/1.2/USB-A_schematic.pdf
[arm tools]: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads
[gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2]: https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2?revision=d830f9dd-cd4f-406d-8672-cca9210dd220?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2018-q4-major

113
docs/solo/programming.md Normal file
View File

@ -0,0 +1,113 @@
# Programming
This page documents how to update or program your Solo.
## Prerequisites
To program Solo, you'll likely only need to use our Solo tool.
```python
pip3 install solo-python
```
## Updating the firmware
If you just want to update the firmware, you can run one of the following commands.
Make sure your key [is in bootloader mode](/solo/bootloader-mode#solo-bootloader) first.
```bash
solo key update <--secure | --hacker>
```
You can manually install the [latest release](https://github.com/solokeys/solo/releases), or use a build that you made.
```bash
# If it's a hacker, it will automatically boot into bootloader mode.
solo program bootloader <firmware.hex | firmware.json>
```
Note you won't be able to use `all.hex` or the `bundle-*.hex` builds, as these include the solo bootloader. You shouldn't
risk changing the Solo bootloader unless you want to make it a secure device, or [make other customizations]().
## Updating a Hacker to a Secure Solo
Updating a hacker to be a secure build overwrites the [Solo bootloader](/solo/bootloader-mode#solo-bootloader).
So it's important to not mess this up or you may brick your device.
You can use a firmware build from the [latest release](https://github.com/solokeys/solo/releases) or use
a build that you made yourself.
You need to use a firmware file that has the combined bootloader and application (or at the very least just the bootloader).
This means using the `bundle-*.hex` file or the `all.hex` from your build. If you overwrite the Solo flash with a missing bootloader,
it will be bricked.
We provide two types of bundled builds. The `bundle-hacker-*.hex` build is the hacker build. If you update with this,
you will update the bootloader and application, but nothing will be secured. The `bundle-secure-non-solokeys.hex`
is a secured build that will lock your device and it will behave just like a Secure Solo. The main difference is that
it uses a "default" attestation key in the device, rather than the SoloKeys attestation key. There is no security
concern with using our default attestation key, aside from a privacy implication that services can distinguish it from Solo Secure.
### Procedure
1. Boot into DFU mode.
# Enter Solo bootloader
solo program aux enter-bootloader
# Enter DFU
solo program aux enter-dfu
The device should be turned off.
2. Program the device
solo program dfu <bundle-secure-non-solokeys.hex | all.hex>
Double check you programmed it with bootloader + application (or just bootloader).
If you messed it up, simply don't do the next step and repeat this step correctly.
3. Boot the device
Once Solo boots a secure build, it will lock the flash permantly from debugger access. Also the bootloader
will only accept signed firmware updates.
solo program aux leave-dfu
If you are having problems with solo tool and DFU mode, you could alternatively try booting into DFU
by holding down the button while Solo is in bootloader mode. Then try another programming tool that works
with ST DFU:
* STM32CubeProg
* openocd
* stlink
Windows users need to install [libusb](https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/)
for solo-python to work with Solo's DFU.
## Programming a Solo that hasn't been programmed
A Solo that hasn't been programmed will boot into DFU mode. You can program
it by following a bootloader, or combined bootloader + application.
```
solo program dfu <bundle-*.hex | all.hex>
```
Then boot the device. Make sure it has a bootloader to boot to.
```
solo program aux leave-dfu
```
## Disable signed firmware updates
If you'd like to also permanently disable signed updates, plug in your programmed Solo and run the following:
```bash
# WARNING: No more signed updates.
solo program disable-bootloader
```
You won't be able to update to any new releases.

19
docs/solo/solo-extras.md Normal file
View File

@ -0,0 +1,19 @@
# Solo Extras
## Random number generation
Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism
that leverages natural phenomenon to generate random numbers, which is can be better than a traditional
RNG that has state and updates deterministically using cryptographic methods.
You can easily access the TRNG stream on Solo using our python tool [solo-python](https://github.com/solokeys/solo-python).
```
solo key rng raw > random.bin
```
Or you can seed the state of the RNG on your kernel (/dev/random).
```
solo key rng feedkernel
```

View File

@ -1,20 +1,30 @@
# tl;dr # Summary
Create a file like [`/etc/udev/rules.d/99-solo.rules`](https://github.com/solokeys/solo/blob/master/99-solo.rules), for instance the following rules should cover access in all cases: On Linux, by default USB dongles can't be accessed by users, for security reasons. To allow user access, so-called "udev rules" must be installed.
For some users, things will work automatically:
- Fedora seems to use a ["universal" udev rule for FIDO devices](https://github.com/amluto/u2f-hidraw-policy)
- Our udev rule made it into [libu2f-host](https://github.com/Yubico/libu2f-host/) v1.1.10
- Arch Linux [has this package](https://www.archlinux.org/packages/community/x86_64/libu2f-host/)
- [Debian sid](https://packages.debian.org/sid/libu2f-udev) and [Ubuntu Eon](https://packages.ubuntu.com/eoan/libu2f-udev) can use the `libu2f-udev` package
- Debian Buster and Ubuntu Disco still distribute v1.1.10, so need the manual rule
- FreeBSD has support in [u2f-devd](https://github.com/solokeys/solo/issues/144#issuecomment-500216020)
There is hope that `udev` itself will adopt the Fedora approach (which is to check for HID usage page `F1D0`, and avoids manually whitelisting each U2F/FIDO2 key): <https://github.com/systemd/systemd/issues/11996>.
Further progress is tracked in: <https://github.com/solokeys/solo/issues/144>.
If you still need to setup a rule, a simple way to do it is:
``` ```
# Solo bootloader + firmware git clone git@github.com:solokeys/solo.git
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev" cd solo/udev
make setup
# ST DFU bootloader
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess", GROUP="plugdev"
# U2F Zero
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev"
``` ```
Then run Or, manually, create a file like [`70-solokeys-access.rules`](https://github.com/solokeys/solo/blob/master/udev/70-solokeys-access.rules) in your `/etc/udev/rules.d` directory.
Additionally, run the following command after you create this file (it is not necessary to do this again in the future):
``` ```
sudo udevadm control --reload-rules && sudo udevadm trigger sudo udevadm control --reload-rules && sudo udevadm trigger
``` ```

122
fido2/apdu.c Normal file
View File

@ -0,0 +1,122 @@
// Copyright 2019 SoloKeys Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
// iso7816:2013. 5.3.2 Decoding conventions for command bodies
#include "apdu.h"
int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
{
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any
apdu->ins = hapdu->ins;
apdu->p1 = hapdu->p1;
apdu->p2 = hapdu->p2;
apdu->lc = 0;
apdu->data = NULL;
apdu->le = 0;
apdu->extended_apdu = false;
apdu->case_type = 0x00;
uint8_t b0 = hapdu->lc[0];
// case 1
if (len == 4)
{
apdu->case_type = 0x01;
}
// case 2S (Le)
if (len == 5)
{
apdu->case_type = 0x02;
apdu->le = b0;
if (!apdu->le)
apdu->le = 0x100;
}
// case 3S (Lc + data)
if (len == 5U + b0 && b0 != 0)
{
apdu->case_type = 0x03;
apdu->lc = b0;
}
// case 4S (Lc + data + Le)
if (len == 5U + b0 + 1U && b0 != 0)
{
apdu->case_type = 0x04;
apdu->lc = b0;
apdu->le = data[len - 1];
if (!apdu->le)
apdu->le = 0x100;
}
// extended length apdu
if (len >= 7 && b0 == 0)
{
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
// case 2E (Le) - extended
if (len == 7)
{
apdu->case_type = 0x12;
apdu->extended_apdu = true;
apdu->le = extlen;
if (!apdu->le)
apdu->le = 0x10000;
}
// case 3E (Lc + data) - extended
if (len == 7U + extlen)
{
apdu->case_type = 0x13;
apdu->extended_apdu = true;
apdu->lc = extlen;
}
// case 4E (Lc + data + Le) - extended 2-byte Le
if (len == 7U + extlen + 2U)
{
apdu->case_type = 0x14;
apdu->extended_apdu = true;
apdu->lc = extlen;
apdu->le = (data[len - 2] << 8) + data[len - 1];
if (!apdu->le)
apdu->le = 0x10000;
}
// case 4E (Lc + data + Le) - extended 3-byte Le
if (len == 7U + extlen + 3U && data[len - 3] == 0)
{
apdu->case_type = 0x24;
apdu->extended_apdu = true;
apdu->lc = extlen;
apdu->le = (data[len - 2] << 8) + data[len - 1];
if (!apdu->le)
apdu->le = 0x10000;
}
}
if (!apdu->case_type)
return 1;
if (apdu->lc)
{
if (apdu->extended_apdu)
{
apdu->data = data + 7;
} else {
apdu->data = data + 5;
}
}
return 0;
}

63
fido2/apdu.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef _APDU_H_
#define _APDU_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint8_t lc;
} __attribute__((packed)) APDU_HEADER;
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint8_t lc[3];
} __attribute__((packed)) EXT_APDU_HEADER;
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint16_t lc;
uint8_t *data;
uint32_t le;
bool extended_apdu;
uint8_t case_type;
} __attribute__((packed)) APDU_STRUCT;
extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
#define APDU_FIDO_U2F_REGISTER 0x01
#define APDU_FIDO_U2F_AUTHENTICATE 0x02
#define APDU_FIDO_U2F_VERSION 0x03
#define APDU_FIDO_NFCCTAP_MSG 0x10
#define APDU_FIDO_U2F_VENDOR_FIRST 0xc0 // First vendor defined command
#define APDU_FIDO_U2F_VENDOR_LAST 0xff // Last vendor defined command
#define APDU_SOLO_RESET 0xee
#define APDU_INS_SELECT 0xA4
#define APDU_INS_READ_BINARY 0xB0
#define APDU_GET_RESPONSE 0xC0
#define SW_SUCCESS 0x9000
#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE.
#define SW_WRONG_LENGTH 0x6700
#define SW_COND_USE_NOT_SATISFIED 0x6985
#define SW_FILE_NOT_FOUND 0x6a82
#define SW_INCORRECT_P1P2 0x6a86
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
#define SW_CLA_INVALID 0x6e00
#define SW_INTERNAL_EXCEPTION 0x6f00
#endif //_APDU_H_

View File

@ -16,7 +16,7 @@
#define COSE_KEY_KTY_EC2 2 #define COSE_KEY_KTY_EC2 2
#define COSE_KEY_CRV_P256 1 #define COSE_KEY_CRV_P256 1
#define COSE_ALG_ES256 -7 #define COSE_ALG_ES256 -7
#define COSE_ALG_ECDH_ES_HKDF_256 -25
#endif #endif

View File

@ -60,7 +60,7 @@ static const uint8_t * _signing_key = NULL;
static int _key_len = 0; static int _key_len = 0;
// Secrets for testing only // Secrets for testing only
static uint8_t master_secret[32]; static uint8_t master_secret[64];
static uint8_t transport_secret[32]; static uint8_t transport_secret[32];
@ -73,13 +73,17 @@ void crypto_sha256_init()
void crypto_reset_master_secret() void crypto_reset_master_secret()
{ {
ctap_generate_rng(master_secret, 32); ctap_generate_rng(master_secret, 64);
ctap_generate_rng(transport_secret, 32);
} }
void crypto_load_master_secret(uint8_t * key) void crypto_load_master_secret(uint8_t * key)
{ {
memmove(master_secret, key, 32); #if KEY_SPACE_BYTES < 96
memmove(transport_secret, key+32, 32); #error "need more key bytes"
#endif
memmove(master_secret, key, 64);
memmove(transport_secret, key+64, 32);
} }
void crypto_sha256_update(uint8_t * data, size_t len) void crypto_sha256_update(uint8_t * data, size_t len)
@ -108,6 +112,11 @@ void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
key = master_secret; key = master_secret;
klen = sizeof(master_secret); klen = sizeof(master_secret);
} }
else if (key == CRYPTO_TRANSPORT_KEY)
{
key = transport_secret;
klen = 32;
}
if(klen > 64) if(klen > 64)
{ {
@ -253,6 +262,11 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
memmove(y,pubkey+32,32); memmove(y,pubkey+32,32);
} }
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
{
uECC_compute_public_key(privkey, pubkey, _es256_curve);
}
void crypto_load_external_key(uint8_t * key, int len) void crypto_load_external_key(uint8_t * key, int len)
{ {
_signing_key = key; _signing_key = key;

View File

@ -19,9 +19,14 @@ void crypto_sha256_final(uint8_t * hash);
void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac); void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac);
void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac); void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac);
void crypto_sha512_init();
void crypto_sha512_update(const uint8_t * data, size_t len);
void crypto_sha512_final(uint8_t * hash);
void crypto_ecc256_init(); void crypto_ecc256_init();
void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y); void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y);
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey);
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2); void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2);
void crypto_ecc256_load_attestation_key(); void crypto_ecc256_load_attestation_key();
@ -34,6 +39,7 @@ void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, ui
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey); void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret); void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret);
#define CRYPTO_TRANSPORT_KEY2 ((uint8_t*)2)
#define CRYPTO_TRANSPORT_KEY ((uint8_t*)1) #define CRYPTO_TRANSPORT_KEY ((uint8_t*)1)
#define CRYPTO_MASTER_KEY ((uint8_t*)0) #define CRYPTO_MASTER_KEY ((uint8_t*)0)

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,13 @@
#define CP_getKeyAgreement 0x07 #define CP_getKeyAgreement 0x07
#define CP_getRetries 0x08 #define CP_getRetries 0x08
#define EXT_HMAC_SECRET_COSE_KEY 0x01
#define EXT_HMAC_SECRET_SALT_ENC 0x02
#define EXT_HMAC_SECRET_SALT_AUTH 0x03
#define EXT_HMAC_SECRET_REQUESTED 0x01
#define EXT_HMAC_SECRET_PARSED 0x02
#define RESP_versions 0x1 #define RESP_versions 0x1
#define RESP_extensions 0x2 #define RESP_extensions 0x2
#define RESP_aaguid 0x3 #define RESP_aaguid 0x3
@ -105,6 +112,8 @@
#define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes #define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes
#define PUB_KEY_CRED_PUB_KEY 0x01 #define PUB_KEY_CRED_PUB_KEY 0x01
#define PUB_KEY_CRED_CTAP1 0x41
#define PUB_KEY_CRED_CUSTOM 0x42
#define PUB_KEY_CRED_UNKNOWN 0x3F #define PUB_KEY_CRED_UNKNOWN 0x3F
#define CREDENTIAL_IS_SUPPORTED 1 #define CREDENTIAL_IS_SUPPORTED 1
@ -122,6 +131,8 @@
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total #define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot #define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
#define CTAP2_UP_DELAY_MS 29000
typedef struct typedef struct
{ {
uint8_t id[USER_ID_MAX_SIZE]; uint8_t id[USER_ID_MAX_SIZE];
@ -142,9 +153,13 @@ struct Credential {
CredentialId id; CredentialId id;
CTAP_userEntity user; CTAP_userEntity user;
}; };
typedef struct Credential CTAP_residentKey; typedef struct Credential CTAP_residentKey;
typedef struct
{
uint8_t type;
struct Credential credential;
} CTAP_credentialDescriptor;
typedef struct typedef struct
{ {
@ -181,34 +196,67 @@ struct rpId
uint8_t name[RP_NAME_LIMIT]; uint8_t name[RP_NAME_LIMIT];
}; };
typedef struct
{
struct{
uint8_t x[32];
uint8_t y[32];
} pubkey;
int kty;
int crv;
} COSE_key;
typedef struct
{
uint8_t saltLen;
uint8_t saltEnc[64];
uint8_t saltAuth[32];
COSE_key keyAgreement;
struct Credential * credential;
} CTAP_hmac_secret;
typedef struct
{
uint8_t hmac_secret_present;
CTAP_hmac_secret hmac_secret;
} CTAP_extensions;
typedef struct
{
CTAP_userEntity user;
uint8_t publicKeyCredentialType;
int32_t COSEAlgorithmIdentifier;
uint8_t rk;
} CTAP_credInfo;
typedef struct typedef struct
{ {
uint32_t paramsParsed; uint32_t paramsParsed;
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE]; uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
struct rpId rp; struct rpId rp;
CTAP_userEntity user;
uint8_t publicKeyCredentialType; CTAP_credInfo credInfo;
int32_t COSEAlgorithmIdentifier;
CborValue excludeList; CborValue excludeList;
size_t excludeListSize; size_t excludeListSize;
uint8_t rk;
uint8_t uv; uint8_t uv;
uint8_t up; uint8_t up;
uint8_t pinAuth[16]; uint8_t pinAuth[16];
uint8_t pinAuthPresent; uint8_t pinAuthPresent;
// pinAuthEmpty is true iff an empty bytestring was provided as pinAuth.
// This is exclusive with |pinAuthPresent|. It exists because an empty
// pinAuth is a special signal to block for touch. See
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorMakeCredential
uint8_t pinAuthEmpty;
int pinProtocol; int pinProtocol;
CTAP_extensions extensions;
} CTAP_makeCredential; } CTAP_makeCredential;
typedef struct
{
uint8_t type;
struct Credential credential;
} CTAP_credentialDescriptor;
typedef struct typedef struct
{ {
@ -226,26 +274,25 @@ typedef struct
uint8_t pinAuth[16]; uint8_t pinAuth[16];
uint8_t pinAuthPresent; uint8_t pinAuthPresent;
// pinAuthEmpty is true iff an empty bytestring was provided as pinAuth.
// This is exclusive with |pinAuthPresent|. It exists because an empty
// pinAuth is a special signal to block for touch. See
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorGetAssertion
uint8_t pinAuthEmpty;
int pinProtocol; int pinProtocol;
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE]; CTAP_credentialDescriptor * creds;
uint8_t allowListPresent; uint8_t allowListPresent;
CTAP_extensions extensions;
} CTAP_getAssertion; } CTAP_getAssertion;
typedef struct typedef struct
{ {
int pinProtocol; int pinProtocol;
int subCommand; int subCommand;
struct COSE_key keyAgreement;
{
struct{
uint8_t x[32];
uint8_t y[32];
} pubkey;
int kty;
int crv;
} keyAgreement;
uint8_t keyAgreementPresent; uint8_t keyAgreementPresent;
uint8_t pinAuth[16]; uint8_t pinAuth[16];
uint8_t pinAuthPresent; uint8_t pinAuthPresent;
@ -258,6 +305,19 @@ typedef struct
} CTAP_clientPin; } CTAP_clientPin;
struct _getAssertionState {
CTAP_authDataHeader authData;
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
uint8_t lastcmd;
uint32_t count;
uint32_t index;
uint32_t time;
uint8_t user_verified;
uint8_t customCredId[256];
uint8_t customCredIdSize;
};
void ctap_response_init(CTAP_RESPONSE * resp); void ctap_response_init(CTAP_RESPONSE * resp);
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp); uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp);

View File

@ -49,6 +49,7 @@
#define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37 #define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37
#define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38 #define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38
#define CTAP2_ERR_REQUEST_TOO_LARGE 0x39 #define CTAP2_ERR_REQUEST_TOO_LARGE 0x39
#define CTAP2_ERR_ACTION_TIMEOUT 0x3A
#define CTAP1_ERR_OTHER 0x7F #define CTAP1_ERR_OTHER 0x7F
#define CTAP2_ERR_SPEC_LAST 0xDF #define CTAP2_ERR_SPEC_LAST 0xDF
#define CTAP2_ERR_EXTENSION_FIRST 0xE0 #define CTAP2_ERR_EXTENSION_FIRST 0xE0

View File

@ -9,12 +9,14 @@
#include "cbor.h" #include "cbor.h"
#include "ctap.h" #include "ctap.h"
#include "u2f.h"
#include "ctap_parse.h" #include "ctap_parse.h"
#include "ctap_errors.h" #include "ctap_errors.h"
#include "cose_key.h" #include "cose_key.h"
#include "util.h" #include "util.h"
#include "log.h" #include "log.h"
extern struct _getAssertionState getAssertionState;
void _check_ret(CborError ret, int line, const char * filename) void _check_ret(CborError ret, int line, const char * filename)
{ {
@ -128,14 +130,13 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
} }
sz = USER_ID_MAX_SIZE; sz = USER_ID_MAX_SIZE;
ret = cbor_value_copy_byte_string(&map, MC->user.id, &sz, NULL); ret = cbor_value_copy_byte_string(&map, MC->credInfo.user.id, &sz, NULL);
if (ret == CborErrorOutOfMemory) if (ret == CborErrorOutOfMemory)
{ {
printf2(TAG_ERR,"Error, USER_ID is too large\n"); printf2(TAG_ERR,"Error, USER_ID is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED; return CTAP2_ERR_LIMIT_EXCEEDED;
} }
MC->user.id_size = sz; MC->credInfo.user.id_size = sz;
printf1(TAG_GREEN,"parsed id_size: %d\r\n", MC->user.id_size);
check_ret(ret); check_ret(ret);
} }
else if (strcmp((const char *)key, "name") == 0) else if (strcmp((const char *)key, "name") == 0)
@ -146,12 +147,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
sz = USER_NAME_LIMIT; sz = USER_NAME_LIMIT;
ret = cbor_value_copy_text_string(&map, (char *)MC->user.name, &sz, NULL); ret = cbor_value_copy_text_string(&map, (char *)MC->credInfo.user.name, &sz, NULL);
if (ret != CborErrorOutOfMemory) if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay { // Just truncate the name it's okay
check_ret(ret); check_ret(ret);
} }
MC->user.name[USER_NAME_LIMIT - 1] = 0; MC->credInfo.user.name[USER_NAME_LIMIT - 1] = 0;
} }
else if (strcmp((const char *)key, "displayName") == 0) else if (strcmp((const char *)key, "displayName") == 0)
{ {
@ -161,12 +162,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
sz = DISPLAY_NAME_LIMIT; sz = DISPLAY_NAME_LIMIT;
ret = cbor_value_copy_text_string(&map, (char *)MC->user.displayName, &sz, NULL); ret = cbor_value_copy_text_string(&map, (char *)MC->credInfo.user.displayName, &sz, NULL);
if (ret != CborErrorOutOfMemory) if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay { // Just truncate the name it's okay
check_ret(ret); check_ret(ret);
} }
MC->user.displayName[DISPLAY_NAME_LIMIT - 1] = 0; MC->credInfo.user.displayName[DISPLAY_NAME_LIMIT - 1] = 0;
} }
else if (strcmp((const char *)key, "icon") == 0) else if (strcmp((const char *)key, "icon") == 0)
{ {
@ -176,12 +177,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
sz = ICON_LIMIT; sz = ICON_LIMIT;
ret = cbor_value_copy_text_string(&map, (char *)MC->user.icon, &sz, NULL); ret = cbor_value_copy_text_string(&map, (char *)MC->credInfo.user.icon, &sz, NULL);
if (ret != CborErrorOutOfMemory) if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay { // Just truncate the name it's okay
check_ret(ret); check_ret(ret);
} }
MC->user.icon[ICON_LIMIT - 1] = 0; MC->credInfo.user.icon[ICON_LIMIT - 1] = 0;
} }
else else
@ -305,8 +306,8 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
{ {
if (pub_key_cred_param_supported(cred_type, alg_type) == CREDENTIAL_IS_SUPPORTED) if (pub_key_cred_param_supported(cred_type, alg_type) == CREDENTIAL_IS_SUPPORTED)
{ {
MC->publicKeyCredentialType = cred_type; MC->credInfo.publicKeyCredentialType = cred_type;
MC->COSEAlgorithmIdentifier = alg_type; MC->credInfo.COSEAlgorithmIdentifier = alg_type;
MC->paramsParsed |= PARAM_pubKeyCredParams; MC->paramsParsed |= PARAM_pubKeyCredParams;
return 0; return 0;
} }
@ -521,7 +522,7 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
if (cbor_value_get_type(&map) != CborBooleanType) if (cbor_value_get_type(&map) != CborBooleanType)
{ {
printf2(TAG_ERR,"Error, expecting text string type for rp map value\n"); printf2(TAG_ERR,"Error, expecting bool type for option map value\n");
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
@ -556,6 +557,154 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
return 0; return 0;
} }
uint8_t ctap_parse_hmac_secret(CborValue * val, CTAP_hmac_secret * hs)
{
size_t map_length;
size_t salt_len;
uint8_t parsed_count = 0;
int key;
int ret;
unsigned int i;
CborValue map;
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(val,&map);
check_ret(ret);
ret = cbor_value_get_map_length(val, &map_length);
check_ret(ret);
for (i = 0; i < map_length; i++)
{
if (cbor_value_get_type(&map) != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting CborIntegerTypefor hmac-secret map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
switch(key)
{
case EXT_HMAC_SECRET_COSE_KEY:
ret = parse_cose_key(&map, &hs->keyAgreement);
check_retr(ret);
parsed_count++;
break;
case EXT_HMAC_SECRET_SALT_ENC:
salt_len = 64;
ret = cbor_value_copy_byte_string(&map, hs->saltEnc, &salt_len, NULL);
if ((salt_len != 32 && salt_len != 64) || ret == CborErrorOutOfMemory)
{
return CTAP1_ERR_INVALID_LENGTH;
}
check_ret(ret);
hs->saltLen = salt_len;
parsed_count++;
break;
case EXT_HMAC_SECRET_SALT_AUTH:
salt_len = 32;
ret = cbor_value_copy_byte_string(&map, hs->saltAuth, &salt_len, NULL);
check_ret(ret);
parsed_count++;
break;
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
if (parsed_count != 3)
{
printf2(TAG_ERR, "ctap_parse_hmac_secret missing parameter. Got %d.\r\n", parsed_count);
return CTAP2_ERR_MISSING_PARAMETER;
}
return 0;
}
uint8_t ctap_parse_extensions(CborValue * val, CTAP_extensions * ext)
{
CborValue map;
size_t sz, map_length;
char key[16];
int ret;
unsigned int i;
bool b;
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(val, &map);
check_ret(ret);
ret = cbor_value_get_map_length(val, &map_length);
check_ret(ret);
for (i = 0; i < map_length; i++)
{
if (cbor_value_get_type(&map) != CborTextStringType)
{
printf2(TAG_ERR,"Error, expecting text string type for options map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
sz = sizeof(key);
ret = cbor_value_copy_text_string(&map, key, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, rp map key is too large. Ignoring.\n");
cbor_value_advance(&map);
cbor_value_advance(&map);
continue;
}
check_ret(ret);
key[sizeof(key) - 1] = 0;
ret = cbor_value_advance(&map);
check_ret(ret);
if (strncmp(key, "hmac-secret",11) == 0)
{
if (cbor_value_get_type(&map) == CborBooleanType)
{
ret = cbor_value_get_boolean(&map, &b);
check_ret(ret);
if (b) ext->hmac_secret_present = EXT_HMAC_SECRET_REQUESTED;
printf1(TAG_CTAP, "set hmac_secret_present to %d\r\n", b);
}
else if (cbor_value_get_type(&map) == CborMapType)
{
ret = ctap_parse_hmac_secret(&map, &ext->hmac_secret);
check_retr(ret);
ext->hmac_secret_present = EXT_HMAC_SECRET_PARSED;
printf1(TAG_CTAP, "parsed hmac_secret request\r\n");
}
else
{
printf1(TAG_RED, "warning: hmac_secret request ignored for being wrong type\r\n");
}
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}
uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length) uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length)
{ {
int ret; int ret;
@ -631,8 +780,8 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
ret = parse_user(MC, &map); ret = parse_user(MC, &map);
printf1(TAG_MC," ID: "); dump_hex1(TAG_MC, MC->user.id, MC->user.id_size); printf1(TAG_MC," ID: "); dump_hex1(TAG_MC, MC->credInfo.user.id, MC->credInfo.user.id_size);
printf1(TAG_MC," name: %s\n", MC->user.name); printf1(TAG_MC," name: %s\n", MC->credInfo.user.name);
break; break;
case MC_pubKeyCredParams: case MC_pubKeyCredParams:
@ -640,8 +789,8 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
ret = parse_pub_key_cred_params(MC, &map); ret = parse_pub_key_cred_params(MC, &map);
printf1(TAG_MC," cred_type: 0x%02x\n", MC->publicKeyCredentialType); printf1(TAG_MC," cred_type: 0x%02x\n", MC->credInfo.publicKeyCredentialType);
printf1(TAG_MC," alg_type: %d\n", MC->COSEAlgorithmIdentifier); printf1(TAG_MC," alg_type: %d\n", MC->credInfo.COSEAlgorithmIdentifier);
break; break;
case MC_excludeList: case MC_excludeList:
@ -665,21 +814,31 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
{ {
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
ret = ctap_parse_extensions(&map, &MC->extensions);
check_retr(ret);
break; break;
case MC_options: case MC_options:
printf1(TAG_MC,"CTAP_options\n"); printf1(TAG_MC,"CTAP_options\n");
ret = parse_options(&map, &MC->rk, &MC->uv, &MC->up); ret = parse_options(&map, &MC->credInfo.rk, &MC->uv, &MC->up);
check_retr(ret); check_retr(ret);
break; break;
case MC_pinAuth: case MC_pinAuth: {
printf1(TAG_MC,"CTAP_pinAuth\n"); printf1(TAG_MC,"CTAP_pinAuth\n");
size_t pinSize;
if (cbor_value_get_type(&map) == CborByteStringType &&
cbor_value_get_string_length(&map, &pinSize) == CborNoError &&
pinSize == 0)
{
MC->pinAuthEmpty = 1;
break;
}
ret = parse_fixed_byte_string(&map, MC->pinAuth, 16); ret = parse_fixed_byte_string(&map, MC->pinAuth, 16);
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
{ {
check_retr(ret); check_retr(ret);
} }
else else
{ {
@ -687,6 +846,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
} }
MC->pinAuthPresent = 1; MC->pinAuthPresent = 1;
break; break;
}
case MC_pinProtocol: case MC_pinProtocol:
printf1(TAG_MC,"CTAP_pinProtocol\n"); printf1(TAG_MC,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
@ -723,6 +883,8 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
size_t buflen; size_t buflen;
char type[12]; char type[12];
CborValue val; CborValue val;
cred->type = 0;
if (cbor_value_get_type(arr) != CborMapType) if (cbor_value_get_type(arr) != CborMapType)
{ {
printf2(TAG_ERR,"Error, CborMapType expected in credential\n"); printf2(TAG_ERR,"Error, CborMapType expected in credential\n");
@ -739,12 +901,22 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
} }
buflen = sizeof(CredentialId); buflen = sizeof(CredentialId);
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL); ret = cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL);
if (buflen != sizeof(CredentialId))
if (buflen == U2F_KEY_HANDLE_SIZE)
{ {
printf2(TAG_ERR,"Ignoring credential is incorrect length\n"); printf2(TAG_PARSE,"CTAP1 credential\n");
//return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail? cred->type = PUB_KEY_CRED_CTAP1;
} }
else if (buflen != sizeof(CredentialId))
{
printf2(TAG_ERR,"Ignoring credential is incorrect length, treating as custom\n");
cred->type = PUB_KEY_CRED_CUSTOM;
buflen = 256;
ret = cbor_value_copy_byte_string(&val, getAssertionState.customCredId, &buflen, NULL);
getAssertionState.customCredIdSize = buflen;
}
check_ret(ret);
ret = cbor_value_map_find_value(arr, "type", &val); ret = cbor_value_map_find_value(arr, "type", &val);
check_ret(ret); check_ret(ret);
@ -756,12 +928,24 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
} }
buflen = sizeof(type); buflen = sizeof(type);
cbor_value_copy_text_string(&val, type, &buflen, NULL); ret = cbor_value_copy_text_string(&val, type, &buflen, NULL);
if (ret == CborErrorOutOfMemory)
{
cred->type = PUB_KEY_CRED_UNKNOWN;
}
else
{
check_ret(ret);
}
if (strncmp(type, "public-key",11) == 0) if (strncmp(type, "public-key",11) == 0)
{
if (0 == cred->type)
{ {
cred->type = PUB_KEY_CRED_PUB_KEY; cred->type = PUB_KEY_CRED_PUB_KEY;
} }
}
else else
{ {
cred->type = PUB_KEY_CRED_UNKNOWN; cred->type = PUB_KEY_CRED_UNKNOWN;
@ -825,6 +1009,8 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
CborValue it,map; CborValue it,map;
memset(GA, 0, sizeof(CTAP_getAssertion)); memset(GA, 0, sizeof(CTAP_getAssertion));
GA->creds = getAssertionState.creds; // Save stack memory
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it); ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret); check_ret(ret);
@ -886,6 +1072,8 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
break; break;
case GA_extensions: case GA_extensions:
printf1(TAG_GA,"GA_extensions\n"); printf1(TAG_GA,"GA_extensions\n");
ret = ctap_parse_extensions(&map, &GA->extensions);
check_retr(ret);
break; break;
case GA_options: case GA_options:
@ -893,9 +1081,18 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up); ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up);
check_retr(ret); check_retr(ret);
break; break;
case GA_pinAuth: case GA_pinAuth: {
printf1(TAG_GA,"CTAP_pinAuth\n"); printf1(TAG_GA,"CTAP_pinAuth\n");
size_t pinSize;
if (cbor_value_get_type(&map) == CborByteStringType &&
cbor_value_get_string_length(&map, &pinSize) == CborNoError &&
pinSize == 0)
{
GA->pinAuthEmpty = 1;
break;
}
ret = parse_fixed_byte_string(&map, GA->pinAuth, 16); ret = parse_fixed_byte_string(&map, GA->pinAuth, 16);
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
{ {
@ -911,6 +1108,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
GA->pinAuthPresent = 1; GA->pinAuthPresent = 1;
break; break;
}
case GA_pinProtocol: case GA_pinProtocol:
printf1(TAG_GA,"CTAP_pinProtocol\n"); printf1(TAG_GA,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
@ -940,15 +1138,15 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
return 0; return 0;
} }
uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv) uint8_t parse_cose_key(CborValue * it, COSE_key * cose)
{ {
CborValue map; CborValue map;
size_t map_length; size_t map_length;
int ret,key; int ret,key;
unsigned int i; unsigned int i;
int xkey = 0,ykey = 0; int xkey = 0,ykey = 0;
*kty = 0; cose->kty = 0;
*crv = 0; cose->crv = 0;
CborType type = cbor_value_get_type(it); CborType type = cbor_value_get_type(it);
@ -986,7 +1184,7 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int
printf1(TAG_PARSE,"COSE_KEY_LABEL_KTY\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_KTY\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
{ {
ret = cbor_value_get_int_checked(&map, kty); ret = cbor_value_get_int_checked(&map, &cose->kty);
check_ret(ret); check_ret(ret);
} }
else else
@ -1001,7 +1199,7 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int
printf1(TAG_PARSE,"COSE_KEY_LABEL_CRV\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_CRV\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
{ {
ret = cbor_value_get_int_checked(&map, crv); ret = cbor_value_get_int_checked(&map, &cose->crv);
check_ret(ret); check_ret(ret);
} }
else else
@ -1011,14 +1209,14 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int
break; break;
case COSE_KEY_LABEL_X: case COSE_KEY_LABEL_X:
printf1(TAG_PARSE,"COSE_KEY_LABEL_X\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_X\n");
ret = parse_fixed_byte_string(&map, x, 32); ret = parse_fixed_byte_string(&map, cose->pubkey.x, 32);
check_retr(ret); check_retr(ret);
xkey = 1; xkey = 1;
break; break;
case COSE_KEY_LABEL_Y: case COSE_KEY_LABEL_Y:
printf1(TAG_PARSE,"COSE_KEY_LABEL_Y\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_Y\n");
ret = parse_fixed_byte_string(&map, y, 32); ret = parse_fixed_byte_string(&map, cose->pubkey.y, 32);
check_retr(ret); check_retr(ret);
ykey = 1; ykey = 1;
@ -1030,7 +1228,7 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int
ret = cbor_value_advance(&map); ret = cbor_value_advance(&map);
check_ret(ret); check_ret(ret);
} }
if (xkey == 0 || ykey == 0 || *kty == 0 || *crv == 0) if (xkey == 0 || ykey == 0 || cose->kty == 0 || cose->crv == 0)
{ {
return CTAP2_ERR_MISSING_PARAMETER; return CTAP2_ERR_MISSING_PARAMETER;
} }
@ -1110,7 +1308,7 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
break; break;
case CP_keyAgreement: case CP_keyAgreement:
printf1(TAG_CP,"CP_keyAgreement\n"); printf1(TAG_CP,"CP_keyAgreement\n");
ret = parse_cose_key(&map, CP->keyAgreement.pubkey.x, CP->keyAgreement.pubkey.y, &CP->keyAgreement.kty, &CP->keyAgreement.crv); ret = parse_cose_key(&map, &CP->keyAgreement);
check_retr(ret); check_retr(ret);
CP->keyAgreementPresent = 1; CP->keyAgreementPresent = 1;
break; break;

View File

@ -30,7 +30,7 @@ uint8_t parse_rp(struct rpId * rp, CborValue * val);
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up); uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up);
uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it); uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it);
uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv); uint8_t parse_cose_key(CborValue * it, COSE_key * cose);
uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length); uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length);

View File

@ -16,6 +16,12 @@
#include "util.h" #include "util.h"
#include "log.h" #include "log.h"
#include "extensions.h" #include "extensions.h"
// move custom SHA512 command out,
// and the following headers too
#include "sha2.h"
#include "crypto.h"
#include APP_CONFIG #include APP_CONFIG
typedef enum typedef enum
@ -528,6 +534,10 @@ static int ctaphid_buffer_packet(uint8_t * pkt_raw, uint8_t * cmd, uint32_t * ci
return buffer_status(); return buffer_status();
} }
extern void _check_ret(CborError ret, int line, const char * filename);
#define check_hardcore(r) _check_ret(r,__LINE__, __FILE__);\
if ((r) != CborNoError) exit(1);
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw) uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
{ {
uint8_t cmd; uint8_t cmd;
@ -718,6 +728,155 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
ctaphid_write(&wb, NULL, 0); ctaphid_write(&wb, NULL, 0);
is_busy = 0; is_busy = 0;
break; break;
#endif
#if defined(SOLO_HACKER) && (DEBUG_LEVEL > 0) && (!IS_BOOTLOADER == 1)
case CTAPHID_PROBE:
/*
* Expects CBOR-serialized data of the form
* {"subcommand": "hash_type", "data": b"the_data"}
* with hash_type in SHA256, SHA512
*/
// some random logging
printf1(TAG_HID,"CTAPHID_PROBE\n");
// initialise CTAP response object
ctap_response_init(&ctap_resp);
// initialise write buffer
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_PROBE;
// prepare parsing (or halt)
int ret;
CborParser parser;
CborValue it, map;
ret = cbor_parser_init(
ctap_buffer, (size_t) buffer_len(),
// strictly speaking, CTAP is not RFC canonical...
CborValidateCanonicalFormat,
&parser, &it);
check_hardcore(ret);
CborType type = cbor_value_get_type(&it);
if (type != CborMapType) exit(1);
ret = cbor_value_enter_container(&it,&map);
check_hardcore(ret);
size_t map_length = 0;
ret = cbor_value_get_map_length(&it, &map_length);
if (map_length != 2) exit(1);
// parse subcommand (or halt)
CborValue val;
ret = cbor_value_map_find_value(&it, "subcommand", &val);
check_hardcore(ret);
if (!cbor_value_is_text_string(&val))
exit(1);
int sha_version = 0;
bool found = false;
if (!found) {
ret = cbor_value_text_string_equals(
&val, "SHA256", &found);
check_hardcore(ret);
if (found)
sha_version = 256;
}
if (!found) {
ret = cbor_value_text_string_equals(
&val, "SHA512", &found);
check_hardcore(ret);
if (found)
sha_version = 512;
}
if (sha_version == 0)
exit(1);
// parse data (or halt)
ret = cbor_value_map_find_value(&it, "data", &val);
check_hardcore(ret);
if (!cbor_value_is_byte_string(&val))
exit(1);
size_t data_length = 0;
ret = cbor_value_calculate_string_length(&val, &data_length);
check_hardcore(ret);
if (data_length > 6*1024)
exit(1);
unsigned char data[6*1024];
ret = cbor_value_copy_byte_string (
&val, &data[0], &data_length, &val);
check_hardcore(ret);
// execute subcommand
if (sha_version == 256) {
// calculate hash
crypto_sha256_init();
crypto_sha256_update(data, data_length);
crypto_sha256_final(ctap_buffer);
// write output
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
}
if (sha_version == 512) {
// calculate hash
crypto_sha512_init();
crypto_sha512_update(data, data_length);
crypto_sha512_final(ctap_buffer);
// write output
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
}
// finalize
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
/*
case CTAPHID_SHA256:
// some random logging
printf1(TAG_HID,"CTAPHID_SHA256\n");
// initialise CTAP response object
ctap_response_init(&ctap_resp);
// initialise write buffer
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_SHA256;
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
// calculate hash
crypto_sha256_init();
crypto_sha256_update(ctap_buffer, buffer_len());
crypto_sha256_final(ctap_buffer);
// copy to output
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
case CTAPHID_SHA512:
// some random logging
printf1(TAG_HID,"CTAPHID_SHA512\n");
// initialise CTAP response object
ctap_response_init(&ctap_resp);
// initialise write buffer
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_SHA512;
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
// calculate hash
crypto_sha512_init();
crypto_sha512_update(ctap_buffer, buffer_len());
crypto_sha512_final(ctap_buffer);
// copy to output
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
*/
#endif #endif
default: default:
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd()); printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());

View File

@ -28,6 +28,8 @@
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51) #define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52) #define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
#define CTAPHID_GETRNG (TYPE_INIT | 0x60) #define CTAPHID_GETRNG (TYPE_INIT | 0x60)
// reserved for debug, not implemented except for HACKER and DEBUG_LEVEl > 0
#define CTAPHID_PROBE (TYPE_INIT | 0x70)
#define ERR_INVALID_CMD 0x01 #define ERR_INVALID_CMD 0x01
#define ERR_INVALID_PAR 0x02 #define ERR_INVALID_PAR 0x02

View File

@ -9,7 +9,7 @@
#include "storage.h" #include "storage.h"
void device_init(); void device_init(int argc, char *argv[]);
uint32_t millis(); uint32_t millis();
@ -30,6 +30,7 @@ void main_loop_delay();
void heartbeat(); void heartbeat();
void device_reboot();
void authenticator_read_state(AuthenticatorState * ); void authenticator_read_state(AuthenticatorState * );
@ -53,11 +54,11 @@ int device_is_button_pressed();
// Test for user presence // Test for user presence
// Return 1 for user is present, 0 user not present, -1 if cancel is requested. // Return 1 for user is present, 0 user not present, -1 if cancel is requested.
extern int ctap_user_presence_test(); int ctap_user_presence_test(uint32_t delay);
// Generate @num bytes of random numbers to @dest // Generate @num bytes of random numbers to @dest
// return 1 if success, error otherwise // return 1 if success, error otherwise
extern int ctap_generate_rng(uint8_t * dst, size_t num); int ctap_generate_rng(uint8_t * dst, size_t num);
// Increment atomic counter and return it. // Increment atomic counter and return it.
// Must support two counters, @sel selects counter0 or counter1. // Must support two counters, @sel selects counter0 or counter1.
@ -65,11 +66,11 @@ uint32_t ctap_atomic_count(int sel);
// Verify the user // Verify the user
// return 1 if user is verified, 0 if not // return 1 if user is verified, 0 if not
extern int ctap_user_verification(uint8_t arg); int ctap_user_verification(uint8_t arg);
// Must be implemented by application // Must be implemented by application
// data is HID_MESSAGE_SIZE long in bytes // data is HID_MESSAGE_SIZE long in bytes
extern void ctaphid_write_block(uint8_t * data); void ctaphid_write_block(uint8_t * data);
// Resident key // Resident key
@ -86,5 +87,27 @@ void boot_st_bootloader();
// HID wink command // HID wink command
void device_wink(); void device_wink();
typedef enum {
DEVICE_LOW_POWER_IDLE = 0,
DEVICE_LOW_POWER_FAST = 1,
DEVICE_FAST = 2,
} DEVICE_CLOCK_RATE;
// Set the clock rate for the device.
// Three modes are targetted for Solo.
// 0: Lowest clock rate for NFC.
// 1: fastest clock rate supported at a low power setting for NFC FIDO.
// 2: fastest clock rate. Generally for USB interface.
void device_set_clock_rate(DEVICE_CLOCK_RATE param);
// Returns NFC_IS_NA, NFC_IS_ACTIVE, or NFC_IS_AVAILABLE
#define NFC_IS_NA 0
#define NFC_IS_ACTIVE 1
#define NFC_IS_AVAILABLE 2
int device_is_nfc();
void request_from_nfc(bool request_active);
void device_init_button();
#endif #endif

View File

@ -35,6 +35,28 @@ int extension_needs_atomic_count(uint8_t klen, uint8_t * keyh)
|| ((wallet_request *) keyh)->operation == WalletSign; || ((wallet_request *) keyh)->operation == WalletSign;
} }
static uint8_t * output_buffer_ptr;
uint8_t output_buffer_offset;
uint8_t output_buffer_size;
void extension_writeback_init(uint8_t * buffer, uint8_t size)
{
output_buffer_ptr = buffer;
output_buffer_offset = 0;
output_buffer_size = size;
}
void extension_writeback(uint8_t * buf, uint8_t size)
{
if ((output_buffer_offset + size) > output_buffer_size)
{
return;
}
memmove(output_buffer_ptr + output_buffer_offset, buf, size);
output_buffer_offset += size;
}
int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh) int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
{ {
int8_t ret = 0; int8_t ret = 0;
@ -55,8 +77,6 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
u2f_response_writeback((uint8_t *)&ret,1); u2f_response_writeback((uint8_t *)&ret,1);
#ifdef IS_BOOTLOADER #ifdef IS_BOOTLOADER
ret = bootloader_bridge(klen, keyh); ret = bootloader_bridge(klen, keyh);
#elif defined(WALLET_EXTENSION)
ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh);
#else #else
ret = bridge_u2f_to_solo(sig, keyh, klen); ret = bridge_u2f_to_solo(sig, keyh, klen);
u2f_response_writeback(sig,72); u2f_response_writeback(sig,72);
@ -82,6 +102,7 @@ int16_t extend_fido2(CredentialId * credid, uint8_t * output)
{ {
if (is_extension_request((uint8_t*)credid, sizeof(CredentialId))) if (is_extension_request((uint8_t*)credid, sizeof(CredentialId)))
{ {
printf1(TAG_EXT,"IS EXT REQ\r\n");
output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId)); output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId));
return 1; return 1;
} }
@ -91,10 +112,10 @@ int16_t extend_fido2(CredentialId * credid, uint8_t * output)
} }
} }
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len) int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len)
{ {
struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) req->payload; struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) payload;
uint16_t rcode; uint16_t rcode;
if (req->ins == U2F_AUTHENTICATE) if (req->ins == U2F_AUTHENTICATE)

View File

@ -7,8 +7,14 @@
#ifndef EXTENSIONS_H_ #ifndef EXTENSIONS_H_
#define EXTENSIONS_H_ #define EXTENSIONS_H_
#include "u2f.h" #include "u2f.h"
#include "apdu.h"
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len); int16_t bridge_u2f_to_extensions(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh);
// return 1 if request is a wallet request
int is_extension_request(uint8_t * req, int len);
int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len);
int16_t extend_fido2(CredentialId * credid, uint8_t * output); int16_t extend_fido2(CredentialId * credid, uint8_t * output);
@ -16,4 +22,8 @@ int bootloader_bridge(int klen, uint8_t * keyh);
int is_extension_request(uint8_t * kh, int len); int is_extension_request(uint8_t * kh, int len);
void extension_writeback_init(uint8_t * buffer, uint8_t size);
void extension_writeback(uint8_t * buf, uint8_t size);
#endif /* EXTENSIONS_H_ */ #endif /* EXTENSIONS_H_ */

View File

@ -31,12 +31,15 @@
#include "log.h" #include "log.h"
#include APP_CONFIG #include APP_CONFIG
// output must be at least 71 bytes // output must be at least 71 bytes
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen) int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
{ {
int8_t ret = 0; int8_t ret = 0;
wallet_request * req = (wallet_request *) keyh; wallet_request * req = (wallet_request *) keyh;
extension_writeback_init(output, 71);
printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen); printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen);
@ -61,6 +64,14 @@ int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
break; break;
#ifdef ENABLE_WALLET
case WalletSign:
case WalletRegister:
case WalletPin:
case WalletReset:
return bridge_to_wallet(keyh, keylen);
#endif
default: default:
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation); printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
ret = CTAP1_ERR_INVALID_COMMAND; ret = CTAP1_ERR_INVALID_COMMAND;

View File

@ -14,8 +14,8 @@
#include "util.h" #include "util.h"
#include "storage.h" #include "storage.h"
#include "device.h" #include "device.h"
#include "extensions.h"
#if defined(USING_PC) || defined(IS_BOOTLOADER)
typedef enum typedef enum
{ {
MBEDTLS_ECP_DP_NONE = 0, MBEDTLS_ECP_DP_NONE = 0,
@ -32,9 +32,7 @@ typedef enum
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */ MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */ MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
} mbedtls_ecp_group_id; } mbedtls_ecp_group_id;
#else
#include "ecp.h"
#endif
// return 1 if hash is valid, 0 otherwise // return 1 if hash is valid, 0 otherwise
@ -70,14 +68,14 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
u2f_response_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB)); extension_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB));
printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64); printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64);
break; break;
case CP_cmdGetRetries: case CP_cmdGetRetries:
printf1(TAG_WALLET,"cmdGetRetries\n"); printf1(TAG_WALLET,"cmdGetRetries\n");
pinTokenEnc[0] = ctap_leftover_pin_attempts(); pinTokenEnc[0] = ctap_leftover_pin_attempts();
u2f_response_writeback(pinTokenEnc,1); extension_writeback(pinTokenEnc,1);
break; break;
case CP_cmdSetPin: case CP_cmdSetPin:
@ -87,7 +85,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
if (!ctap_user_presence_test()) if (!ctap_user_presence_test(5000))
{ {
return CTAP2_ERR_OPERATION_DENIED; return CTAP2_ERR_OPERATION_DENIED;
} }
@ -113,7 +111,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
if (!ctap_user_presence_test()) if (!ctap_user_presence_test(5000))
{ {
return CTAP2_ERR_OPERATION_DENIED; return CTAP2_ERR_OPERATION_DENIED;
} }
@ -135,7 +133,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
if (!ctap_user_presence_test()) if (!ctap_user_presence_test(5000))
{ {
return CTAP2_ERR_OPERATION_DENIED; return CTAP2_ERR_OPERATION_DENIED;
} }
@ -145,7 +143,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return ret; return ret;
printf1(TAG_WALLET,"pinToken: "); dump_hex1(TAG_WALLET, PIN_TOKEN, 16); printf1(TAG_WALLET,"pinToken: "); dump_hex1(TAG_WALLET, PIN_TOKEN, 16);
u2f_response_writeback(pinTokenEnc, PIN_TOKEN_SIZE); extension_writeback(pinTokenEnc, PIN_TOKEN_SIZE);
break; break;
@ -159,7 +157,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return 0; return 0;
} }
int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh) int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen)
{ {
static uint8_t msg_buf[WALLET_MAX_BUFFER]; static uint8_t msg_buf[WALLET_MAX_BUFFER];
int reqlen = klen; int reqlen = klen;
@ -259,7 +257,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
crypto_load_external_key(key, keysize); crypto_load_external_key(key, keysize);
crypto_ecdsa_sign(args[0], lens[0], sig, MBEDTLS_ECP_DP_SECP256K1); crypto_ecdsa_sign(args[0], lens[0], sig, MBEDTLS_ECP_DP_SECP256K1);
u2f_response_writeback(sig,64); extension_writeback(sig,64);
break; break;
case WalletRegister: case WalletRegister:
@ -361,7 +359,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
} }
} }
if (ctap_user_presence_test()) if (ctap_user_presence_test(5000))
{ {
printf1(TAG_WALLET,"Reseting device!\n"); printf1(TAG_WALLET,"Reseting device!\n");
ctap_reset(); ctap_reset();
@ -374,39 +372,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
break; break;
case WalletVersion:
u2f_response_writeback((uint8_t*)WALLET_VERSION, sizeof(WALLET_VERSION)-1);
break;
case WalletRng:
printf1(TAG_WALLET,"WalletRng\n");
if ( ctap_device_locked() )
{
printf1(TAG_ERR,"device locked\n");
ret = CTAP2_ERR_NOT_ALLOWED;
goto cleanup;
}
if ( ctap_is_pin_set() )
{
if ( ! check_pinhash(req->pinAuth, msg_buf, reqlen))
{
printf2(TAG_ERR,"pinAuth is NOT valid\n");
dump_hex1(TAG_ERR,msg_buf,reqlen);
ret = CTAP2_ERR_PIN_AUTH_INVALID;
goto cleanup;
}
}
ret = ctap_generate_rng(sig, 72);
if (ret != 1)
{
printf1(TAG_WALLET,"Rng failed\n");
ret = CTAP2_ERR_PROCESSING;
goto cleanup;
}
ret = 0;
u2f_response_writeback((uint8_t *)sig,72);
break;
default: default:
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation); printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);

View File

@ -87,10 +87,7 @@ typedef enum
} WalletOperation; } WalletOperation;
int16_t bridge_u2f_to_extensions(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh); int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen);
// return 1 if request is a wallet request
int is_extension_request(uint8_t * req, int len);
void wallet_init(); void wallet_init();

View File

@ -48,6 +48,8 @@ struct logtag tagtable[] = {
{TAG_STOR,"STOR"}, {TAG_STOR,"STOR"},
{TAG_BOOT,"BOOT"}, {TAG_BOOT,"BOOT"},
{TAG_EXT,"EXT"}, {TAG_EXT,"EXT"},
{TAG_NFC,"NFC"},
{TAG_NFC_APDU, "NAPDU"},
}; };
@ -68,7 +70,7 @@ void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...)
{ {
if (tag & tagtable[i].tagn) if (tag & tagtable[i].tagn)
{ {
if (tagtable[i].tag[0]) printf("[%s] ", tagtable[i].tag); if (tagtable[i].tag[0] && !(tag & TAG_NO_TAG)) printf("[%s] ", tagtable[i].tag);
i = 0; i = 0;
break; break;
} }

View File

@ -42,8 +42,11 @@ typedef enum
TAG_DUMP2 = (1 << 16), TAG_DUMP2 = (1 << 16),
TAG_BOOT = (1 << 17), TAG_BOOT = (1 << 17),
TAG_EXT = (1 << 18), TAG_EXT = (1 << 18),
TAG_NFC = (1 << 19),
TAG_NFC_APDU = (1 << 20),
TAG_FILENO = (1u << 31) TAG_NO_TAG = (1UL << 30),
TAG_FILENO = (1UL << 31)
} LOG_TAG; } LOG_TAG;
#if DEBUG_LEVEL > 0 #if DEBUG_LEVEL > 0

View File

@ -7,6 +7,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include "cbor.h" #include "cbor.h"
#include "device.h" #include "device.h"
@ -19,7 +21,8 @@
#if !defined(TEST) #if !defined(TEST)
int main()
int main(int argc, char *argv[])
{ {
uint8_t hidmsg[64]; uint8_t hidmsg[64];
uint32_t t1 = 0; uint32_t t1 = 0;
@ -31,35 +34,25 @@ int main()
// TAG_GA | // TAG_GA |
TAG_WALLET | TAG_WALLET |
TAG_STOR | TAG_STOR |
//TAG_NFC_APDU |
TAG_NFC |
//TAG_CP | //TAG_CP |
// TAG_CTAP| // TAG_CTAP|
//TAG_HID| //TAG_HID|
/*TAG_U2F|*/ TAG_U2F|
//TAG_PARSE | //TAG_PARSE |
//TAG_TIME| //TAG_TIME|
// TAG_DUMP| // TAG_DUMP|
TAG_GREEN| TAG_GREEN|
TAG_RED| TAG_RED|
TAG_EXT|
TAG_ERR TAG_ERR
); );
device_init(); device_init(argc, argv);
printf1(TAG_GEN,"init device\n");
usbhid_init();
printf1(TAG_GEN,"init usb\n");
ctaphid_init();
printf1(TAG_GEN,"init ctaphid\n");
ctap_init();
printf1(TAG_GEN,"init ctap\n");
memset(hidmsg,0,sizeof(hidmsg)); memset(hidmsg,0,sizeof(hidmsg));
printf1(TAG_GEN,"recv'ing hid msg \n");
while(1) while(1)
{ {
@ -80,6 +73,7 @@ int main()
{ {
} }
ctaphid_check_timeouts(); ctaphid_check_timeouts();
} }
// Should never get here // Should never get here

View File

@ -7,9 +7,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "u2f.h" #include "u2f.h"
#include "ctap.h" #include "ctap.h"
#include "ctaphid.h"
#include "crypto.h" #include "crypto.h"
#include "log.h" #include "log.h"
#include "device.h" #include "device.h"
#include "apdu.h"
#include "wallet.h" #include "wallet.h"
#ifdef ENABLE_U2F_EXTENSIONS #ifdef ENABLE_U2F_EXTENSIONS
#include "extensions.h" #include "extensions.h"
@ -27,12 +29,12 @@ void u2f_reset_response();
static CTAP_RESPONSE * _u2f_resp = NULL; static CTAP_RESPONSE * _u2f_resp = NULL;
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPONSE * resp)
{ {
uint16_t rcode = 0; uint16_t rcode = 0;
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
uint8_t byte; uint8_t byte;
ctap_response_init(resp);
u2f_set_writeback_buffer(resp); u2f_set_writeback_buffer(resp);
if (req->cla != 0) if (req->cla != 0)
@ -42,7 +44,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
goto end; goto end;
} }
#ifdef ENABLE_U2F_EXTENSIONS #ifdef ENABLE_U2F_EXTENSIONS
rcode = extend_u2f(req, len); rcode = extend_u2f(req, payload, len);
#endif #endif
if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything... if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything...
{ {
@ -59,7 +61,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
{ {
timestamp(); timestamp();
rcode = u2f_register((struct u2f_register_request*)req->payload); rcode = u2f_register((struct u2f_register_request*)payload);
printf1(TAG_TIME,"u2f_register time: %d ms\n", timestamp()); printf1(TAG_TIME,"u2f_register time: %d ms\n", timestamp());
} }
@ -67,7 +69,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
case U2F_AUTHENTICATE: case U2F_AUTHENTICATE:
printf1(TAG_U2F, "U2F_AUTHENTICATE\n"); printf1(TAG_U2F, "U2F_AUTHENTICATE\n");
timestamp(); timestamp();
rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1); rcode = u2f_authenticate((struct u2f_authenticate_request*)payload, req->p1);
printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", timestamp()); printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", timestamp());
break; break;
case U2F_VERSION: case U2F_VERSION:
@ -94,6 +96,8 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
#endif #endif
} }
device_set_status(CTAPHID_STATUS_IDLE);
end: end:
if (rcode != U2F_SW_NO_ERROR) if (rcode != U2F_SW_NO_ERROR)
{ {
@ -109,6 +113,22 @@ end:
printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length); printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length);
} }
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp)
{
if (!header)
return;
request_from_nfc(true); // disable presence test
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
request_from_nfc(false); // enable presence test
}
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
{
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
u2f_request_ex((APDU_HEADER *)req, req->payload, len, resp);
}
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len) int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len)
{ {
@ -156,7 +176,7 @@ static void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8
memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE); memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE);
} }
static int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey) int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey)
{ {
ctap_generate_rng(kh->key, U2F_KEY_HANDLE_KEY_SIZE); ctap_generate_rng(kh->key, U2F_KEY_HANDLE_KEY_SIZE);
u2f_make_auth_tag(kh, appid, kh->tag); u2f_make_auth_tag(kh, appid, kh->tag);
@ -166,26 +186,25 @@ static int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8
} }
// Return 1 if authenticate, 0 if not.
static int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid) int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid)
{ {
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE]; uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
u2f_make_auth_tag(kh, appid, tag); u2f_make_auth_tag(kh, appid, tag);
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0) if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
{ {
return 0; return 1;
} }
else else
{ {
printf1(TAG_U2F, "key handle + appid not authentic\n"); printf1(TAG_U2F, "key handle + appid not authentic\n");
printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE); printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE);
printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE); printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
return -1; return 0;
} }
} }
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control) static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control)
{ {
@ -197,7 +216,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
if (control == U2F_AUTHENTICATE_CHECK) if (control == U2F_AUTHENTICATE_CHECK)
{ {
printf1(TAG_U2F, "CHECK-ONLY\r\n"); printf1(TAG_U2F, "CHECK-ONLY\r\n");
if (u2f_appid_eq(&req->kh, req->app) == 0) if (u2f_authenticate_credential(&req->kh, req->app))
{ {
return U2F_SW_CONDITIONS_NOT_SATISFIED; return U2F_SW_CONDITIONS_NOT_SATISFIED;
} }
@ -207,9 +226,9 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
} }
} }
if ( if (
control != U2F_AUTHENTICATE_SIGN || (control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) ||
req->khl != U2F_KEY_HANDLE_SIZE || req->khl != U2F_KEY_HANDLE_SIZE ||
u2f_appid_eq(&req->kh, req->app) != 0 || // Order of checks is important (!u2f_authenticate_credential(&req->kh, req->app)) || // Order of checks is important
u2f_load_key(&req->kh, req->app) != 0 u2f_load_key(&req->kh, req->app) != 0
) )
@ -217,15 +236,20 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
return U2F_SW_WRONG_DATA; return U2F_SW_WRONG_DATA;
} }
// dont-enforce-user-presence-and-sign
if (control == U2F_AUTHENTICATE_SIGN_NO_USER)
up = 0;
if(up)
if (ctap_user_presence_test() == 0) {
if (ctap_user_presence_test(750) == 0)
{ {
return U2F_SW_CONDITIONS_NOT_SATISFIED; return U2F_SW_CONDITIONS_NOT_SATISFIED;
} }
}
count = ctap_atomic_count(0); count = ctap_atomic_count(0);
hash[0] = 0xff; hash[0] = (count >> 24) & 0xff;
hash[1] = (count >> 16) & 0xff; hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff; hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff; hash[3] = (count >> 0) & 0xff;
@ -242,7 +266,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
crypto_ecc256_sign(hash, 32, sig); crypto_ecc256_sign(hash, 32, sig);
u2f_response_writeback(&up,1); u2f_response_writeback(&up,1);
hash[0] = 0xff; hash[0] = (count >> 24) & 0xff;
hash[1] = (count >> 16) & 0xff; hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff; hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff; hash[3] = (count >> 0) & 0xff;
@ -264,7 +288,7 @@ static int16_t u2f_register(struct u2f_register_request * req)
const uint16_t attest_size = attestation_cert_der_size; const uint16_t attest_size = attestation_cert_der_size;
if ( ! ctap_user_presence_test()) if ( ! ctap_user_presence_test(750))
{ {
return U2F_SW_CONDITIONS_NOT_SATISFIED; return U2F_SW_CONDITIONS_NOT_SATISFIED;
} }
@ -301,8 +325,6 @@ static int16_t u2f_register(struct u2f_register_request * req)
dump_signature_der(sig); dump_signature_der(sig);
/*printf1(TAG_U2F, "dersig: "); dump_hex1(TAG_U2F,sig,74);*/
return U2F_SW_NO_ERROR; return U2F_SW_NO_ERROR;
} }

View File

@ -38,6 +38,7 @@
// U2F Authenticate // U2F Authenticate
#define U2F_AUTHENTICATE_CHECK 0x7 #define U2F_AUTHENTICATE_CHECK 0x7
#define U2F_AUTHENTICATE_SIGN 0x3 #define U2F_AUTHENTICATE_SIGN 0x3
#define U2F_AUTHENTICATE_SIGN_NO_USER 0x8
// Command status responses // Command status responses
@ -97,6 +98,12 @@ struct u2f_authenticate_request
// @req U2F message // @req U2F message
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp); void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
// u2f_request send a U2F message to NFC protocol
// @req data with iso7816 apdu message
// @len data length
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp);
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid);
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len); int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
void u2f_reset_response(); void u2f_reset_response();

View File

@ -7,6 +7,7 @@ export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
cd /solo/targets/stm32l432 cd /solo/targets/stm32l432
git fetch --tags git fetch --tags
git checkout ${version} git checkout ${version}
git submodule update --init --recursive
version=$(git describe) version=$(git describe)
make cbor make cbor
@ -34,4 +35,21 @@ function build() {
build bootloader nonverifying build bootloader nonverifying
build bootloader verifying build bootloader verifying
build firmware hacker solo build firmware hacker solo
build firmware hacker-debug-1 solo
build firmware hacker-debug-2 solo
build firmware secure solo build firmware secure solo
build firmware secure-non-solokeys solo
pip install -U pip
pip install -U solo-python
cd ${out_dir}
bundle="bundle-hacker-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-hacker-debug-1-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-1-${version}.hex ${bundle}.hex
bundle="bundle-hacker-debug-2-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-2-${version}.hex ${bundle}.hex
bundle="bundle-secure-non-solokeys-${version}"
/opt/conda/bin/solo mergehex bootloader-verifying-${version}.hex firmware-secure-non-solokeys-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2

View File

@ -20,6 +20,9 @@
], ],
"userVerificationDetails": [ "userVerificationDetails": [
[ [
{
"userVerification": 1
},
{ {
"userVerification": 4 "userVerification": 4
} }

View File

@ -11,6 +11,11 @@ nav:
- FIDO2 Implementation: solo/fido2-impl.md - FIDO2 Implementation: solo/fido2-impl.md
- Metadata Statements: solo/metadata-statements.md - Metadata Statements: solo/metadata-statements.md
- Build instructions: solo/building.md - Build instructions: solo/building.md
- Programming instructions: solo/programming.md
- Bootloader mode: solo/bootloader-mode.md
- Customization: solo/customization.md
- Solo Extras: solo/solo-extras.md
- Running on Nucleo32 board: solo/nucleo32-board.md
- Signed update process: solo/signed-updates.md - Signed update process: solo/signed-updates.md
- Code documentation: solo/code-overview.md - Code documentation: solo/code-overview.md
- Contributing Code: solo/contributing.md - Contributing Code: solo/contributing.md

View File

@ -7,6 +7,7 @@
#ifndef SRC_APP_H_ #ifndef SRC_APP_H_
#define SRC_APP_H_ #define SRC_APP_H_
#include <stdbool.h>
#define USING_DEV_BOARD #define USING_DEV_BOARD
@ -15,11 +16,13 @@
#define DEBUG_LEVEL 1 #define DEBUG_LEVEL 1
#define ENABLE_U2F #define ENABLE_U2F
#define ENABLE_U2F_EXTENSIONS
//#define BRIDGE_TO_WALLET //#define BRIDGE_TO_WALLET
void printing_init(); void printing_init();
extern bool use_udp;
// 0xRRGGBB // 0xRRGGBB
#define LED_INIT_VALUE 0x000800 #define LED_INIT_VALUE 0x000800
#define LED_WINK_VALUE 0x000008 #define LED_WINK_VALUE 0x000008

View File

@ -15,6 +15,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <fcntl.h>
#include "device.h" #include "device.h"
#include "cbor.h" #include "cbor.h"
@ -22,6 +23,13 @@
#include "log.h" #include "log.h"
#include "ctaphid.h" #include "ctaphid.h"
#define RK_NUM 50
bool use_udp = true;
struct ResidentKeyStore {
CTAP_residentKey rks[RK_NUM];
} RK_STORE;
void authenticator_initialize(); void authenticator_initialize();
@ -35,7 +43,11 @@ void device_set_status(uint32_t status)
__device_status = status; __device_status = status;
} }
void device_reboot()
{
printf1(TAG_RED, "REBOOT command recieved!\r\n");
exit(100);
}
int udp_server() int udp_server()
{ {
@ -113,12 +125,6 @@ void udp_send(int fd, uint8_t * buf, int size)
} }
} }
void udp_close(int fd)
{
close(fd);
}
uint32_t millis() uint32_t millis()
{ {
@ -129,35 +135,79 @@ uint32_t millis()
} }
static int serverfd = 0; static int fd = 0;
void usbhid_init() void usbhid_init()
{ {
// just bridge to UDP for now for pure software testing if (use_udp)
serverfd = udp_server(); {
fd = udp_server();
}
else
{
fd = open("/dev/hidg0", O_RDWR);
if (fd < 0)
{
perror("hidg open");
exit(1);
}
}
} }
// Receive 64 byte USB HID message, don't block, return size of packet, return 0 if nothing // Receive 64 byte USB HID message, don't block, return size of packet, return 0 if nothing
int usbhid_recv(uint8_t * msg) int usbhid_recv(uint8_t * msg)
{ {
int l = udp_recv(serverfd, msg, HID_MESSAGE_SIZE); int l = 0;
/*if (l && l != HID_MESSAGE_SIZE)*/ if (use_udp)
/*{*/ {
/*printf("Error, recv'd message of wrong size %d", l);*/ l = udp_recv(fd, msg, HID_MESSAGE_SIZE);
/*exit(1);*/ }
/*}*/ else
{
l = read(fd, msg, HID_MESSAGE_SIZE); /* Flawfinder: ignore */
if (l < 0)
{
perror("hidg read");
exit(1);
}
}
uint8_t magic_cmd[] = "\xac\x10\x52\xca\x95\xe5\x69\xde\x69\xe0\x2e\xbf"
"\xf3\x33\x48\x5f\x13\xf9\xb2\xda\x34\xc5\xa8\xa3"
"\x40\x52\x66\x97\xa9\xab\x2e\x0b\x39\x4d\x8d\x04"
"\x97\x3c\x13\x40\x05\xbe\x1a\x01\x40\xbf\xf6\x04"
"\x5b\xb2\x6e\xb7\x7a\x73\xea\xa4\x78\x13\xf6\xb4"
"\x9a\x72\x50\xdc";
if ( memcmp(magic_cmd, msg, 64) == 0 )
{
printf1(TAG_RED, "MAGIC REBOOT command recieved!\r\n");
memset(msg,0,64);
exit(100);
return 0;
}
return l; return l;
} }
// Send 64 byte USB HID message // Send 64 byte USB HID message
void usbhid_send(uint8_t * msg) void usbhid_send(uint8_t * msg)
{ {
udp_send(serverfd, msg, HID_MESSAGE_SIZE); if (use_udp)
{
udp_send(fd, msg, HID_MESSAGE_SIZE);
}
else
{
if (write(fd, msg, HID_MESSAGE_SIZE) < 0)
{
perror("hidg write");
exit(1);
}
}
} }
void usbhid_close() void usbhid_close()
{ {
udp_close(serverfd); close(fd);
} }
void int_handler(int i) void int_handler(int i)
@ -167,13 +217,54 @@ void int_handler(int i)
exit(0); exit(0);
} }
void device_init()
void usage(const char * cmd)
{ {
fprintf(stderr, "Usage: %s [-b udp|hidg]\n", cmd);
fprintf(stderr, " -b backing implementation: udp(default) or hidg\n");
exit(1);
}
void device_init(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "b:")) != -1)
{
switch (opt)
{
case 'b':
if (strcmp("udp", optarg) == 0)
{
use_udp = true;
}
else if (strcmp("hidg", optarg) == 0)
{
use_udp = false;
}
else
{
usage(argv[0]);
}
break;
default:
usage(argv[0]);
break;
}
}
signal(SIGINT, int_handler); signal(SIGINT, int_handler);
printf1(TAG_GREEN, "Using %s backing\n", use_udp ? "UDP" : "hidg");
usbhid_init(); usbhid_init();
authenticator_initialize(); authenticator_initialize();
ctaphid_init();
ctap_init( 1 );
} }
@ -181,7 +272,15 @@ void main_loop_delay()
{ {
struct timespec ts; struct timespec ts;
ts.tv_sec = 0; ts.tv_sec = 0;
ts.tv_nsec = 1000*1000*25; ts.tv_nsec = 1000*1000*100;
nanosleep(&ts,NULL);
}
void delay(uint32_t ms)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 1000*1000*ms;
nanosleep(&ts,NULL); nanosleep(&ts,NULL);
} }
@ -198,7 +297,7 @@ void ctaphid_write_block(uint8_t * data)
} }
int ctap_user_presence_test() int ctap_user_presence_test(uint32_t d)
{ {
return 1; return 1;
} }
@ -247,6 +346,7 @@ int ctap_generate_rng(uint8_t * dst, size_t num)
const char * state_file = "authenticator_state.bin"; const char * state_file = "authenticator_state.bin";
const char * backup_file = "authenticator_state2.bin"; const char * backup_file = "authenticator_state2.bin";
const char * rk_file = "resident_keys.bin";
void authenticator_read_state(AuthenticatorState * state) void authenticator_read_state(AuthenticatorState * state)
{ {
@ -366,6 +466,24 @@ int authenticator_is_backup_initialized()
/*}*/ /*}*/
static void sync_rk()
{
FILE * f = fopen(rk_file, "wb+");
if (f== NULL)
{
perror("fopen");
exit(1);
}
int ret = fwrite(&RK_STORE, 1, sizeof(RK_STORE), f);
fclose(f);
if (ret != sizeof(RK_STORE))
{
perror("fwrite");
exit(1);
}
}
void authenticator_initialize() void authenticator_initialize()
{ {
uint8_t header[16]; uint8_t header[16];
@ -389,6 +507,22 @@ void authenticator_initialize()
perror("fwrite"); perror("fwrite");
exit(1); exit(1);
} }
// resident_keys
f = fopen(rk_file, "rb");
if (f== NULL)
{
perror("fopen");
exit(1);
}
ret = fread(&RK_STORE, 1, sizeof(RK_STORE), f);
fclose(f);
if(ret != sizeof(RK_STORE))
{
perror("fwrite");
exit(1);
}
} }
else else
{ {
@ -427,6 +561,12 @@ void authenticator_initialize()
exit(1); exit(1);
} }
// resident_keys
memset(&RK_STORE,0xff,sizeof(RK_STORE));
sync_rk();
} }
} }
@ -435,29 +575,65 @@ void device_manage()
} }
void ctap_reset_rk() void ctap_reset_rk()
{ {
memset(&RK_STORE,0xff,sizeof(RK_STORE));
sync_rk();
} }
uint32_t ctap_rk_size() uint32_t ctap_rk_size()
{ {
printf("Warning: rk not implemented\n"); return RK_NUM;
return 0;
} }
void ctap_store_rk(int index, CTAP_residentKey * rk) void ctap_store_rk(int index, CTAP_residentKey * rk)
{ {
printf("Warning: rk not implemented\n"); if (index < RK_NUM)
{
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
sync_rk();
} }
else
{
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
}
}
void ctap_load_rk(int index, CTAP_residentKey * rk) void ctap_load_rk(int index, CTAP_residentKey * rk)
{ {
printf("Warning: rk not implemented\n"); memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey));
} }
void ctap_overwrite_rk(int index, CTAP_residentKey * rk) void ctap_overwrite_rk(int index, CTAP_residentKey * rk)
{ {
printf("Warning: rk not implemented\n"); if (index < RK_NUM)
{
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
sync_rk();
}
else
{
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
}
} }
void device_wink() void device_wink()
{ {
printf("*WINK*\n"); printf("*WINK*\n");
} }
int device_is_nfc()
{
return 0;
}
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
{
}

Submodule python-fido2 deleted from 329434fdd4

View File

@ -5,7 +5,7 @@ endif
APPMAKE=build/application.mk APPMAKE=build/application.mk
BOOTMAKE=build/bootloader.mk BOOTMAKE=build/bootloader.mk
merge_hex=../../tools/solotool.py mergehex merge_hex=solo mergehex
.PHONY: all all-hacker all-locked debugboot-app debugboot-boot boot-sig-checking boot-no-sig build-release-locked build-release build-release build-hacker build-debugboot clean clean2 flash flash_dfu flashboot detach cbor test .PHONY: all all-hacker all-locked debugboot-app debugboot-boot boot-sig-checking boot-no-sig build-release-locked build-release build-release build-hacker build-debugboot clean clean2 flash flash_dfu flashboot detach cbor test
@ -15,6 +15,15 @@ merge_hex=../../tools/solotool.py mergehex
firmware-hacker: firmware-hacker:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware-hacker-debug-1:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware-hacker-debug-2:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware-secure-non-solokeys:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DFLASH_ROP=2'
firmware-secure: firmware-secure:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2' $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2'
@ -53,7 +62,6 @@ boot-no-sig:
build-release-locked: cbor clean2 boot-sig-checking clean all-locked build-release-locked: cbor clean2 boot-sig-checking clean all-locked
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex $(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
rm -f solo.hex bootloader.hex # don't program solo.hex ...
build-release: cbor clean2 boot-sig-checking clean all build-release: cbor clean2 boot-sig-checking clean all
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex $(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
@ -87,6 +95,11 @@ flashboot: solo.hex bootloader.hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
flash-firmware:
arm-none-eabi-size -A solo.elf
solo program aux enter-bootloader
solo program bootloader solo.hex
# tell ST DFU to enter application # tell ST DFU to enter application
detach: detach:
STM32_Programmer_CLI -c port=usb1 -ob nBOOT0=1 STM32_Programmer_CLI -c port=usb1 -ob nBOOT0=1

View File

@ -1,73 +0,0 @@
CC=arm-none-eabi-gcc
CP=arm-none-eabi-objcopy
SZ=arm-none-eabi-size
AR=arm-none-eabi-ar
# ST related
SRC = src/main.c src/init.c src/flash.c src/led.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += lib/stm32l4xx_ll_gpio.c lib/stm32l4xx_ll_pwr.c lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_tim.c lib/stm32l4xx_ll_utils.c
OBJ1=$(SRC:.c=.o)
OBJ=$(OBJ1:.s=.o)
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
INC += -I../../crypto/tiny-AES-c
SEARCH=-L../../tinycbor/lib
LDSCRIPT=stm32l432xx.ld
CFLAGS= $(INC)
TARGET=solo
HW=-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
# Solo or Nucleo board
CHIP=STM32L432xx
DEFINES = -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER
DEFINES += -DTEST_SOLO_STM32 -DTEST
CFLAGS=$(INC) -c $(DEFINES) -Wall -fdata-sections -ffunction-sections $(HW)
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref
.PRECIOUS: %.o
all: $(TARGET).elf
$(SZ) $^
%.o: %.c
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c
$(CC) $^ $(HW) -O3 $(CFLAGS) -o $@
%.o: %.s
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
%.elf: $(OBJ)
$(CC) $^ $(HW) $(LDFLAGS) -o $@
%.hex: %.elf
$(CP) -O ihex $^ $(TARGET).hex
$(CP) -O binary $^ $(TARGET).bin
clean:
rm -f *.o src/*.o src/*.elf *.elf *.hex $(OBJ)
flash: $(TARGET).hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d $(TARGET).hex -rst
detach:
STM32_Programmer_CLI -c port=usb1 -ob nBOOT0=1
cbor:
cd ../../tinycbor/ && make clean
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
LDFLAGS="$(LDFLAGS_LIB)" \
CFLAGS="$(CFLAGS)"

View File

@ -55,7 +55,7 @@
#define SOLO_PRODUCT_NAME "Solo Bootloader " SOLO_VERSION #define SOLO_PRODUCT_NAME "Solo Bootloader " SOLO_VERSION
void printing_init(); void printing_init();
void hw_init(void); void hw_init(int lf);
// Trigger software reset // Trigger software reset
void device_reboot(); void device_reboot();

View File

@ -8,6 +8,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx.h"
#include "cbor.h" #include "cbor.h"
#include "device.h" #include "device.h"
#include "ctaphid.h" #include "ctaphid.h"
@ -17,12 +21,12 @@
#include "ctap.h" #include "ctap.h"
#include "app.h" #include "app.h"
#include "memory_layout.h" #include "memory_layout.h"
#include "stm32l4xx_ll_rcc.h" #include "init.h"
#include "stm32l4xx.h"
uint8_t REBOOT_FLAG = 0; uint8_t REBOOT_FLAG = 0;
void SystemClock_Config(void);
void BOOT_boot(void) void BOOT_boot(void)
{ {
@ -69,7 +73,18 @@ int main()
TAG_ERR TAG_ERR
); );
device_init(); // device_init();
init_gpio();
init_millisecond_timer(1);
#if DEBUG_LEVEL > 0
init_debug_uart();
#endif
device_init_button();
printf1(TAG_GEN,"init device\n"); printf1(TAG_GEN,"init device\n");
t1 = millis(); t1 = millis();
@ -107,7 +122,13 @@ int main()
#ifdef SOLO_HACKER #ifdef SOLO_HACKER
start_bootloader: start_bootloader:
#endif #endif
SystemClock_Config();
init_gpio();
init_millisecond_timer(0);
init_pwm();
init_rng();
usbhid_init(); usbhid_init();
printf1(TAG_GEN,"init usb\n"); printf1(TAG_GEN,"init usb\n");
ctaphid_init(); ctaphid_init();

View File

@ -2,18 +2,20 @@ include build/common.mk
# ST related # ST related
SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
SRC += src/fifo.c src/crypto.c src/attestation.c SRC += src/fifo.c src/crypto.c src/attestation.c src/nfc.c src/ams.c src/sense.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(DRIVER_LIBS) $(USB_LIB) SRC += $(DRIVER_LIBS) $(USB_LIB)
# FIDO2 lib # FIDO2 lib
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
SRC += ../../fido2/extensions/wallet.c
# Crypto libs # Crypto libs
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c ../../crypto/tiny-AES-c/aes.c SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c ../../crypto/tiny-AES-c/aes.c
SRC += ../../crypto/cifra/src/sha512.c ../../crypto/cifra/src/blockwise.c
OBJ1=$(SRC:.c=.o) OBJ1=$(SRC:.c=.o)
OBJ=$(OBJ1:.s=.o) OBJ=$(OBJ1:.s=.o)
@ -21,6 +23,7 @@ OBJ=$(OBJ1:.s=.o)
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
INC += -I../../crypto/tiny-AES-c INC += -I../../crypto/tiny-AES-c
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
SEARCH=-L../../tinycbor/lib SEARCH=-L../../tinycbor/lib
@ -41,12 +44,14 @@ DEBUG=0
endif endif
DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"app.h\" $(EXTRA_DEFINES) DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"app.h\" $(EXTRA_DEFINES)
# DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1
CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections $(HW) -g $(VERSION_FLAGS) CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections \
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -u _printf_float -lnosys -fomit-frame-pointer $(HW) -g $(VERSION_FLAGS)
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor
ECC_CFLAGS = $(CFLAGS) -DuECC_PLATFORM=5 -DuECC_OPTIMIZATION_LEVEL=4 -DuECC_SQUARE_FUNC=1 -DuECC_SUPPORT_COMPRESSED_POINT=0
.PRECIOUS: %.o .PRECIOUS: %.o
@ -57,7 +62,7 @@ all: $(TARGET).elf
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@ $(CC) $^ $(HW) -Os $(CFLAGS) -o $@
../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c ../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c
$(CC) $^ $(HW) -O3 $(CFLAGS) -o $@ $(CC) $^ $(HW) -O3 $(ECC_CFLAGS) -o $@
%.o: %.s %.o: %.s
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@ $(CC) $^ $(HW) -Os $(CFLAGS) -o $@
@ -66,6 +71,7 @@ all: $(TARGET).elf
$(CC) $^ $(HW) $(LDFLAGS) -o $@ $(CC) $^ $(HW) $(LDFLAGS) -o $@
%.hex: %.elf %.hex: %.elf
$(SZ) $^
$(CP) -O ihex $^ $(TARGET).hex $(CP) -O ihex $^ $(TARGET).hex
clean: clean:
@ -76,4 +82,4 @@ cbor:
cd ../../tinycbor/ && make clean cd ../../tinycbor/ && make clean
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \ cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
LDFLAGS="$(LDFLAGS_LIB)" \ LDFLAGS="$(LDFLAGS_LIB)" \
CFLAGS="$(CFLAGS)" CFLAGS="$(CFLAGS) -Os"

View File

@ -3,7 +3,7 @@ include build/common.mk
# ST related # ST related
SRC = bootloader/main.c bootloader/bootloader.c SRC = bootloader/main.c bootloader/bootloader.c
SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
SRC += src/fifo.c src/crypto.c src/attestation.c SRC += src/fifo.c src/crypto.c src/attestation.c src/sense.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(DRIVER_LIBS) $(USB_LIB) SRC += $(DRIVER_LIBS) $(USB_LIB)
@ -13,6 +13,7 @@ SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2
# Crypto libs # Crypto libs
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c
SRC += ../../crypto/cifra/src/sha512.c ../../crypto/cifra/src/blockwise.c
OBJ1=$(SRC:.c=.o) OBJ1=$(SRC:.c=.o)
OBJ=$(OBJ1:.s=.o) OBJ=$(OBJ1:.s=.o)
@ -21,6 +22,7 @@ OBJ=$(OBJ1:.s=.o)
INC = -Ibootloader/ -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions INC = -Ibootloader/ -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
INC += -I../../crypto/tiny-AES-c INC += -I../../crypto/tiny-AES-c
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
ifndef LDSCRIPT ifndef LDSCRIPT
LDSCRIPT=linker/bootloader_stm32l4xx.ld LDSCRIPT=linker/bootloader_stm32l4xx.ld

View File

@ -6,7 +6,7 @@ AR=$(PREFIX)arm-none-eabi-ar
DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_ll_gpio.c \ DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_ll_gpio.c \
lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_rng.c lib/stm32l4xx_ll_tim.c \ lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_rng.c lib/stm32l4xx_ll_tim.c \
lib/stm32l4xx_ll_usb.c lib/stm32l4xx_ll_utils.c lib/stm32l4xx_ll_pwr.c \ lib/stm32l4xx_ll_usb.c lib/stm32l4xx_ll_utils.c lib/stm32l4xx_ll_pwr.c \
lib/stm32l4xx_ll_usart.c lib/stm32l4xx_ll_usart.c lib/stm32l4xx_ll_spi.c lib/stm32l4xx_ll_exti.c
USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \ USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \ lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \

View File

@ -0,0 +1,844 @@
/**
******************************************************************************
* @file stm32l4xx_hal_tsc.h
* @author MCD Application Team
* @brief Header file of TSC HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32L4xx_HAL_TSC_H
#define STM32L4xx_HAL_TSC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal_def.h"
/** @addtogroup STM32L4xx_HAL_Driver
* @{
*/
/** @addtogroup TSC
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup TSC_Exported_Types TSC Exported Types
* @{
*/
/**
* @brief TSC state structure definition
*/
typedef enum
{
HAL_TSC_STATE_RESET = 0x00UL, /*!< TSC registers have their reset value */
HAL_TSC_STATE_READY = 0x01UL, /*!< TSC registers are initialized or acquisition is completed with success */
HAL_TSC_STATE_BUSY = 0x02UL, /*!< TSC initialization or acquisition is on-going */
HAL_TSC_STATE_ERROR = 0x03UL /*!< Acquisition is completed with max count error */
} HAL_TSC_StateTypeDef;
/**
* @brief TSC group status structure definition
*/
typedef enum
{
TSC_GROUP_ONGOING = 0x00UL, /*!< Acquisition on group is on-going or not started */
TSC_GROUP_COMPLETED = 0x01UL /*!< Acquisition on group is completed with success (no max count error) */
} TSC_GroupStatusTypeDef;
/**
* @brief TSC init structure definition
*/
typedef struct
{
uint32_t CTPulseHighLength; /*!< Charge-transfer high pulse length
This parameter can be a value of @ref TSC_CTPulseHL_Config */
uint32_t CTPulseLowLength; /*!< Charge-transfer low pulse length
This parameter can be a value of @ref TSC_CTPulseLL_Config */
uint32_t SpreadSpectrum; /*!< Spread spectrum activation
This parameter can be a value of @ref TSC_CTPulseLL_Config */
uint32_t SpreadSpectrumDeviation; /*!< Spread spectrum deviation
This parameter must be a number between Min_Data = 0 and Max_Data = 127 */
uint32_t SpreadSpectrumPrescaler; /*!< Spread spectrum prescaler
This parameter can be a value of @ref TSC_SpreadSpec_Prescaler */
uint32_t PulseGeneratorPrescaler; /*!< Pulse generator prescaler
This parameter can be a value of @ref TSC_PulseGenerator_Prescaler */
uint32_t MaxCountValue; /*!< Max count value
This parameter can be a value of @ref TSC_MaxCount_Value */
uint32_t IODefaultMode; /*!< IO default mode
This parameter can be a value of @ref TSC_IO_Default_Mode */
uint32_t SynchroPinPolarity; /*!< Synchro pin polarity
This parameter can be a value of @ref TSC_Synchro_Pin_Polarity */
uint32_t AcquisitionMode; /*!< Acquisition mode
This parameter can be a value of @ref TSC_Acquisition_Mode */
uint32_t MaxCountInterrupt; /*!< Max count interrupt activation
This parameter can be set to ENABLE or DISABLE. */
uint32_t ChannelIOs; /*!< Channel IOs mask */
uint32_t ShieldIOs; /*!< Shield IOs mask */
uint32_t SamplingIOs; /*!< Sampling IOs mask */
} TSC_InitTypeDef;
/**
* @brief TSC IOs configuration structure definition
*/
typedef struct
{
uint32_t ChannelIOs; /*!< Channel IOs mask */
uint32_t ShieldIOs; /*!< Shield IOs mask */
uint32_t SamplingIOs; /*!< Sampling IOs mask */
} TSC_IOConfigTypeDef;
/**
* @brief TSC handle Structure definition
*/
typedef struct __TSC_HandleTypeDef
{
TSC_TypeDef *Instance; /*!< Register base address */
TSC_InitTypeDef Init; /*!< Initialization parameters */
__IO HAL_TSC_StateTypeDef State; /*!< Peripheral state */
HAL_LockTypeDef Lock; /*!< Lock feature */
__IO uint32_t ErrorCode; /*!< I2C Error code */
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
void (* ConvCpltCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Conversion complete callback */
void (* ErrorCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Error callback */
void (* MspInitCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Msp Init callback */
void (* MspDeInitCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Msp DeInit callback */
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
} TSC_HandleTypeDef;
/**
* @brief TSC Group Index Structure definition
*/
typedef enum
{
TSC_GROUP1_IDX = 0x00UL,
TSC_GROUP2_IDX,
TSC_GROUP3_IDX,
TSC_GROUP4_IDX,
#if defined(TSC_IOCCR_G5_IO1)
TSC_GROUP5_IDX,
#endif
#if defined(TSC_IOCCR_G6_IO1)
TSC_GROUP6_IDX,
#endif
#if defined(TSC_IOCCR_G7_IO1)
TSC_GROUP7_IDX,
#endif
#if defined(TSC_IOCCR_G8_IO1)
TSC_GROUP8_IDX,
#endif
TSC_NB_OF_GROUPS
}TSC_GroupIndexTypeDef;
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
/**
* @brief HAL TSC Callback ID enumeration definition
*/
typedef enum
{
HAL_TSC_CONV_COMPLETE_CB_ID = 0x00UL, /*!< TSC Conversion completed callback ID */
HAL_TSC_ERROR_CB_ID = 0x01UL, /*!< TSC Error callback ID */
HAL_TSC_MSPINIT_CB_ID = 0x02UL, /*!< TSC Msp Init callback ID */
HAL_TSC_MSPDEINIT_CB_ID = 0x03UL /*!< TSC Msp DeInit callback ID */
} HAL_TSC_CallbackIDTypeDef;
/**
* @brief HAL TSC Callback pointer definition
*/
typedef void (*pTSC_CallbackTypeDef)(TSC_HandleTypeDef *htsc); /*!< pointer to an TSC callback function */
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup TSC_Exported_Constants TSC Exported Constants
* @{
*/
/** @defgroup TSC_Error_Code_definition TSC Error Code definition
* @brief TSC Error Code definition
* @{
*/
#define HAL_TSC_ERROR_NONE 0x00000000UL /*!< No error */
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
#define HAL_TSC_ERROR_INVALID_CALLBACK 0x00000001UL /*!< Invalid Callback error */
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup TSC_CTPulseHL_Config CTPulse High Length
* @{
*/
#define TSC_CTPH_1CYCLE 0x00000000UL /*!< Charge transfer pulse high during 1 cycle (PGCLK) */
#define TSC_CTPH_2CYCLES TSC_CR_CTPH_0 /*!< Charge transfer pulse high during 2 cycles (PGCLK) */
#define TSC_CTPH_3CYCLES TSC_CR_CTPH_1 /*!< Charge transfer pulse high during 3 cycles (PGCLK) */
#define TSC_CTPH_4CYCLES (TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 4 cycles (PGCLK) */
#define TSC_CTPH_5CYCLES TSC_CR_CTPH_2 /*!< Charge transfer pulse high during 5 cycles (PGCLK) */
#define TSC_CTPH_6CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 6 cycles (PGCLK) */
#define TSC_CTPH_7CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 7 cycles (PGCLK) */
#define TSC_CTPH_8CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 8 cycles (PGCLK) */
#define TSC_CTPH_9CYCLES TSC_CR_CTPH_3 /*!< Charge transfer pulse high during 9 cycles (PGCLK) */
#define TSC_CTPH_10CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 10 cycles (PGCLK) */
#define TSC_CTPH_11CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 11 cycles (PGCLK) */
#define TSC_CTPH_12CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 12 cycles (PGCLK) */
#define TSC_CTPH_13CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2) /*!< Charge transfer pulse high during 13 cycles (PGCLK) */
#define TSC_CTPH_14CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 14 cycles (PGCLK) */
#define TSC_CTPH_15CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 15 cycles (PGCLK) */
#define TSC_CTPH_16CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 16 cycles (PGCLK) */
/**
* @}
*/
/** @defgroup TSC_CTPulseLL_Config CTPulse Low Length
* @{
*/
#define TSC_CTPL_1CYCLE 0x00000000UL /*!< Charge transfer pulse low during 1 cycle (PGCLK) */
#define TSC_CTPL_2CYCLES TSC_CR_CTPL_0 /*!< Charge transfer pulse low during 2 cycles (PGCLK) */
#define TSC_CTPL_3CYCLES TSC_CR_CTPL_1 /*!< Charge transfer pulse low during 3 cycles (PGCLK) */
#define TSC_CTPL_4CYCLES (TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 4 cycles (PGCLK) */
#define TSC_CTPL_5CYCLES TSC_CR_CTPL_2 /*!< Charge transfer pulse low during 5 cycles (PGCLK) */
#define TSC_CTPL_6CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 6 cycles (PGCLK) */
#define TSC_CTPL_7CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 7 cycles (PGCLK) */
#define TSC_CTPL_8CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 8 cycles (PGCLK) */
#define TSC_CTPL_9CYCLES TSC_CR_CTPL_3 /*!< Charge transfer pulse low during 9 cycles (PGCLK) */
#define TSC_CTPL_10CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 10 cycles (PGCLK) */
#define TSC_CTPL_11CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 11 cycles (PGCLK) */
#define TSC_CTPL_12CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 12 cycles (PGCLK) */
#define TSC_CTPL_13CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2) /*!< Charge transfer pulse low during 13 cycles (PGCLK) */
#define TSC_CTPL_14CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 14 cycles (PGCLK) */
#define TSC_CTPL_15CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 15 cycles (PGCLK) */
#define TSC_CTPL_16CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 16 cycles (PGCLK) */
/**
* @}
*/
/** @defgroup TSC_SpreadSpec_Prescaler Spread Spectrum Prescaler
* @{
*/
#define TSC_SS_PRESC_DIV1 0x00000000UL /*!< Spread Spectrum Prescaler Div1 */
#define TSC_SS_PRESC_DIV2 TSC_CR_SSPSC /*!< Spread Spectrum Prescaler Div2 */
/**
* @}
*/
/** @defgroup TSC_PulseGenerator_Prescaler Pulse Generator Prescaler
* @{
*/
#define TSC_PG_PRESC_DIV1 0x00000000UL /*!< Pulse Generator HCLK Div1 */
#define TSC_PG_PRESC_DIV2 TSC_CR_PGPSC_0 /*!< Pulse Generator HCLK Div2 */
#define TSC_PG_PRESC_DIV4 TSC_CR_PGPSC_1 /*!< Pulse Generator HCLK Div4 */
#define TSC_PG_PRESC_DIV8 (TSC_CR_PGPSC_1 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div8 */
#define TSC_PG_PRESC_DIV16 TSC_CR_PGPSC_2 /*!< Pulse Generator HCLK Div16 */
#define TSC_PG_PRESC_DIV32 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div32 */
#define TSC_PG_PRESC_DIV64 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_1) /*!< Pulse Generator HCLK Div64 */
#define TSC_PG_PRESC_DIV128 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_1 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div128 */
/**
* @}
*/
/** @defgroup TSC_MaxCount_Value Max Count Value
* @{
*/
#define TSC_MCV_255 0x00000000UL /*!< 255 maximum number of charge transfer pulses */
#define TSC_MCV_511 TSC_CR_MCV_0 /*!< 511 maximum number of charge transfer pulses */
#define TSC_MCV_1023 TSC_CR_MCV_1 /*!< 1023 maximum number of charge transfer pulses */
#define TSC_MCV_2047 (TSC_CR_MCV_1 | TSC_CR_MCV_0) /*!< 2047 maximum number of charge transfer pulses */
#define TSC_MCV_4095 TSC_CR_MCV_2 /*!< 4095 maximum number of charge transfer pulses */
#define TSC_MCV_8191 (TSC_CR_MCV_2 | TSC_CR_MCV_0) /*!< 8191 maximum number of charge transfer pulses */
#define TSC_MCV_16383 (TSC_CR_MCV_2 | TSC_CR_MCV_1) /*!< 16383 maximum number of charge transfer pulses */
/**
* @}
*/
/** @defgroup TSC_IO_Default_Mode IO Default Mode
* @{
*/
#define TSC_IODEF_OUT_PP_LOW 0x00000000UL /*!< I/Os are forced to output push-pull low */
#define TSC_IODEF_IN_FLOAT TSC_CR_IODEF /*!< I/Os are in input floating */
/**
* @}
*/
/** @defgroup TSC_Synchro_Pin_Polarity Synchro Pin Polarity
* @{
*/
#define TSC_SYNC_POLARITY_FALLING 0x00000000UL /*!< Falling edge only */
#define TSC_SYNC_POLARITY_RISING TSC_CR_SYNCPOL /*!< Rising edge and high level */
/**
* @}
*/
/** @defgroup TSC_Acquisition_Mode Acquisition Mode
* @{
*/
#define TSC_ACQ_MODE_NORMAL 0x00000000UL /*!< Normal acquisition mode (acquisition starts as soon as START bit is set) */
#define TSC_ACQ_MODE_SYNCHRO TSC_CR_AM /*!< Synchronized acquisition mode (acquisition starts if START bit is set and when the selected signal is detected on the SYNC input pin) */
/**
* @}
*/
/** @defgroup TSC_interrupts_definition Interrupts definition
* @{
*/
#define TSC_IT_EOA TSC_IER_EOAIE /*!< End of acquisition interrupt enable */
#define TSC_IT_MCE TSC_IER_MCEIE /*!< Max count error interrupt enable */
/**
* @}
*/
/** @defgroup TSC_flags_definition Flags definition
* @{
*/
#define TSC_FLAG_EOA TSC_ISR_EOAF /*!< End of acquisition flag */
#define TSC_FLAG_MCE TSC_ISR_MCEF /*!< Max count error flag */
/**
* @}
*/
/** @defgroup TSC_Group_definition Group definition
* @{
*/
#define TSC_GROUP1 (uint32_t)(0x1UL << TSC_GROUP1_IDX)
#define TSC_GROUP2 (uint32_t)(0x1UL << TSC_GROUP2_IDX)
#define TSC_GROUP3 (uint32_t)(0x1UL << TSC_GROUP3_IDX)
#define TSC_GROUP4 (uint32_t)(0x1UL << TSC_GROUP4_IDX)
#if defined(TSC_IOCCR_G5_IO1)
#define TSC_GROUP5 (uint32_t)(0x1UL << TSC_GROUP5_IDX)
#endif
#if defined(TSC_IOCCR_G6_IO1)
#define TSC_GROUP6 (uint32_t)(0x1UL << TSC_GROUP6_IDX)
#endif
#if defined(TSC_IOCCR_G7_IO1)
#define TSC_GROUP7 (uint32_t)(0x1UL << TSC_GROUP7_IDX)
#endif
#if defined(TSC_IOCCR_G8_IO1)
#define TSC_GROUP8 (uint32_t)(0x1UL << TSC_GROUP8_IDX)
#endif
#define TSC_GROUPX_NOT_SUPPORTED 0xFF000000UL /*!< TSC GroupX not supported */
#define TSC_GROUP1_IO1 TSC_IOCCR_G1_IO1 /*!< TSC Group1 IO1 */
#define TSC_GROUP1_IO2 TSC_IOCCR_G1_IO2 /*!< TSC Group1 IO2 */
#define TSC_GROUP1_IO3 TSC_IOCCR_G1_IO3 /*!< TSC Group1 IO3 */
#define TSC_GROUP1_IO4 TSC_IOCCR_G1_IO4 /*!< TSC Group1 IO4 */
#define TSC_GROUP2_IO1 TSC_IOCCR_G2_IO1 /*!< TSC Group2 IO1 */
#define TSC_GROUP2_IO2 TSC_IOCCR_G2_IO2 /*!< TSC Group2 IO2 */
#define TSC_GROUP2_IO3 TSC_IOCCR_G2_IO3 /*!< TSC Group2 IO3 */
#define TSC_GROUP2_IO4 TSC_IOCCR_G2_IO4 /*!< TSC Group2 IO4 */
#define TSC_GROUP3_IO1 TSC_IOCCR_G3_IO1 /*!< TSC Group3 IO1 */
#define TSC_GROUP3_IO2 TSC_IOCCR_G3_IO2 /*!< TSC Group3 IO2 */
#define TSC_GROUP3_IO3 TSC_IOCCR_G3_IO3 /*!< TSC Group3 IO3 */
#define TSC_GROUP3_IO4 TSC_IOCCR_G3_IO4 /*!< TSC Group3 IO4 */
#define TSC_GROUP4_IO1 TSC_IOCCR_G4_IO1 /*!< TSC Group4 IO1 */
#define TSC_GROUP4_IO2 TSC_IOCCR_G4_IO2 /*!< TSC Group4 IO2 */
#define TSC_GROUP4_IO3 TSC_IOCCR_G4_IO3 /*!< TSC Group4 IO3 */
#define TSC_GROUP4_IO4 TSC_IOCCR_G4_IO4 /*!< TSC Group4 IO4 */
#if defined(TSC_IOCCR_G5_IO1)
#define TSC_GROUP5_IO1 TSC_IOCCR_G5_IO1 /*!< TSC Group5 IO1 */
#define TSC_GROUP5_IO2 TSC_IOCCR_G5_IO2 /*!< TSC Group5 IO2 */
#define TSC_GROUP5_IO3 TSC_IOCCR_G5_IO3 /*!< TSC Group5 IO3 */
#define TSC_GROUP5_IO4 TSC_IOCCR_G5_IO4 /*!< TSC Group5 IO4 */
#else
#define TSC_GROUP5_IO1 (uint32_t)(0x00000010UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group5 IO1 not supported */
#define TSC_GROUP5_IO2 TSC_GROUP5_IO1 /*!< TSC Group5 IO2 not supported */
#define TSC_GROUP5_IO3 TSC_GROUP5_IO1 /*!< TSC Group5 IO3 not supported */
#define TSC_GROUP5_IO4 TSC_GROUP5_IO1 /*!< TSC Group5 IO4 not supported */
#endif
#if defined(TSC_IOCCR_G6_IO1)
#define TSC_GROUP6_IO1 TSC_IOCCR_G6_IO1 /*!< TSC Group6 IO1 */
#define TSC_GROUP6_IO2 TSC_IOCCR_G6_IO2 /*!< TSC Group6 IO2 */
#define TSC_GROUP6_IO3 TSC_IOCCR_G6_IO3 /*!< TSC Group6 IO3 */
#define TSC_GROUP6_IO4 TSC_IOCCR_G6_IO4 /*!< TSC Group6 IO4 */
#else
#define TSC_GROUP6_IO1 (uint32_t)(0x00000020UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group6 IO1 not supported */
#define TSC_GROUP6_IO2 TSC_GROUP6_IO1 /*!< TSC Group6 IO2 not supported */
#define TSC_GROUP6_IO3 TSC_GROUP6_IO1 /*!< TSC Group6 IO3 not supported */
#define TSC_GROUP6_IO4 TSC_GROUP6_IO1 /*!< TSC Group6 IO4 not supported */
#endif
#if defined(TSC_IOCCR_G7_IO1)
#define TSC_GROUP7_IO1 TSC_IOCCR_G7_IO1 /*!< TSC Group7 IO1 */
#define TSC_GROUP7_IO2 TSC_IOCCR_G7_IO2 /*!< TSC Group7 IO2 */
#define TSC_GROUP7_IO3 TSC_IOCCR_G7_IO3 /*!< TSC Group7 IO3 */
#define TSC_GROUP7_IO4 TSC_IOCCR_G7_IO4 /*!< TSC Group7 IO4 */
#else
#define TSC_GROUP7_IO1 (uint32_t)(0x00000040UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group7 IO1 not supported */
#define TSC_GROUP7_IO2 TSC_GROUP7_IO1 /*!< TSC Group7 IO2 not supported */
#define TSC_GROUP7_IO3 TSC_GROUP7_IO1 /*!< TSC Group7 IO3 not supported */
#define TSC_GROUP7_IO4 TSC_GROUP7_IO1 /*!< TSC Group7 IO4 not supported */
#endif
#if defined(TSC_IOCCR_G8_IO1)
#define TSC_GROUP8_IO1 TSC_IOCCR_G8_IO1 /*!< TSC Group8 IO1 */
#define TSC_GROUP8_IO2 TSC_IOCCR_G8_IO2 /*!< TSC Group8 IO2 */
#define TSC_GROUP8_IO3 TSC_IOCCR_G8_IO3 /*!< TSC Group8 IO3 */
#define TSC_GROUP8_IO4 TSC_IOCCR_G8_IO4 /*!< TSC Group8 IO4 */
#else
#define TSC_GROUP8_IO1 (uint32_t)(0x00000080UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group8 IO1 not supported */
#define TSC_GROUP8_IO2 TSC_GROUP8_IO1 /*!< TSC Group8 IO2 not supported */
#define TSC_GROUP8_IO3 TSC_GROUP8_IO1 /*!< TSC Group8 IO3 not supported */
#define TSC_GROUP8_IO4 TSC_GROUP8_IO1 /*!< TSC Group8 IO4 not supported */
#endif
/**
* @}
*/
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup TSC_Exported_Macros TSC Exported Macros
* @{
*/
/** @brief Reset TSC handle state.
* @param __HANDLE__ TSC handle
* @retval None
*/
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
#define __HAL_TSC_RESET_HANDLE_STATE(__HANDLE__) do{ \
(__HANDLE__)->State = HAL_TSC_STATE_RESET; \
(__HANDLE__)->MspInitCallback = NULL; \
(__HANDLE__)->MspDeInitCallback = NULL; \
} while(0)
#else
#define __HAL_TSC_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_TSC_STATE_RESET)
#endif
/**
* @brief Enable the TSC peripheral.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_TSCE)
/**
* @brief Disable the TSC peripheral.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_TSCE))
/**
* @brief Start acquisition.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_START_ACQ(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_START)
/**
* @brief Stop acquisition.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_STOP_ACQ(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_START))
/**
* @brief Set IO default mode to output push-pull low.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_IODEF_OUTPPLOW(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_IODEF))
/**
* @brief Set IO default mode to input floating.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_IODEF_INFLOAT(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_IODEF)
/**
* @brief Set synchronization polarity to falling edge.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_SYNC_POL_FALL(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_SYNCPOL))
/**
* @brief Set synchronization polarity to rising edge and high level.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_SYNC_POL_RISE_HIGH(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_SYNCPOL)
/**
* @brief Enable TSC interrupt.
* @param __HANDLE__ TSC handle
* @param __INTERRUPT__ TSC interrupt
* @retval None
*/
#define __HAL_TSC_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER |= (__INTERRUPT__))
/**
* @brief Disable TSC interrupt.
* @param __HANDLE__ TSC handle
* @param __INTERRUPT__ TSC interrupt
* @retval None
*/
#define __HAL_TSC_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER &= (uint32_t)(~(__INTERRUPT__)))
/** @brief Check whether the specified TSC interrupt source is enabled or not.
* @param __HANDLE__ TSC Handle
* @param __INTERRUPT__ TSC interrupt
* @retval SET or RESET
*/
#define __HAL_TSC_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->IER & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET)
/**
* @brief Check whether the specified TSC flag is set or not.
* @param __HANDLE__ TSC handle
* @param __FLAG__ TSC flag
* @retval SET or RESET
*/
#define __HAL_TSC_GET_FLAG(__HANDLE__, __FLAG__) ((((__HANDLE__)->Instance->ISR & (__FLAG__)) == (__FLAG__)) ? SET : RESET)
/**
* @brief Clear the TSC's pending flag.
* @param __HANDLE__ TSC handle
* @param __FLAG__ TSC flag
* @retval None
*/
#define __HAL_TSC_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->ICR = (__FLAG__))
/**
* @brief Enable schmitt trigger hysteresis on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_ENABLE_HYSTERESIS(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOHCR |= (__GX_IOY_MASK__))
/**
* @brief Disable schmitt trigger hysteresis on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_DISABLE_HYSTERESIS(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOHCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Open analog switch on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_OPEN_ANALOG_SWITCH(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOASCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Close analog switch on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_CLOSE_ANALOG_SWITCH(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOASCR |= (__GX_IOY_MASK__))
/**
* @brief Enable a group of IOs in channel mode.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_ENABLE_CHANNEL(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOCCR |= (__GX_IOY_MASK__))
/**
* @brief Disable a group of channel IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_DISABLE_CHANNEL(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOCCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Enable a group of IOs in sampling mode.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_ENABLE_SAMPLING(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOSCR |= (__GX_IOY_MASK__))
/**
* @brief Disable a group of sampling IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_DISABLE_SAMPLING(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOSCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Enable acquisition groups.
* @param __HANDLE__ TSC handle
* @param __GX_MASK__ Groups mask
* @retval None
*/
#define __HAL_TSC_ENABLE_GROUP(__HANDLE__, __GX_MASK__) ((__HANDLE__)->Instance->IOGCSR |= (__GX_MASK__))
/**
* @brief Disable acquisition groups.
* @param __HANDLE__ TSC handle
* @param __GX_MASK__ Groups mask
* @retval None
*/
#define __HAL_TSC_DISABLE_GROUP(__HANDLE__, __GX_MASK__) ((__HANDLE__)->Instance->IOGCSR &= (uint32_t)(~(__GX_MASK__)))
/** @brief Gets acquisition group status.
* @param __HANDLE__ TSC Handle
* @param __GX_INDEX__ Group index
* @retval SET or RESET
*/
#define __HAL_TSC_GET_GROUP_STATUS(__HANDLE__, __GX_INDEX__) \
((((__HANDLE__)->Instance->IOGCSR & (uint32_t)(1UL << (((__GX_INDEX__) & (uint32_t)TSC_NB_OF_GROUPS) + 16UL))) == (uint32_t)(1UL << (((__GX_INDEX__) & (uint32_t)TSC_NB_OF_GROUPS) + 16UL))) ? TSC_GROUP_COMPLETED : TSC_GROUP_ONGOING)
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup TSC_Private_Macros TSC Private Macros
* @{
*/
#define IS_TSC_CTPH(__VALUE__) (((__VALUE__) == TSC_CTPH_1CYCLE) || \
((__VALUE__) == TSC_CTPH_2CYCLES) || \
((__VALUE__) == TSC_CTPH_3CYCLES) || \
((__VALUE__) == TSC_CTPH_4CYCLES) || \
((__VALUE__) == TSC_CTPH_5CYCLES) || \
((__VALUE__) == TSC_CTPH_6CYCLES) || \
((__VALUE__) == TSC_CTPH_7CYCLES) || \
((__VALUE__) == TSC_CTPH_8CYCLES) || \
((__VALUE__) == TSC_CTPH_9CYCLES) || \
((__VALUE__) == TSC_CTPH_10CYCLES) || \
((__VALUE__) == TSC_CTPH_11CYCLES) || \
((__VALUE__) == TSC_CTPH_12CYCLES) || \
((__VALUE__) == TSC_CTPH_13CYCLES) || \
((__VALUE__) == TSC_CTPH_14CYCLES) || \
((__VALUE__) == TSC_CTPH_15CYCLES) || \
((__VALUE__) == TSC_CTPH_16CYCLES))
#define IS_TSC_CTPL(__VALUE__) (((__VALUE__) == TSC_CTPL_1CYCLE) || \
((__VALUE__) == TSC_CTPL_2CYCLES) || \
((__VALUE__) == TSC_CTPL_3CYCLES) || \
((__VALUE__) == TSC_CTPL_4CYCLES) || \
((__VALUE__) == TSC_CTPL_5CYCLES) || \
((__VALUE__) == TSC_CTPL_6CYCLES) || \
((__VALUE__) == TSC_CTPL_7CYCLES) || \
((__VALUE__) == TSC_CTPL_8CYCLES) || \
((__VALUE__) == TSC_CTPL_9CYCLES) || \
((__VALUE__) == TSC_CTPL_10CYCLES) || \
((__VALUE__) == TSC_CTPL_11CYCLES) || \
((__VALUE__) == TSC_CTPL_12CYCLES) || \
((__VALUE__) == TSC_CTPL_13CYCLES) || \
((__VALUE__) == TSC_CTPL_14CYCLES) || \
((__VALUE__) == TSC_CTPL_15CYCLES) || \
((__VALUE__) == TSC_CTPL_16CYCLES))
#define IS_TSC_SS(__VALUE__) (((FunctionalState)(__VALUE__) == DISABLE) || ((FunctionalState)(__VALUE__) == ENABLE))
#define IS_TSC_SSD(__VALUE__) (((__VALUE__) == 0UL) || (((__VALUE__) > 0UL) && ((__VALUE__) < 128UL)))
#define IS_TSC_SS_PRESC(__VALUE__) (((__VALUE__) == TSC_SS_PRESC_DIV1) || ((__VALUE__) == TSC_SS_PRESC_DIV2))
#define IS_TSC_PG_PRESC(__VALUE__) (((__VALUE__) == TSC_PG_PRESC_DIV1) || \
((__VALUE__) == TSC_PG_PRESC_DIV2) || \
((__VALUE__) == TSC_PG_PRESC_DIV4) || \
((__VALUE__) == TSC_PG_PRESC_DIV8) || \
((__VALUE__) == TSC_PG_PRESC_DIV16) || \
((__VALUE__) == TSC_PG_PRESC_DIV32) || \
((__VALUE__) == TSC_PG_PRESC_DIV64) || \
((__VALUE__) == TSC_PG_PRESC_DIV128))
#define IS_TSC_MCV(__VALUE__) (((__VALUE__) == TSC_MCV_255) || \
((__VALUE__) == TSC_MCV_511) || \
((__VALUE__) == TSC_MCV_1023) || \
((__VALUE__) == TSC_MCV_2047) || \
((__VALUE__) == TSC_MCV_4095) || \
((__VALUE__) == TSC_MCV_8191) || \
((__VALUE__) == TSC_MCV_16383))
#define IS_TSC_IODEF(__VALUE__) (((__VALUE__) == TSC_IODEF_OUT_PP_LOW) || ((__VALUE__) == TSC_IODEF_IN_FLOAT))
#define IS_TSC_SYNC_POL(__VALUE__) (((__VALUE__) == TSC_SYNC_POLARITY_FALLING) || ((__VALUE__) == TSC_SYNC_POLARITY_RISING))
#define IS_TSC_ACQ_MODE(__VALUE__) (((__VALUE__) == TSC_ACQ_MODE_NORMAL) || ((__VALUE__) == TSC_ACQ_MODE_SYNCHRO))
#define IS_TSC_MCE_IT(__VALUE__) (((FunctionalState)(__VALUE__) == DISABLE) || ((FunctionalState)(__VALUE__) == ENABLE))
#define IS_TSC_GROUP_INDEX(__VALUE__) (((__VALUE__) == 0UL) || (((__VALUE__) > 0UL) && ((__VALUE__) < (uint32_t)TSC_NB_OF_GROUPS)))
#define IS_TSC_GROUP(__VALUE__) ((((__VALUE__) & TSC_GROUPX_NOT_SUPPORTED) != TSC_GROUPX_NOT_SUPPORTED) && \
((((__VALUE__) & TSC_GROUP1_IO1) == TSC_GROUP1_IO1) ||\
(((__VALUE__) & TSC_GROUP1_IO2) == TSC_GROUP1_IO2) ||\
(((__VALUE__) & TSC_GROUP1_IO3) == TSC_GROUP1_IO3) ||\
(((__VALUE__) & TSC_GROUP1_IO4) == TSC_GROUP1_IO4) ||\
(((__VALUE__) & TSC_GROUP2_IO1) == TSC_GROUP2_IO1) ||\
(((__VALUE__) & TSC_GROUP2_IO2) == TSC_GROUP2_IO2) ||\
(((__VALUE__) & TSC_GROUP2_IO3) == TSC_GROUP2_IO3) ||\
(((__VALUE__) & TSC_GROUP2_IO4) == TSC_GROUP2_IO4) ||\
(((__VALUE__) & TSC_GROUP3_IO1) == TSC_GROUP3_IO1) ||\
(((__VALUE__) & TSC_GROUP3_IO2) == TSC_GROUP3_IO2) ||\
(((__VALUE__) & TSC_GROUP3_IO3) == TSC_GROUP3_IO3) ||\
(((__VALUE__) & TSC_GROUP3_IO4) == TSC_GROUP3_IO4) ||\
(((__VALUE__) & TSC_GROUP4_IO1) == TSC_GROUP4_IO1) ||\
(((__VALUE__) & TSC_GROUP4_IO2) == TSC_GROUP4_IO2) ||\
(((__VALUE__) & TSC_GROUP4_IO3) == TSC_GROUP4_IO3) ||\
(((__VALUE__) & TSC_GROUP4_IO4) == TSC_GROUP4_IO4) ||\
(((__VALUE__) & TSC_GROUP5_IO1) == TSC_GROUP5_IO1) ||\
(((__VALUE__) & TSC_GROUP5_IO2) == TSC_GROUP5_IO2) ||\
(((__VALUE__) & TSC_GROUP5_IO3) == TSC_GROUP5_IO3) ||\
(((__VALUE__) & TSC_GROUP5_IO4) == TSC_GROUP5_IO4) ||\
(((__VALUE__) & TSC_GROUP6_IO1) == TSC_GROUP6_IO1) ||\
(((__VALUE__) & TSC_GROUP6_IO2) == TSC_GROUP6_IO2) ||\
(((__VALUE__) & TSC_GROUP6_IO3) == TSC_GROUP6_IO3) ||\
(((__VALUE__) & TSC_GROUP6_IO4) == TSC_GROUP6_IO4) ||\
(((__VALUE__) & TSC_GROUP7_IO1) == TSC_GROUP7_IO1) ||\
(((__VALUE__) & TSC_GROUP7_IO2) == TSC_GROUP7_IO2) ||\
(((__VALUE__) & TSC_GROUP7_IO3) == TSC_GROUP7_IO3) ||\
(((__VALUE__) & TSC_GROUP7_IO4) == TSC_GROUP7_IO4) ||\
(((__VALUE__) & TSC_GROUP8_IO1) == TSC_GROUP8_IO1) ||\
(((__VALUE__) & TSC_GROUP8_IO2) == TSC_GROUP8_IO2) ||\
(((__VALUE__) & TSC_GROUP8_IO3) == TSC_GROUP8_IO3) ||\
(((__VALUE__) & TSC_GROUP8_IO4) == TSC_GROUP8_IO4)))
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup TSC_Exported_Functions
* @{
*/
/** @addtogroup TSC_Exported_Functions_Group1 Initialization and de-initialization functions
* @{
*/
/* Initialization and de-initialization functions *****************************/
HAL_StatusTypeDef HAL_TSC_Init(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_DeInit(TSC_HandleTypeDef *htsc);
void HAL_TSC_MspInit(TSC_HandleTypeDef *htsc);
void HAL_TSC_MspDeInit(TSC_HandleTypeDef *htsc);
/* Callbacks Register/UnRegister functions ***********************************/
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
HAL_StatusTypeDef HAL_TSC_RegisterCallback(TSC_HandleTypeDef *htsc, HAL_TSC_CallbackIDTypeDef CallbackID, pTSC_CallbackTypeDef pCallback);
HAL_StatusTypeDef HAL_TSC_UnRegisterCallback(TSC_HandleTypeDef *htsc, HAL_TSC_CallbackIDTypeDef CallbackID);
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
/**
* @}
*/
/** @addtogroup TSC_Exported_Functions_Group2 Input and Output operation functions
* @{
*/
/* IO operation functions *****************************************************/
HAL_StatusTypeDef HAL_TSC_Start(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_Start_IT(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_Stop(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_Stop_IT(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_PollForAcquisition(TSC_HandleTypeDef *htsc);
TSC_GroupStatusTypeDef HAL_TSC_GroupGetStatus(TSC_HandleTypeDef *htsc, uint32_t gx_index);
uint32_t HAL_TSC_GroupGetValue(TSC_HandleTypeDef *htsc, uint32_t gx_index);
/**
* @}
*/
/** @addtogroup TSC_Exported_Functions_Group3 Peripheral Control functions
* @{
*/
/* Peripheral Control functions ***********************************************/
HAL_StatusTypeDef HAL_TSC_IOConfig(TSC_HandleTypeDef *htsc, TSC_IOConfigTypeDef *config);
HAL_StatusTypeDef HAL_TSC_IODischarge(TSC_HandleTypeDef *htsc, uint32_t choice);
/**
* @}
*/
/** @addtogroup TSC_Exported_Functions_Group4 Peripheral State and Errors functions
* @{
*/
/* Peripheral State and Error functions ***************************************/
HAL_TSC_StateTypeDef HAL_TSC_GetState(TSC_HandleTypeDef *htsc);
/**
* @}
*/
/** @addtogroup TSC_IRQ_Handler_and_Callbacks IRQ Handler and Callbacks
* @{
*/
/******* TSC IRQHandler and Callbacks used in Interrupt mode */
void HAL_TSC_IRQHandler(TSC_HandleTypeDef *htsc);
void HAL_TSC_ConvCpltCallback(TSC_HandleTypeDef *htsc);
void HAL_TSC_ErrorCallback(TSC_HandleTypeDef *htsc);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* STM32L4xx_HAL_TSC_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,290 @@
/**
******************************************************************************
* @file stm32l4xx_ll_exti.c
* @author MCD Application Team
* @brief EXTI LL module driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_ll_exti.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32L4xx_LL_Driver
* @{
*/
#if defined (EXTI)
/** @defgroup EXTI_LL EXTI
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup EXTI_LL_Private_Macros
* @{
*/
#define IS_LL_EXTI_LINE_0_31(__VALUE__) (((__VALUE__) & ~LL_EXTI_LINE_ALL_0_31) == 0x00000000U)
#define IS_LL_EXTI_LINE_32_63(__VALUE__) (((__VALUE__) & ~LL_EXTI_LINE_ALL_32_63) == 0x00000000U)
#define IS_LL_EXTI_MODE(__VALUE__) (((__VALUE__) == LL_EXTI_MODE_IT) \
|| ((__VALUE__) == LL_EXTI_MODE_EVENT) \
|| ((__VALUE__) == LL_EXTI_MODE_IT_EVENT))
#define IS_LL_EXTI_TRIGGER(__VALUE__) (((__VALUE__) == LL_EXTI_TRIGGER_NONE) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_RISING) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_FALLING) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_RISING_FALLING))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup EXTI_LL_Exported_Functions
* @{
*/
/** @addtogroup EXTI_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the EXTI registers to their default reset values.
* @retval An ErrorStatus enumeration value:
* - 0x00: EXTI registers are de-initialized
*/
uint32_t LL_EXTI_DeInit(void)
{
/* Interrupt mask register set to default reset values */
LL_EXTI_WriteReg(IMR1, 0xFF820000U);
/* Event mask register set to default reset values */
LL_EXTI_WriteReg(EMR1, 0x00000000U);
/* Rising Trigger selection register set to default reset values */
LL_EXTI_WriteReg(RTSR1, 0x00000000U);
/* Falling Trigger selection register set to default reset values */
LL_EXTI_WriteReg(FTSR1, 0x00000000U);
/* Software interrupt event register set to default reset values */
LL_EXTI_WriteReg(SWIER1, 0x00000000U);
/* Pending register clear */
LL_EXTI_WriteReg(PR1, 0x007DFFFFU);
/* Interrupt mask register 2 set to default reset values */
#if defined(LL_EXTI_LINE_40)
LL_EXTI_WriteReg(IMR2, 0x00000187U);
#else
LL_EXTI_WriteReg(IMR2, 0x00000087U);
#endif
/* Event mask register 2 set to default reset values */
LL_EXTI_WriteReg(EMR2, 0x00000000U);
/* Rising Trigger selection register 2 set to default reset values */
LL_EXTI_WriteReg(RTSR2, 0x00000000U);
/* Falling Trigger selection register 2 set to default reset values */
LL_EXTI_WriteReg(FTSR2, 0x00000000U);
/* Software interrupt event register 2 set to default reset values */
LL_EXTI_WriteReg(SWIER2, 0x00000000U);
/* Pending register 2 clear */
LL_EXTI_WriteReg(PR2, 0x00000078U);
return 0x00u;
}
/**
* @brief Initialize the EXTI registers according to the specified parameters in EXTI_InitStruct.
* @param EXTI_InitStruct pointer to a @ref LL_EXTI_InitTypeDef structure.
* @retval An ErrorStatus enumeration value:
* - 0x00: EXTI registers are initialized
* - any other calue : wrong configuration
*/
uint32_t LL_EXTI_Init(LL_EXTI_InitTypeDef *EXTI_InitStruct)
{
uint32_t status = 0x00u;
/* Check the parameters */
assert_param(IS_LL_EXTI_LINE_0_31(EXTI_InitStruct->Line_0_31));
assert_param(IS_LL_EXTI_LINE_32_63(EXTI_InitStruct->Line_32_63));
assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->LineCommand));
assert_param(IS_LL_EXTI_MODE(EXTI_InitStruct->Mode));
/* ENABLE LineCommand */
if (EXTI_InitStruct->LineCommand != DISABLE)
{
assert_param(IS_LL_EXTI_TRIGGER(EXTI_InitStruct->Trigger));
/* Configure EXTI Lines in range from 0 to 31 */
if (EXTI_InitStruct->Line_0_31 != LL_EXTI_LINE_NONE)
{
switch (EXTI_InitStruct->Mode)
{
case LL_EXTI_MODE_IT:
/* First Disable Event on provided Lines */
LL_EXTI_DisableEvent_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable IT on provided Lines */
LL_EXTI_EnableIT_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_MODE_EVENT:
/* First Disable IT on provided Lines */
LL_EXTI_DisableIT_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Event on provided Lines */
LL_EXTI_EnableEvent_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_MODE_IT_EVENT:
/* Directly Enable IT & Event on provided Lines */
LL_EXTI_EnableIT_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_EnableEvent_0_31(EXTI_InitStruct->Line_0_31);
break;
default:
status = 0x01u;
break;
}
if (EXTI_InitStruct->Trigger != LL_EXTI_TRIGGER_NONE)
{
switch (EXTI_InitStruct->Trigger)
{
case LL_EXTI_TRIGGER_RISING:
/* First Disable Falling Trigger on provided Lines */
LL_EXTI_DisableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Rising Trigger on provided Lines */
LL_EXTI_EnableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_TRIGGER_FALLING:
/* First Disable Rising Trigger on provided Lines */
LL_EXTI_DisableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Falling Trigger on provided Lines */
LL_EXTI_EnableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_TRIGGER_RISING_FALLING:
LL_EXTI_EnableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_EnableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
default:
status |= 0x02u;
break;
}
}
}
/* Configure EXTI Lines in range from 32 to 63 */
if (EXTI_InitStruct->Line_32_63 != LL_EXTI_LINE_NONE)
{
switch (EXTI_InitStruct->Mode)
{
case LL_EXTI_MODE_IT:
/* First Disable Event on provided Lines */
LL_EXTI_DisableEvent_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable IT on provided Lines */
LL_EXTI_EnableIT_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_MODE_EVENT:
/* First Disable IT on provided Lines */
LL_EXTI_DisableIT_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable Event on provided Lines */
LL_EXTI_EnableEvent_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_MODE_IT_EVENT:
/* Directly Enable IT & Event on provided Lines */
LL_EXTI_EnableIT_32_63(EXTI_InitStruct->Line_32_63);
LL_EXTI_EnableEvent_32_63(EXTI_InitStruct->Line_32_63);
break;
default:
status |= 0x04u;
break;
}
if (EXTI_InitStruct->Trigger != LL_EXTI_TRIGGER_NONE)
{
switch (EXTI_InitStruct->Trigger)
{
case LL_EXTI_TRIGGER_RISING:
/* First Disable Falling Trigger on provided Lines */
LL_EXTI_DisableFallingTrig_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable IT on provided Lines */
LL_EXTI_EnableRisingTrig_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_TRIGGER_FALLING:
/* First Disable Rising Trigger on provided Lines */
LL_EXTI_DisableRisingTrig_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable Falling Trigger on provided Lines */
LL_EXTI_EnableFallingTrig_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_TRIGGER_RISING_FALLING:
LL_EXTI_EnableRisingTrig_32_63(EXTI_InitStruct->Line_32_63);
LL_EXTI_EnableFallingTrig_32_63(EXTI_InitStruct->Line_32_63);
break;
default:
status = ERROR;
break;
}
}
}
}
/* DISABLE LineCommand */
else
{
/* De-configure EXTI Lines in range from 0 to 31 */
LL_EXTI_DisableIT_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_DisableEvent_0_31(EXTI_InitStruct->Line_0_31);
/* De-configure EXTI Lines in range from 32 to 63 */
LL_EXTI_DisableIT_32_63(EXTI_InitStruct->Line_32_63);
LL_EXTI_DisableEvent_32_63(EXTI_InitStruct->Line_32_63);
}
return status;
}
/**
* @brief Set each @ref LL_EXTI_InitTypeDef field to default value.
* @param EXTI_InitStruct Pointer to a @ref LL_EXTI_InitTypeDef structure.
* @retval None
*/
void LL_EXTI_StructInit(LL_EXTI_InitTypeDef *EXTI_InitStruct)
{
EXTI_InitStruct->Line_0_31 = LL_EXTI_LINE_NONE;
EXTI_InitStruct->Line_32_63 = LL_EXTI_LINE_NONE;
EXTI_InitStruct->LineCommand = DISABLE;
EXTI_InitStruct->Mode = LL_EXTI_MODE_IT;
EXTI_InitStruct->Trigger = LL_EXTI_TRIGGER_FALLING;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined (EXTI) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,307 @@
/**
******************************************************************************
* @file stm32l4xx_ll_spi.c
* @author MCD Application Team
* @brief SPI LL module driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_ll_spi.h"
#include "stm32l4xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32L4xx_LL_Driver
* @{
*/
#if defined (SPI1) || defined (SPI2) || defined (SPI3)
/** @addtogroup SPI_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup SPI_LL_Private_Constants SPI Private Constants
* @{
*/
/* SPI registers Masks */
#define SPI_CR1_CLEAR_MASK (SPI_CR1_CPHA | SPI_CR1_CPOL | SPI_CR1_MSTR | \
SPI_CR1_BR | SPI_CR1_LSBFIRST | SPI_CR1_SSI | \
SPI_CR1_SSM | SPI_CR1_RXONLY | SPI_CR1_CRCL | \
SPI_CR1_CRCNEXT | SPI_CR1_CRCEN | SPI_CR1_BIDIOE | \
SPI_CR1_BIDIMODE)
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup SPI_LL_Private_Macros SPI Private Macros
* @{
*/
#define IS_LL_SPI_TRANSFER_DIRECTION(__VALUE__) (((__VALUE__) == LL_SPI_FULL_DUPLEX) \
|| ((__VALUE__) == LL_SPI_SIMPLEX_RX) \
|| ((__VALUE__) == LL_SPI_HALF_DUPLEX_RX) \
|| ((__VALUE__) == LL_SPI_HALF_DUPLEX_TX))
#define IS_LL_SPI_MODE(__VALUE__) (((__VALUE__) == LL_SPI_MODE_MASTER) \
|| ((__VALUE__) == LL_SPI_MODE_SLAVE))
#define IS_LL_SPI_DATAWIDTH(__VALUE__) (((__VALUE__) == LL_SPI_DATAWIDTH_4BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_5BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_6BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_7BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_8BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_9BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_10BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_11BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_12BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_13BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_14BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_15BIT) \
|| ((__VALUE__) == LL_SPI_DATAWIDTH_16BIT))
#define IS_LL_SPI_POLARITY(__VALUE__) (((__VALUE__) == LL_SPI_POLARITY_LOW) \
|| ((__VALUE__) == LL_SPI_POLARITY_HIGH))
#define IS_LL_SPI_PHASE(__VALUE__) (((__VALUE__) == LL_SPI_PHASE_1EDGE) \
|| ((__VALUE__) == LL_SPI_PHASE_2EDGE))
#define IS_LL_SPI_NSS(__VALUE__) (((__VALUE__) == LL_SPI_NSS_SOFT) \
|| ((__VALUE__) == LL_SPI_NSS_HARD_INPUT) \
|| ((__VALUE__) == LL_SPI_NSS_HARD_OUTPUT))
#define IS_LL_SPI_BAUDRATE(__VALUE__) (((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV2) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV4) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV8) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV16) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV32) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV64) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV128) \
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV256))
#define IS_LL_SPI_BITORDER(__VALUE__) (((__VALUE__) == LL_SPI_LSB_FIRST) \
|| ((__VALUE__) == LL_SPI_MSB_FIRST))
#define IS_LL_SPI_CRCCALCULATION(__VALUE__) (((__VALUE__) == LL_SPI_CRCCALCULATION_ENABLE) \
|| ((__VALUE__) == LL_SPI_CRCCALCULATION_DISABLE))
#define IS_LL_SPI_CRC_POLYNOMIAL(__VALUE__) ((__VALUE__) >= 0x1U)
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup SPI_LL_Exported_Functions
* @{
*/
/** @addtogroup SPI_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the SPI registers to their default reset values.
* @param SPIx SPI Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: SPI registers are de-initialized
* - ERROR: SPI registers are not de-initialized
*/
ErrorStatus LL_SPI_DeInit(SPI_TypeDef *SPIx)
{
ErrorStatus status = ERROR;
/* Check the parameters */
assert_param(IS_SPI_ALL_INSTANCE(SPIx));
#if defined(SPI1)
if (SPIx == SPI1)
{
/* Force reset of SPI clock */
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
/* Release reset of SPI clock */
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
status = SUCCESS;
}
#endif /* SPI1 */
#if defined(SPI2)
if (SPIx == SPI2)
{
/* Force reset of SPI clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
/* Release reset of SPI clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
status = SUCCESS;
}
#endif /* SPI2 */
#if defined(SPI3)
if (SPIx == SPI3)
{
/* Force reset of SPI clock */
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI3);
/* Release reset of SPI clock */
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI3);
status = SUCCESS;
}
#endif /* SPI3 */
return status;
}
/**
* @brief Initialize the SPI registers according to the specified parameters in SPI_InitStruct.
* @note As some bits in SPI configuration registers can only be written when the SPI is disabled (SPI_CR1_SPE bit =0),
* SPI IP should be in disabled state prior calling this function. Otherwise, ERROR result will be returned.
* @param SPIx SPI Instance
* @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure
* @retval An ErrorStatus enumeration value. (Return always SUCCESS)
*/
ErrorStatus LL_SPI_Init(SPI_TypeDef *SPIx, LL_SPI_InitTypeDef *SPI_InitStruct)
{
ErrorStatus status = ERROR;
/* Check the SPI Instance SPIx*/
assert_param(IS_SPI_ALL_INSTANCE(SPIx));
/* Check the SPI parameters from SPI_InitStruct*/
assert_param(IS_LL_SPI_TRANSFER_DIRECTION(SPI_InitStruct->TransferDirection));
assert_param(IS_LL_SPI_MODE(SPI_InitStruct->Mode));
assert_param(IS_LL_SPI_DATAWIDTH(SPI_InitStruct->DataWidth));
assert_param(IS_LL_SPI_POLARITY(SPI_InitStruct->ClockPolarity));
assert_param(IS_LL_SPI_PHASE(SPI_InitStruct->ClockPhase));
assert_param(IS_LL_SPI_NSS(SPI_InitStruct->NSS));
assert_param(IS_LL_SPI_BAUDRATE(SPI_InitStruct->BaudRate));
assert_param(IS_LL_SPI_BITORDER(SPI_InitStruct->BitOrder));
assert_param(IS_LL_SPI_CRCCALCULATION(SPI_InitStruct->CRCCalculation));
if (LL_SPI_IsEnabled(SPIx) == 0x00000000U)
{
/*---------------------------- SPIx CR1 Configuration ------------------------
* Configure SPIx CR1 with parameters:
* - TransferDirection: SPI_CR1_BIDIMODE, SPI_CR1_BIDIOE and SPI_CR1_RXONLY bits
* - Master/Slave Mode: SPI_CR1_MSTR bit
* - ClockPolarity: SPI_CR1_CPOL bit
* - ClockPhase: SPI_CR1_CPHA bit
* - NSS management: SPI_CR1_SSM bit
* - BaudRate prescaler: SPI_CR1_BR[2:0] bits
* - BitOrder: SPI_CR1_LSBFIRST bit
* - CRCCalculation: SPI_CR1_CRCEN bit
*/
MODIFY_REG(SPIx->CR1,
SPI_CR1_CLEAR_MASK,
SPI_InitStruct->TransferDirection | SPI_InitStruct->Mode |
SPI_InitStruct->ClockPolarity | SPI_InitStruct->ClockPhase |
SPI_InitStruct->NSS | SPI_InitStruct->BaudRate |
SPI_InitStruct->BitOrder | SPI_InitStruct->CRCCalculation);
/*---------------------------- SPIx CR2 Configuration ------------------------
* Configure SPIx CR2 with parameters:
* - DataWidth: DS[3:0] bits
* - NSS management: SSOE bit
*/
MODIFY_REG(SPIx->CR2,
SPI_CR2_DS | SPI_CR2_SSOE,
SPI_InitStruct->DataWidth | (SPI_InitStruct->NSS >> 16U));
/*---------------------------- SPIx CRCPR Configuration ----------------------
* Configure SPIx CRCPR with parameters:
* - CRCPoly: CRCPOLY[15:0] bits
*/
if (SPI_InitStruct->CRCCalculation == LL_SPI_CRCCALCULATION_ENABLE)
{
assert_param(IS_LL_SPI_CRC_POLYNOMIAL(SPI_InitStruct->CRCPoly));
LL_SPI_SetCRCPolynomial(SPIx, SPI_InitStruct->CRCPoly);
}
status = SUCCESS;
}
return status;
}
/**
* @brief Set each @ref LL_SPI_InitTypeDef field to default value.
* @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure
* whose fields will be set to default values.
* @retval None
*/
void LL_SPI_StructInit(LL_SPI_InitTypeDef *SPI_InitStruct)
{
/* Set SPI_InitStruct fields to default values */
SPI_InitStruct->TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct->Mode = LL_SPI_MODE_SLAVE;
SPI_InitStruct->DataWidth = LL_SPI_DATAWIDTH_8BIT;
SPI_InitStruct->ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitStruct->ClockPhase = LL_SPI_PHASE_1EDGE;
SPI_InitStruct->NSS = LL_SPI_NSS_HARD_INPUT;
SPI_InitStruct->BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
SPI_InitStruct->BitOrder = LL_SPI_MSB_FIRST;
SPI_InitStruct->CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitStruct->CRCPoly = 7U;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined (SPI1) || defined (SPI2) || defined (SPI3) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

View File

@ -26,16 +26,18 @@ static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length);
static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length); static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
#define NUM_INTERFACES 2 #define NUM_CLASSES 2
#define NUM_INTERFACES 3
#if NUM_INTERFACES>1 #if NUM_INTERFACES>1
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (90) #define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (90 + 8+9 + 4)
#else #else
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (41) #define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (41)
#endif #endif
#define HID_INTF_NUM 0 #define HID_INTF_NUM 0
#define CDC_INTF_NUM 1 #define CDC_MASTER_INTF_NUM 1
#define CDC_SLAVE_INTF_NUM 2
__ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END = __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END =
{ {
/*Configuration Descriptor*/ /*Configuration Descriptor*/
@ -43,7 +45,7 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
COMPOSITE_CDC_HID_DESCRIPTOR_SIZE, /* wTotalLength:no of returned bytes */ COMPOSITE_CDC_HID_DESCRIPTOR_SIZE, /* wTotalLength:no of returned bytes */
0x00, 0x00,
NUM_INTERFACES, /* bNumInterfaces: 1 interface */ NUM_INTERFACES, /* bNumInterfaces */
0x01, /* bConfigurationValue: Configuration value */ 0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0x80, /* bmAttributes: self powered */ 0x80, /* bmAttributes: self powered */
@ -92,25 +94,31 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
0x00, 0x00,
HID_BINTERVAL, /*bInterval: Polling Interval */ HID_BINTERVAL, /*bInterval: Polling Interval */
#if NUM_INTERFACES > 1 #if NUM_INTERFACES > 1
/* */ /* */
/* CDC */ /* CDC */
/* */ /* */
// This "IAD" is needed for Windows since it ignores the standard Union Functional Descriptor
0x08, // bLength
0x0B, // IAD type
CDC_MASTER_INTF_NUM, // First interface
CDC_SLAVE_INTF_NUM, // Next interface
0x02, // bInterfaceClass of the first interface
0x02, // bInterfaceSubClass of the first interface
0x00, // bInterfaceProtocol of the first interface
0x00, // Interface string index
/*Interface Descriptor */ /*Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */ 0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
/* Interface descriptor type */ /* Interface descriptor type */
/*!*/ CDC_INTF_NUM, /* bInterfaceNumber: Number of Interface */ /*!*/ CDC_MASTER_INTF_NUM, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */ 0x00, /* bAlternateSetting: Alternate setting */
0x03, /* bNumEndpoints: 3 endpoints used */ 0x01, /* bNumEndpoints: 1 endpoint used */
0x02, /* bInterfaceClass: Communication Interface Class */ 0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */ 0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */ 0x00, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */ 0x00, /* iInterface: */
/*Header Functional Descriptor*/ /*Header Functional Descriptor*/
@ -125,7 +133,7 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
0x24, /* bDescriptorType: CS_INTERFACE */ 0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */ 0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */ 0x00, /* bmCapabilities: D0+D1 */
/*!*/ CDC_INTF_NUM, /* bDataInterface: 0 */ /*!*/ CDC_SLAVE_INTF_NUM, /* bDataInterface: 0 */
/*ACM Functional Descriptor*/ /*ACM Functional Descriptor*/
0x04, /* bFunctionLength */ 0x04, /* bFunctionLength */
@ -137,10 +145,10 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
0x05, /* bFunctionLength */ 0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */ 0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */ 0x06, /* bDescriptorSubtype: Union func desc */
/*!*/ CDC_INTF_NUM, /* bMasterInterface: Communication class interface */ /*!*/ CDC_MASTER_INTF_NUM, /* bMasterInterface: Communication class interface */
/*!*/ CDC_INTF_NUM, /* bSlaveInterface0: Data Class Interface */ /*!*/ CDC_SLAVE_INTF_NUM, /* bSlaveInterface0: Data Class Interface */
/*Endpoint 2 Descriptor*/ /* Control Endpoint Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */ 0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_CMD_EP, /* bEndpointAddress */ CDC_CMD_EP, /* bEndpointAddress */
@ -149,6 +157,17 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
HIBYTE(CDC_CMD_PACKET_SIZE), HIBYTE(CDC_CMD_PACKET_SIZE),
0x10, /* bInterval: */ 0x10, /* bInterval: */
/* Interface descriptor */
0x09, /* bLength */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType */
CDC_SLAVE_INTF_NUM, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x0A, /* bInterfaceClass: Communication class data */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00,
/*Endpoint OUT Descriptor*/ /*Endpoint OUT Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */ 0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
@ -167,10 +186,13 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */ 0x00, /* bInterval: ignore for Bulk transfer */
4, /* Descriptor size */
3, /* Descriptor type */
0x09,
0x04,
#endif #endif
}; };
USBD_ClassTypeDef USBD_Composite = USBD_ClassTypeDef USBD_Composite =
{ {
USBD_Composite_Init, USBD_Composite_Init,
@ -195,14 +217,27 @@ int in_endpoint_to_class[MAX_ENDPOINTS];
int out_endpoint_to_class[MAX_ENDPOINTS]; int out_endpoint_to_class[MAX_ENDPOINTS];
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1) { void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *cdc_class) {
USBD_Classes[0] = class0; USBD_Classes[0] = hid_class;
USBD_Classes[1] = class1; USBD_Classes[1] = cdc_class;
}
static USBD_ClassTypeDef * getClass(uint8_t index)
{
switch(index)
{
case HID_INTF_NUM:
return USBD_Classes[0];
case CDC_MASTER_INTF_NUM:
case CDC_SLAVE_INTF_NUM:
return USBD_Classes[1];
}
return NULL;
} }
static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
int i; int i;
for(i = 0; i < NUM_INTERFACES; i++) { for(i = 0; i < NUM_CLASSES; i++) {
if (USBD_Classes[i]->Init(pdev, cfgidx) != USBD_OK) { if (USBD_Classes[i]->Init(pdev, cfgidx) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;
} }
@ -213,7 +248,7 @@ static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
int i; int i;
for(i = 0; i < NUM_INTERFACES; i++) { for(i = 0; i < NUM_CLASSES; i++) {
if (USBD_Classes[i]->DeInit(pdev, cfgidx) != USBD_OK) { if (USBD_Classes[i]->DeInit(pdev, cfgidx) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;
} }
@ -224,10 +259,13 @@ static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) {
int i; int i;
USBD_ClassTypeDef * device_class;
device_class = getClass(req->wIndex);
switch (req->bmRequest & USB_REQ_TYPE_MASK) { switch (req->bmRequest & USB_REQ_TYPE_MASK) {
case USB_REQ_TYPE_CLASS : case USB_REQ_TYPE_CLASS :
if (req->wIndex < NUM_INTERFACES) if (device_class != NULL)
return USBD_Classes[req->wIndex]->Setup(pdev, req); return device_class->Setup(pdev, req);
else else
return USBD_FAIL; return USBD_FAIL;
@ -236,7 +274,7 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
switch (req->bRequest) { switch (req->bRequest) {
case USB_REQ_GET_DESCRIPTOR : case USB_REQ_GET_DESCRIPTOR :
for(i = 0; i < NUM_INTERFACES; i++) { for(i = 0; i < NUM_CLASSES; i++) {
if (USBD_Classes[i]->Setup(pdev, req) != USBD_OK) { if (USBD_Classes[i]->Setup(pdev, req) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;
} }
@ -246,8 +284,8 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
case USB_REQ_GET_INTERFACE : case USB_REQ_GET_INTERFACE :
case USB_REQ_SET_INTERFACE : case USB_REQ_SET_INTERFACE :
if (req->wIndex < NUM_INTERFACES) if (device_class != NULL)
return USBD_Classes[req->wIndex]->Setup(pdev, req); return device_class->Setup(pdev, req);
else else
return USBD_FAIL; return USBD_FAIL;
} }
@ -274,7 +312,7 @@ static uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) { static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) {
int i; int i;
for(i = 0; i < NUM_INTERFACES; i++) { for(i = 0; i < NUM_CLASSES; i++) {
if (USBD_Classes[i]->EP0_RxReady != NULL) { if (USBD_Classes[i]->EP0_RxReady != NULL) {
if (USBD_Classes[i]->EP0_RxReady(pdev) != USBD_OK) { if (USBD_Classes[i]->EP0_RxReady(pdev) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;

View File

@ -821,12 +821,16 @@ void USBD_CtlError( USBD_HandleTypeDef *pdev ,
* @param len : descriptor length * @param len : descriptor length
* @retval None * @retval None
*/ */
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t unicode_size, uint16_t *len)
{ {
uint8_t idx = 0U; uint8_t idx = 0U;
if (desc != NULL) if (desc != NULL)
{ {
if ((idx + 4) >= unicode_size)
{
return;
}
*len = (uint16_t)USBD_GetLen(desc) * 2U + 2U; *len = (uint16_t)USBD_GetLen(desc) * 2U + 2U;
unicode[idx++] = *(uint8_t *)(void *)len; unicode[idx++] = *(uint8_t *)(void *)len;
unicode[idx++] = USB_DESC_TYPE_STRING; unicode[idx++] = USB_DESC_TYPE_STRING;

View File

@ -108,7 +108,7 @@ void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata); void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata);
void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len); void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t unicode_size, uint16_t *len);
/** /**
* @} * @}
*/ */

View File

@ -108,7 +108,7 @@ const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC]=
HIBYTE(USBD_LANGID_STRING), HIBYTE(USBD_LANGID_STRING),
}; };
uint8_t USBD_StrDesc[32]; uint8_t USBD_StrDesc[48];
/** /**
* @brief Returns the device descriptor. * @brief Returns the device descriptor.
@ -142,7 +142,7 @@ uint8_t *USBD_HID_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
*/ */
uint8_t *USBD_HID_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) uint8_t *USBD_HID_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ {
USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length); USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, sizeof(USBD_StrDesc), length);
return USBD_StrDesc; return USBD_StrDesc;
} }
@ -154,7 +154,7 @@ uint8_t *USBD_HID_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length
*/ */
uint8_t *USBD_HID_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) uint8_t *USBD_HID_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ {
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length); USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, sizeof(USBD_StrDesc), length);
return USBD_StrDesc; return USBD_StrDesc;
} }
@ -192,6 +192,6 @@ uint8_t *USBD_HID_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
} }
USBD_GetString((uint8_t *)uuid_str, USBD_StrDesc, length); USBD_GetString((uint8_t *)uuid_str, USBD_StrDesc, sizeof(USBD_StrDesc), length);
return USBD_StrDesc; return USBD_StrDesc;
} }

View File

@ -342,6 +342,7 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
uint8_t *pbuf = NULL; uint8_t *pbuf = NULL;
uint16_t status_info = 0U; uint16_t status_info = 0U;
USBD_StatusTypeDef ret = USBD_OK; USBD_StatusTypeDef ret = USBD_OK;
req->wLength = req->wLength & 0x7f;
switch (req->bmRequest & USB_REQ_TYPE_MASK) switch (req->bmRequest & USB_REQ_TYPE_MASK)
{ {
@ -386,6 +387,7 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
break; break;
case USB_REQ_GET_DESCRIPTOR: case USB_REQ_GET_DESCRIPTOR:
req->wLength = req->wLength & 0x7f;
if(req->wValue >> 8 == HID_REPORT_DESC) if(req->wValue >> 8 == HID_REPORT_DESC)
{ {
len = MIN(HID_FIDO_REPORT_DESC_SIZE , req->wLength); len = MIN(HID_FIDO_REPORT_DESC_SIZE , req->wLength);

View File

@ -1,201 +1,74 @@
/* /* Copyright 2019 SoloKeys Developers */
***************************************************************************** /* */
** /* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* Highest address of the user mode stack */ /* End of RAM */
_estack = 0x2000c000; /* end of RAM */ _estack = 0x2000c000;
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */ _MIN_STACK_SIZE = 0x400;
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY MEMORY
{ {
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 20K flash (rx) : ORIGIN = 0x08000000, LENGTH = 20K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
/* The startup code goes first into FLASH */
.isr_vector : .isr_vector :
{ {
. = ALIGN(8); . = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */ KEEP(*(.isr_vector))
. = ALIGN(8); . = ALIGN(8);
} >FLASH } >flash
/* The program code and other data goes into FLASH */
.text : .text :
{ {
. = ALIGN(8); . = ALIGN(8);
*(.text) /* .text sections (code) */ *(.text*)
*(.text*) /* .text* sections (code) */ *(.rodata*)
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP(*(.init)) KEEP(*(.init))
KEEP (*(.fini)) KEEP(*(.finit))
. = ALIGN(8);
_etext = .;
} >flash
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data); _sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : .data :
{ {
. = ALIGN(8); . = ALIGN(8);
_sdata = .; /* create a global symbol at data start */ _sdata = .;
*(.data) /* .data sections */ *(.data*)
*(.data*) /* .data* sections */
. = ALIGN(8); . = ALIGN(8);
_edata = .; /* define a global symbol at data end */ _edata = .;
} >RAM AT> FLASH } >ram AT> flash
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss : .bss :
{ {
/* This is used by the startup in order to initialize the .bss secion */ . = ALIGN(4);
_sbss = .; /* define a global symbol at bss start */ _sbss = .;
__bss_start__ = _sbss; __bss_start__ = _sbss;
*(.bss)
*(.bss*) *(.bss*)
*(COMMON) *(COMMON)
. = ALIGN(4); . = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */ _ebss = .;
__bss_end__ = _ebss; __bss_end__ = _ebss;
} >RAM } > ram
/* User_heap_stack section, used to check that there is enough RAM left */ ._stack :
._user_heap_stack :
{ {
. = ALIGN(8); . = ALIGN(8);
PROVIDE ( end = . ); end = .;
PROVIDE ( _end = . ); _end = .;
. = . + _Min_Heap_Size; . = . + _MIN_STACK_SIZE;
. = . + _Min_Stack_Size;
. = ALIGN(8); . = ALIGN(8);
} >RAM } > ram
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

View File

@ -1,201 +1,74 @@
/* /* Copyright 2019 SoloKeys Developers */
***************************************************************************** /* */
** /* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* Highest address of the user mode stack */ /* End of RAM */
_estack = 0x2000c000; /* end of RAM */ _estack = 0x2000c000;
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */ _MIN_STACK_SIZE = 0x400;
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY MEMORY
{ {
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K flash (rx) : ORIGIN = 0x08000000, LENGTH = 32K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
/* The startup code goes first into FLASH */
.isr_vector : .isr_vector :
{ {
. = ALIGN(8); . = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */ KEEP(*(.isr_vector))
. = ALIGN(8); . = ALIGN(8);
} >FLASH } >flash
/* The program code and other data goes into FLASH */
.text : .text :
{ {
. = ALIGN(8); . = ALIGN(8);
*(.text) /* .text sections (code) */ *(.text*)
*(.text*) /* .text* sections (code) */ *(.rodata*)
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP(*(.init)) KEEP(*(.init))
KEEP (*(.fini)) KEEP(*(.finit))
. = ALIGN(8);
_etext = .;
} >flash
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data); _sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : .data :
{ {
. = ALIGN(8); . = ALIGN(8);
_sdata = .; /* create a global symbol at data start */ _sdata = .;
*(.data) /* .data sections */ *(.data*)
*(.data*) /* .data* sections */
. = ALIGN(8); . = ALIGN(8);
_edata = .; /* define a global symbol at data end */ _edata = .;
} >RAM AT> FLASH } >ram AT> flash
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss : .bss :
{ {
/* This is used by the startup in order to initialize the .bss secion */ . = ALIGN(4);
_sbss = .; /* define a global symbol at bss start */ _sbss = .;
__bss_start__ = _sbss; __bss_start__ = _sbss;
*(.bss)
*(.bss*) *(.bss*)
*(COMMON) *(COMMON)
. = ALIGN(4); . = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */ _ebss = .;
__bss_end__ = _ebss; __bss_end__ = _ebss;
} >RAM } > ram
/* User_heap_stack section, used to check that there is enough RAM left */ ._stack :
._user_heap_stack :
{ {
. = ALIGN(8); . = ALIGN(8);
PROVIDE ( end = . ); end = .;
PROVIDE ( _end = . ); _end = .;
. = . + _Min_Heap_Size; . = . + _MIN_STACK_SIZE;
. = . + _Min_Stack_Size;
. = ALIGN(8); . = ALIGN(8);
} >RAM } > ram
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

View File

@ -1,202 +1,80 @@
/* /* Copyright 2019 SoloKeys Developers */
***************************************************************************** /* */
** /* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* Highest address of the user mode stack */ /* End of RAM */
_estack = 0x2000c000; /* end of RAM */ _estack = 0x2000c000;
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */ _MIN_STACK_SIZE = 0x400;
_Min_Stack_Size = 0x400; /* required amount of stack */
/*
Memory layout of device:
20 KB 198KB-8 38 KB
| bootloader | application | secrets/data |
*/
/* Specify the memory areas */
MEMORY MEMORY
{ {
/* First 20 KB is bootloader */ flash (rx) : ORIGIN = 0x08005000, LENGTH = 198K - 8
FLASH (rx) : ORIGIN = 0x08005000, LENGTH = 198K-8 /* Leave out 38 Kb at end for data */ ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
/* The startup code goes first into FLASH */
.isr_vector : .isr_vector :
{ {
. = ALIGN(8); . = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */ KEEP(*(.isr_vector))
. = ALIGN(8); . = ALIGN(8);
} >FLASH } >flash
/* The program code and other data goes into FLASH */
.text : .text :
{ {
. = ALIGN(8); . = ALIGN(8);
*(.text) /* .text sections (code) */ *(.text*)
*(.text*) /* .text* sections (code) */ *(.rodata*)
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP(*(.init)) KEEP(*(.init))
KEEP (*(.fini)) KEEP(*(.finit))
. = ALIGN(8);
_etext = .;
} >flash
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data); _sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : .data :
{ {
. = ALIGN(8); . = ALIGN(8);
_sdata = .; /* create a global symbol at data start */ _sdata = .;
*(.data) /* .data sections */ *(.data*)
*(.data*) /* .data* sections */
. = ALIGN(8); . = ALIGN(8);
_edata = .; /* define a global symbol at data end */ _edata = .;
} >RAM AT> FLASH } >ram AT> flash
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss : .bss :
{ {
/* This is used by the startup in order to initialize the .bss secion */ . = ALIGN(4);
_sbss = .; /* define a global symbol at bss start */ _sbss = .;
__bss_start__ = _sbss; __bss_start__ = _sbss;
*(.bss)
*(.bss*) *(.bss*)
*(COMMON) *(COMMON)
. = ALIGN(4); . = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */ _ebss = .;
__bss_end__ = _ebss; __bss_end__ = _ebss;
} >RAM } > ram
/* User_heap_stack section, used to check that there is enough RAM left */ ._stack :
._user_heap_stack :
{ {
. = ALIGN(8); . = ALIGN(8);
PROVIDE ( end = . ); end = .;
PROVIDE ( _end = . ); _end = .;
. = . + _Min_Heap_Size; . = . + _MIN_STACK_SIZE;
. = . + _Min_Stack_Size;
. = ALIGN(8); . = ALIGN(8);
} >RAM } > ram
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

View File

@ -1,203 +1,74 @@
/* /* Copyright 2019 SoloKeys Developers */
***************************************************************************** /* */
** /* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* Highest address of the user mode stack */ /* End of RAM */
_estack = 0x2000c000; /* end of RAM */ _estack = 0x2000c000;
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */ _MIN_STACK_SIZE = 0x400;
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY MEMORY
{ {
/* First 32 KB is bootloader */ flash (rx) : ORIGIN = 0x08008000, LENGTH = 186K - 8
/*FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 238K-8 [> Leave out 38 Kb at end for data <]*/ ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 186K-8 /* Leave out 38 Kb at end for data */ sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
/* The startup code goes first into FLASH */
.isr_vector : .isr_vector :
{ {
. = ALIGN(8); . = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */ KEEP(*(.isr_vector))
. = ALIGN(8); . = ALIGN(8);
} >FLASH } >flash
/* The program code and other data goes into FLASH */
.text : .text :
{ {
. = ALIGN(8); . = ALIGN(8);
*(.text) /* .text sections (code) */ *(.text*)
*(.text*) /* .text* sections (code) */ *(.rodata*)
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP(*(.init)) KEEP(*(.init))
KEEP (*(.fini)) KEEP(*(.finit))
. = ALIGN(8);
_etext = .;
} >flash
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data); _sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : .data :
{ {
. = ALIGN(8); . = ALIGN(8);
_sdata = .; /* create a global symbol at data start */ _sdata = .;
*(.data) /* .data sections */ *(.data*)
*(.data*) /* .data* sections */
. = ALIGN(8); . = ALIGN(8);
_edata = .; /* define a global symbol at data end */ _edata = .;
} >RAM AT> FLASH } >ram AT> flash
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss : .bss :
{ {
/* This is used by the startup in order to initialize the .bss secion */ . = ALIGN(4);
_sbss = .; /* define a global symbol at bss start */ _sbss = .;
__bss_start__ = _sbss; __bss_start__ = _sbss;
*(.bss)
*(.bss*) *(.bss*)
*(COMMON) *(COMMON)
. = ALIGN(4); . = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */ _ebss = .;
__bss_end__ = _ebss; __bss_end__ = _ebss;
} >RAM } > ram
/* User_heap_stack section, used to check that there is enough RAM left */ ._stack :
._user_heap_stack :
{ {
. = ALIGN(8); . = ALIGN(8);
PROVIDE ( end = . ); end = .;
PROVIDE ( _end = . ); _end = .;
. = . + _Min_Heap_Size; . = . + _MIN_STACK_SIZE;
. = . + _Min_Stack_Size;
. = ALIGN(8); . = ALIGN(8);
} >RAM } > ram
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

373
targets/stm32l432/src/ams.c Normal file
View File

@ -0,0 +1,373 @@
#include <string.h>
#include "stm32l4xx_ll_spi.h"
#include "ams.h"
#include "log.h"
#include "util.h"
#include "device.h"
#include "nfc.h"
static void flush_rx()
{
while(LL_SPI_IsActiveFlag_RXNE(SPI1) != 0)
{
LL_SPI_ReceiveData8(SPI1);
}
}
static void wait_for_tx()
{
// while (LL_SPI_IsActiveFlag_BSY(SPI1) == 1)
// ;
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY)
;
}
static void wait_for_rx()
{
while(LL_SPI_IsActiveFlag_RXNE(SPI1) == 0)
;
}
void ams_print_device(AMS_DEVICE * dev)
{
printf1(TAG_NFC, "AMS_DEVICE:\r\n");
printf1(TAG_NFC, " io_conf: %02x\r\n",dev->regs.io_conf);
printf1(TAG_NFC, " ic_conf0: %02x\r\n",dev->regs.ic_conf0);
printf1(TAG_NFC, " ic_conf1: %02x\r\n",dev->regs.ic_conf1);
printf1(TAG_NFC, " ic_conf2: %02x\r\n",dev->regs.ic_conf2);
printf1(TAG_NFC, " rfid_status: %02x\r\n",dev->regs.rfid_status);
printf1(TAG_NFC, " ic_status: %02x\r\n",dev->regs.ic_status);
printf1(TAG_NFC, " mask_int0: %02x\r\n",dev->regs.mask_int0);
printf1(TAG_NFC, " mask_int1: %02x\r\n",dev->regs.mask_int1);
printf1(TAG_NFC, " int0: %02x\r\n",dev->regs.int0);
printf1(TAG_NFC, " int1: %02x\r\n",dev->regs.int1);
printf1(TAG_NFC, " buffer_status2: %02x\r\n",dev->regs.buffer_status2);
printf1(TAG_NFC, " buffer_status1: %02x\r\n",dev->regs.buffer_status1);
printf1(TAG_NFC, " last_nfc_addr: %02x\r\n",dev->regs.last_nfc_addr);
printf1(TAG_NFC, " product_type: %02x\r\n",dev->regs.product_type);
printf1(TAG_NFC, " product_subtype:%02x\r\n",dev->regs.product_subtype);
printf1(TAG_NFC, " version_maj: %02x\r\n",dev->regs.version_maj);
printf1(TAG_NFC, " version_min: %02x\r\n",dev->regs.version_min);
}
static uint8_t send_recv(uint8_t b)
{
wait_for_tx();
LL_SPI_TransmitData8(SPI1, b);
wait_for_rx();
b = LL_SPI_ReceiveData8(SPI1);
return b;
}
void ams_write_reg(uint8_t addr, uint8_t tx)
{
send_recv(0x00| addr);
send_recv(tx);
UNSELECT();
SELECT();
}
uint8_t ams_read_reg(uint8_t addr)
{
send_recv(0x20| (addr & 0x1f));
uint8_t data = send_recv(0);
UNSELECT();
SELECT();
return data;
}
// data must be 14 bytes long
void read_reg_block(AMS_DEVICE * dev)
{
int i;
uint8_t mode = 0x20 | (4 );
flush_rx();
send_recv(mode);
for (i = 0x04; i < 0x0d; i++)
{
dev->buf[i] = send_recv(0);
}
UNSELECT();
SELECT();
}
void ams_read_buffer(uint8_t * data, int len)
{
send_recv(0xa0);
while(len--)
{
*data++ = send_recv(0x00);
}
UNSELECT();
SELECT();
}
void ams_write_buffer(uint8_t * data, int len)
{
send_recv(0x80);
while(len--)
{
send_recv(*data++);
}
UNSELECT();
SELECT();
}
// data must be 4 bytes
void ams_read_eeprom_block(uint8_t block, uint8_t * data)
{
send_recv(0x7f);
send_recv(block << 1);
data[0] = send_recv(0);
data[1] = send_recv(0);
data[2] = send_recv(0);
data[3] = send_recv(0);
UNSELECT();
SELECT();
}
// data must be 4 bytes
void ams_write_eeprom_block(uint8_t block, uint8_t * data)
{
send_recv(0x40);
send_recv(block << 1);
send_recv(data[0]);
send_recv(data[1]);
send_recv(data[2]);
send_recv(data[3]);
UNSELECT();
SELECT();
}
void ams_write_command(uint8_t cmd)
{
send_recv(0xc0 | cmd);
UNSELECT();
SELECT();
}
const char * ams_get_state_string(uint8_t regval)
{
if (regval & AMS_STATE_INVALID)
{
return "STATE_INVALID";
}
switch (regval & AMS_STATE_MASK)
{
case AMS_STATE_OFF:
return "STATE_OFF";
case AMS_STATE_SENSE:
return "STATE_SENSE";
case AMS_STATE_RESOLUTION:
return "STATE_RESOLUTION";
case AMS_STATE_RESOLUTION_L2:
return "STATE_RESOLUTION_L2";
case AMS_STATE_SELECTED:
return "STATE_SELECTED";
case AMS_STATE_SECTOR2:
return "STATE_SECTOR2";
case AMS_STATE_SECTORX_2:
return "STATE_SECTORX_2";
case AMS_STATE_SELECTEDX:
return "STATE_SELECTEDX";
case AMS_STATE_SENSEX_L2:
return "STATE_SENSEX_L2";
case AMS_STATE_SENSEX:
return "STATE_SENSEX";
case AMS_STATE_SLEEP:
return "STATE_SLEEP";
}
return "STATE_WRONG";
}
int ams_state_is_valid(uint8_t regval)
{
if (regval & AMS_STATE_INVALID)
{
return 0;
}
switch (regval & AMS_STATE_MASK)
{
case AMS_STATE_OFF:
case AMS_STATE_SENSE:
case AMS_STATE_RESOLUTION:
case AMS_STATE_RESOLUTION_L2:
case AMS_STATE_SELECTED:
case AMS_STATE_SECTOR2:
case AMS_STATE_SECTORX_2:
case AMS_STATE_SELECTEDX:
case AMS_STATE_SENSEX_L2:
case AMS_STATE_SENSEX:
case AMS_STATE_SLEEP:
return 1;
}
return 0;
}
void ams_print_int0(uint8_t int0)
{
#if DEBUG_LEVEL
uint32_t tag = (TAG_NFC)|(TAG_NO_TAG);
printf1(TAG_NFC," ");
if (int0 & AMS_INT_XRF)
printf1(tag," XRF");
if (int0 & AMS_INT_TXE)
printf1(tag," TXE");
if (int0 & AMS_INT_RXE)
printf1(tag," RXE");
if (int0 & AMS_INT_EER_RF)
printf1(tag," EER_RF");
if (int0 & AMS_INT_EEW_RF)
printf1(tag," EEW_RF");
if (int0 & AMS_INT_SLP)
printf1(tag," SLP");
if (int0 & AMS_INT_WU_A)
printf1(tag," WU_A");
if (int0 & AMS_INT_INIT)
printf1(tag," INIT");
printf1(tag,"\r\n");
#endif
}
void ams_print_int1(uint8_t int0)
{
#if DEBUG_LEVEL
uint32_t tag = (TAG_NFC)|(TAG_NO_TAG);
printf1(TAG_NFC," ");
if (int0 & AMS_INT_ACC_ERR)
printf1(tag," ACC_ERR");
if (int0 & AMS_INT_EEAC_ERR)
printf1(tag," EEAC_ERR");
if (int0 & AMS_INT_IO_EEWR)
printf1(tag," IO_EEWR");
if (int0 & AMS_INT_BF_ERR)
printf1(tag," BF_ERR");
if (int0 & AMS_INT_CRC_ERR)
printf1(tag," CRC_ERR");
if (int0 & AMS_INT_PAR_ERR)
printf1(tag," PAR_ERR");
if (int0 & AMS_INT_FRM_ERR)
printf1(tag," FRM_ERR");
if (int0 & AMS_INT_RXS)
printf1(tag," RXS");
printf1(tag,"\r\n");
#endif
}
int ams_init()
{
LL_GPIO_SetPinMode(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN,LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN);
LL_SPI_SetClockPolarity(SPI1,LL_SPI_POLARITY_LOW);
LL_SPI_SetClockPhase(SPI1,LL_SPI_PHASE_2EDGE);
LL_SPI_SetRxFIFOThreshold(SPI1,LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable(SPI1);
// delay(10);
SELECT();
delay(1);
uint8_t productType = ams_read_reg(AMS_REG_PRODUCT_TYPE);
if (productType == 0x14)
{
return 1;
}
return 0;
}
void ams_configure()
{
// Should not be used during passive operation.
uint8_t block[4];
// check connection
uint8_t productType = ams_read_reg(AMS_REG_PRODUCT_TYPE);
if (productType != 0x14)
{
printf1(TAG_ERR, "Have wrong product type [0x%02x]. AMS3956 connection error.\n", productType);
}
printf1(TAG_NFC,"AMS3956 product type 0x%02x.\n", productType);
ams_read_eeprom_block(AMS_CONFIG_UID_ADDR, block);
printf1(TAG_NFC,"UID: 3F 14 02 - "); dump_hex1(TAG_NFC,block,4);
ams_read_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block);
printf1(TAG_NFC,"conf0: "); dump_hex1(TAG_NFC,block,4);
uint8_t sense1 = 0x44;
uint8_t sense2 = 0x00;
uint8_t selr = 0x20; // SAK
if(block[0] != sense1 || block[1] != sense2 || block[2] != selr)
{
printf1(TAG_NFC,"Writing config block 0\r\n");
block[0] = sense1;
block[1] = sense2;
block[2] = selr;
block[3] = 0x00;
ams_write_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block);
UNSELECT();
delay(10);
SELECT();
delay(10);
ams_read_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block);
printf1(TAG_NFC,"conf0: "); dump_hex1(TAG_NFC,block,4);
}
ams_read_eeprom_block(AMS_CONFIG_BLOCK1_ADDR, block);
printf1(TAG_NFC,"conf1: "); dump_hex1(TAG_NFC,block,4);
uint8_t ic_cfg1 = AMS_CFG1_OUTPUT_RESISTANCE_100 | AMS_CFG1_VOLTAGE_LEVEL_2V0;
uint8_t ic_cfg2 = AMS_CFG2_TUN_MOD;
if (block[0] != ic_cfg1 || block[1] != ic_cfg2)
{
printf1(TAG_NFC,"Writing config block 1\r\n");
ams_write_reg(AMS_REG_IC_CONF1,ic_cfg1);
ams_write_reg(AMS_REG_IC_CONF2,ic_cfg2);
// set IC_CFG1
block[0] = ic_cfg1;
// set IC_CFG2
block[1] = ic_cfg2;
// mask interrupt bits
block[2] = 0x80;
block[3] = 0;
ams_write_eeprom_block(AMS_CONFIG_BLOCK1_ADDR, block);
UNSELECT();
delay(10);
SELECT();
delay(10);
ams_read_eeprom_block(0x7F, block);
printf1(TAG_NFC,"conf1: "); dump_hex1(TAG_NFC,block,4);
}
}

162
targets/stm32l432/src/ams.h Normal file
View File

@ -0,0 +1,162 @@
// AS3956 interface
// https://ams.com/as3956
// https://ams.com/documents/20143/36005/AS3956_DS000546_7-00.pdf
#ifndef _AMS_H_
#define _AMS_H_
#include <stdint.h>
#include <stdbool.h>
#include "stm32l4xx_ll_gpio.h"
typedef union
{
uint8_t buf[0x20];
struct {
uint8_t io_conf; // 0x00
uint8_t ic_conf0; // 0x01
uint8_t ic_conf1; // 0x02
uint8_t ic_conf2; // 0x03
uint8_t rfid_status; // 0x04
uint8_t ic_status; // 0x05
uint8_t _nc0[2]; // 0x06 - 0x07
uint8_t mask_int0; // 0x08
uint8_t mask_int1; // 0x09
uint8_t int0; // 0x0a
uint8_t int1; // 0x0b
uint8_t buffer_status2; // 0x0c
uint8_t buffer_status1; // 0x0d
uint8_t last_nfc_addr; // 0x0e
uint8_t _nc1[0x1b - 0x0f + 1]; // 0x0f - 0x1b
uint8_t product_type; // 0x1c
uint8_t product_subtype; // 0x1d
uint8_t version_maj; // 0x1e
uint8_t version_min; // 0x1f
} regs;
} __attribute__((packed)) AMS_DEVICE;
#define SELECT() LL_GPIO_ResetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
#define UNSELECT() LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
int ams_init();
void ams_configure();
void ams_read_buffer(uint8_t * data, int len);
void ams_write_buffer(uint8_t * data, int len);
void ams_write_command(uint8_t cmd);
void read_reg_block(AMS_DEVICE * dev);
uint8_t ams_read_reg(uint8_t addr);
void ams_write_reg(uint8_t addr, uint8_t tx);
const char * ams_get_state_string(uint8_t regval);
int ams_state_is_valid(uint8_t regval);
#define AMS_REG_IO_CONF 0x00
#define AMS_REG_IC_CONF0 0x01
#define AMS_REG_IC_CONF1 0x02
#define AMS_REG_IC_CONF2 0x03
#define AMS_RFCFG_EN 0x80
#define AMS_TUN_MOD 0x40
#define AMS_REG_RFID_STATUS 0x04
#define AMS_HF_PON 0x80
#define AMS_STATE_MASK 0x78
#define AMS_STATE_INVALID 0x04
#define AMS_STATE_OFF (0 << 3)
#define AMS_STATE_SENSE (1 << 3)
#define AMS_STATE_RESOLUTION (3 << 3)
#define AMS_STATE_RESOLUTION_L2 (2 << 3)
#define AMS_STATE_SELECTED (6 << 3)
#define AMS_STATE_SECTOR2 (7 << 3)
#define AMS_STATE_SECTORX_2 (0xf << 3)
#define AMS_STATE_SELECTEDX (0xe << 3)
#define AMS_STATE_SENSEX_L2 (0xa << 3)
#define AMS_STATE_SENSEX (0xb << 3)
#define AMS_STATE_SLEEP (0x9 << 3)
// ... //
#define AMS_REG_MASK_INT0 0x08
#define AMS_MASK0_PU (1<<7) // power up
#define AMS_MASK0_WU_A (1<<6) // selected INT
#define AMS_MASK0_SLP (1<<5)
#define AMS_MASK0_EEW_RF (1<<4)
#define AMS_MASK0_EER_RF (1<<3)
#define AMS_MASK0_RXE (1<<2)
#define AMS_MASK0_TXE (1<<1)
#define AMS_MASK0_XRF (1<<0)
#define AMS_REG_MASK_INT1 0x09
#define AMS_REG_INT0 0x0a
#define AMS_INT_XRF (1<<0)
#define AMS_INT_TXE (1<<1)
#define AMS_INT_RXE (1<<2)
#define AMS_INT_EER_RF (1<<3)
#define AMS_INT_EEW_RF (1<<4)
#define AMS_INT_SLP (1<<5)
#define AMS_INT_WU_A (1<<6)
#define AMS_INT_INIT (1<<7)
#define AMS_REG_INT1 0x0b
#define AMS_INT_ACC_ERR (1<<0)
#define AMS_INT_EEAC_ERR (1<<1)
#define AMS_INT_IO_EEWR (1<<2)
#define AMS_INT_BF_ERR (1<<3)
#define AMS_INT_CRC_ERR (1<<4)
#define AMS_INT_PAR_ERR (1<<5)
#define AMS_INT_FRM_ERR (1<<6)
#define AMS_INT_RXS (1<<7)
#define AMS_REG_BUF2 0x0c
#define AMS_BUF_LEN_MASK 0x1f
#define AMS_BUF_INVALID 0x80
#define AMS_REG_BUF1 0x0d
// ... //
#define AMS_REG_PRODUCT_TYPE 0x1c
#define AMS_REG_PRODUCT_SUBTYPE 0x1d
#define AMS_REG_VERSION_MAJOR 0x1e
#define AMS_REG_VERSION_MINOR 0x1f
#define AMS_CONFIG_UID_ADDR 0x00
#define AMS_CONFIG_BLOCK0_ADDR 0x7e
#define AMS_CONFIG_BLOCK1_ADDR 0x7f
#define AMS_CFG1_VOLTAGE_LEVEL_1V9 (0x00<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V0 (0x01<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V1 (0x02<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V2 (0x03<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V3 (0x04<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V4 (0x05<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V5 (0x06<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V6 (0x07<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V7 (0x08<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V8 (0x09<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_2V9 (0x0a<<2)
#define AMS_CFG1_VOLTAGE_LEVEL_3V0 (0x0b<<2)
#define AMS_CFG1_OUTPUT_RESISTANCE_ZZ 0x00
#define AMS_CFG1_OUTPUT_RESISTANCE_100 0x01
#define AMS_CFG1_OUTPUT_RESISTANCE_50 0x02
#define AMS_CFG1_OUTPUT_RESISTANCE_25 0x03
#define AMS_CFG2_RFCFG_EN (1<<7)
#define AMS_CFG2_TUN_MOD (1<<6)
#define AMS_CMD_DEFAULT 0x02
#define AMS_CMD_CLEAR_BUFFER 0x04
#define AMS_CMD_RESTART_TRANSCEIVER 0x06
#define AMS_CMD_DIS_EN_TRANSCEIVER 0x07
#define AMS_CMD_TRANSMIT_BUFFER 0x08
#define AMS_CMD_TRANSMIT_ACK 0x09
#define AMS_CMD_TRANSMIT_NACK0 0x0A
#define AMS_CMD_TRANSMIT_NACK1 0x0B
#define AMS_CMD_TRANSMIT_NACK4 0x0D
#define AMS_CMD_TRANSMIT_NACK5 0x0C
#define AMS_CMD_SLEEP 0x10
#define AMS_CMD_SENSE 0x11
#define AMS_CMD_SENSE_SLEEP 0x12
#endif

View File

@ -23,6 +23,7 @@
//#define USING_DEV_BOARD //#define USING_DEV_BOARD
#define ENABLE_U2F_EXTENSIONS #define ENABLE_U2F_EXTENSIONS
// #define ENABLE_WALLET
#define ENABLE_U2F #define ENABLE_U2F
@ -30,6 +31,7 @@
// #define DISABLE_CTAPHID_WINK // #define DISABLE_CTAPHID_WINK
// #define DISABLE_CTAPHID_CBOR // #define DISABLE_CTAPHID_CBOR
// #define ENABLE_SERIAL_PRINTING
#if defined(SOLO_HACKER) #if defined(SOLO_HACKER)
#define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION #define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION
@ -38,7 +40,7 @@
#endif #endif
void printing_init(); void printing_init();
void hw_init(void); void hw_init(int lf);
//#define TEST //#define TEST
//#define TEST_POWER //#define TEST_POWER
@ -63,6 +65,12 @@ void hw_init(void);
#define SOLO_BUTTON_PORT GPIOA #define SOLO_BUTTON_PORT GPIOA
#define SOLO_BUTTON_PIN LL_GPIO_PIN_0 #define SOLO_BUTTON_PIN LL_GPIO_PIN_0
#define SOLO_AMS_CS_PORT GPIOB
#define SOLO_AMS_CS_PIN LL_GPIO_PIN_0
#define SOLO_AMS_IRQ_PORT GPIOC
#define SOLO_AMS_IRQ_PIN LL_GPIO_PIN_15
#define SKIP_BUTTON_CHECK_WITH_DELAY 0 #define SKIP_BUTTON_CHECK_WITH_DELAY 0
#define SKIP_BUTTON_CHECK_FAST 0 #define SKIP_BUTTON_CHECK_FAST 0

View File

@ -24,6 +24,9 @@
#include "aes.h" #include "aes.h"
#include "ctap.h" #include "ctap.h"
#include "device.h" #include "device.h"
// stuff for SHA512
#include "sha2.h"
#include "blockwise.h"
#include APP_CONFIG #include APP_CONFIG
#include "log.h" #include "log.h"
#include "memory_layout.h" #include "memory_layout.h"
@ -48,6 +51,7 @@ typedef enum
static SHA256_CTX sha256_ctx; static SHA256_CTX sha256_ctx;
static cf_sha512_context sha512_ctx;
static const struct uECC_Curve_t * _es256_curve = NULL; static const struct uECC_Curve_t * _es256_curve = NULL;
static const uint8_t * _signing_key = NULL; static const uint8_t * _signing_key = NULL;
static int _key_len = 0; static int _key_len = 0;
@ -62,6 +66,9 @@ void crypto_sha256_init()
sha256_init(&sha256_ctx); sha256_init(&sha256_ctx);
} }
void crypto_sha512_init() {
cf_sha512_init(&sha512_ctx);
}
void crypto_load_master_secret(uint8_t * key) void crypto_load_master_secret(uint8_t * key)
{ {
@ -86,6 +93,10 @@ void crypto_sha256_update(uint8_t * data, size_t len)
sha256_update(&sha256_ctx, data, len); sha256_update(&sha256_ctx, data, len);
} }
void crypto_sha512_update(const uint8_t * data, size_t len) {
cf_sha512_update(&sha512_ctx, data, len);
}
void crypto_sha256_update_secret() void crypto_sha256_update_secret()
{ {
sha256_update(&sha256_ctx, master_secret, 32); sha256_update(&sha256_ctx, master_secret, 32);
@ -96,6 +107,11 @@ void crypto_sha256_final(uint8_t * hash)
sha256_final(&sha256_ctx, hash); sha256_final(&sha256_ctx, hash);
} }
void crypto_sha512_final(uint8_t * hash) {
// NB: there is also cf_sha512_digest
cf_sha512_digest_final(&sha512_ctx, hash);
}
void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac) void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
{ {
uint8_t buf[64]; uint8_t buf[64];
@ -141,6 +157,11 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
key = master_secret; key = master_secret;
klen = sizeof(master_secret)/2; klen = sizeof(master_secret)/2;
} }
else if (key == CRYPTO_TRANSPORT_KEY2)
{
key = transport_secret;
klen = 32;
}
if(klen > 64) if(klen > 64)
@ -261,6 +282,11 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
memmove(x,pubkey,32); memmove(x,pubkey,32);
memmove(y,pubkey+32,32); memmove(y,pubkey+32,32);
} }
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
{
uECC_compute_public_key(privkey, pubkey, _es256_curve);
}
void crypto_load_external_key(uint8_t * key, int len) void crypto_load_external_key(uint8_t * key, int len)
{ {

View File

@ -10,6 +10,7 @@
#include "stm32l4xx_ll_gpio.h" #include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_ll_tim.h" #include "stm32l4xx_ll_tim.h"
#include "stm32l4xx_ll_usart.h" #include "stm32l4xx_ll_usart.h"
#include "stm32l4xx_ll_pwr.h"
#include "usbd_hid.h" #include "usbd_hid.h"
#include APP_CONFIG #include APP_CONFIG
@ -26,16 +27,74 @@
#include "memory_layout.h" #include "memory_layout.h"
#include "stm32l4xx_ll_iwdg.h" #include "stm32l4xx_ll_iwdg.h"
#include "usbd_cdc_if.h" #include "usbd_cdc_if.h"
#include "nfc.h"
#include "init.h"
#include "sense.h"
#define LOW_FREQUENCY 1
#define HIGH_FREQUENCY 0
void wait_for_usb_tether(); void wait_for_usb_tether();
uint32_t __90_ms = 0; uint32_t __90_ms = 0;
uint32_t __last_button_press_time = 0;
uint32_t __last_button_bounce_time = 0;
uint32_t __device_status = 0; uint32_t __device_status = 0;
uint32_t __last_update = 0; uint32_t __last_update = 0;
extern PCD_HandleTypeDef hpcd; extern PCD_HandleTypeDef hpcd;
static int _NFC_status = 0;
static bool isLowFreq = 0;
static bool _RequestComeFromNFC = false;
#define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN)) // #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
static int is_physical_button_pressed()
{
return (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN));
}
static int is_touch_button_pressed()
{
int is_pressed = (tsc_read_button(0) || tsc_read_button(1));
#ifndef IS_BOOTLOADER
if (is_pressed)
{
// delay for debounce, and longer than polling timer period.
delay(95);
return (tsc_read_button(0) || tsc_read_button(1));
}
#endif
return is_pressed;
}
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
static void edge_detect_touch_button()
{
static uint8_t last_touch = 0;
uint8_t current_touch = 0;
if (is_touch_button_pressed == IS_BUTTON_PRESSED)
{
current_touch = (tsc_read_button(0) || tsc_read_button(1));
// 1 sample per 25 ms
if ((millis() - __last_button_bounce_time) > 25)
{
// Detect "touch / rising edge"
if (!last_touch && current_touch)
{
__last_button_press_time = millis();
}
__last_button_bounce_time = millis();
last_touch = current_touch;
}
}
}
void request_from_nfc(bool request_active) {
_RequestComeFromNFC = request_active;
}
// Timer6 overflow handler. happens every ~90ms. // Timer6 overflow handler. happens every ~90ms.
void TIM6_DAC_IRQHandler() void TIM6_DAC_IRQHandler()
@ -43,13 +102,38 @@ void TIM6_DAC_IRQHandler()
// timer is only 16 bits, so roll it over here // timer is only 16 bits, so roll it over here
TIM6->SR = 0; TIM6->SR = 0;
__90_ms += 1; __90_ms += 1;
if ((millis() - __last_update) > 8) if ((millis() - __last_update) > 90)
{ {
if (__device_status != CTAPHID_STATUS_IDLE) if (__device_status != CTAPHID_STATUS_IDLE)
{ {
ctaphid_update_status(__device_status); ctaphid_update_status(__device_status);
} }
} }
edge_detect_touch_button();
#ifndef IS_BOOTLOADER
// NFC sending WTX if needs
if (device_is_nfc() == NFC_IS_ACTIVE)
{
WTX_timer_exec();
}
#endif
}
// Interrupt on rising edge of button (button released)
void EXTI0_IRQHandler(void)
{
EXTI->PR1 = EXTI->PR1;
if (is_physical_button_pressed == IS_BUTTON_PRESSED)
{
// Only allow 1 press per 25 ms.
if ((millis() - __last_button_bounce_time) > 25)
{
__last_button_press_time = millis();
}
__last_button_bounce_time = millis();
}
} }
// Global USB interrupt handler // Global USB interrupt handler
@ -91,32 +175,60 @@ void device_reboot()
{ {
NVIC_SystemReset(); NVIC_SystemReset();
} }
void device_init()
{
hw_init();
LL_GPIO_SetPinMode(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP);
#ifndef IS_BOOTLOADER void device_init_button()
{
if (tsc_sensor_exists())
{
tsc_init();
IS_BUTTON_PRESSED = is_touch_button_pressed;
}
else
{
IS_BUTTON_PRESSED = is_physical_button_pressed;
}
}
void device_init(int argc, char *argv[])
{
hw_init(LOW_FREQUENCY);
if (! tsc_sensor_exists())
{
_NFC_status = nfc_init();
}
if (_NFC_status == NFC_IS_ACTIVE)
{
printf1(TAG_NFC, "Have NFC\r\n");
isLowFreq = 1;
IS_BUTTON_PRESSED = is_physical_button_pressed;
}
else
{
printf1(TAG_NFC, "Have NO NFC\r\n");
hw_init(HIGH_FREQUENCY);
isLowFreq = 0;
device_init_button();
}
usbhid_init();
ctaphid_init();
ctap_init();
#if BOOT_TO_DFU #if BOOT_TO_DFU
flash_option_bytes_init(1); flash_option_bytes_init(1);
#else #else
flash_option_bytes_init(0); flash_option_bytes_init(0);
#endif
#endif #endif
printf1(TAG_GEN,"hello solo\r\n");
} }
void usb_init(void); int device_is_nfc()
void usbhid_init()
{ {
usb_init(); return _NFC_status;
#if DEBUG_LEVEL>1
wait_for_usb_tether();
#endif
} }
void wait_for_usb_tether() void wait_for_usb_tether()
@ -130,6 +242,26 @@ void wait_for_usb_tether()
; ;
} }
void usbhid_init()
{
if (!isLowFreq)
{
init_usb();
#if DEBUG_LEVEL>1
wait_for_usb_tether();
#endif
}
else
{
}
}
int usbhid_recv(uint8_t * msg) int usbhid_recv(uint8_t * msg)
{ {
if (fifo_hidmsg_size()) if (fifo_hidmsg_size())
@ -366,6 +498,7 @@ uint32_t ctap_atomic_count(int sel)
} }
void device_manage() void device_manage()
{ {
#if NON_BLOCK_PRINTING #if NON_BLOCK_PRINTING
@ -386,6 +519,10 @@ void device_manage()
} }
} }
#endif #endif
#ifndef IS_BOOTLOADER
if(device_is_nfc())
nfc_loop();
#endif
} }
static int handle_packets() static int handle_packets()
@ -407,9 +544,49 @@ static int handle_packets()
return 0; return 0;
} }
int ctap_user_presence_test() static int wait_for_button_activate(uint32_t wait)
{ {
int ret; int ret;
uint32_t start = millis();
do
{
if ((start + wait) < millis())
{
return 0;
}
delay(1);
ret = handle_packets();
if (ret)
return ret;
} while (!IS_BUTTON_PRESSED());
return 0;
}
static int wait_for_button_release(uint32_t wait)
{
int ret;
uint32_t start = millis();
do
{
if ((start + wait) < millis())
{
return 0;
}
delay(1);
ret = handle_packets();
if (ret)
return ret;
} while (IS_BUTTON_PRESSED());
return 0;
}
int ctap_user_presence_test(uint32_t up_delay)
{
int ret;
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
{
return 1;
}
#if SKIP_BUTTON_CHECK_WITH_DELAY #if SKIP_BUTTON_CHECK_WITH_DELAY
int i=500; int i=500;
while(i--) while(i--)
@ -422,49 +599,41 @@ int ctap_user_presence_test()
#elif SKIP_BUTTON_CHECK_FAST #elif SKIP_BUTTON_CHECK_FAST
delay(2); delay(2);
ret = handle_packets(); ret = handle_packets();
if (ret) return ret; if (ret)
return ret;
goto done; goto done;
#endif #endif
uint32_t t1 = millis();
// If button was pressed within last [2] seconds, succeed.
if (__last_button_press_time && (millis() - __last_button_press_time < 2000))
{
goto done;
}
// Set LED status and wait.
led_rgb(0xff3520); led_rgb(0xff3520);
while (IS_BUTTON_PRESSED()) // Block and wait for some time.
{ ret = wait_for_button_activate(up_delay);
if (t1 + 5000 < millis())
{
printf1(TAG_GEN,"Button not pressed\n");
goto fail;
}
ret = handle_packets();
if (ret) return ret; if (ret) return ret;
} ret = wait_for_button_release(up_delay);
t1 = millis();
do
{
if (t1 + 5000 < millis())
{
goto fail;
}
delay(1);
ret = handle_packets();
if (ret) return ret; if (ret) return ret;
// If button was pressed within last [2] seconds, succeed.
if (__last_button_press_time && (millis() - __last_button_press_time < 2000))
{
goto done;
} }
while (! IS_BUTTON_PRESSED());
led_rgb(0x001040);
delay(50);
#if SKIP_BUTTON_CHECK_WITH_DELAY || SKIP_BUTTON_CHECK_FAST return 0;
done: done:
#endif ret = wait_for_button_release(up_delay);
__last_button_press_time = 0;
return 1; return 1;
fail:
return 0;
} }
int ctap_generate_rng(uint8_t * dst, size_t num) int ctap_generate_rng(uint8_t * dst, size_t num)
@ -543,7 +712,7 @@ void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
memmove(tmppage + (sizeof(CTAP_residentKey) * index) % PAGE_SIZE, rk, sizeof(CTAP_residentKey)); memmove(tmppage + (sizeof(CTAP_residentKey) * index) % PAGE_SIZE, rk, sizeof(CTAP_residentKey));
flash_erase_page(page); flash_erase_page(page);
flash_write(flash_addr(page), tmppage, ((sizeof(CTAP_residentKey) * (index + 1)) % PAGE_SIZE) ); flash_write(flash_addr(page), tmppage, PAGE_SIZE);
} }
else else
{ {

View File

@ -18,7 +18,9 @@
#include "stm32l4xx_ll_bus.h" #include "stm32l4xx_ll_bus.h"
#include "stm32l4xx_ll_tim.h" #include "stm32l4xx_ll_tim.h"
#include "stm32l4xx_ll_rng.h" #include "stm32l4xx_ll_rng.h"
#include "stm32l4xx_ll_spi.h"
#include "stm32l4xx_ll_usb.h" #include "stm32l4xx_ll_usb.h"
#include "stm32l4xx_ll_exti.h"
#include "stm32l4xx_hal_pcd.h" #include "stm32l4xx_hal_pcd.h"
#include "stm32l4xx_hal.h" #include "stm32l4xx_hal.h"
@ -29,57 +31,86 @@
#include "usbd_composite.h" #include "usbd_composite.h"
#include "usbd_cdc_if.h" #include "usbd_cdc_if.h"
#include "device.h" #include "device.h"
#include "init.h"
#include "sense.h"
#include APP_CONFIG #include APP_CONFIG
/* USER CODE BEGIN Includes */ // KHz
#define MAX_CLOCK_RATE 24000
/* USER CODE END Includes */ #define SET_CLOCK_RATE2() SystemClock_Config()
/* Private variables ---------------------------------------------------------*/ #if MAX_CLOCK_RATE == 48000
#define SET_CLOCK_RATE0() SystemClock_Config_LF32()
#define SET_CLOCK_RATE1() SystemClock_Config_LF48()
#elif MAX_CLOCK_RATE == 32000
#define SET_CLOCK_RATE0() SystemClock_Config_LF24()
#define SET_CLOCK_RATE1() SystemClock_Config_LF32()
#elif MAX_CLOCK_RATE == 28000
#define SET_CLOCK_RATE0() SystemClock_Config_LF24()
#define SET_CLOCK_RATE1() SystemClock_Config_LF28()
#elif MAX_CLOCK_RATE == 24000
#define SET_CLOCK_RATE0() SystemClock_Config_LF16()
#define SET_CLOCK_RATE1() SystemClock_Config_LF24()
#elif MAX_CLOCK_RATE == 20000
#define SET_CLOCK_RATE0() SystemClock_Config_LF16()
#define SET_CLOCK_RATE1() SystemClock_Config_LF20()
#elif MAX_CLOCK_RATE == 16000
#define SET_CLOCK_RATE0() SystemClock_Config_LF8()
#define SET_CLOCK_RATE1() SystemClock_Config_LF16()
#else
#error "Invalid clock rate selected"
#endif
USBD_HandleTypeDef Solo_USBD_Device; USBD_HandleTypeDef Solo_USBD_Device;
/* Private function prototypes -----------------------------------------------*/
static void LL_Init(void); static void LL_Init(void);
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
#if DEBUG_LEVEL > 0
static void MX_USART1_UART_Init(void);
#endif
static void MX_TIM2_Init(void);
static void MX_TIM6_Init(void);
static void MX_RNG_Init(void);
#define Error_Handler() _Error_Handler(__FILE__,__LINE__) #define Error_Handler() _Error_Handler(__FILE__,__LINE__)
void _Error_Handler(char *file, int line); void _Error_Handler(char *file, int line);
void SystemClock_Config(void);
void SystemClock_Config_LF16(void);
void SystemClock_Config_LF20(void);
void SystemClock_Config_LF24(void);
void SystemClock_Config_LF28(void);
void SystemClock_Config_LF48(void);
void hw_init(void) void hw_init(int lowfreq)
{ {
#ifdef IS_BOOTLOADER #ifdef IS_BOOTLOADER
SCB->VTOR = FLASH_BASE; SCB->VTOR = FLASH_BASE;
#else #else
#endif #endif
LL_Init(); LL_Init();
init_gpio();
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); if (lowfreq)
{
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); // Under voltage
device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
}
else
{
SystemClock_Config();
}
SystemClock_Config(); // TODO bootloader should not change clk freq. if (!lowfreq)
{
init_pwm();
}
MX_GPIO_Init(); init_millisecond_timer(lowfreq);
MX_TIM2_Init(); // PWM for LEDs
MX_TIM6_Init(); // ~1 ms timer
#if DEBUG_LEVEL > 0 #if DEBUG_LEVEL > 0
MX_USART1_UART_Init();// debug uart init_debug_uart();
#endif #endif
MX_RNG_Init(); init_rng();
init_spi();
TIM6->SR = 0;
__enable_irq();
NVIC_EnableIRQ(TIM6_IRQn);
} }
static void LL_Init(void) static void LL_Init(void)
@ -107,12 +138,29 @@ static void LL_Init(void)
} }
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
{
switch(param)
{
case DEVICE_LOW_POWER_IDLE:
SET_CLOCK_RATE0();
break;
case DEVICE_LOW_POWER_FAST:
SET_CLOCK_RATE1();
break;
case DEVICE_FAST:
SET_CLOCK_RATE2();
break;
}
}
/** /**
* @brief System Clock Configuration * @brief System Clock Configuration
* @retval None * @retval None
*/ */
void SystemClock_Config(void) void SystemClock_Config(void)
{ {
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_FLASH_SetLatency(LL_FLASH_LATENCY_2); LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
@ -129,8 +177,15 @@ void SystemClock_Config(void)
{ {
} }
LL_RCC_MSI_Enable();
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */ /* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1) while(LL_RCC_MSI_IsReady() != 1)
{ {
@ -187,7 +242,463 @@ void SystemClock_Config(void)
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
} }
void usb_init() void SystemClock_Config_LF4(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
LL_Init1msTick(4000000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(4000000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
{
Error_Handler();
}
}
// 8MHz
void SystemClock_Config_LF8(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_7);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
LL_Init1msTick(8000000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(8000000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
{
Error_Handler();
}
}
// 16MHz
void SystemClock_Config_LF16(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_8);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8);
LL_Init1msTick(16000000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(16000000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
{
Error_Handler();
}
}
// 24 MHz
void SystemClock_Config_LF24(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
{
Error_Handler();
}
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_9);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8);
LL_Init1msTick(24000000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(24000000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
}
// 32 MHz
void SystemClock_Config_LF32(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
{
Error_Handler();
}
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_10);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16);
LL_Init1msTick(32000000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(32000000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
}
// 28 MHz
void SystemClock_Config_LF28(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
{
Error_Handler();
}
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_RCC_HSI_Enable();
/* Wait till HSI is ready */
while(LL_RCC_HSI_IsReady() != 1)
{
}
LL_RCC_HSI_SetCalibTrimming(16);
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_2, 28, LL_RCC_PLLR_DIV_8);
LL_RCC_PLL_EnableDomain_SYS();
LL_RCC_PLL_Enable();
/* Wait till PLL is ready */
while(LL_RCC_PLL_IsReady() != 1)
{
}
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8);
LL_Init1msTick(28000000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(28000000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
}
// 48 MHz
void SystemClock_Config_LF48(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2)
{
Error_Handler();
}
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_11);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16);
LL_Init1msTick(48000000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(48000000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
}
// 20 MHz
void SystemClock_Config_LF20(void)
{
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
}
void init_usb()
{ {
// enable USB power // enable USB power
SET_BIT(PWR->CR2, PWR_CR2_USV); SET_BIT(PWR->CR2, PWR_CR2_USV);
@ -217,8 +728,7 @@ void usb_init()
USBD_Start(&Solo_USBD_Device); USBD_Start(&Solo_USBD_Device);
} }
/* TIM2 init function */ void init_pwm(void)
static void MX_TIM2_Init(void)
{ {
LL_TIM_InitTypeDef TIM_InitStruct; LL_TIM_InitTypeDef TIM_InitStruct;
@ -289,9 +799,7 @@ static void MX_TIM2_Init(void)
} }
#if DEBUG_LEVEL > 0 void init_debug_uart(void)
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{ {
LL_USART_InitTypeDef USART_InitStruct; LL_USART_InitTypeDef USART_InitStruct;
@ -301,6 +809,8 @@ static void MX_USART1_UART_Init(void)
/* Peripheral clock enable */ /* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
LL_USART_DeInit(USART1);
/**USART1 GPIO Configuration /**USART1 GPIO Configuration
PB6 ------> USART1_TX PB6 ------> USART1_TX
PB7 ------> USART1_RX PB7 ------> USART1_RX
@ -327,22 +837,35 @@ static void MX_USART1_UART_Init(void)
LL_USART_Enable(USART1); LL_USART_Enable(USART1);
} }
#endif
/** Pinout Configuration void init_gpio(void)
*/
static void MX_GPIO_Init(void)
{ {
/* GPIO Ports Clock Enable */ /* GPIO Ports Clock Enable */
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
LL_GPIO_SetPinMode(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP);
#ifndef IS_BOOTLOADER
LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTA, LL_SYSCFG_EXTI_LINE0);
LL_EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_0; // GPIOA_0
EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE;
EXTI_InitStruct.LineCommand = ENABLE;
EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING;
LL_EXTI_Init(&EXTI_InitStruct);
NVIC_EnableIRQ(EXTI0_IRQn);
#endif
} }
void init_millisecond_timer(int lf)
/* TIM6 init function */
static void MX_TIM6_Init(void)
{ {
LL_TIM_InitTypeDef TIM_InitStruct; LL_TIM_InitTypeDef TIM_InitStruct;
@ -352,7 +875,11 @@ static void MX_TIM6_Init(void)
// 48 MHz sys clock --> 6 MHz timer clock // 48 MHz sys clock --> 6 MHz timer clock
// 48 MHz / 48000 == 1000 Hz // 48 MHz / 48000 == 1000 Hz
if (!lf)
TIM_InitStruct.Prescaler = 48000; TIM_InitStruct.Prescaler = 48000;
else
TIM_InitStruct.Prescaler = MAX_CLOCK_RATE;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 90; TIM_InitStruct.Autoreload = 90;
LL_TIM_Init(TIM6, &TIM_InitStruct); LL_TIM_Init(TIM6, &TIM_InitStruct);
@ -368,39 +895,14 @@ static void MX_TIM6_Init(void)
// Start immediately // Start immediately
LL_TIM_EnableCounter(TIM6); LL_TIM_EnableCounter(TIM6);
TIM6->SR = 0;
__enable_irq();
NVIC_EnableIRQ(TIM6_IRQn);
} }
/* TIM7 init function */
// static void MX_TIM7_Init(void)
// {
//
// LL_TIM_InitTypeDef TIM_InitStruct;
//
// /* Peripheral clock enable */
// LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);
//
// // 48 MHz sys clock --> 6 MHz timer clock
// // 6 MHz / 6000 == 1000 Hz
// TIM_InitStruct.Prescaler = 48000;
// TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
// TIM_InitStruct.Autoreload = 0xffff;
// LL_TIM_Init(TIM6, &TIM_InitStruct);
//
// LL_TIM_DisableARRPreload(TIM7);
//
// LL_TIM_SetTriggerOutput(TIM7, LL_TIM_TRGO_RESET);
//
// LL_TIM_DisableMasterSlaveMode(TIM7);
//
// // enable interrupt
// TIM7->DIER |= 1;
//
// // Start immediately
// LL_TIM_EnableCounter(TIM7);
// }
/* RNG init function */ void init_rng(void)
static void MX_RNG_Init(void)
{ {
/* Peripheral clock enable */ /* Peripheral clock enable */
@ -409,3 +911,45 @@ static void MX_RNG_Init(void)
LL_RNG_Enable(RNG); LL_RNG_Enable(RNG);
} }
/* SPI1 init function */
void init_spi(void)
{
LL_SPI_InitTypeDef SPI_InitStruct;
LL_GPIO_InitTypeDef GPIO_InitStruct;
/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_6|LL_GPIO_PIN_7;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* SPI1 parameter configuration*/
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SPI_InitStruct.CRCPoly = 7;
LL_SPI_Init(SPI1, &SPI_InitStruct);
LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2018 SoloKeys, Inc. <https://solokeys.com/>
*
* This file is part of Solo.
*
* Solo 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.
*
* Solo 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 Solo. If not, see <https://www.gnu.org/licenses/>
*
* This code is available under licenses for commercial use.
* Please contact SoloKeys for more information.
*/
#ifndef _INIT_H_
#define _INIT_H_
void init_usb();
void init_gpio(void);
void init_debug_uart(void);
void init_pwm(void);
void init_millisecond_timer(int lf);
void init_rng(void);
void init_spi(void);
#endif

1019
targets/stm32l432/src/nfc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
#ifndef _NFC_H_
#define _NFC_H_
#include <stdint.h>
#include <stdbool.h>
#include "apdu.h"
// Return number of bytes read if any.
int nfc_loop();
int nfc_init();
typedef struct
{
uint8_t cclen_hi;
uint8_t cclen_lo;
uint8_t version;
uint8_t MLe_hi;
uint8_t MLe_lo;
uint8_t MLc_hi;
uint8_t MLc_lo;
uint8_t tlv[8];
} __attribute__((packed)) CAPABILITY_CONTAINER;
// WTX time in ms
#define WTX_TIME_DEFAULT 300
#define NFC_CMD_REQA 0x26
#define NFC_CMD_WUPA 0x52
#define NFC_CMD_HLTA 0x50
#define NFC_CMD_RATS 0xe0
#define NFC_CMD_PPSS 0xd0
#define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS)
#define NFC_CMD_IBLOCK 0x00
#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) )
#define NFC_CMD_RBLOCK 0x80
#define NFC_CMD_RBLOCK_ACK 0x20
#define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
#define NFC_CMD_SBLOCK 0xc0
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )
extern uint8_t p14443_block_offset(uint8_t pcb);
#define NFC_SBLOCK_DESELECT 0x30
#define NFC_SBLOCK_WTX 0x30
#define AID_NDEF_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x01"
#define AID_NDEF_MIFARE_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x00"
#define AID_CAPABILITY_CONTAINER "\xE1\x03"
#define AID_NDEF_TAG "\xE1\x04"
#define AID_FIDO "\xa0\x00\x00\x06\x47\x2f\x00\x01"
typedef enum
{
APP_NOTHING = 0,
APP_NDEF_TYPE_4 = 1,
APP_MIFARE_TYPE_4,
APP_CAPABILITY_CONTAINER,
APP_NDEF_TAG,
APP_FIDO,
} APPLETS;
void WTX_timer_exec();
#endif

View File

@ -24,19 +24,33 @@ void _putchar(char c)
} }
int _write (int fd, const void *buf, unsigned long int len)
int _write (int fd, const void *buf, long int len)
{ {
uint8_t * data = (uint8_t *) buf; uint8_t * data = (uint8_t *) buf;
#if DEBUG_LEVEL>0
// static uint8_t logbuf[1000] = {0};
// static int logbuflen = 0;
// if (logbuflen + len > sizeof(logbuf)) {
// int mlen = logbuflen + len - sizeof(logbuf);
// memmove(logbuf, &logbuf[mlen], sizeof(logbuf) - mlen);
// logbuflen -= mlen;
// }
// memcpy(&logbuf[logbuflen], data, len);
// logbuflen += len;
// Send out USB serial // Send out USB serial
CDC_Transmit_FS(data, len); CDC_Transmit_FS(data, len);
// if (res == USBD_OK)
// logbuflen = 0;
#endif
#ifdef ENABLE_SERIAL_PRINTING
// Send out UART serial // Send out UART serial
while(len--) while(len--)
{ {
_putchar(*data++); _putchar(*data++);
} }
#endif
return 0; return 0;
} }
#endif #endif

View File

@ -17,7 +17,7 @@ int __errno = 0;
void rng_get_bytes(uint8_t * dst, size_t sz) void rng_get_bytes(uint8_t * dst, size_t sz)
{ {
uint8_t r[8]; uint8_t r[4];
unsigned int i,j; unsigned int i,j;
for (i = 0; i < sz; i += 4) for (i = 0; i < sz; i += 4)
{ {
@ -33,7 +33,7 @@ void rng_get_bytes(uint8_t * dst, size_t sz)
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
{ {
if ((i + j) > sz) if ((i + j) >= sz)
{ {
return; return;
} }

View File

@ -1,183 +0,0 @@
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20010000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(8);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(8);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

View File

@ -0,0 +1,136 @@
#include "sense.h"
#include "device.h"
#include "log.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_hal_tsc.h"
#define ELECTRODE_0 TSC_GROUP2_IO1
#define ELECTRODE_1 TSC_GROUP2_IO2
void tsc_init()
{
LL_GPIO_InitTypeDef GPIO_InitStruct;
// Enable TSC clock
RCC->AHB1ENR |= (1<<16);
/** TSC GPIO Configuration
PA4 ------> Channel 1
PA5 ------> Channel 2
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_4;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_9;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/** TSC GPIO Configuration
PA6 ------> sampling cap
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// Channel IOs
uint32_t channel_ios = TSC_GROUP2_IO1 | TSC_GROUP2_IO2;
// enable
TSC->CR = TSC_CR_TSCE;
TSC->CR |= (TSC_CTPH_8CYCLES |
TSC_CTPL_10CYCLES |
(uint32_t)(1 << TSC_CR_SSD_Pos) |
TSC_SS_PRESC_DIV1 |
TSC_PG_PRESC_DIV16 |
TSC_MCV_16383 |
TSC_SYNC_POLARITY_FALLING |
TSC_ACQ_MODE_NORMAL);
// Spread spectrum
if (0)
{
TSC->CR |= TSC_CR_SSE;
}
// Schmitt trigger and hysteresis
TSC->IOHCR = (uint32_t)(~(channel_ios | 0 | TSC_GROUP2_IO3));
// Sampling IOs
TSC->IOSCR = TSC_GROUP2_IO3;
// Groups
uint32_t grps = 0x02;
TSC->IOGCSR = grps;
TSC->IER &= (uint32_t)(~(TSC_IT_EOA | TSC_IT_MCE));
TSC->ICR = (TSC_FLAG_EOA | TSC_FLAG_MCE);
}
void tsc_set_electrode(uint32_t channel_ids)
{
TSC->IOCCR = (channel_ids);
}
void tsc_start_acq()
{
TSC->CR &= ~(TSC_CR_START);
TSC->ICR = TSC_FLAG_EOA | TSC_FLAG_MCE;
// Set IO output to output push-pull low
TSC->CR &= (~TSC_CR_IODEF);
TSC->CR |= TSC_CR_START;
}
void tsc_wait_on_acq()
{
while ( ! (TSC->ISR & TSC_FLAG_EOA) )
;
if ( TSC->ISR & TSC_FLAG_MCE )
{
printf1(TAG_ERR,"Max count reached\r\n");
}
}
uint32_t tsc_read(uint32_t indx)
{
return TSC->IOGXCR[indx];
}
uint32_t tsc_read_button(uint32_t index)
{
switch(index)
{
case 0:
tsc_set_electrode(ELECTRODE_0);
break;
case 1:
tsc_set_electrode(ELECTRODE_1);
break;
}
tsc_start_acq();
tsc_wait_on_acq();
return tsc_read(1) < 45;
}
int tsc_sensor_exists()
{
static uint8_t does = 0;
if (does) return 1;
LL_GPIO_SetPinMode(GPIOB, (1 << 1), LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinPull(GPIOB, (1 << 1), LL_GPIO_PULL_UP);
// Short delay before reading pin
asm("nop"); asm("nop"); asm("nop"); asm("nop");
does = (LL_GPIO_ReadInputPort(GPIOB) & (1 << 1)) == 0;
LL_GPIO_SetPinPull(GPIOB, 1, LL_GPIO_PULL_NO);
return does;
}

View File

@ -0,0 +1,14 @@
#ifndef _SENSE_H_
#define _SENSE_H_
#include <stdint.h>
void tsc_init();
int tsc_sensor_exists();
// Read button0 or button1
// Returns 1 if pressed, 0 if not.
uint32_t tsc_read_button(uint32_t index);
#endif

View File

@ -79,6 +79,8 @@ Reset_Handler:
ldr sp, =_estack /* Atollic update: set stack pointer */ ldr sp, =_estack /* Atollic update: set stack pointer */
/* Copy the data segment initializers from flash to SRAM */ /* Copy the data segment initializers from flash to SRAM */
/* Call the clock system intitialization function.*/
bl SystemInit
movs r1, #0 movs r1, #0
b LoopCopyDataInit b LoopCopyDataInit
@ -106,8 +108,7 @@ LoopFillZerobss:
cmp r2, r3 cmp r2, r3
bcc FillZerobss bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */ /* Call static constructors */
bl __libc_init_array bl __libc_init_array
/* Call the application's entry point.*/ /* Call the application's entry point.*/

View File

@ -106,6 +106,8 @@
*/ */
#include "stm32l4xx.h" #include "stm32l4xx.h"
#include "device.h"
#include "init.h"
#if !defined (HSE_VALUE) #if !defined (HSE_VALUE)
#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */
@ -219,6 +221,9 @@ void SystemInit(void)
/* Disable all interrupts */ /* Disable all interrupts */
RCC->CIER = 0x00000000U; RCC->CIER = 0x00000000U;
// TODO this is causing boot issues for old bootloader
device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
} }
/** /**

View File

@ -1,851 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2019 SoloKeys Developers
#
# Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
# http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
# http://opensource.org/licenses/MIT>, at your option. This file may not be
# copied, modified, or distributed except according to those terms.
#
# Script for testing correctness of CTAP2/CTAP1 security token
from __future__ import print_function, absolute_import, unicode_literals
import sys, os, time
from random import randint
from binascii import hexlify
import array, struct, socket
from fido2.hid import CtapHidDevice, CTAPHID
from fido2.client import Fido2Client, ClientError
from fido2.ctap import CtapError
from fido2.ctap1 import CTAP1
from fido2.ctap2 import *
from fido2.cose import *
from fido2.utils import Timeout, sha256
from fido2.attestation import Attestation
from solo.fido2 import forceUDPBackend
# Set up a FIDO 2 client using the origin https://example.com
def ForceU2F(client, device):
client.ctap = CTAP1(device)
client.pin_protocol = None
client._do_make_credential = client._ctap1_make_credential
client._do_get_assertion = client._ctap1_get_assertion
def VerifyAttestation(attest, data):
verifier = Attestation.for_type(attest.fmt)
verifier().verify(attest.att_statement, attest.auth_data, data.hash)
class Packet(object):
def __init__(self, data):
l = len(data)
self.data = data
def ToWireFormat(self,):
return self.data
@staticmethod
def FromWireFormat(pkt_size, data):
return Packet(data)
class Tester:
def __init__(self,):
self.origin = "https://examplo.org"
self.host = "examplo.org"
def find_device(self,):
print(list(CtapHidDevice.list_devices()))
dev = next(CtapHidDevice.list_devices(), None)
if not dev:
raise RuntimeError("No FIDO device found")
self.dev = dev
self.client = Fido2Client(dev, self.origin)
self.ctap = self.client.ctap2
self.ctap1 = CTAP1(dev)
# consume timeout error
# cmd,resp = self.recv_raw()
def send_data(self, cmd, data):
if type(data) != type(b""):
data = struct.pack("%dB" % len(data), *[ord(x) for x in data])
with Timeout(1.0) as event:
return self.dev.call(cmd, data, event)
def send_raw(self, data, cid=None):
if cid is None:
cid = self.dev._dev.cid
elif type(cid) != type(b""):
cid = struct.pack("%dB" % len(cid), *[ord(x) for x in cid])
if type(data) != type(b""):
data = struct.pack("%dB" % len(data), *[ord(x) for x in data])
data = cid + data
l = len(data)
if l != 64:
pad = "\x00" * (64 - l)
pad = struct.pack("%dB" % len(pad), *[ord(x) for x in pad])
data = data + pad
data = list(data)
assert len(data) == 64
self.dev._dev.InternalSendPacket(Packet(data))
def cid(self,):
return self.dev._dev.cid
def set_cid(self, cid):
if type(cid) not in [type(b""), type(bytearray())]:
cid = struct.pack("%dB" % len(cid), *[ord(x) for x in cid])
self.dev._dev.cid = cid
def recv_raw(self,):
with Timeout(1.0) as t:
cmd, payload = self.dev._dev.InternalRecv()
return cmd, payload
def check_error(self, data, err=None):
assert len(data) == 1
if err is None:
if data[0] != 0:
raise CtapError(data[0])
elif data[0] != err:
raise ValueError("Unexpected error: %02x" % data[0])
def test_long_ping(self):
amt = 1000
pingdata = os.urandom(amt)
try:
t1 = time.time() * 1000
r = self.send_data(CTAPHID.PING, pingdata)
t2 = time.time() * 1000
delt = t2 - t1
# if (delt < 140 ):
# raise RuntimeError('Fob is too fast (%d ms)' % delt)
if delt > 555 * (amt / 1000):
raise RuntimeError("Fob is too slow (%d ms)" % delt)
if r != pingdata:
raise ValueError("Ping data not echo'd")
print("1000 byte ping time: %s ms" % delt)
except CtapError as e:
print("7609 byte Ping failed:", e)
raise RuntimeError("ping failed")
print("PASS: 7609 byte ping")
# sys.flush(sys.sto)
sys.stdout.flush()
def test_hid(self, check_timeouts=False):
if check_timeouts:
print("Test idle")
try:
cmd, resp = self.recv_raw()
except socket.timeout:
print("Pass: Idle")
print("Test init")
r = self.send_data(CTAPHID.INIT, "\x11\x11\x11\x11\x11\x11\x11\x11")
pingdata = os.urandom(100)
try:
r = self.send_data(CTAPHID.PING, pingdata)
if r != pingdata:
raise ValueError("Ping data not echo'd")
except CtapError as e:
print("100 byte Ping failed:", e)
raise RuntimeError("ping failed")
print("PASS: 100 byte ping")
self.test_long_ping()
try:
r = self.send_data(CTAPHID.WINK, "")
print(hexlify(r))
# assert(len(r) == 0)
except CtapError as e:
print("wink failed:", e)
raise RuntimeError("wink failed")
print("PASS: wink")
# try:
# r = self.send_data(CTAPHID.WINK, 'we9gofrei8g')
# raise RuntimeError('Wink is not supposed to have payload')
# except CtapError as e:
# assert(e.code == CtapError.ERR.INVALID_LENGTH)
# print('PASS: malformed wink')
try:
r = self.send_data(CTAPHID.CBOR, "")
if len(r) > 1 or r[0] == 0:
raise RuntimeError("Cbor is supposed to have payload")
except CtapError as e:
assert e.code == CtapError.ERR.INVALID_LENGTH
print("PASS: no data cbor")
try:
r = self.send_data(CTAPHID.MSG, "")
print(hexlify(r))
if len(r) > 2:
raise RuntimeError("MSG is supposed to have payload")
except CtapError as e:
assert e.code == CtapError.ERR.INVALID_LENGTH
print("PASS: no data msg")
try:
r = self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
except CtapError as e:
raise RuntimeError("resync fail: ", e)
print("PASS: resync")
try:
r = self.send_data(0x66, "")
raise RuntimeError("Invalid command did not return error")
except CtapError as e:
assert e.code == CtapError.ERR.INVALID_COMMAND
print("PASS: invalid HID command")
print("Sending packet with too large of a length.")
self.send_raw("\x81\x1d\xba\x00")
cmd, resp = self.recv_raw()
self.check_error(resp, CtapError.ERR.INVALID_LENGTH)
print("PASS: invalid length")
r = self.send_data(CTAPHID.PING, "\x44" * 200)
print("Sending packets that skip a sequence number.")
self.send_raw("\x81\x04\x90")
self.send_raw("\x00")
self.send_raw("\x01")
# skip 2
self.send_raw("\x03")
cmd, resp = self.recv_raw()
self.check_error(resp, CtapError.ERR.INVALID_SEQ)
if check_timeouts:
cmd, resp = self.recv_raw()
assert cmd == 0xBF # timeout
print("PASS: invalid sequence")
print("Resync and send ping")
try:
r = self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
pingdata = os.urandom(100)
r = self.send_data(CTAPHID.PING, pingdata)
if r != pingdata:
raise ValueError("Ping data not echo'd")
except CtapError as e:
raise RuntimeError("resync fail: ", e)
print("PASS: resync and ping")
print("Send ping and abort it")
self.send_raw("\x81\x04\x00")
self.send_raw("\x00")
self.send_raw("\x01")
try:
r = self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
except CtapError as e:
raise RuntimeError("resync fail: ", e)
print("PASS: interrupt ping with resync")
print("Send ping and abort it with different cid, expect timeout")
oldcid = self.cid()
newcid = "\x11\x22\x33\x44"
self.send_raw("\x81\x10\x00")
self.send_raw("\x00")
self.send_raw("\x01")
self.set_cid(newcid)
self.send_raw(
"\x86\x00\x08\x11\x22\x33\x44\x55\x66\x77\x88"
) # init from different cid
print("wait for init response")
cmd, r = self.recv_raw() # init response
assert cmd == 0x86
self.set_cid(oldcid)
if check_timeouts:
# print('wait for timeout')
cmd, r = self.recv_raw() # timeout response
assert cmd == 0xBF
print("PASS: resync and timeout")
print("Test timeout")
self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
t1 = time.time() * 1000
self.send_raw("\x81\x04\x00")
self.send_raw("\x00")
self.send_raw("\x01")
cmd, r = self.recv_raw() # timeout response
t2 = time.time() * 1000
delt = t2 - t1
assert cmd == 0xBF
assert r[0] == CtapError.ERR.TIMEOUT
assert delt < 1000 and delt > 400
print("Pass timeout")
print("Test not cont")
self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
self.send_raw("\x81\x04\x00")
self.send_raw("\x00")
self.send_raw("\x01")
self.send_raw("\x81\x10\x00") # init packet
cmd, r = self.recv_raw() # timeout response
assert cmd == 0xBF
assert r[0] == CtapError.ERR.INVALID_SEQ
print("PASS: Test not cont")
if check_timeouts:
print("Check random cont ignored")
self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
self.send_raw("\x01\x10\x00")
try:
cmd, r = self.recv_raw() # timeout response
except socket.timeout:
pass
print("PASS: random cont")
print("Check busy")
t1 = time.time() * 1000
self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
oldcid = self.cid()
newcid = "\x11\x22\x33\x44"
self.send_raw("\x81\x04\x00")
self.set_cid(newcid)
self.send_raw("\x81\x04\x00")
cmd, r = self.recv_raw() # busy response
t2 = time.time() * 1000
assert t2 - t1 < 100
assert cmd == 0xBF
assert r[0] == CtapError.ERR.CHANNEL_BUSY
self.set_cid(oldcid)
cmd, r = self.recv_raw() # timeout response
assert cmd == 0xBF
assert r[0] == CtapError.ERR.TIMEOUT
print("PASS: busy")
print("Check busy interleaved")
cid1 = "\x11\x22\x33\x44"
cid2 = "\x01\x22\x33\x44"
self.set_cid(cid2)
self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
self.set_cid(cid1)
self.send_data(CTAPHID.INIT, "\x11\x22\x33\x44\x55\x66\x77\x88")
self.send_raw("\x81\x00\x63") # echo 99 bytes first channel
self.set_cid(cid2) # send ping on 2nd channel
self.send_raw("\x81\x00\x63")
self.send_raw("\x00")
cmd, r = self.recv_raw() # busy response
self.set_cid(cid1) # finish 1st channel ping
self.send_raw("\x00")
self.set_cid(cid2)
assert cmd == 0xBF
assert r[0] == CtapError.ERR.CHANNEL_BUSY
self.set_cid(cid1)
cmd, r = self.recv_raw() # ping response
assert cmd == 0x81
assert len(r) == 0x63
if check_timeouts:
cmd, r = self.recv_raw() # timeout
assert cmd == 0xBF
assert r[0] == CtapError.ERR.TIMEOUT
print("PASS: busy interleaved")
if check_timeouts:
print("Test idle, wait for timeout")
sys.stdout.flush()
try:
cmd, resp = self.recv_raw()
except socket.timeout:
print("Pass: Idle")
print("Test cid 0 is invalid")
self.set_cid("\x00\x00\x00\x00")
self.send_raw(
"\x86\x00\x08\x11\x22\x33\x44\x55\x66\x77\x88", cid="\x00\x00\x00\x00"
)
cmd, r = self.recv_raw() # timeout
assert cmd == 0xBF
assert r[0] == CtapError.ERR.INVALID_CHANNEL
print("Pass: cid 0")
print("Test invalid broadcast cid use")
self.set_cid("\xff\xff\xff\xff")
self.send_raw(
"\x81\x00\x08\x11\x22\x33\x44\x55\x66\x77\x88", cid="\xff\xff\xff\xff"
)
cmd, r = self.recv_raw() # timeout
assert cmd == 0xBF
assert r[0] == CtapError.ERR.INVALID_CHANNEL
print("Pass: cid broadcast")
def test_u2f(self,):
chal = sha256(b"AAA")
appid = sha256(b"BBB")
lastc = 0
for i in range(0, 5):
reg = self.ctap1.register(chal, appid)
reg.verify(appid, chal)
auth = self.ctap1.authenticate(chal, appid, reg.key_handle)
# check endianness
if lastc:
assert (auth.counter - lastc) < 10
lastc = auth.counter
print(hex(lastc))
print("U2F reg + auth pass %d/5" % (i + 1))
def test_fido2_simple(self, pin_token=None):
creds = []
exclude_list = []
rp = {"id": self.host, "name": "ExaRP"}
user = {"id": b"usee_od", "name": "AB User"}
challenge = "Y2hhbGxlbmdl"
PIN = pin_token
fake_id1 = array.array("B", [randint(0, 255) for i in range(0, 150)]).tobytes()
fake_id2 = array.array("B", [randint(0, 255) for i in range(0, 73)]).tobytes()
exclude_list.append({"id": fake_id1, "type": "public-key"})
exclude_list.append({"id": fake_id2, "type": "public-key"})
print("MC")
t1 = time.time() * 1000
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=[]
)
t2 = time.time() * 1000
VerifyAttestation(attest, data)
print("Register valid (%d ms)" % (t2 - t1))
cred = attest.auth_data.credential_data
creds.append(cred)
allow_list = [{"id": creds[0].credential_id, "type": "public-key"}]
t1 = time.time() * 1000
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, allow_list, pin=PIN
)
t2 = time.time() * 1000
assertions[0].verify(client_data.hash, creds[0].public_key)
print("Assertion valid (%d ms)" % (t2 - t1))
def test_fido2_brute_force(self):
creds = []
exclude_list = []
rp = {"id": self.host, "name": "ExaRP"}
user = {"id": b"usee_od", "name": "AB User"}
PIN = None
abc = "abcdefghijklnmopqrstuvwxyz"
abc += abc.upper()
self.ctap.reset()
for i in range(0, 2048 ** 2):
creds = []
challenge = "".join([abc[randint(0, len(abc) - 1)] for x in range(0, 32)])
fake_id1 = array.array(
"B", [randint(0, 255) for i in range(0, 150)]
).tostring()
fake_id2 = array.array(
"B", [randint(0, 255) for i in range(0, 73)]
).tostring()
exclude_list.append({"id": fake_id1, "type": "public-key"})
exclude_list.append({"id": fake_id2, "type": "public-key"})
# for i in range(0,2048**2):
for i in range(0, 1):
t1 = time.time() * 1000
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=[]
)
print(attest.auth_data.counter)
t2 = time.time() * 1000
VerifyAttestation(attest, data)
print("Register valid (%d ms)" % (t2 - t1))
sys.stdout.flush()
cred = attest.auth_data.credential_data
creds.append(cred)
# for i in range(0,2048**2):
for i in range(0, 1):
allow_list = [{"id": creds[0].credential_id, "type": "public-key"}]
t1 = time.time() * 1000
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, allow_list, pin=PIN
)
t2 = time.time() * 1000
assertions[0].verify(client_data.hash, creds[0].public_key)
print(assertions[0].auth_data.counter)
print("Assertion valid (%d ms)" % (t2 - t1))
sys.stdout.flush()
def test_fido2(self):
def test(self, pincode=None):
creds = []
exclude_list = []
rp = {"id": self.host, "name": "ExaRP"}
user = {"id": b"usee_od", "name": "AB User"}
challenge = "Y2hhbGxlbmdl"
PIN = pincode
fake_id1 = array.array(
"B", [randint(0, 255) for i in range(0, 150)]
).tostring()
fake_id2 = array.array(
"B", [randint(0, 255) for i in range(0, 73)]
).tostring()
exclude_list.append({"id": fake_id1, "type": "public-key"})
exclude_list.append({"id": fake_id2, "type": "public-key"})
# test make credential
print("make 3 credentials")
for i in range(0, 3):
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=[]
)
VerifyAttestation(attest, data)
# verify endian-ness is correct
assert attest.auth_data.counter < 0x10000
cred = attest.auth_data.credential_data
creds.append(cred)
print(cred)
print("PASS")
if PIN is not None:
print("make credential with wrong pin code")
try:
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN + " ", exclude_list=[]
)
except CtapError as e:
assert e.code == CtapError.ERR.PIN_INVALID
except ClientError as e:
assert e.cause.code == CtapError.ERR.PIN_INVALID
print("PASS")
print("make credential with exclude list")
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=exclude_list
)
VerifyAttestation(attest, data)
cred = attest.auth_data.credential_data
creds.append(cred)
print("PASS")
print("make credential with exclude list including real credential")
real_excl = [{"id": cred.credential_id, "type": "public-key"}]
try:
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=exclude_list + real_excl
)
raise RuntimeError("Exclude list did not return expected error")
except CtapError as e:
assert e.code == CtapError.ERR.CREDENTIAL_EXCLUDED
except ClientError as e:
assert e.cause.code == CtapError.ERR.CREDENTIAL_EXCLUDED
print("PASS")
for i, x in enumerate(creds):
print("get assertion %d" % i)
allow_list = [{"id": x.credential_id, "type": "public-key"}]
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, allow_list, pin=PIN
)
assertions[0].verify(client_data.hash, x.public_key)
print("PASS")
if PIN is not None:
print("get assertion with wrong pin code")
try:
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, allow_list, pin=PIN + " "
)
except CtapError as e:
assert e.code == CtapError.ERR.PIN_INVALID
except ClientError as e:
assert e.cause.code == CtapError.ERR.PIN_INVALID
print("PASS")
print("get multiple assertions")
allow_list = [{"id": x.credential_id, "type": "public-key"} for x in creds]
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, allow_list, pin=PIN
)
for ass, cred in zip(assertions, creds):
i += 1
ass.verify(client_data.hash, cred.public_key)
print("%d verified" % i)
print("PASS")
print("Reset device")
try:
self.ctap.reset()
except CtapError as e:
print("Warning, reset failed: ", e)
pass
print("PASS")
test(self, None)
print("Set a pin code")
PIN = "1122aabbwfg0h9g !@#=="
self.client.pin_protocol.set_pin(PIN)
print("PASS")
print("Illegally set pin code again")
try:
self.client.pin_protocol.set_pin(PIN)
except CtapError as e:
assert e.code == CtapError.ERR.NOT_ALLOWED
print("PASS")
print("Change pin code")
PIN2 = PIN + "_pin2"
self.client.pin_protocol.change_pin(PIN, PIN2)
PIN = PIN2
print("PASS")
print("Change pin code using wrong pin")
try:
self.client.pin_protocol.change_pin(PIN.replace("a", "b"), "1234")
except CtapError as e:
assert e.code == CtapError.ERR.PIN_INVALID
print("PASS")
print("MC using wrong pin")
try:
self.test_fido2_simple("abcd3")
except ClientError as e:
assert e.cause.code == CtapError.ERR.PIN_INVALID
print("PASS")
print("get info")
inf = self.ctap.get_info()
print("PASS")
self.test_fido2_simple(PIN)
print("Re-run make_credential and get_assertion tests with pin code")
test(self, PIN)
print("Reset device")
try:
self.ctap.reset()
except CtapError as e:
print("Warning, reset failed: ", e)
print("PASS")
def test_rk(self,):
creds = []
rp = {"id": self.host, "name": "ExaRP"}
user0 = {"id": b"first one", "name": "single User"}
users = [
{"id": b"user" + os.urandom(16), "name": "AB User"} for i in range(0, 2)
]
challenge = "Y2hhbGxlbmdl"
PIN = None
print("reset")
self.ctap.reset()
# if PIN: self.client.pin_protocol.set_pin(PIN)
print("registering 1 user with RK")
t1 = time.time() * 1000
attest, data = self.client.make_credential(
rp, user0, challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
VerifyAttestation(attest, data)
creds.append(attest.auth_data.credential_data)
print("Register valid (%d ms)" % (t2 - t1))
print("1 assertion")
t1 = time.time() * 1000
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, pin=PIN
)
t2 = time.time() * 1000
assertions[0].verify(client_data.hash, creds[0].public_key)
print("Assertion valid (%d ms)" % (t2 - t1))
print(assertions[0], client_data)
print("registering %d users with RK" % len(users))
for i in range(0, len(users)):
t1 = time.time() * 1000
attest, data = self.client.make_credential(
rp, users[i], challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
VerifyAttestation(attest, data)
print("Register valid (%d ms)" % (t2 - t1))
creds.append(attest.auth_data.credential_data)
t1 = time.time() * 1000
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, pin=PIN
)
t2 = time.time() * 1000
for x, y in zip(assertions, creds):
x.verify(client_data.hash, y.public_key)
print("Assertion(s) valid (%d ms)" % (t2 - t1))
print("registering a duplicate user ")
t1 = time.time() * 1000
attest, data = self.client.make_credential(
rp, users[1], challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
VerifyAttestation(attest, data)
creds = creds[:2] + creds[3:] + [attest.auth_data.credential_data]
print("Register valid (%d ms)" % (t2 - t1))
t1 = time.time() * 1000
assertions, client_data = self.client.get_assertion(
rp["id"], challenge, pin=PIN
)
t2 = time.time() * 1000
assert len(assertions) == len(users) + 1
for x, y in zip(assertions, creds):
x.verify(client_data.hash, y.public_key)
print("Assertion(s) valid (%d ms)" % (t2 - t1))
def test_responses(self,):
PIN = "1234"
RPID = self.host
for dev in CtapHidDevice.list_devices():
print("dev", dev)
client = Fido2Client(dev, RPID)
ctap = client.ctap2
# ctap.reset()
try:
if PIN:
client.pin_protocol.set_pin(PIN)
except:
pass
inf = ctap.get_info()
# print (inf)
print("versions: ", inf.versions)
print("aaguid: ", inf.aaguid)
print("rk: ", inf.options["rk"])
print("clientPin: ", inf.options["clientPin"])
print("max_message_size: ", inf.max_msg_size)
# rp = {'id': 'SelectDevice', 'name': 'SelectDevice'}
rp = {"id": RPID, "name": "ExaRP"}
user = {"id": os.urandom(10), "name": "SelectDevice"}
user = {"id": b"21first one", "name": "single User"}
challenge = "Y2hhbGxlbmdl"
if 1:
attest, data = client.make_credential(
rp, user, challenge, exclude_list=[], pin=PIN, rk=True
)
cred = attest.auth_data.credential_data
creds = [cred]
allow_list = [{"id": creds[0].credential_id, "type": "public-key"}]
allow_list = []
assertions, client_data = client.get_assertion(
rp["id"], challenge, pin=PIN
)
assertions[0].verify(client_data.hash, creds[0].public_key)
if 0:
print("registering 1 user with RK")
t1 = time.time() * 1000
attest, data = client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
VerifyAttestation(attest, data)
creds = [attest.auth_data.credential_data]
print("Register valid (%d ms)" % (t2 - t1))
print("1 assertion")
t1 = time.time() * 1000
assertions, client_data = client.get_assertion(
rp["id"], challenge, pin=PIN
)
t2 = time.time() * 1000
assertions[0].verify(client_data.hash, creds[0].public_key)
print("Assertion valid (%d ms)" % (t2 - t1))
# print('fmt:',attest.fmt)
# print('rp_id_hash',attest.auth_data.rp_id_hash)
# print('flags:', hex(attest.auth_data.flags))
# print('count:', hex(attest.auth_data.counter))
print("flags MC:", attest.auth_data)
print("flags GA:", assertions[0].auth_data)
# print('cred_id:',attest.auth_data.credential_data.credential_id)
# print('pubkey:',attest.auth_data.credential_data.public_key)
# print('aaguid:',attest.auth_data.credential_data.aaguid)
# print('cred data:',attest.auth_data.credential_data)
# print('auth_data:',attest.auth_data)
# print('auth_data:',attest.auth_data)
# print('alg:',attest.att_statement['alg'])
# print('sig:',attest.att_statement['sig'])
# print('x5c:',attest.att_statement['x5c'])
# print('data:',data)
print("assertion:", assertions[0])
print("clientData:", client_data)
print()
# break
def test_find_brute_force():
i = 0
while 1:
t1 = time.time() * 1000
t = Tester()
t.find_device()
t2 = time.time() * 1000
print("connected %d (%d ms)" % (i, t2 - t1))
i += 1
time.sleep(0.01)
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "sim":
print("Using UDP backend.")
forceUDPBackend()
t = Tester()
t.find_device()
# t.test_hid()
# t.test_long_ping()
t.test_fido2()
t.test_u2f()
# t.test_rk()
# t.test_responses()
# test_find_brute_force()
# t.test_fido2_simple()
# t.test_fido2_brute_force()

65
tools/gadgetfs/Makefile Normal file
View File

@ -0,0 +1,65 @@
TOP := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
KERNEL_FULL_VERSION := $(shell uname -r)
KERNEL_VERSION := $(shell uname -r | grep -o "^[^-]*")
KERNEL_MAJOR := $(shell uname -r | cut -d. -f1)
KERNEL_MINOR := $(shell uname -r | cut -d. -f2)
MANUFACTURER = "Solo"
SERIAL = "1234567890"
IDVENDOR = "0x0483"
IDPRODUCT = "0xa2ca"
PRODUCT = "Solo Software Authenticator"
CONFIGFS = /sys/kernel/config
CONFIGFS_FIDO2 = $(CONFIGFS)/usb_gadget/fido2
obj-m := dummy_hcd.o
KVERSION := $(shell uname -r)
SHELL := /bin/bash
all: dummy_hcd.ko
install: dummy_hcd.ko
modprobe libcomposite
insmod dummy_hcd.ko
mkdir -p $(CONFIGFS_FIDO2)
mkdir -p $(CONFIGFS_FIDO2)/configs/c.1
mkdir -p $(CONFIGFS_FIDO2)/functions/hid.usb0
echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/protocol
echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/subclass
echo 64 > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_length
echo -ne "\x06\xd0\xf1\x09\x01\xa1\x01\x09\x20\x15\x00\x26\xff\x00\x75\x08\x95\x40\x81\x02\x09\x21\x15\x00\x26\xff\x00\x75\x08\x95\x40\x91\x02\xc0" > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_desc
mkdir $(CONFIGFS_FIDO2)/strings/0x409
mkdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409
echo $(IDPRODUCT) > $(CONFIGFS_FIDO2)/idProduct
echo $(IDVENDOR) > $(CONFIGFS_FIDO2)/idVendor
echo $(SERIAL) > $(CONFIGFS_FIDO2)/strings/0x409/serialnumber
echo $(MANUFACTURER) > $(CONFIGFS_FIDO2)/strings/0x409/manufacturer
echo $(PRODUCT) > $(CONFIGFS_FIDO2)/strings/0x409/product
echo "Configuration 1" > $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409/configuration
echo 120 > $(CONFIGFS_FIDO2)/configs/c.1/MaxPower
ln -s $(CONFIGFS_FIDO2)/functions/hid.usb0 $(CONFIGFS_FIDO2)/configs/c.1
echo "dummy_udc.0" > $(CONFIGFS_FIDO2)/UDC
uninstall:
echo "" > $(CONFIGFS_FIDO2)/UDC
rm $(CONFIGFS_FIDO2)/configs/c.1/hid.usb0
rmdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409
rmdir $(CONFIGFS_FIDO2)/configs/c.1
rmdir $(CONFIGFS_FIDO2)/functions/hid.usb0
rmdir $(CONFIGFS_FIDO2)/strings/0x409
rmdir $(CONFIGFS_FIDO2)
rmmod dummy_hcd.ko
dummy_hcd.ko: dummy_hcd.c
$(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) modules
dummy_hcd.c: /usr/src/linux-source-$(KERNEL_VERSION).tar.bz2
tar -xvf $^ linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c
cp linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c $@
clean:
$(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) clean
rm -rf linux-source-$(KERNEL_VERSION)
rm -f dummy_hcd.c

View File

@ -2,5 +2,6 @@ ecdsa
fido2 fido2
intelhex intelhex
pyserial pyserial
solo-python
pyusb pyusb
wheel wheel

File diff suppressed because it is too large Load Diff

8
tools/test_sw_token.sh Normal file
View File

@ -0,0 +1,8 @@
#!/bin/bash
./main
while [ $? == 100 ] ; do
echo "Restarting software authentictor."
./main
done

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