Compare commits

..

758 Commits

Author SHA1 Message Date
ba6da64605
build standalone 2020-11-01 14:56:26 +01:00
393051f407
UNDO: hmac-secret should be different when UV=1 2020-10-30 16:45:53 +01:00
c9894ab68a
filter result 2020-10-30 16:23:49 +01:00
65dc8de490
allow pin removal 2020-10-30 16:13:22 +01:00
d0124c615a
nix 2020-10-30 16:07:57 +01:00
Nicolas Stalder
8b91ec7c53
Update SECURITY.md
Link to renewed GPG key.
2020-10-08 20:12:07 +02:00
Julian Rösner
b86f0ee4e5 Add tutorials 2020-09-05 01:48:49 +02:00
Nicolas Stalder
13c882b532 Redirect on Netlify level 2020-06-10 01:07:40 +02:00
Nicolas Stalder
483edcb56d Some leftover old doc links 2020-06-10 00:31:58 +02:00
Nicolas Stalder
b7b5d51cc2
Merge pull request #448 from solokeys/simplify-docs
Host solo docs directly at docs.solokeys.dev
2020-06-10 00:20:17 +02:00
Nicolas Stalder
c52af54e8f Host solo docs directly at docs.solokeys.{dev,io} 2020-06-10 00:17:31 +02:00
Nicolas Stalder
cc4cd340da
Merge pull request #439 from Nuc1eoN/Nuc1eoN-patch-1
Update documentation for Arch Linux
2020-05-19 23:25:48 +02:00
Philip Pokarowski
ca885941f0
Update udev.md 2020-05-19 23:15:13 +02:00
Nicolas Stalder
dc27b48101
Merge pull request #435 from FabianHenneke/patch-1
Mention that systemd 244+ detects FIDO devices
2020-05-08 22:43:02 +02:00
Fabian Henneke
1bf071f8b4
Update udev.md 2020-05-08 19:28:16 +02:00
Fabian Henneke
cc3d3c63ec
Mention that systemd 244+ detects FIDO devices 2020-05-08 19:25:11 +02:00
Nicolas Stalder
c248b5d569
Merge pull request #428 from Iolaum/dev1
Explicitly call that a DFU update erases everything.
2020-04-27 00:21:05 +02:00
Nikolaos Perrakis
85cf25559c doc: DFU update fully erases previous flash 2020-04-25 23:51:26 +01:00
Conor Patrick
299e91b91b dont return index >= ctap_rk_size()
Fixes issue found by @My1: https://github.com/solokeys/solo/issues/407
2020-03-28 15:45:16 -04:00
Conor Patrick
cbf40f4ec7 hmac-secret should be different when UV=1 2020-03-28 12:28:05 -04:00
Conor Patrick
8d93f88631
Update STABLE_VERSION 2020-03-27 11:29:11 -04:00
Conor Patrick
5f8a9a44fc refactor credmgmt 2020-03-27 10:56:51 -04:00
Conor Patrick
8aa1f4ad01 change parsing TAG_CM to TAG_PARSE 2020-03-27 10:56:51 -04:00
Conor Patrick
04cffb6509 allow depth-first-search and account for interleaved RK's 2020-03-27 10:56:51 -04:00
Radoslav Gerganov
f002d08071 Add support for the security manager in Google Chrome
This patch fixes the following issues to make Google Chrome happy:
1. Adds CTAP_CBOR_CRED_MGMT(0x0A) which is an alias to CTAP_CBOR_CRED_MGMT_PRE(0x41)
2. Returns success instead of NO_CREDENTIALS when there are no RKs
3. Skip the "icon" property if it's empty

Tested with Google Chrome Version 80.0.3987.149
2020-03-27 00:22:28 -04:00
Radoslav Gerganov
e53b83257d Do not return NO_CREDENTIALS if there are no RKs and meta is requested
Fixes-issue: #403
2020-03-27 00:22:28 -04:00
Conor Patrick
05e149fb17
Update STABLE_VERSION 2020-03-25 15:16:14 -04:00
Conor Patrick
530e175ad1 cleanup 2020-03-25 14:57:39 -04:00
Conor Patrick
6cd3873b37 add reboot command for better testing 2020-03-25 14:57:39 -04:00
Conor Patrick
241f58657b consider credProtect with exclude list, and also check user presence 2020-03-25 14:57:39 -04:00
Conor Patrick
3b42289cce add rpId to RK's, fix counting of unique RP's 2020-03-25 14:57:39 -04:00
Conor Patrick
b3712b57fc refactor to reuse more code 2020-03-25 14:57:39 -04:00
Conor Patrick
37769bb735 to support deleted credentials, need to scan all rk slots since it's no longer continuous 2020-03-25 14:57:39 -04:00
Conor Patrick
d677f8c346 add rk delete implementations 2020-03-25 14:57:39 -04:00
Conor Patrick
98bcf647c4 implement rk delete command for cred mgmt 2020-03-25 14:57:39 -04:00
Conor Patrick
682a443f4e refactor credMgmt to parse as subCommandParams, and get ready for delete command 2020-03-25 14:57:39 -04:00
Conor Patrick
a28a05673f definitely need to update rpIdHash 2020-03-25 14:57:39 -04:00
Conor Patrick
3a70ee0ec6 refactor authData and extension handling to work for getNextAssertion 2020-03-25 14:57:39 -04:00
Conor Patrick
872a320abc Fix credential order: need to start with most recent 2020-03-25 14:57:39 -04:00
Conor Patrick
3cbf7ec451 move credProtect checking to credential filtering step 2020-03-25 14:57:39 -04:00
Conor Patrick
748c552eea fix overflow error for 5th resident key 2020-03-25 14:57:39 -04:00
Conor Patrick
98f996fcfe save some ram 2020-03-25 14:57:39 -04:00
Conor Patrick
97eb6bba8a bug fix 2020-03-25 14:57:39 -04:00
Conor Patrick
fdc5a68fcd update info/feature detection details 2020-03-25 14:57:39 -04:00
Conor Patrick
1c1005a0e8 add credprotect parameter to output 2020-03-25 14:57:39 -04:00
Conor Patrick
4831410111 add credProtect extension 2020-03-25 14:57:39 -04:00
Radoslav Gerganov
05bc8bee55 Check return values when parsing CTAP commands 2020-03-21 12:49:05 -04:00
Radoslav Gerganov
7112633779 Fix user presence test when pinAuth is empty
The check_retr macro is evaluating its argument twice, so when we do:

    check_retr( ctap2_user_presence_test(...) )

the user presence function is called twice and the user has to press the
button twice. This is regression introduced with commit 3b53537.
2020-03-21 12:48:05 -04:00
Radoslav Gerganov
79b43a90fd Implement commands for management of resident keys
Implement command 0x41 which is used by OpenSSH for reading RKs. It has
the following subcommands:
 * CMD_CRED_METADATA - get number of saved/remaining RKs
 * CMD_RP_BEGIN/CMD_RP_NEXT - iterate over the saved RPs
 * CMD_RK_BEGIN/CMD_RK_NEXT - iterate over the RKs for a given RP

Fixes issue #374 and issue #314
2020-03-21 11:59:22 -04:00
Conor Patrick
ec7a6fd740
Update STABLE_VERSION 2020-03-16 15:04:45 -04:00
Conor Patrick
f2d6698066 Update version.c 2020-03-16 14:59:01 -04:00
Somebodyisnobody
3c9315e34c Update README.md
Basic steps how to apply updates
2020-03-09 12:06:39 -04:00
Conor Patrick
8ed7157bfe bump 3.1.2 2020-02-27 15:50:46 -05:00
Conor Patrick
28a1b1cc06 limit possible recursions in tinycbor 2020-02-27 15:40:27 -05:00
Conor Patrick
5738bcc7a3 more strict checks in cbor parsing 2020-02-27 15:40:27 -05:00
Conor Patrick
4fb166631d remove SOLO_EXPERIMENTAL default 2020-02-18 11:18:08 -05:00
Conor Patrick
1b862d3b0c fix error return 2020-02-18 11:18:08 -05:00
Conor Patrick
094420b32b overwrite if >256 is more clear 2020-02-18 11:18:08 -05:00
Conor Patrick
349cbc39f2 fix offset 2020-02-18 11:18:08 -05:00
Conor Patrick
e294cb3458 replace counter instead of increment for large increment 2020-02-18 11:18:08 -05:00
Conor Patrick
da31f984dd add version check 2020-02-18 11:18:08 -05:00
Conor Patrick
9d3e8c06fc subsequent button presses do not need to wait long 2020-02-18 11:18:08 -05:00
Conor Patrick
b378bbf61d
Update building.md 2020-02-18 10:53:47 -05:00
Conor Patrick
04b89a9739
Update customization.md 2020-02-18 10:38:53 -05:00
Conor Patrick
0d28a7bcf6
Update customization.md 2020-02-18 10:03:19 -05:00
Conor Patrick
aeafd09007 only use .flag section for hw builds 2020-02-17 13:41:05 -05:00
Conor Patrick
8b6148ac90 bump 3.1.1 2020-02-13 17:32:26 -05:00
Conor Patrick
15a4fdfa66 remove unused code in bootloader 2020-02-13 17:17:23 -05:00
Conor Patrick
e713daba26 add temporary command to force flash locking 2020-02-13 17:17:23 -05:00
Conor Patrick
b78f2cd2e7 keep initialize last_addr and reject if it doesnt change 2020-02-13 17:17:23 -05:00
Arno Onken
601c98000a Correct path for gencert tools and use python3 2020-02-12 14:52:53 -05:00
Arno Onken
ab1c9417b1 Fix certification information 2020-02-12 14:52:53 -05:00
Conor Patrick
f6d96013e1 bump 3.1.0 2020-02-06 13:41:07 -05:00
Conor Patrick
f74dba7ff0 enforce ascending writes in bootloader update 2020-02-06 13:05:57 -05:00
Jan A
794accf3dc Added how to setup Manjaro 18.x.
Added Manjaro setup for passwordless and second factor login to
documentation of applcation ideas. Also did some text formating.
2020-02-06 12:47:36 -05:00
Conor Patrick
2ca0ced808
Update programming.md 2020-01-22 12:41:39 -05:00
Nicolas Stalder
17b430fd44 Remove stale python-fido2 dependency 2020-01-16 10:35:22 +01:00
Nicolas Stalder
0d4197fb2c
Merge pull request #356 from jnaulty/jnaulty/no-root-artifacts
Use current user at build container runtime
2020-01-15 21:17:53 +01:00
John Naulty
f74a77d80b
Use current user at build container runtime
Using the current user id and group removes the need to use `sudo` when
cleaning up build artifacts from the docker build stage.

Issue: #355
2020-01-06 01:55:47 -08:00
Conor Patrick
5f1d61a3ba bump 2019-12-01 18:25:45 -05:00
Conor Patrick
46f2920e63 bugfix hid cancel 2019-12-01 18:09:08 -05:00
Conor Patrick
53427c4279 update metadata statements 2019-12-01 18:09:08 -05:00
Conor Patrick
ac10933379 pin fido2 dependency 2019-12-01 18:09:08 -05:00
Conor Patrick
8a44d14fef adjust default impl 2019-12-01 18:09:08 -05:00
Conor Patrick
1d59bbfdd4 support different aaguid's in cert for different solo models 2019-12-01 18:09:08 -05:00
Conor Patrick
54c66d80b6 overwrite x509 fields for tap or somu 2019-12-01 18:09:08 -05:00
Conor Patrick
6217fc34b9 update solo_cert to include aaguid field 2019-12-01 18:09:08 -05:00
Conor Patrick
af23e84a8d Update device.c 2019-11-22 19:02:52 -05:00
Conor Patrick
9650d99b34 add more clarity 2019-11-22 19:02:52 -05:00
Conor Patrick
145b04750e Update Makefile 2019-11-22 19:02:52 -05:00
Conor Patrick
078acbc4b4 prepend solo to version 2019-11-22 19:02:52 -05:00
Conor Patrick
670a4e5d62 version string 2019-11-22 19:02:52 -05:00
Conor Patrick
de55e521cc fix bootloader build 2019-11-22 19:02:52 -05:00
Conor Patrick
bbfe51499f document 2019-11-22 19:02:52 -05:00
Conor Patrick
6cb15a6482 small fixes 2019-11-22 19:02:52 -05:00
Conor Patrick
85ddc40036 add weak definitions for nonvolatila functions 2019-11-22 19:02:52 -05:00
Conor Patrick
1d63154699 move sense of "backup" from ctap to device layer 2019-11-22 19:02:52 -05:00
Conor Patrick
ee55bf3ba0 document device.h 2019-11-22 19:02:52 -05:00
Conor Patrick
3b4b6dd4fe remove solo functions from device.h 2019-11-22 19:02:52 -05:00
Conor Patrick
28e607ddac fix stm32 build 2019-11-22 19:02:52 -05:00
Conor Patrick
dcd256faf4 add initial weak definitions 2019-11-22 19:02:52 -05:00
Conor Patrick
85365c635d refactor to use libsolo 2019-11-22 19:02:52 -05:00
Conor Patrick
a388607dab build fido2 locally as lib 2019-11-22 19:02:52 -05:00
Conor Patrick
d266e7927c reorganize crypto and device.c to be more based on fido2/ 2019-11-22 19:02:52 -05:00
Nicolas Stalder
0ac074e8a8
Merge pull request #341 from emosenkis/patch-1
Fix typo in CERN OHL version 2.1 -> 1.2
2019-11-11 10:47:02 +01:00
Eitan Mosenkis
67eb721da2
Fix typo in CERN OHL version 2.1 -> 1.2 2019-11-10 23:04:48 +02:00
allcontributors[bot]
6b5d353501 docs: update .all-contributorsrc 2019-11-07 08:29:08 -05:00
allcontributors[bot]
bacce7d978 docs: update README.md 2019-11-07 08:29:08 -05:00
Conor Patrick
975cdf02f2 bump 3.0.0 2019-10-28 13:19:11 -04:00
Conor Patrick
21f3a0d10f remove hacker constraint for booting into bootloader 2019-10-28 12:55:38 -04:00
allcontributors[bot]
b535b41d92 docs: update .all-contributorsrc 2019-10-28 11:09:54 -04:00
allcontributors[bot]
fd32cc0761 docs: update README.md 2019-10-28 11:09:54 -04:00
Conor Patrick
78dd2a10d3 remove binary count check 2019-10-28 10:51:35 -04:00
Conor Patrick
fa1bb0dce5 update docs 2019-10-28 10:51:35 -04:00
Conor Patrick
169dfd2f0d check attestation tag 2019-10-28 10:51:35 -04:00
Conor Patrick
dafd974d93 do not lock flash when booting to dfu 2019-10-28 10:51:35 -04:00
Conor Patrick
712fde6858 add git 2019-10-28 10:51:35 -04:00
Conor Patrick
fcc2e86a6d remove hacker/secure builds 2019-10-28 10:51:35 -04:00
Conor Patrick
8b146c4a16 fix issue with bootloader not replying data 2019-10-28 10:51:35 -04:00
Conor Patrick
a1a79b05fd fix solo locked flag for bootloader 2019-10-27 10:25:00 -04:00
Conor Patrick
c0df8b680d fix build 2019-10-27 10:25:00 -04:00
Conor Patrick
9ac2aa90c3 store all info in same page, dont use authenticator state 2019-10-27 10:25:00 -04:00
Conor Patrick
d33749fc16 add locked variable to GETVERSION hid command 2019-10-27 10:25:00 -04:00
Conor Patrick
96a2cbcb41 remove logs 2019-10-27 10:25:00 -04:00
Conor Patrick
7212982385 remove hacker macros 2019-10-27 10:25:00 -04:00
Conor Patrick
89e218e561 lock flash based on state setting 2019-10-27 10:25:00 -04:00
Conor Patrick
666cd6a0ba migrate certs 2019-10-27 10:25:00 -04:00
Conor Patrick
b4f59ec355 pull certificate from flash page 2019-10-27 10:25:00 -04:00
Chris Cinelli
b7d74cc99f Add default git describe in makefile 2019-10-27 10:11:39 -04:00
Chris Cinelli
375a607356 Add test for docker in travis 2019-10-27 10:11:39 -04:00
Chris Cinelli
ea8409c072 Fixing Travis 2019-10-27 10:11:39 -04:00
Chris Cinelli
04f06b3b0d Updating README: adding more details on how to compile the solo firmware (especially Docker) 2019-10-27 10:11:39 -04:00
Chris Cinelli
a57c5170e1 Add .sha2 to .gitignore 2019-10-27 10:11:39 -04:00
Chris Cinelli
aaffce4021 Make dependency on git optinal in the target/stm32l432/Makefile
"git describe" is used to get the version of the firmware from GIT tags ans it is used for build artifacts' names
We would prefer not to have this depency inside Docker
2019-10-27 10:11:39 -04:00
Chris Cinelli
463a8b444d Splitting toolchain creation from firmware compilation 2019-10-27 10:11:39 -04:00
Chris Cinelli
44ed3ceea5 Optimize Dockerfile 2019-10-27 10:11:39 -04:00
Chris Cinelli
30f73b41e4 Move python install in the docker file 2019-10-27 10:11:39 -04:00
Chris Cinelli
6f6e831fba Upgrade to the latest ARM compiler 2019-10-27 10:11:39 -04:00
Chris Cinelli
9fd608d3ee Use local copy of the files 2019-10-27 10:11:39 -04:00
Chris Cinelli
765dc27b15 Fix docker build 2019-10-27 10:10:27 -04:00
Emanuele Cesena
48147a39df
Remove Somu campaign from readme 2019-10-24 12:53:03 +02:00
Nicolas Stalder
6c48d75e44
Merge pull request #324 from jolo1581/document_application_ideas
Document application ideas
2019-10-23 13:01:49 +02:00
Jan A.
fca1e9d405 Added new document for Application Ideas.
Added manual how to setup Linux to use Solo for passwordless login or as
second factor by pressing button after password login. Added chapter
"Application Ideas" below chapter "Solo Extras" in official
documentation.
2019-10-18 11:44:03 +02:00
Conor Patrick
0fbc28fbc1 fix pc build 2019-10-08 16:10:29 -04:00
Conor Patrick
2a02d0de33 small errors 2019-10-08 16:10:29 -04:00
Conor Patrick
00b09e0d40 add u2f length arg 2019-10-08 16:10:29 -04:00
Conor Patrick
26db2b3f6b check FIDO2 credential IDs in U2F 2019-10-08 16:10:29 -04:00
Conor Patrick
ff88660027 fix const qualifer warnings 2019-10-08 14:43:24 -04:00
Conor Patrick
9ecfda02c5 remove atomic counter from bootloader to save space 2019-10-08 14:43:24 -04:00
Conor Patrick
9158453830
Merge pull request #238 from Nitrokey/bootloader-downgrade-protection
Bootloader downgrade protection
2019-10-08 13:53:57 -04:00
Conor Patrick
08658eb11e
Merge branch 'master' into bootloader-downgrade-protection 2019-10-08 13:44:20 -04:00
Conor Patrick
49d79fa5da reduce lines/size 2019-10-08 13:42:37 -04:00
Conor Patrick
69a7191860 fix warnings 2019-10-08 13:42:37 -04:00
Conor Patrick
a2fd507f45 typo 2019-10-08 13:42:37 -04:00
Conor Patrick
a58658e35d fix pointer 2019-10-08 13:42:37 -04:00
Conor Patrick
bb2929b28f change ctap_atomic_count to increase by user-specified amount 2019-10-08 13:42:37 -04:00
Conor Patrick
8e0eda8ed4 refactor custom commands and add LOADKEY 2019-10-08 13:42:37 -04:00
Conor Patrick
0ebe0ff502 add ctap function to overwrite key bytes 2019-10-08 13:42:37 -04:00
allcontributors[bot]
7bcb7ea840 docs: update .all-contributorsrc 2019-10-08 13:42:23 -04:00
allcontributors[bot]
811a57f7ab docs: update README.md 2019-10-08 13:42:23 -04:00
Jan A
5168afa16e Code cosmetics, added missing void statement to empty parameter of
functions
2019-10-08 12:31:08 -04:00
Nicolas Stalder
208d26be89
Merge pull request #315 from My1/patch-1
clone using https instead
2019-09-26 23:01:42 +02:00
My1
45293fe998
clone using https instead
not everyone has a github account, wants one or wants to setup ssh keys.
2019-09-26 16:11:40 +02:00
Conor Patrick
a1a42fec5c
Bump stable version to 2.5.3 2019-09-17 17:22:15 +08:00
Conor Patrick
8c256298ae default up to enabled 2019-09-17 00:13:57 +08:00
Conor Patrick
01b928c0ec allow in bootloader as well 2019-09-17 00:13:57 +08:00
Conor Patrick
018a4d394c add get_version command to hid 2019-09-17 00:13:57 +08:00
Conor Patrick
7a75fba6d3 delete old code 2019-09-17 00:13:57 +08:00
Conor Patrick
c61f15a090 allow get_assertion with disabled UP 2019-09-17 00:13:57 +08:00
Conor Patrick
f072561899 properly check the rpId in request 2019-09-17 00:13:57 +08:00
merlokk
6652feb4a2 added CID transfer and NAK-ACK sequence 2019-09-05 23:26:15 +08:00
Nicolas Stalder
fc7ea68d4a
Bump STABLE_VERSION to 2.5.2 2019-09-05 00:30:59 +02:00
Nicolas Stalder
cb116efcc9
Merge pull request #303 from StoyanDimitrov/patch-3
Typo
2019-09-03 00:48:23 +02:00
Nicolas Stalder
80b9df3e04
Merge pull request #302 from StoyanDimitrov/patch-2
Highlight command and few file names
2019-09-03 00:48:08 +02:00
Nicolas Stalder
194ef5edcf
Merge pull request #304 from StoyanDimitrov/patch-4
Fix broken formating
2019-09-03 00:47:21 +02:00
StoyanDimitrov
006117bb6b
Fix broken formating 2019-09-02 20:56:55 +00:00
StoyanDimitrov
75c75fa897
Hilight file name 2019-09-02 20:41:42 +00:00
StoyanDimitrov
2969d09ffa
Typo 2019-09-02 20:36:02 +00:00
StoyanDimitrov
b871e10d08
Highlight command and few file names 2019-09-02 20:34:20 +00:00
Conor Patrick
18d39a7047
Merge pull request #240 from Nitrokey/remove-pin-storage
Replace FIDO2 PIN storage with its hash
2019-09-02 21:50:44 +08:00
Conor Patrick
a9bbdee35b
Merge branch 'master' into remove-pin-storage 2019-09-02 21:45:21 +08:00
Conor Patrick
321bbe3691
Merge pull request #293 from solokeys/ccid
Ccid
2019-09-02 21:42:38 +08:00
merlokk
1ce191343f add checking some rare case in iso14443-4 chaining. add NAK checking and aborting the data sending. 2019-08-31 02:12:05 +08:00
Conor Patrick
9041e5903c return SW_WRONG_LENGTH for incorrect lc 2019-08-30 16:37:17 +08:00
allcontributors[bot]
689d471688 docs: update .all-contributorsrc 2019-08-30 01:46:40 +02:00
allcontributors[bot]
8b9e44c3ed docs: update README.md 2019-08-30 01:46:40 +02:00
Conor Patrick
83dd92d9ba Update STABLE_VERSION 2019-08-29 22:05:10 +08:00
Szczepan Zalega
a5e1dc2a0c
Correct linker documentation 2019-08-24 11:27:28 +02:00
Szczepan Zalega
a053bbc669
Do not verify version for the hacker edition 2019-08-24 10:26:44 +02:00
Szczepan Zalega
3621f2ed4f
Add missed doc update in the linker script 2019-08-24 10:26:41 +02:00
Szczepan Zalega
3c7bf5a264
Remove obsolete debug messages 2019-08-24 10:26:38 +02:00
Conor Patrick
8bf1921263 dont reference not-enabled ccid 2019-08-24 16:20:52 +08:00
Szczepan Zalega
e3ff136196
Remove obsolete region for the app static firmware version address 2019-08-24 10:17:59 +02:00
Szczepan Zalega
74181406fe
Rename last_addr->last_written_app_address 2019-08-24 10:17:55 +02:00
Szczepan Zalega
987b04523d
Correct memory layout 2019-08-24 10:17:52 +02:00
Szczepan Zalega
8023347c8e
Makefile: add debug info 2019-08-24 10:17:49 +02:00
Szczepan Zalega
9dae7b2e7c
Makefile: fix flashboot recipe 2019-08-24 10:17:46 +02:00
Szczepan Zalega
cb13fb65de
Store version in the bootloader. Debug code. 2019-08-24 10:17:43 +02:00
Szczepan Zalega
7fddd58704
Bootloader: get uploaded application version from the 4 last bytes of its firmware 2019-08-24 10:17:40 +02:00
Szczepan Zalega
3a1ea275cc
Move _extra* debug linker scripts content to main 2019-08-24 10:17:37 +02:00
Szczepan Zalega
22293f82f2
Rename flash2 -> flash_cfg 2019-08-24 10:17:34 +02:00
Szczepan Zalega
40c3c13b07
Correct flash2 region. Rename _bconfig_start->bootloader_configuration. 2019-08-24 10:17:30 +02:00
Szczepan Zalega
7042b0b656
Move app version to the end of the firmware code, without specific address. Move bootloader config 8B forward. 2019-08-24 10:17:27 +02:00
Szczepan Zalega
ea803aab95
Make the flash memory structure depend on the APPLICATION_START_PAGE macro 2019-08-24 10:17:24 +02:00
Szczepan Zalega
1100b159a9
Refactor. Add debug code. Use %u for unsigned. Use volatile pointer instead of memory storage. 2019-08-24 10:17:21 +02:00
Szczepan Zalega
9ddba5dfc3
Add extra linker script changes 2019-08-24 10:17:18 +02:00
Szczepan Zalega
35e52f4968
Initial modification to move bootloader data after the application 2019-08-24 10:17:15 +02:00
Szczepan Zalega
efddd2f3a8
Use the same public bootloader key as before 2019-08-24 10:17:12 +02:00
Szczepan Zalega
17ceb7b9e8
Make the public key generic 2019-08-24 10:17:09 +02:00
Szczepan Zalega
188a34d1da
Add missing Makefile entry. Rename pubkey file. 2019-08-24 10:17:05 +02:00
Szczepan Zalega
9248c6462c
Add missing is_newer and pubkey 2019-08-24 10:17:02 +02:00
Szczepan Zalega
118e129152
Set firmware version in the flash 2019-08-24 10:16:59 +02:00
Szczepan Zalega
beb5a5892c
Add linker scripts 2019-08-24 10:16:56 +02:00
Szczepan Zalega
d618081dd0
Add version code 2019-08-24 10:16:53 +02:00
Szczepan Zalega
e4e0a3a84e
Add code responsible for firmware version verification in the bootloader 2019-08-24 10:16:50 +02:00
Conor Patrick
3ba9b671fc dont use composit for bootloader 2019-08-24 16:01:44 +08:00
Conor Patrick
69c34f9ca9 Merge branch 'master' into ccid 2019-08-24 15:54:51 +08:00
Conor Patrick
3b4c154fd1 add enable macro for CCID interface 2019-08-24 15:49:02 +08:00
Conor Patrick
ccd9a04146 add ccid log tag 2019-08-24 15:08:14 +08:00
Conor Patrick
bde4c09c21 CCID basics working 2019-08-24 15:06:16 +08:00
merlokk
5d3914bc5e remove delays 2019-08-23 22:25:22 +08:00
Conor Patrick
abe306a649 Merge branch 'master' of github.com:solokeys/solo 2019-08-23 14:53:22 +08:00
Conor Patrick
41ceb78f6c add user presence to flags 2019-08-23 14:48:21 +08:00
Conor Patrick
8e192f2363 do not delay bootloader 2019-08-23 14:41:26 +08:00
Conor Patrick
affc256ca2 add delay to cap button improve reliability 2019-08-23 14:41:26 +08:00
Conor Patrick
b3ac739a35 make touch sensor edge based to avoid approving >1 transaction 2019-08-23 13:44:06 +08:00
Conor Patrick
3b53537077 refactor fido2 user presence handling & increase timeout to 29s 2019-08-23 13:19:28 +08:00
merlokk
3fad9a7a7d add response to reset command and delete debug 2019-08-23 10:43:09 +08:00
allcontributors[bot]
8973608f59 docs: update .all-contributorsrc 2019-08-22 22:42:17 +02:00
allcontributors[bot]
8af6505f6d docs: update README.md 2019-08-22 22:42:17 +02:00
merlokk
d39d7978fd small fix 2019-08-22 21:04:01 +08:00
merlokk
c972a13034 fix reboot 2019-08-22 20:55:25 +08:00
merlokk
a95e62e2ea reset 2019-08-22 20:55:25 +08:00
merlokk
c79b7abfb6 add reset placeholder 2019-08-22 20:55:25 +08:00
merlokk
dfb124dc8b refactoring 2019-08-22 20:55:12 +08:00
merlokk
972760eb78 added APDU input chaining 2019-08-22 20:55:12 +08:00
merlokk
0d621d13f9 fix decoding apdu 2019-08-22 20:55:12 +08:00
Conor Patrick
32f920e372 compile/crash fixes 2019-08-22 19:52:21 +08:00
Conor Patrick
a5aff478dd Merge branch 'master' into ccid 2019-08-22 17:13:55 +08:00
merlokk
728acc1671 chaining not needs to go to the start 2019-08-21 12:13:16 +08:00
merlokk
62b4418dac fix pck length math 2019-08-21 12:13:16 +08:00
merlokk
8059a9765f was wrong buffer 2019-08-21 12:13:16 +08:00
merlokk
b743d5fac5 sketch 2019-08-21 12:13:16 +08:00
Conor Patrick
dccfb0d1b3 stub pc build 2019-08-21 12:06:06 +08:00
Conor Patrick
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
Conor Patrick
adcbd3aeb8 speed up public key derivation slightly for nfc 2019-08-21 12:06:06 +08:00
Conor Patrick
d931954a13 remove WTX, move debug log 2019-08-21 12:06:06 +08:00
Conor Patrick
b706cc30b0 for now, always gen key agreement 2019-08-21 12:06:06 +08:00
Nicolas Stalder
57fe39704b Merge pull request #282 from solokeys/update-udev-docs
Update udev docs
2019-08-21 02:48:33 +02:00
Nicolas Stalder
4b6619b705 Update udev docs 2019-08-21 02:37:15 +02:00
Szczepan Zalega
a5877f518f
Additional assertions and reordering 2019-08-20 12:42:46 +02:00
Szczepan Zalega
5a0cc0d02c
Version used STATE data structures 2019-08-20 11:57:32 +02:00
Szczepan Zalega
b452e3dfe4
Correct doc 2019-08-20 11:47:14 +02:00
Szczepan Zalega
7f82233d17
Add missing unit for firmware compilation 2019-08-20 11:38:29 +02:00
Szczepan Zalega
8e3753e711
Add initial STATE migration code (2) 2019-08-20 11:34:51 +02:00
Szczepan Zalega
816ca21f08
Correct writing salted hash
pinHashEnc is 16 bytes, which is too small to store sha256 result.
2019-08-20 11:34:48 +02:00
Szczepan Zalega
6c60a37e8a
Add initial STATE migration code 2019-08-20 11:34:45 +02:00
Szczepan Zalega
ee351421cb
Add missing definition for the simulation to run 2019-08-20 11:34:42 +02:00
Szczepan Zalega
bac576f3a0
Make the state structure backward-compatible. Add version. 2019-08-20 11:34:39 +02:00
Szczepan Zalega
6e637299e5
Add missing declaration, and comment out wallet message 2019-08-20 11:34:35 +02:00
Szczepan Zalega
43b3e93854
Modify state struct 2019-08-20 11:34:32 +02:00
Szczepan Zalega
5a448d636c
Add comments 2019-08-20 11:34:29 +02:00
Szczepan Zalega
7be0553377
Replace FIDO2 PIN storage with its hash 2019-08-20 11:34:26 +02:00
merlokk
095b08e3d9 add some stability in small responses 2019-08-19 22:33:32 +08:00
merlokk
89e021003a small fix for HID readers 2019-08-19 22:33:32 +08:00
Emanuele Cesena
4f3d4b09eb Update README.md 2019-08-16 17:22:46 -04:00
Nicolas Stalder
3f4843b03a
Merge pull request #270 from solokeys/bump_2.4.3
Update STABLE_VERSION
2019-08-16 21:07:59 +02:00
Conor Patrick
26af0c423e Update solo-extras.md 2019-08-16 14:04:43 +08:00
Conor Patrick
19422d9daa add info for rng use 2019-08-16 14:04:43 +08:00
Conor Patrick
b7a4cf001a run through fixes 2019-08-16 14:04:43 +08:00
Conor Patrick
3927aec06d dont remove solo.hex bootloader.hex 2019-08-16 14:04:43 +08:00
Conor Patrick
f5794481ae initial draft 2019-08-16 14:04:43 +08:00
Conor Patrick
caac9d0cc1 add secure build that uses default attestation key 2019-08-16 14:04:43 +08:00
Conor Patrick
ffadab05a3 Update STABLE_VERSION 2019-08-15 19:35:54 +08:00
Conor Patrick
2423154fee fix warning 2019-08-15 18:07:40 +08:00
merlokk
cf79b7865d small fix 2019-08-15 17:50:16 +08:00
merlokk
6f0cf99c92 PPS implementation 2019-08-15 17:50:16 +08:00
Conor Patrick
7ef68fd5d3
Merge pull request #265 from solokeys/fix_cdc_interfaces
Fix cdc interfaces
2019-08-15 17:49:53 +08:00
Conor Patrick
3be8611fcf remove duplicate from merge 2019-08-15 17:44:09 +08:00
Conor Patrick
21489658a7
Merge branch 'master' into fix_cdc_interfaces 2019-08-15 17:38:57 +08:00
Conor Patrick
a07a3dee8d refactor user_presence handling 2019-08-15 17:36:35 +08:00
Conor Patrick
416da63a9a not for bootloader 2019-08-15 17:36:35 +08:00
Conor Patrick
027fa791a3 only 1 user presence auth per button press 2019-08-15 17:36:35 +08:00
Conor Patrick
3e52d7b42b cache button press for 2s 2019-08-15 17:36:35 +08:00
merlokk
301e18c6a2 add some int0 logic to main cycle 2019-08-14 14:32:03 +08:00
merlokk
44205141eb add one place for int0 2019-08-14 14:32:03 +08:00
merlokk
6e1110ca9b fix bug with ams_wait_for_tx 2019-08-14 14:32:03 +08:00
merlokk
9105b988e2 fix some warnings 2019-08-14 14:32:03 +08:00
Dan Drown
14c94ea8f5 minor typo 2019-08-14 14:26:45 +08:00
Conor Patrick
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
Conor Patrick
78280e570b adjust whitespace 2019-08-12 16:18:47 +08:00
Conor Patrick
36aec9f20b separate interface into two and add "IAD" descriptor 2019-08-12 16:18:30 +08:00
Conor Patrick
b5d3276df6 not for bootloader 2019-08-11 18:16:58 +08:00
Conor Patrick
ffd854a303 only 1 user presence auth per button press 2019-08-11 18:05:08 +08:00
Conor Patrick
349a84dcec cache button press for 2s 2019-08-11 17:59:31 +08:00
Nicolas Stalder
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
allcontributors[bot]
e1528cb248 docs: update .all-contributorsrc 2019-08-07 23:14:18 +00:00
allcontributors[bot]
e0955c190e docs: update README.md 2019-08-07 23:14:17 +00:00
Nicolas Stalder
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
allcontributors[bot]
f6c7dbdbdd docs: update .all-contributorsrc 2019-08-07 23:05:02 +00:00
allcontributors[bot]
ea1969ca94 docs: update README.md 2019-08-07 23:05:01 +00:00
Nicolas Stalder
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
allcontributors[bot]
f7fd30b9ae docs: update .all-contributorsrc 2019-08-07 22:59:27 +00:00
allcontributors[bot]
11763b6502 docs: update README.md 2019-08-07 22:59:26 +00:00
Nicolas Stalder
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
Nicolas Stalder
afed99bae9
Merge branch 'master' into all-contributors/add-rgerganov 2019-08-08 00:57:16 +02:00
Nicolas Stalder
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
allcontributors[bot]
d630254224 docs: update .all-contributorsrc 2019-08-07 22:53:47 +00:00
allcontributors[bot]
b2ac7b5479 docs: update README.md 2019-08-07 22:53:46 +00:00
Nicolas Stalder
c050b82210 editing fail 2019-08-08 00:53:23 +02:00
Nicolas Stalder
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
Nicolas Stalder
d350f9a638
Update .all-contributorsrc 2019-08-08 00:50:53 +02:00
allcontributors[bot]
53275e0182 docs: update .all-contributorsrc 2019-08-07 22:49:29 +00:00
allcontributors[bot]
2e14ac5b11 docs: update README.md 2019-08-07 22:49:28 +00:00
allcontributors[bot]
a760bed29f docs: update .all-contributorsrc 2019-08-07 22:45:57 +00:00
allcontributors[bot]
e854184a11 docs: update README.md 2019-08-07 22:45:56 +00:00
Nicolas Stalder
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
allcontributors[bot]
9be192b82f docs: update .all-contributorsrc 2019-08-07 22:44:17 +00:00
allcontributors[bot]
e95233bb5f docs: update README.md 2019-08-07 22:44:16 +00:00
Nicolas Stalder
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
allcontributors[bot]
7cfd0ccb19 docs: update .all-contributorsrc 2019-08-07 22:42:57 +00:00
allcontributors[bot]
7d84caa754 docs: update README.md 2019-08-07 22:42:56 +00:00
Nicolas Stalder
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
allcontributors[bot]
04570aaf15 docs: update .all-contributorsrc 2019-08-07 22:42:17 +00:00
allcontributors[bot]
1a3aad9761 docs: update README.md 2019-08-07 22:42:16 +00:00
Nicolas Stalder
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
allcontributors[bot]
b5e592adc9 docs: update .all-contributorsrc 2019-08-07 22:40:47 +00:00
allcontributors[bot]
1cd6692246 docs: update README.md 2019-08-07 22:40:46 +00:00
Nicolas Stalder
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
allcontributors[bot]
c2312fa69a docs: update .all-contributorsrc 2019-08-07 22:37:54 +00:00
allcontributors[bot]
832f06b6b4 docs: update README.md 2019-08-07 22:37:53 +00:00
Nicolas Stalder
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
allcontributors[bot]
434f2f89ec docs: update .all-contributorsrc 2019-08-07 22:35:54 +00:00
allcontributors[bot]
9174c00abf docs: update README.md 2019-08-07 22:35:53 +00:00
Nicolas Stalder
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
allcontributors[bot]
763995763f docs: update .all-contributorsrc 2019-08-07 22:33:40 +00:00
allcontributors[bot]
4f317863e9 docs: update README.md 2019-08-07 22:33:39 +00:00
Nicolas Stalder
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
allcontributors[bot]
86c6b3cbc8 docs: update .all-contributorsrc 2019-08-07 22:32:05 +00:00
allcontributors[bot]
a53dfb2812 docs: update README.md 2019-08-07 22:32:05 +00:00
Nicolas Stalder
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
Nicolas Stalder
76e46605e3
Merge branch 'master' into all-contributors/add-agl 2019-08-08 00:28:36 +02:00
Nicolas Stalder
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
allcontributors[bot]
018311cfab docs: update .all-contributorsrc 2019-08-07 22:24:54 +00:00
allcontributors[bot]
c37638d4cb docs: update README.md 2019-08-07 22:24:53 +00:00
allcontributors[bot]
81a67eda24 docs: update .all-contributorsrc 2019-08-07 22:23:26 +00:00
allcontributors[bot]
70c176e9ef docs: update README.md 2019-08-07 22:23:25 +00:00
Nicolas Stalder
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
allcontributors[bot]
25bf9d8e54 docs: update .all-contributorsrc 2019-08-07 21:58:17 +00:00
allcontributors[bot]
2e67a5f772 docs: update README.md 2019-08-07 21:58:16 +00:00
Nicolas Stalder
66befb96b8 Clarify that code contributions are assumed to be dual-licensed 2019-08-07 23:55:44 +02:00
Nicolas Stalder
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
Nicolas Stalder
b4b59a6d4d Merge all-contributors with existing Contributors section 2019-08-07 23:52:52 +02:00
allcontributors[bot]
c18a08b14b docs: create .all-contributorsrc 2019-08-07 21:26:37 +00:00
allcontributors[bot]
c249148d80 docs: update README.md 2019-08-07 21:26:36 +00:00
Wessel de Roode
02a51454b7 Added OsX arm install, updated FIDO2 test site links 2019-08-07 18:35:41 +02:00
Nicolas Stalder
4e3420f19f
Merge pull request #236 from Wesseldr/patch-3
Cleaned nucleo32-board.md
2019-08-06 13:48:00 +02:00
Wessel dR
6b8e575fac
Merge branch 'master' into patch-3 2019-08-06 13:43:13 +02:00
Nicolas Stalder
28788d1eeb
Merge pull request #237 from solokeys/remove_tests
Remove tests
2019-08-06 13:22:29 +02:00
Nicolas Stalder
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
Wessel de Roode
6dfe42e486 All cleaned up now ? 2019-08-06 13:11:51 +02:00
Wessel de Roode
29b2032dae fixing final-definitions and misc 2019-08-06 13:06:06 +02:00
Conor Patrick
f9f1e96c73 Update README.md 2019-08-06 18:54:57 +08:00
Conor Patrick
e2738d11d3 remove tests 2019-08-06 18:50:05 +08:00
Wessel dR
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
Wessel dR
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
Wessel dR
09d450ed02
Little typo
Fixes https://github.com/Nitrokey/nitrokey-fido2-firmware/pull/19
2019-08-05 16:04:19 +02:00
Szczepan Zalega
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
Szczepan Zalega
420d052ac9
Describe running Solo on the Nucleo32 board
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2019-08-05 16:00:27 +02:00
Nicolas Stalder
3698c942a2
Merge pull request #233 from solokeys/bump
Update STABLE_VERSION
2019-07-29 22:40:20 +02:00
Conor Patrick
17a170bb90 Update STABLE_VERSION 2019-07-29 14:58:30 -04:00
Conor Patrick
d4e61421b6
Merge pull request #232 from solokeys/windows_hello_error_codes
Windows hello response codes
2019-07-29 14:09:48 -04:00
Conor Patrick
690d7c716a move CTAPHID_STATUS_PROCESSING to after UP 2019-07-29 12:39:59 -04:00
Conor Patrick
78e3b291c2 make sure device status is set in all user presence tests 2019-07-28 22:10:56 -04:00
Conor Patrick
b47854c335 use error code PIN_AUTH_INVALID 2019-07-28 21:41:11 -04:00
Conor Patrick
2af747ddaa
Merge pull request #229 from solokeys/fix-hmac-secret
Fix hmac secret
2019-07-27 12:49:30 -04:00
Conor Patrick
9ead11de8d
Merge pull request #224 from solokeys/fault_tolerance
limit length of wLength
2019-07-27 12:47:28 -04:00
Conor Patrick
f17faca689 use correct size for auth_data for signature 2019-07-26 23:53:20 -04:00
Conor Patrick
ca66b6e43b verify signature for hmac-secret 2019-07-26 23:51:39 -04:00
Conor Patrick
1cd1b3c295 check attestation signature on all MC requests 2019-07-26 23:50:23 -04:00
Conor Patrick
df2cff2350 patch hmac final to use correct key 2019-07-26 23:49:55 -04:00
Conor Patrick
f5d50e001d test assertions work post reboot 2019-07-26 19:00:07 -04:00
Nicolas Stalder
235785b225
Bump stable version to 2.4.0 2019-07-17 23:42:56 +02:00
Conor Patrick
303c42901a limit length of wLength 2019-07-15 11:32:02 -04:00
Conor Patrick
df2f950e69
Merge pull request #217 from merlokk/extapdu
Extended length apdu, iso14443 chaining and select
2019-07-08 22:03:02 -04:00
Conor Patrick
10bf4242e1 fail with more import related info 2019-07-08 21:54:48 -04:00
Conor Patrick
9e95b0075c default no serial printing 2019-07-08 21:54:36 -04:00
Conor Patrick
ddbe31776c
Merge pull request #220 from merlokk/obt_src
added text how to obtain source code
2019-07-08 21:22:48 -04:00
merlokk
645ca6a5a0 add 3-space list 2019-07-08 18:12:28 +03:00
merlokk
15fc39faed added text how to obtain source code 2019-07-08 17:58:57 +03:00
merlokk
a1eedc0048 small fix 2019-07-06 13:09:19 +03:00
merlokk
89e00482e4 some improvements 2019-07-06 12:52:23 +03:00
merlokk
533ce39237 fix nfc_cc length 2019-07-06 00:15:21 +03:00
Conor Patrick
63ee003535
Merge pull request #202 from winksaville/patch-1
Update building.md
2019-07-05 10:29:40 -04:00
merlokk
fa9408d5d6 fix u2f tests 2019-07-05 12:39:32 +03:00
merlokk
ed9689435d APDU_FIDO_U2F_VERSION 2019-07-05 12:33:23 +03:00
merlokk
24a006068d fix extended apdu decode 2019-07-05 12:25:46 +03:00
merlokk
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
merlokk
4d9285085f fix tests 2019-07-04 20:42:24 +03:00
merlokk
2272e69e15 fix tests 2019-07-04 20:14:24 +03:00
merlokk
151e1d0e9b fix some errors in tests 2019-07-04 20:09:47 +03:00
merlokk
d1df8b8b77 u2f authenticate fix 2019-07-04 19:54:00 +03:00
merlokk
cb76c34ed2 fix addressing 2019-07-04 19:45:09 +03:00
merlokk
f2ebaf6abe invalid cla and r-block works 2019-07-04 19:14:26 +03:00
merlokk
4845d2c172 fix 14443 apdu decode and select 2019-07-04 17:52:00 +03:00
merlokk
75b1d9cd01 offset calc refactoring 2019-07-04 17:38:34 +03:00
merlokk
26bc8a2889 apdu decoding works 2019-07-04 17:27:03 +03:00
merlokk
88a8eba424 gitignore 2019-07-04 16:32:11 +03:00
merlokk
d2c85881e6 applet selection and apdu check 2019-07-04 16:29:30 +03:00
merlokk
236498ee03 add make 2019-07-04 16:27:57 +03:00
merlokk
a51c9192b1 add apdu_decode 2019-07-04 16:27:33 +03:00
merlokk
4dc6bcf771 apdu decode sketch 2019-07-03 23:01:37 +03:00
merlokk
cce81b23d9 Merge branch 'master' of https://github.com/merlokk/solo into extapdu 2019-07-03 22:59:41 +03:00
merlokk
8c2e2386a9 fix NFC applet selection does not work correctly #213 2019-07-03 20:35:50 +03:00
Conor Patrick
c783a1442a
Merge pull request #215 from merlokk/nfc-testing
Nfc testing
2019-07-03 11:37:19 -04:00
merlokk
b61e5db736 style 2019-07-03 17:57:27 +03:00
merlokk
b41cd5d5b8 add nfc test force flag 2019-07-03 17:54:53 +03:00
merlokk
b42e990f67 format fix 2019-07-03 01:39:38 +03:00
merlokk
ff53bb1e32 fix style 2019-07-03 01:16:55 +03:00
merlokk
2d72e02051 remove unused lib 2019-07-03 01:03:34 +03:00
merlokk
91c77da179 cbor.loads changed to cbor.decode_from 2019-07-03 00:43:51 +03:00
merlokk
795cf5c4a1 selecting NFC key works 2019-07-02 19:55:04 +03:00
merlokk
d1722b85af add library not found error 2019-07-02 19:45:46 +03:00
merlokk
2c500fe25a check pyscard module first 2019-06-28 12:32:52 +03:00
merlokk
751b2fd69c add nfc device search 2019-06-28 12:16:59 +03:00
Nicolas Stalder
c2216929a9
Create SECURITY.md 2019-06-14 00:19:14 +02:00
Conor Patrick
a51417bf61 fix epout connection 2019-05-31 15:58:13 -04:00
Wink Saville
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
Conor Patrick
dd4ff920ad
Merge pull request #200 from solokeys/persistedkey
use persisted key info
2019-05-28 18:36:50 -04:00
Conor Patrick
bddd60c080 use persisted key info 2019-05-27 13:54:29 -04:00
Conor Patrick
ba581db49c delete excess 2019-05-21 20:17:44 -04:00
Conor Patrick
3a5cd786dc enumerates correctly 2019-05-21 20:17:37 -04:00
Conor Patrick
5f878ff022
Merge pull request #196 from solokeys/fido2-conformance
Fido2 conformance
2019-05-19 12:24:36 -04:00
Conor Patrick
14f91a6e15 add screenshots of tests passing 2019-05-19 12:24:15 -04:00
Conor Patrick
4fad28ea47 compile new class 2019-05-18 21:47:51 -04:00
Conor Patrick
0ff9870612 add interface descriptor 2019-05-18 21:26:18 -04:00
Conor Patrick
cd29a0e0fe python black 2019-05-18 21:11:22 -04:00
Conor Patrick
46b7f9a778 add UP as UV method for when PIN is not set 2019-05-18 14:35:30 -04:00
Conor Patrick
31328fe7e7 dont fail when public key type is too large 2019-05-18 14:34:54 -04:00
Nicolas Stalder
035b1a8632
Merge pull request #195 from solokeys/bump_2.3.0
Update STABLE_VERSION
2019-05-13 23:11:33 +02:00
Conor Patrick
b1563dbe94 Update STABLE_VERSION 2019-05-13 16:43:14 -04:00
Conor Patrick
2a9e3ac576
Merge pull request #194 from solokeys/sanitize
fix potential memory leaks
2019-05-13 16:10:42 -04:00
Conor Patrick
e1474e8e8e fix potential memory leaks 2019-05-13 15:32:04 -04:00
Conor Patrick
1564df5305
Merge pull request #192 from solokeys/cap
Capacitive touch sensing
2019-05-13 14:30:37 -04:00
Emanuele Cesena
1f3db3fe51
Fix image in README 2019-05-12 09:41:12 -07:00
Conor Patrick
36876e1528 fix build 2019-05-10 15:57:57 -04:00
Conor Patrick
0f50ae7d63 change u2f to return early if button not immediately pressed 2019-05-10 15:56:52 -04:00
Conor Patrick
4854192c63 decrease sensitivity slightly 2019-05-09 18:37:17 -04:00
Conor Patrick
e105afd647 fix build 2019-05-09 17:51:41 -04:00
Conor Patrick
9fb02d4da3 add UP wait HID messages to U2F for windows 2019-05-09 17:46:01 -04:00
Conor Patrick
e402d36bf1 fix user presence skipping for nfc 2019-05-09 17:26:28 -04:00
Conor Patrick
54792b345c status fix 2019-05-09 16:07:05 -04:00
Conor Patrick
84740f3d6a changes to make firmware interop on all hw models 2019-05-09 16:01:07 -04:00
Conor Patrick
4ac61f7f18 slight cleanup 2019-05-09 14:53:22 -04:00
Conor Patrick
30cfa46186 fix gpio pin reading 2019-05-09 14:17:50 -04:00
Conor Patrick
aca28fde61 add to bootloader 2019-05-09 02:44:17 -04:00
Conor Patrick
60e3d01e0d refactor 2019-05-09 02:44:04 -04:00
Conor Patrick
aff8d10432 connect to application 2019-05-09 02:26:32 -04:00
Conor Patrick
898d45f871 bugfix 2019-05-09 01:34:54 -04:00
Conor Patrick
2b2835b823 initial cap sensing boilerplate 2019-05-08 22:26:57 -04:00
Conor Patrick
f9202b2b6a
Merge pull request #186 from solokeys/bump2.2.2
bump
2019-04-24 20:39:00 -04:00
Conor Patrick
1b74f6a93b bump 2019-04-24 20:38:00 -04:00
Conor Patrick
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
Conor Patrick
09b73d694f fix build 2019-04-24 19:33:26 -04:00
Conor Patrick
9ab5e761c3 Update tinycbor 2019-04-24 19:04:33 -04:00
Conor Patrick
b3604f49ba use ctap2 instead of client 2019-04-24 19:00:32 -04:00
Conor Patrick
6ae1cd3865 remove not-useful logs 2019-04-24 18:36:36 -04:00
Conor Patrick
f9d3b9561d test that getassertions are correct for solo ext 2019-04-24 18:27:11 -04:00
Conor Patrick
ec98af115f restore button in ctap_make_auth_data 2019-04-24 16:54:26 -04:00
Conor Patrick
fecf258116 disable wallet by default 2019-04-24 16:44:25 -04:00
Conor Patrick
437f691d12 Update solo.c 2019-04-24 16:41:22 -04:00
Conor Patrick
55aadfd78e add delay implementation 2019-04-24 11:45:41 -04:00
Conor Patrick
813eb97d2f reuse memory for allow_list of creds 2019-04-24 11:45:30 -04:00
Nicolas Stalder
32afdccfb3
Rebump 2019-04-24 17:41:08 +02:00
Conor Patrick
41ae0e4a2c Update application.mk 2019-04-24 00:16:19 -04:00
Conor Patrick
b0baace2e7 move custom credid to different location 2019-04-24 00:15:32 -04:00
Conor Patrick
6ff4200f5d unbump 2019-04-23 21:58:26 -04:00
Conor Patrick
1fab0b8f1f add wallet api in as compile option 2019-04-23 21:57:50 -04:00
Conor Patrick
ce96fffddd add info to authData for ext reqs 2019-04-23 21:57:27 -04:00
Conor Patrick
4fb25e165a remove old web assets 2019-04-23 21:15:11 -04:00
Conor Patrick
8fc0da7934 move args to device_init 2019-04-23 21:12:40 -04:00
Conor Patrick
494e856198
Merge pull request #131 from rgerganov/hidg
Add support for hidg devices on Linux
2019-04-23 20:22:33 -04:00
Conor Patrick
472b094acb bump 2019-04-23 20:21:19 -04:00
Conor Patrick
e0ce23034f
Merge pull request #180 from solokeys/test_pin_fixes
Test pin fixes
2019-04-23 19:58:44 -04:00
Conor Patrick
5f3974a4e6
Merge pull request #182 from solokeys/nfc_adjustments
Nfc adjustments
2019-04-23 19:42:14 -04:00
Conor Patrick
26adac1730 size optimize tinycbor 2019-04-23 19:17:18 -04:00
Conor Patrick
eab8b81c95 include nfc in user presence test 2019-04-23 14:05:18 -04:00
Conor Patrick
325396d518 dont change clock freq if powered 2019-04-23 13:54:23 -04:00
Conor Patrick
6d04c86018 update lowFreq flag correctly 2019-04-23 13:54:10 -04:00
Conor Patrick
56d6624e4e Test correct alg parameter #179 2019-04-22 16:26:26 -04:00
Conor Patrick
3094c87b0a Test empty pinAuth in MC and GA #179 2019-04-22 16:25:08 -04:00
Conor Patrick
212f98e384
Merge pull request #179 from agl/pinfixes
Couple of fixes for PIN support
2019-04-22 16:11:34 -04:00
Adam Langley
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
Adam Langley
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
Conor Patrick
f28cf9c6d0 new release 2019-04-18 20:41:18 -07:00
Conor Patrick
6068fb9868
Merge pull request #173 from solokeys/fix_u2f_on_fido2
Fix u2f on fido2
2019-04-17 22:42:38 -04:00
Nicolas Stalder
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
Radoslav Gerganov
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
Conor Patrick
74cbe00e3b Enable debug logs for >0 2019-04-14 15:13:39 -04:00
Conor Patrick
7e490f17fc delete 2019-04-13 22:42:16 -04:00
Conor Patrick
9bb706987f solo ext bugfix 2019-04-13 22:42:05 -04:00
Conor Patrick
88a759566d Improve testing 2019-04-13 22:37:47 -04:00
Conor Patrick
44fa3bbb8e Add checks to use U2F key if necessary 2019-04-13 22:37:31 -04:00
Conor Patrick
89e9296825 Add test 2019-04-13 20:43:26 -04:00
Conor Patrick
873d65b823
Merge pull request #172 from StoyanDimitrov/patch-1
Improve readability of code filenames
2019-04-13 11:54:55 -04:00
StoyanDimitrov
eb8e3ed46a
Improve readability of code filenames 2019-04-13 15:31:35 +00:00
Conor Patrick
8b97276e32
Merge pull request #171 from solokeys/fix_cbor
Fix cbor
2019-04-12 12:04:01 -04:00
Conor Patrick
78579c27dc Refactor and self test the CBOR sorting 2019-04-11 13:42:17 -04:00
Conor Patrick
ca80329b4c Compare string length and sort from start of string 2019-04-11 13:22:55 -04:00
Conor Patrick
7a49169492 consider major type and refactor 2019-04-11 00:04:33 -04:00
Conor Patrick
46dd4fe818 unused import 2019-04-10 13:56:23 -04:00
Conor Patrick
c71bbd8689 re-enable all tests 2019-04-10 13:42:38 -04:00
Conor Patrick
7068be9cd5 reorder options 2019-04-10 13:13:38 -04:00
Conor Patrick
f8635f1682 refactor tests 2019-04-10 13:12:33 -04:00
Conor Patrick
ffa9ad4923 refactor cbor sorting test 2019-04-10 12:47:39 -04:00
Conor Patrick
5fc8d214fd remove add_user param 2019-04-10 12:47:23 -04:00
Conor Patrick
5f49f4680e re-order items in get_assertion response 2019-04-10 12:22:35 -04:00
Conor Patrick
86393c46b4 Test it is correct 2019-04-10 12:11:43 -04:00
Conor Patrick
4cc72bcd97 rearrange cbor encoding order in make_credential and get_info 2019-04-10 12:11:31 -04:00
Nicolas Stalder
5e0edf3e11
Update index.md 2019-04-06 21:45:51 +02:00
Nicolas Stalder
bd810fff87
Merge pull request #165 from ehershey/patch-3
More docs fixups
2019-04-06 21:41:19 +02:00
Nicolas Stalder
d9fb508949
Merge pull request #166 from ehershey/patch-2
include markdown-include mkdocs dependency
2019-04-06 21:40:13 +02:00
Ernie Hershey
c2b7acb6aa
include markdown-include mkdocs dependency 2019-04-06 15:29:16 -04:00
Ernie Hershey
4690a7ce65
More docs fixups 2019-04-06 13:50:51 -04:00
Conor Patrick
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
Conor Patrick
f5c6f99423
Merge pull request #164 from ehershey/patch-2
Docs fixups
2019-04-06 13:40:51 -04:00
Ernie Hershey
96de4f0850
Docs fixups
Spelling, grammar
2019-04-06 13:28:16 -04:00
Ernie Hershey
331ebdfccf
link to readme and reference TC in docs start page 2019-04-06 13:20:10 -04:00
Nicolas Stalder
a6a6d653ad
Update README.md 2019-04-06 14:49:44 +02:00
Nicolas Stalder
928bc0216d
Merge pull request #161 from solokeys/bump_2.1.0
bump to 2.1.0
2019-04-02 01:31:48 +02:00
Conor Patrick
6d52c9ede7 bump to 2.1.0 2019-03-31 23:49:29 -04:00
Conor Patrick
89769ecc18 fix u2f counter for real 2019-03-31 23:29:00 -04:00
Conor Patrick
3b3f47bfcf
Merge pull request #155 from solokeys/pin_lockout_ga
Pin lockout ga
2019-03-29 17:11:48 -04:00
Conor Patrick
6fa443b0bc tests for GA without pin 2019-03-26 19:00:42 -04:00
Conor Patrick
893d4131b2 change how pin is enforced for GA 2019-03-26 19:00:12 -04:00
Conor Patrick
4e21c0bd8f
Merge pull request #152 from solokeys/testing_yubikey
Testing yubikey
2019-03-26 18:33:03 -04:00
Conor Patrick
251eb6bf64 Merge branch 'master' into testing_yubikey 2019-03-26 16:36:08 -04:00
Conor Patrick
08e236df69 fix code quality issues x/2 2019-03-26 16:14:28 -04:00
Conor Patrick
d2091563ab fix code quality issues 2019-03-26 16:09:30 -04:00
Conor Patrick
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
Nicolas Stalder
40b9dae38a Fix buffer overrun and use correct size for random u32 2019-03-26 01:55:42 +01:00
Nicolas Stalder
98a209e330 make target to flash firmware via bootloader 2019-03-23 13:54:04 +01:00
Nicolas Stalder
d3b5fb68ee Build debug 1/2 versions of hacker firmware and bundle 2019-03-23 13:52:47 +01:00
Conor Patrick
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
Nicolas Stalder
e21172fff8
Merge pull request #149 from solokeys/hmac-secret
Hmac-secret
2019-03-22 22:05:41 +01:00
Nicolas Stalder
9d3144e9b1 oops. black 2019-03-22 21:56:18 +01:00
Nicolas Stalder
a2a774125f Fix usage and display fido2-ext in it 2019-03-22 21:40:55 +01:00
Nicolas Stalder
349ea5343a Remove paranoid MM stuff, not signaling AT modem is enough + better 2019-03-22 20:01:31 +01:00
Nicolas Stalder
c851807376 Do not advertise AT modem capabilities 2019-03-22 20:00:02 +01:00
Nicolas Stalder
84d1629aa3 Allow toggling between strict and paranoid ModemManager filter-policy 2019-03-22 20:00:02 +01:00
Nicolas Stalder
8f6ae29163 Fix ModemManager udev rule for some distros 2019-03-22 20:00:02 +01:00
Conor Patrick
a0d27c2c56 add memory layout commment, undo -8 simplification 2019-03-22 19:55:25 +01:00
Conor Patrick
3a10427bd9 remove unused files 2019-03-22 19:55:25 +01:00
Nicolas Stalder
f3b591e570 Apply suggestions from code review
Co-Authored-By: conorpp <conorpp94@gmail.com>
2019-03-22 19:55:25 +01:00
Conor Patrick
175f59d206 paste into other linker scripts 2019-03-22 19:55:25 +01:00
Conor Patrick
f5ff6a11f0 rewrite base linker script 2019-03-22 19:55:25 +01:00
Conor Patrick
d979420324 u2f work with yubikey5 2019-03-22 01:59:19 -04:00
Conor Patrick
5076af1be4 works with yubikey5 2019-03-22 01:22:55 -04:00
Conor Patrick
0a7845459c breakup test_fido2 2019-03-22 00:45:28 -04:00
Conor Patrick
c4262b0f5b rename 2019-03-22 00:20:48 -04:00
Conor Patrick
53fb0059a7 break into separate files 2019-03-22 00:20:20 -04:00
Conor Patrick
a1a75e4ab5 check errors 2019-03-21 12:47:15 -04:00
Conor Patrick
d68011ef04 remove warnings 2019-03-21 00:01:37 -04:00
Conor Patrick
02e83073e0 add hmac-secret to reg response 2019-03-20 23:58:42 -04:00
Conor Patrick
3a48756f96 remove extra layer of map 2019-03-20 23:40:58 -04:00
Conor Patrick
946e932b1e refactor to use less ram 2019-03-20 23:28:45 -04:00
Conor Patrick
142d4002e5 remove warning, reduce memory 2019-03-20 23:14:17 -04:00
Conor Patrick
dbe5283e1f test solo commands on fido2 layer 2019-03-20 21:06:18 -04:00
Conor Patrick
2d233f164e small bug fixes 2019-03-20 21:03:03 -04:00
Conor Patrick
b62e9906c7 make new function 2019-03-20 20:13:16 -04:00
Conor Patrick
e22e636475 hmac-secret tested 2019-03-20 20:03:25 -04:00
Conor Patrick
074225d87a hmac-secret fully functional 2019-03-20 20:03:12 -04:00
Conor Patrick
bb9b2ea9d4 validate saltAuth 2019-03-20 18:10:52 -04:00
Conor Patrick
e8d5bc5829 refactor ctap_make_auth_data arguments 2019-03-20 17:43:50 -04:00
Conor Patrick
850381a633 test parsing 2019-03-20 16:52:10 -04:00
Conor Patrick
ce3ad0e56f bugfix 2019-03-20 16:51:58 -04:00
Conor Patrick
00d86379e5 parse full hmac-secret 2019-03-20 16:21:21 -04:00
Conor Patrick
6098810167 start to test hmac-secret 2019-03-20 15:45:35 -04:00
Conor Patrick
821880a8d6 parse extension info in MC 2019-03-20 15:45:10 -04:00
Conor Patrick
44f96f5843
Merge pull request #148 from solokeys/testing_refactor
Testing refactor
2019-03-20 15:06:12 -04:00
Conor Patrick
6ec9fb962a delay send_raw in test 2019-03-20 14:59:31 -04:00
Conor Patrick
c9bfe001ee refactored version, previously lost 2019-03-20 14:56:52 -04:00
Nicolas Stalder
5e46fd96ac
Create LICENSE 2019-03-19 16:29:39 +01:00
Nicolas Stalder
103cc3cfb0
Some fun with shields 2019-03-19 16:28:47 +01:00
Conor Patrick
9544330dc3 delay send_raw in test 2019-03-18 04:36:02 +01:00
Conor Patrick
0964ff69b7 refactor a bit 2019-03-18 04:36:02 +01:00
Nicolas Stalder
e4a2b9e1ca Get udev instructions up to date 2019-03-18 02:52:34 +01:00
Conor Patrick
d29fa34da1
Update README.md 2019-03-15 22:08:07 -04:00
Conor Patrick
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
Nicolas Stalder
3b9d4e5023 Set STABLE_VERSION to 2.0.0 2019-03-15 00:35:50 +01:00
Conor Patrick
2da083c18a
Merge pull request #138 from solokeys/fix-warning
I think this does it
2019-03-11 14:33:02 -04:00
Nicolas Stalder
50bfbc1eff I think this does it 2019-03-10 15:26:45 +01:00
Nicolas Stalder
86739df7a1 Improvements to Docker build 2019-03-10 15:19:16 +01:00
Nicolas Stalder
c7f0d050d7 Fix udev rule for STM bootloader 2019-03-08 14:25:29 +01:00
Conor Patrick
b79670a447
Merge pull request #133 from solokeys/more_testing
More testing
2019-03-07 21:25:53 -05:00
Conor Patrick
169ba59ed4 use alpha 2019-03-07 21:19:10 -05:00
Conor Patrick
f3003c58c9 new release 2.0.0 2019-03-07 20:33:20 -05:00
Conor Patrick
084e518018 refactor 2019-03-06 17:43:28 -05:00
Conor Patrick
6674f0a8ff add more tests 2019-03-06 16:17:12 -05:00
Conor Patrick
f704851419 add bootloader tests 2019-03-06 14:23:56 -05:00
Conor Patrick
0d5e1ee872 Test solo specific commands 2019-03-06 14:06:07 -05:00
Conor Patrick
5cb81c753d Add version/extensions to PC build 2019-03-06 14:05:44 -05:00
Conor Patrick
b0b0564df9 fix imports 2019-03-06 13:13:43 -05:00
Conor Patrick
195dc2a8ae use 0x7f as upper counter byte 2019-03-04 02:36:47 -05:00
Conor Patrick
4982b13f64
Merge pull request #129 from solokeys/testing_fido2
Testing fido2
2019-03-04 02:26:06 -05:00
Conor Patrick
63a93f6ec2 test pin lock out 2019-03-03 19:01:08 -05:00
Conor Patrick
7b8ec18e76 add reboot capability for tests 2019-03-03 18:43:14 -05:00
Conor Patrick
67faef0117 tests for client pin 2019-03-03 17:17:04 -05:00
Conor Patrick
0b9f0af3c7 spin pc less 2019-03-03 17:15:26 -05:00
Conor Patrick
880d54a4f0 more fido2 tests 2019-03-03 03:43:15 -05:00
Conor Patrick
1507758ad1 bring pc crypto impl up to date 2019-03-02 23:10:43 -05:00
Conor Patrick
e883c5aa6e add many fido2 tests 2019-03-02 22:40:51 -05:00
Conor Patrick
afc85e0d2e update log message 2019-03-02 22:40:27 -05:00
Conor Patrick
a40dcf3f17 reduce nfc detect period to 10ms 2019-03-02 20:08:28 -05:00
Conor Patrick
4b82e80d7a init device with nfc detection 2019-03-02 20:08:15 -05:00
Conor Patrick
246dea8a44 fix clock init by setting flash latency last for low freqs 2019-03-02 20:05:27 -05:00
Conor Patrick
7a98764a5b organize ECC flags 2019-03-02 19:48:09 -05:00
Conor Patrick
dc946f5b35 centralize reset key agreement 2019-03-02 19:38:27 -05:00
Conor Patrick
0232893611 increase buffer size for USB strings, check string length 2019-03-02 19:38:03 -05:00
Conor Patrick
5995f84822 buffering logs sometimes freezes, stop for now 2019-03-02 15:43:12 -05:00
Conor Patrick
1ff00895b1 init nfc, fix freeze 2019-03-02 02:02:01 -05:00
Conor Patrick
83641b3789 disable clock settings for NFC passive for now 2019-03-02 01:30:09 -05:00
Conor Patrick
9b356076c5
Merge pull request #127 from solokeys/testing
Testing
2019-03-02 01:12:48 -05:00
Conor Patrick
6c96521c7d slight cleanup 2019-03-02 00:55:46 -05:00
Conor Patrick
35707c3797 wrong size, causes RK's to be overwritten 2019-03-02 00:55:25 -05:00
Conor Patrick
e31e703afd minor improvements 2019-03-01 23:42:22 -05:00
Conor Patrick
3a8be9eef7 add more u2f tests 2019-03-01 23:16:48 -05:00
Conor Patrick
e2b30ec087 basic interface 2019-03-01 22:35:50 -05:00
Conor Patrick
495e10f3a1 add basic rk support for pc 2019-03-01 22:28:25 -05:00
Conor Patrick
11ca6bd517 fix pc testing 2019-03-01 22:11:36 -05:00
Conor Patrick
a265da09fb Update u2f.c 2019-03-01 22:00:17 -05:00
Conor Patrick
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
Conor Patrick
32f2436380
Merge pull request #120 from nickray/sha512
SHA512 (via Cifra)
2019-03-01 21:44:13 -05:00
Conor Patrick
7255c4f8db
Merge pull request #121 from solokeys/nfc
Nfc
2019-03-01 21:43:12 -05:00
Conor Patrick
4e215db42a start from 0 2019-02-28 23:13:12 -05:00
Conor Patrick
a1ad641076 Merge branch 'master' of github.com:solokeys/solo 2019-02-28 22:47:25 -05:00
Nicolas Stalder
daf56b0cc7 Silence warning about out of date pip in Travis 2019-02-28 01:06:06 +01:00
Nicolas Stalder
5859073cb8 Build bundle-hacker-{version}.hex 2019-02-28 01:06:06 +01:00
Nicolas Stalder
ff5207ba77 First attempt 2019-02-27 21:43:20 +01:00
Nicolas Stalder
324b4a89cc Remove python-fido2 submodule 2019-02-27 21:43:20 +01:00
Conor Patrick
9f60caf9c1 for docker on windows 2019-02-26 22:00:21 -05:00
Nicolas Stalder
0865f2a660 do not probe bootloader 2019-02-27 03:18:12 +01:00
Conor Patrick
b1c72c9d94 for docker on windows 2019-02-26 21:11:33 -05:00
Nicolas Stalder
5e70c11b54 Hide onboard crypto tests behind a reserved ctaphid command 2019-02-27 02:58:56 +01:00
Conor Patrick
46ada5a8b9 WRONG_DATA apdu error code fix 2019-02-26 20:34:07 -05:00
Conor Patrick
0eac67259d remove stm32l442 target 2019-02-26 18:24:40 -05:00
Nicolas Stalder
9399a5f195 Cleanup udev rules, keep 99-solo.rules as symlink 2019-02-27 00:00:49 +01:00
Nicolas Stalder
47aa287480 Vanilla cifra needs more includes 2019-02-26 23:50:01 +01:00
Nicolas Stalder
865b698bed ...and bootloader 2019-02-26 23:33:57 +01:00
Conor Patrick
14974e0ebe fix compile issues 2019-02-26 15:30:57 -05:00
Conor Patrick
1ed7833c9f fix pc build 2019-02-26 15:08:09 -05:00
Conor Patrick
e8d0ad5e7c autodetect passive nfc operation or usb operation 2019-02-26 15:04:23 -05:00
Conor Patrick
e2ca7f52db optimize ecc for arm 2019-02-26 14:19:07 -05:00
Nicolas Stalder
c97b9f9b8f Need includes in main Makefile too 2019-02-26 20:16:38 +01:00
Conor Patrick
ecf994b647 fix warnings and compile errors 2019-02-26 14:13:29 -05:00
Conor Patrick
347d0942b1 refactor fromNFC 2019-02-26 14:07:27 -05:00
Conor Patrick
ff0d42c8d5 refactor clock rates, fix warnings 2019-02-26 13:56:06 -05:00
Nicolas Stalder
a6673b0917 Use our cifra fork, rename command, keep room for sha256 2019-02-26 19:52:59 +01:00
Nicolas Stalder
0c296bba30 First go at using cifra for SHA512 2019-02-26 19:52:59 +01:00
Conor Patrick
57930aaa13 fix compilation errors 2019-02-26 13:27:25 -05:00
Conor Patrick
1a6895ca25 merge 2019-02-26 13:10:16 -05:00
Conor Patrick
54241ecd42 add option 'sim' to select UDP/simulated backend 2019-02-26 18:37:42 +01:00
Conor Patrick
e537d00173 update to new fido2 version 2019-02-26 18:37:42 +01:00
Conor Patrick
a195408a11 scale up to 24 MHz only for register 2019-02-26 01:51:07 -05:00
Conor Patrick
54b7f42056 passive operation works as is (refactor needed) 2019-02-26 01:19:35 -05:00
Conor Patrick
6128e86da2
Merge pull request #114 from merlokk/nfc4
NFC. added hardware part of UID
2019-02-19 22:05:15 -05:00
merlokk
fed9f473aa added hardware part of UID 2019-02-19 18:12:01 +02:00
Nicolas Stalder
f6ff3c1b87 Fetch tags in docker build script. More robust udev rules in docs 2019-02-19 00:32:07 +01:00
Conor Patrick
afd3218358 Create CHANGELOG.md 2019-02-17 18:19:30 -05:00
Conor Patrick
3b320e0aeb initialize at 24 MHz at very start instead of 16 2019-02-12 18:34:13 -05:00
Conor Patrick
529b879c08 init in device_init 2019-02-11 22:02:41 -05:00
Conor Patrick
2893cd7ce3 move inits to device_init 2019-02-11 22:00:18 -05:00
Conor Patrick
120fb95541 compile for bootloader 2019-02-08 13:09:32 -05:00
Conor Patrick
665e84d183 delay to allow spi interface to initialize 2019-02-08 13:09:12 -05:00
Conor Patrick
13d9885da4 initialize at 16MHz, add 24 and 32 options 2019-02-08 13:08:28 -05:00
Conor Patrick
e230a9464e enable ctap from usb 2019-02-07 20:09:13 -05:00
Conor Patrick
342af18b1f initialize ctap 2019-02-07 20:09:00 -05:00
Conor Patrick
be9bd941c8 simplify ams init 2019-02-07 19:45:02 -05:00
Conor Patrick
0f6be6740b
Merge pull request #101 from merlokk/nfc2
Nfc2
2019-02-07 19:14:12 -05:00
Conor Patrick
9054736e0e delete debugging code 2019-02-07 19:03:45 -05:00
merlokk
c6d946136e small fix 2019-02-07 16:05:08 +02:00
Oleg Moiseenko
32400c8d09
Merge branch 'nfc' into nfc2 2019-02-07 14:49:47 +02:00
Conor Patrick
587c9aad14 refactor 2019-02-06 18:09:53 -05:00
Conor Patrick
c624a32ef6 default 8 thread build 2019-02-06 18:07:38 -05:00
Conor Patrick
3005a63938 re-arrange some logic for better passive operation 2019-02-06 18:07:09 -05:00
Conor Patrick
f470e9a9cd dont need to init clock at first in bootloader 2019-02-06 18:05:22 -05:00
Conor Patrick
e3971a5e0f change ams init, read less regs 2019-02-06 17:56:53 -05:00
Conor Patrick
2ed8667f18 immedately change clock rate to load data sections faster 2019-02-06 17:55:27 -05:00
Conor Patrick
765d532f82 add low freq clocking options 4,8,16MHz 2019-02-06 17:54:52 -05:00
merlokk
ca05385513 log fixing 2019-02-06 20:06:46 +02:00
merlokk
5328610ff1 delete debug messages 2019-02-06 19:51:32 +02:00
merlokk
bc1bb3509f move APDU dumps to separate log channel 2019-02-06 19:21:06 +02:00
merlokk
375db69e3a fido2 works 2019-02-06 19:06:49 +02:00
merlokk
771fffe329 WTX works. todo: clean debug unneeded messages 2019-02-06 17:12:22 +02:00
merlokk
4611f05051 small fix in AMS3956 debug texts 2019-02-06 15:17:52 +02:00
merlokk
e657e26886 check AMS product type 2019-02-06 15:15:37 +02:00
merlokk
3ffcc47374 fix logger 2019-02-06 14:11:49 +02:00
Conor Patrick
1b5e230d45 merge u2f endian fix 2019-02-02 00:32:36 -05:00
Conor Patrick
81a89ed6aa go back to high freq 2019-02-02 00:29:32 -05:00
Conor Patrick
ca2074de36 Update Makefile 2019-02-02 00:25:01 -05:00
Conor Patrick
ee98340a03 temporarily remove prints at start 2019-02-02 00:24:42 -05:00
Conor Patrick
3d0d91fa5c lf param 2019-02-02 00:24:11 -05:00
Conor Patrick
38171dba06 low freq init 2019-02-02 00:23:51 -05:00
Conor Patrick
4ba57ccc85 refactor init functions 2019-02-02 00:23:01 -05:00
Conor Patrick
c3bddee814 dont do this when powered by nfc 2019-02-02 00:21:26 -05:00
Conor Patrick
b7bc50bc4f
Merge pull request #96 from merlokk/nfc2
small fixes in NFC branch
2019-02-02 00:16:07 -05:00
merlokk
19627a959a some TODOs 2019-02-01 21:35:45 +02:00
merlokk
429e4b2a77 add WTX_clear(); 2019-02-01 21:33:57 +02:00
merlokk
6e5de7bd6b read data if we sent WTX 2019-02-01 21:31:20 +02:00
merlokk
c6daa4acc9 more WTX sketch 2019-02-01 21:27:43 +02:00
merlokk
ab01d0c73d delete comment 2019-02-01 21:02:02 +02:00
merlokk
0ef42b2df7 added WTX sending sketch 2019-02-01 20:45:36 +02:00
merlokk
f6e2bfa683 yubikey answers U2F_SW_WRONG_PAYLOAD instead of U2F_SW_WRONG_DATA 2019-02-01 20:06:19 +02:00
merlokk
5c8acdd666 fix u2f user presence check, added dont-enforce-user-presence-and-sign, fix counter 2019-02-01 20:00:13 +02:00
merlokk
e996d470f9 small fixes 2019-02-01 19:15:48 +02:00
Conor Patrick
e2e29492e6 point to website 2019-01-29 22:39:49 -05:00
Conor Patrick
5f637992b1 implement capability container and ndef tag to work with nexus 6 2019-01-29 22:12:38 -05:00
Conor Patrick
91d092a27a tell AMS to go to sleep if deselected 2019-01-27 23:55:11 -05:00
Conor Patrick
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
merlokk
cce25b2a1c u2f auth works 2019-01-28 00:04:17 +02:00
merlokk
f24058d2e8 u2f authenticate wrong length fix 2019-01-27 23:58:35 +02:00
merlokk
4c941997b4 check as3956 on startup 2019-01-27 23:35:20 +02:00
merlokk
2049020b92 refactoring 2019-01-27 11:44:33 +02:00
merlokk
1857482617 add some len check 2019-01-27 00:01:04 +02:00
merlokk
2feef8b043 add some profiling... 2019-01-26 23:53:13 +02:00
merlokk
3eddfbf8a9 u2f register works 2019-01-26 23:44:51 +02:00
merlokk
a662a9a619 remove dump 2019-01-26 23:36:45 +02:00
merlokk
1a656d60e4 register works. but it needs to press a button.... 2019-01-26 23:35:45 +02:00
merlokk
e235402fb8 u2f register 2019-01-26 21:34:53 +02:00
merlokk
6ca9f1946b I block on receive 2019-01-26 21:08:18 +02:00
merlokk
df671775ba add some profiling. looks good. 2019-01-26 19:30:03 +02:00
merlokk
3ba83f6407 remove debug msg 2019-01-26 19:11:51 +02:00
merlokk
ffa4225827 chip have too less memory. so reusing ctap_resp buffer. 2019-01-26 19:07:12 +02:00
merlokk
cde6bc107a GetVersion works. not so clean. needs additional memory.... 2019-01-25 19:54:02 +02:00
merlokk
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
merlokk
94fe58d020 small fix 2019-01-24 20:09:57 +02:00
merlokk
e8634a2d61 add u2f errors 2019-01-24 20:04:44 +02:00
merlokk
67b0abde4b some refactoring 2019-01-24 19:56:18 +02:00
merlokk
d713167ec4 works. needs to add chaining 2019-01-24 19:21:31 +02:00
merlokk
45888c9a25 ins check is ok 2019-01-24 18:22:58 +02:00
merlokk
d02206ba09 SELECT works as expected and U2F GetVersion command done 2019-01-24 18:19:23 +02:00
merlokk
ad9186c13b SELECT works 2019-01-24 17:57:42 +02:00
merlokk
4e0dc15dfd add historical bytes 2019-01-24 16:56:38 +02:00
Conor Patrick
dcf7940b3d basic ndef message works 2019-01-13 17:25:32 -05:00
Conor Patrick
1874e11fba organize 2019-01-13 00:02:37 -05:00
Conor Patrick
302ce75ce6 responds to RATS correctly 2019-01-12 20:20:47 -05:00
Conor Patrick
62cd7cc728 enable energy harvesting and tunneling in eeprom 2019-01-12 16:20:11 -05:00
Conor Patrick
20f8aac768 option to boot at 4MHz with no USB 2019-01-12 16:19:44 -05:00
Conor Patrick
121070822f Update main.c 2019-01-07 21:20:07 -05:00
Conor Patrick
96f65be9c2 disable main app for now 2019-01-07 21:19:56 -05:00
Conor Patrick
78c40976c3 log interrupts and recv'd data 2019-01-07 21:19:45 -05:00
Conor Patrick
aa978abfc7 cleanup 2019-01-07 19:40:20 -05:00
Conor Patrick
b7c0e4ea92 no delays 2019-01-07 19:05:39 -05:00
Conor Patrick
6ffba7d472 move to new file 2019-01-07 18:50:01 -05:00
Conor Patrick
c330346c31 add nfc log tag 2019-01-07 18:29:38 -05:00
Conor Patrick
eda26e3c93 add ST spi LL driver 2019-01-07 18:17:33 -05:00
Conor Patrick
44077a4f2f spi interface WORKS 2019-01-06 17:12:26 -05:00
Conor Patrick
4c6f0969c1 add spi 2019-01-05 20:58:39 -05:00
157 changed files with 14272 additions and 18587 deletions

228
.all-contributorsrc Normal file
View File

@ -0,0 +1,228 @@
{
"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"
]
},
{
"login": "jolo1581",
"name": "Jan A.",
"avatar_url": "https://avatars1.githubusercontent.com/u/53423977?v=4",
"profile": "https://github.com/jolo1581",
"contributions": [
"code",
"doc"
]
},
{
"login": "ccinelli",
"name": "ccinelli",
"avatar_url": "https://avatars0.githubusercontent.com/u/38021940?v=4",
"profile": "https://github.com/ccinelli",
"contributions": [
"infra",
"test"
]
},
{
"login": "Nitrokey",
"name": "Nitrokey",
"avatar_url": "https://avatars1.githubusercontent.com/u/9438831?v=4",
"profile": "https://www.nitrokey.com",
"contributions": [
"code",
"test",
"ideas"
]
}
],
"contributorsPerLine": 7,
"projectName": "solo",
"projectOwner": "solokeys",
"repoType": "github",
"repoHost": "https://github.com"
}

15
.gitignore vendored
View File

@ -34,7 +34,8 @@
*.app
*.i*86
*.x86_64
*.hex
targets/*/*.hex
targets/*/*.sha2
# Debug files
*.dSYM/
@ -81,15 +82,7 @@ env3/
.tags*
targets/*/docs/
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/*
tools/testing/.idea/*
tools/testing/tests/__pycache__/*

6
.gitmodules vendored
View File

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

View File

@ -6,14 +6,15 @@ addons:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-7
- gcc-8
- cppcheck
services:
- docker
before_install:
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
- sudo apt-get update -q
- sudo apt-get install -y gcc-arm-embedded
- sudo apt-get install -y python3-venv
- sudo apt-get install -y gcc-arm-embedded python3-venv
script:
- export CC=gcc-7
- export CC=gcc-8
- pyenv shell 3.6.7
- make travis

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

@ -1,31 +1,38 @@
FROM debian:stretch-slim
FROM debian:9.11-slim
MAINTAINER SoloKeys <hello@solokeys.com>
RUN apt-get update -qq
RUN apt-get install -qq bzip2 git make wget >/dev/null
# Install necessary packages
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
make \
wget \
bzip2 \
git \
&& rm -rf /var/lib/apt/lists/*
# 1. ARM GCC: for compilation
RUN wget -q -O gcc.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
# from website
RUN echo "f55f90d483ddb3bcf4dae5882c2094cd gcc.tar.bz2" > gcc.md5
RUN md5sum -c gcc.md5
# self-generated
RUN echo "fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.tar.bz2" > gcc.sha256
RUN sha256sum -c gcc.sha256
RUN tar -C /opt -xf gcc.tar.bz2
# Install ARM compiler
RUN set -eux; \
url="https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2019q3/RC1.1/gcc-arm-none-eabi-8-2019-q3-update-linux.tar.bz2?revision=c34d758a-be0c-476e-a2de-af8c6e16a8a2?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2019-q3-update"; \
wget -O gcc.tar.bz2 "$url"; \
echo "6341f11972dac8de185646d0fbd73bfc gcc.tar.bz2" | md5sum -c -; \
echo "b50b02b0a16e5aad8620e9d7c31110ef285c1dde28980b1a9448b764d77d8f92 gcc.tar.bz2" | sha256sum -c -; \
tar -C /opt -xf gcc.tar.bz2; \
rm gcc.tar.bz2;
# 2. Python3.7: for solotool (merging etc.)
RUN wget -q -O miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh
# from website
RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5
RUN md5sum -c miniconda.md5
# self-generated
RUN echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" > miniconda.sha256
RUN sha256sum -c miniconda.sha256
# Python3.7: for solo-python (merging etc.)
RUN set -eux; \
url="https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh"; \
wget -O miniconda.sh "$url"; \
echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" | md5sum -c -; \
echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" | sha256sum -c -; \
bash ./miniconda.sh -b -p /opt/conda; \
ln -s /opt/conda/bin/python /usr/local/bin/python3; \
ln -s /opt/conda/bin/python /usr/local/bin/python; \
ln -s /opt/conda/bin/pip /usr/local/bin/pip3; \
ln -s /opt/conda/bin/pip /usr/local/bin/pip; \
rm miniconda.sh; \
pip install -U pip
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/python3 /usr/local/bin/python
# 3. Source code
RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input
# solo-python (Python3.7 script for merging etc.)
RUN pip install -U solo-python

1
LICENSE Normal file
View File

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

View File

@ -1,3 +1,5 @@
include fido2/version.mk
#define uECC_arch_other 0
#define uECC_x86 1
#define uECC_x86_64 2
@ -6,31 +8,34 @@
#define uECC_arm_thumb2 5
#define uECC_arm64 6
#define uECC_avr 7
ecc_platform=2
src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard crypto/sha256/*.c) crypto/tiny-AES-c/aes.c
obj = $(src:.c=.o) crypto/micro-ecc/uECC.o
src = pc/device.c pc/main.c
obj = $(src:.c=.o)
LIBCBOR = tinycbor/lib/libtinycbor.a
LIBSOLO = fido2/libsolo.a
ifeq ($(shell uname -s),Darwin)
export LDFLAGS = -Wl,-dead_strip
else
export LDFLAGS = -Wl,--gc-sections
endif
LDFLAGS += $(LIBCBOR)
CFLAGS = -O2 -fdata-sections -ffunction-sections
LDFLAGS += $(LIBSOLO) $(LIBCBOR)
INCLUDES = -I./tinycbor/src -I./crypto/sha256 -I./crypto/micro-ecc/ -Icrypto/tiny-AES-c/ -I./fido2/ -I./pc -I./fido2/extensions
CFLAGS = -O2 -fdata-sections -ffunction-sections -g
ECC_CFLAGS = -O2 -fdata-sections -ffunction-sections -DuECC_PLATFORM=$(ecc_platform)
INCLUDES = -I../ -I./fido2/ -I./pc -I../pc -I./tinycbor/src
CFLAGS += $(INCLUDES)
# for crypto/tiny-AES-c
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\"
CFLAGS += -DAES256=1 -DSOLO_EXPERIMENTAL=1 -DDEBUG_LEVEL=1
name = main
.PHONY: all $(LIBCBOR) black blackcheck cppcheck wink fido2-test clean full-clean travis test clean version
.PHONY: all $(LIBCBOR) $(LIBSOLO) black blackcheck cppcheck wink fido2-test clean full-clean travis test clean version
all: main
tinycbor/Makefile crypto/tiny-AES-c/aes.c:
@ -40,7 +45,10 @@ tinycbor/Makefile crypto/tiny-AES-c/aes.c:
cbor: $(LIBCBOR)
$(LIBCBOR):
cd tinycbor/ && $(MAKE) clean && $(MAKE) -j8
cd tinycbor/ && $(MAKE) LDFLAGS='' -j8
$(LIBSOLO):
cd fido2/ && $(MAKE) CFLAGS="$(CFLAGS)" ECC_CFLAGS="$(ECC_CFLAGS)" APP_CONFIG=app.h -j8
version:
@git describe
@ -49,18 +57,16 @@ test: venv
$(MAKE) clean
$(MAKE) -C . main
$(MAKE) clean
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)"
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" VERSION_FULL=${SOLO_VERSION_FULL}
$(MAKE) clean
$(MAKE) cppcheck
$(name): $(obj) $(LIBCBOR)
$(name): $(obj) $(LIBCBOR) $(LIBSOLO)
$(CC) $(LDFLAGS) -o $@ $(obj) $(LDFLAGS)
crypto/micro-ecc/uECC.o: ./crypto/micro-ecc/uECC.c
$(CC) -c -o $@ $^ -O2 -fdata-sections -ffunction-sections -DuECC_PLATFORM=$(ecc_platform) -I./crypto/micro-ecc/
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 black
@ -69,18 +75,36 @@ black: venv
venv/bin/black --skip-string-normalization --check tools/
wink: venv
venv/bin/python tools/solotool.py solo --wink
venv/bin/solo key wink
fido2-test: venv
venv/bin/python tools/ctap_test.py
DOCKER_IMAGE := "solokeys/solo-firmware:local"
SOLO_VERSIONISH := "master"
docker-build:
docker build -t $(DOCKER_IMAGE) .
update:
git fetch --tags
git checkout master
git rebase origin/master
git submodule update --init --recursive
DOCKER_TOOLCHAIN_IMAGE := "solokeys/solo-firmware-toolchain"
docker-build-toolchain:
docker build -t $(DOCKER_TOOLCHAIN_IMAGE) .
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}.${SOLO_VERSION_MIN}
uncached-docker-build-toolchain:
docker build --no-cache -t $(DOCKER_TOOLCHAIN_IMAGE) .
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}.${SOLO_VERSION_MIN}
docker-build-all:
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)
-v "$(CURDIR):/solo" \
-u $(shell id -u ${USER}):$(shell id -g ${USER}) \
$(DOCKER_TOOLCHAIN_IMAGE) "solo/in-docker-build.sh" ${SOLO_VERSION_FULL}
CPPCHECK_FLAGS=--quiet --error-exitcode=2
@ -97,10 +121,19 @@ clean:
(cd `dirname $$f` ; git checkout -- .) ;\
fi ;\
done
cd fido2 && $(MAKE) clean
full-clean: clean
rm -rf venv
test-docker:
rm -rf builds/*
$(MAKE) uncached-docker-build-toolchain
# Check if there are 4 docker images/tas named "solokeys/solo-firmware-toolchain"
NTAGS=$$(docker images | grep -c "solokeys/solo-firmware-toolchain") && [ $$NTAGS -eq 4 ]
$(MAKE) docker-build-all
travis:
$(MAKE) test VENV=". ../../venv/bin/activate;"
$(MAKE) black
$(MAKE) test-docker
$(MAKE) black

177
README.md
View File

@ -1,19 +1,14 @@
[![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE)
[![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)
[![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)
[![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)
# Solo
[![Build Status](https://travis-ci.com/solokeys/solo.svg?style=flat-square&branch=master)](https://travis-ci.com/solokeys/solo)
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.
<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, and it's ported to NRF52840 and EFM32J.
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.
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,14 +28,64 @@ 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.
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.dev/building/). We support Python3.
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.
Then recompile, load your new firmware, and enjoy a different LED color Solo.
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.
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.
## Checking out the code
```bash
git clone --recurse-submodules https://github.com/solokeys/solo
cd solo
```
If you forgot the `--recurse-submodules` while cloning, simply run `git submodule update --init --recursive`.
`make update` will also checkout the latest code on `master` and submodules.
## Checking out the code to build a specific version
You can checkout the code to build a specific version of the firmware with:
```
VERSION_TO_BUILD=2.5.3
git fetch --tags
git checkout ${VERSION_TO_BUILD}
git submodule update --init --recursive
```
## Installing the toolchain and applying updates
In order to compile ARM code, you need the ARM compiler and other things like bundling bootloader and firmware require the [solo-python](https://github.com/solokeys/solo-python) python package. Check our [documentation](https://docs.solokeys.dev/) for details.
You can update your solokey after running `pip3 install solo-python` with `solo key update` for the latest version. To apply a custom image use `solo program bootloader <file>(.json|.hex)`.
## Installing the toolkit and compiling in Docker
Alternatively, you can use Docker to create a container with the toolchain.
You can run:
```bash
# Build the toolchain container
make docker-build-toolchain
# Build all versions of the firmware in the "builds" folder
make docker-build-all
```
The `builds` folder will contain all the variation on the firmware in `.hex` files.
## Build locally
If you have the toolchain installed on your machine you can build the firmware with:
```bash
cd targets/stm32l432
make cbor
make build-hacker
@ -48,25 +93,10 @@ cd ../..
make venv
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`.
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:
```
uint32_t b = 0;
```
Then recompile, load your new firmware, and enjoy a blue-light-free version of 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.
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.
# Developing Solo (No Hardware Needed)
Clone Solo and build it
@ -82,7 +112,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:
```bash
cd python-fido2 && python setup.py install
pip install -r tools/requirements.txt
```
Run the Solo application:
@ -90,38 +120,78 @@ Run the Solo application:
./main
```
In another shell, you can run client software, for example our tests:
```bash
python tools/ctap_test.py
```
In another shell, you can run our [test suite](https://github.com/solokeys/fido2-tests).
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.dev/), including how to build on the the NUCLEO-L432KC development board.
# Documentation
Check out our [official documentation](https://docs.solokeys.io/solo/).
Check out our [official documentation](https://docs.solokeys.dev/).
# 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.
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.
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>
<td align="center"><a href="https://github.com/jolo1581"><img src="https://avatars1.githubusercontent.com/u/53423977?v=4" width="100px;" alt="Jan A."/><br /><sub><b>Jan A.</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ccinelli"><img src="https://avatars0.githubusercontent.com/u/38021940?v=4" width="100px;" alt="ccinelli"/><br /><sub><b>ccinelli</b></sub></a><br /><a href="#infra-ccinelli" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/solokeys/solo/commits?author=ccinelli" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://www.nitrokey.com"><img src="https://avatars1.githubusercontent.com/u/9438831?v=4" width="100px;" alt="Nitrokey"/><br /><sub><b>Nitrokey</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=Nitrokey" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=Nitrokey" title="Tests">⚠️</a> <a href="#ideas-Nitrokey" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
</table>
<!-- ALL-CONTRIBUTORS-LIST:END -->
# License
Solo is fully open source.
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 1.2 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)
@ -129,3 +199,20 @@ You may use Solo under the terms of either the Apache 2.0 license or MIT license
# Where To Buy Solo
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-22-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/BFA3F5387D025E8945CF907FC2F2505A63868DFA>
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

1
STABLE_VERSION Normal file
View File

@ -0,0 +1 @@
4.0.0

1
crypto/cifra Submodule

@ -0,0 +1 @@
Subproject commit d04dd318609733d809904d4f2973597240655cde

27
default.nix Normal file
View File

@ -0,0 +1,27 @@
let
pkgs = import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/20.03.tar.gz"; sha256 = "0182ys095dfx02vl2a20j1hz92dx3mfgz2a6fhn31bqlp1wa8hlq"; }) { };
pyPackages = (python-packages: with python-packages; ([
solo-python
pytest
] ++ (with builtins; map (d: getAttr d python-packages) (filter (d: stringLength d > 0) (pkgs.lib.splitString "\n" (builtins.readFile ./tools/requirements.txt))))));
python-with-my-packages = pkgs.python3.withPackages pyPackages;
src = with pkgs.lib; builtins.filterSource (path: type: !(hasSuffix path "hex" || hasSuffix path "sha256" || baseNameOf path == "result")) ./.;
in
with pkgs; stdenv.mkDerivation {
name = "solo";
outputs = [ "out" ];
inherit src;
buildInputs = [ src gnumake gcc gcc-arm-embedded-8 git python-with-my-packages ];
phases = [ "unpackPhase" "configurePhase" "buildPhase" "installPhase" ];
installPhase = ''
mkdir -p $out/firmware $out/standalone/bin
make
cp main $out/standalone/bin/
cd targets/stm32l432
make cbor
make build-hacker
cp *.hex *.sha256 *.elf cubeconfig_stm32l442.ioc $out/firmware/
ln -s ${src} $out/src
'';
keepDebugInfo = true;
}

1
docs/_redirects Normal file
View File

@ -0,0 +1 @@
/solo/* /:splat 302

147
docs/application-ideas.md Normal file
View File

@ -0,0 +1,147 @@
# Using Solo for passwordless or second factor login on Linux
## Setup on Ubuntu and Manjaro
Before you can use Solo for passwordless or second factor login in your Linux system you have to install some packages.
This was tested on **Linux Mint 19.3** and on **Manjaro 18.x**
First you have to install PAM modules for u2f.
**Ubuntu (Linux Mint):**
```
sudo apt install libpam-u2f pamu2fcfg
```
**Manjaro**
```
pacman -Syu pam-u2f
```
## Setting up key
To use Solo as passwordless or second factor login, you have to setup your system with your Solo.
First create a new folder named **Yubico** in your **.config** folder in your **home** directory
```
mkdir ~/.config/Yubico
```
Then create a new key for PAM U2F module. If it is your first key you want to register use following command:
```
pamu2fcfg > ~/.config/Yubico/u2f_keys
```
If you want to register an additional key use this command instead:
```
pamu2fcfg >> ~/.config/Yubico/u2f_keys
```
Now press the button on your Solo.
<br>
<br>
If you can't generate your key on **Ubuntu** (error message), you may add Yubico Team from PPA and install latest libpam-u2f and pamu2fcfg and try again.
```
sudo add-apt-repository ppa:yubico/stable
sudo apt-get update
sudo apt-get upgrade
```
**Manjaro** should work without problems.
## Login into Linux
### Passwordless
To login passwordless into your Linux system, you have to edit the file **lightdm** (or **gdm** or which display manager you prefered).
In case of lightdm and VIM as editor:
```
sudo vim /etc/pam.d/lightdm
```
**On Ubuntu:**<br>
Search following entry:
```
@include common-auth
```
and add
```
auth sufficient pam_u2f.so
```
**before** *@include common-auth.*
<br>
<br>
**On Manjaro**<br>
Search following enrty
```
auth include system-login
```
and add
```
auth sufficient pam_u2f.so
```
** before** *auth include system-login*.
<br>
<br>
Now save the file and test it.<br>
Insert Solo in your USB port and logout.
Now you should be able to login into Linux without password, only with pressing your button on Solo and press enter.
Why **sufficient**? The difference between the keyword sufficient and required is, if you don't have your Solo available, you can also login, because the system falls back to password mode.
The login mechanism can be also used for additional features like:
- Login after screen timeout - edit /etc/pam.d/mate-screensaver (or kde-screensaver, ...)
- Passwordless sudo - edit /etc/pam.d/sudo
Check out your folder **/etc/pam.d/** and do some experiments.
**But remember:** <br>
The login passwordless won't make your system more secure, but maybe more comfortable. If somebody have access to your Solo, this person will be also able to login into your system.
### Solo as second factor
To use Solo as second factor, for login into your Linux system, is nearly the same.
```
sudo vim /etc/pam.d/lightdm
```
**On Ubuntu**<br>
Search following entry:
```
@include common-auth
```
and add
```
auth required pam_u2f.so
```
**after** *@include common-auth*.
<br>
<br>
**On Manjaro**<br>
Search following entry:
```
auth include system-login
```
Add following entry
```
auth required pam_u2f.so
```
**after** *auth include system-login*.
<br>
<br>
Save the file and test it. <br>
In case your Solo is not present, your password will be incrorrect. If Solo is plugged into your USB port, it will signal pressing the button and you will be able to login into Linux.
Why **required**? If you choose the option **sufficent** your Solo is optional. You could also login without second factor if your Solo is not connected.
**But remember:**<br>
If you loose your Solo you won't be able to login into your system.

53
docs/bootloader-mode.md Normal file
View File

@ -0,0 +1,53 @@
# Booting into bootloader mode
If you have a recent version of Solo, you can put it into bootloader mode by running this command.
```bash
solo program aux enter-bootloader
```
If your Solo is a bit older (<=2.5.3) You can put Solo into bootloader mode by using the button method:
Hold down button while 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](/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format.
# 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/nonverifying-bootloader 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 you 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.

137
docs/building.md Normal file
View File

@ -0,0 +1,137 @@
# Building solo
To build, develop and debug the firmware for the STM32L432. This will work
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)).
## 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.
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`.
Install `solo-python` usually with `pip3 install solo-python`. The `solo` python application may also be used for [programming](#programming).
## Obtain source code and solo tool
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.
```
cd targets/stm32l432
```
Now build the Solo application.
```
make firmware
```
The `firmware` recipe builds the solo application, and outputs `solo.hex`. You can use this
to reprogram any unlocked/hacker Solo model. Note that it does not include the Solo bootloader,
so it is not a full reprogram.
<!-- First it builds the bootloader, with
signature checking disabled. Then it builds the Solo application with "hacker" features
enabled, like being able to jump to the bootloader on command. It then merges bootloader
and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex`
into `all.hex`. -->
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`.
### Building with debug messages
If you're developing, you probably want to see debug messages! Solo has a USB
Serial port that it will send debug messages through (from `printf`). You can read them using
a normal serial terminal like `picocom` or `putty`.
Just add `-debug-1` or `-debug-2` to your build recipe, like this.
```
make firmware-debug-1
```
If you use `debug-2`, that means Solo will not boot until something starts reading
its debug messages. So it basically waits to tether to a serial terminal so that you don't
miss any debug messages.
We recommend using our `solo` tool as a serial emulator since it will automatically
reconnect each time you program Solo.
```
solo monitor <serial-port>
```
#### Linux Users:
[See issue 62](https://github.com/solokeys/solo/issues/62).
### Building a complete Solo build (application + bootloader + certificate)
To make a complete Solo build, you need to build the bootloader. We provide
two easy recipes:
* `bootloader-nonverifying`: bootloader with no signature checking on updates. I.e. "unlocked".
* `bootloader-verifying`: bootloader with signature checking enforced on updated. I.e. "Locked".
To be safe, let's use the `-nonverifying` build.
```
make bootloader-nonverifying
```
This outputs `bootloader.hex`. We can then merge the bootloader and application.
```
solo mergehex bootloader.hex solo.hex bundle.hex
```
`bundle.hex` is our complete firmware build. Note it is in this step that you can
include a custom attestation certificate or lock the device from debugging/DFU.
By default the "hacker" attestation certifcate and key is used. Use the `--lock` flag
to make this permanent.
```
solo mergehex \
--attestation-key "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" \
--attestation-cert attestation.der \
solo.hex \
bootloader.hex \
bundle.hex
```
**Warning**: If you use `--lock`, this will permanently lock the device to this new bootloader. You
won't be able to program the bootloader again or be able to connect a hardware debugger.
The new bootloader may be able to accept (signed) updates still, depending on how you configured it.
```
# Permanent!
solo mergehex \
--attestation-key "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" \
--attestation-cert attestation.der \
--lock \
solo.hex \
bootloader.hex \
bundle.hex
```
See [here for more information on custom attestation](/customization/).
To learn more about normal updates or a "full" update, you should [read more on Solo's boot stages](/bootloader-mode).

View File

@ -5,22 +5,22 @@ and easy to understand, especially when paired with a high level overview.
## 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.
* 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

142
docs/customization.md Normal file
View File

@ -0,0 +1,142 @@
# 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-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=$CN/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" # MUST KEEP THIS AS "Authenticator Attestation" for FIDO2.
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=$CN/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
First, [Build your solo application and bootloader](/building).
Print your attestation key in a hex string format. Using our utility script:
```
python3 tools/gencert/print_x_y.py device_key.pem
```
Merge the `bootloader.hex`, `solo.hex`, attestion key, and certificate into one firmware file.
```
solo mergehex \
--attestation-key "(The 32-byte hex string extracted from device_key.pem)" \
--attestation-cert device_cert.der \
--lock \
solo.hex \
bootloader.hex \
bundle.hex
```
**Warning**: Using the `--lock` flag prevents the DFU from being accessed on the device again. It's recommended to try first without the `--lock` flag to make sure it works.
Now you have a newly created `bundle.hex` file with a custom attestation key and cert. You can [program this `bundle.hex` file
with Solo in DFU mode](/programming#procedure).
Are you interested in customizing in bulk? Contact hello@solokeys.com and we can help.

View File

@ -3,7 +3,7 @@ Documentation of the `master` branch is deployed to Netlify automatically.
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).

View File

@ -22,8 +22,8 @@ for FIDO2 operation.
When you register a service with a FIDO2 or U2F authenticator, the
authenticator must generate a new keypair unique to that service. This keypair
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
devices, there isn't much memory to spare and users will allows frustratingly
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 would frustratingly
hit the limit of this memory.
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)
4. Service stores `P` and `R`.
Now on authenication.
Now on authentication.
1. Service issues authentication request with `R` in `KEYID` parameter.
2. \* Authenticator generates `K` by calculating `HMAC(M,R)`.

BIN
docs/images/conforms.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 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).
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.

257
docs/nucleo32-board.md Normal file
View File

@ -0,0 +1,257 @@
# 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.dev/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 MacOS X 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.dev/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

60
docs/porting.md Normal file
View File

@ -0,0 +1,60 @@
# Usage and Porting
Solo is designed to be used as a library or ported to other platforms easily. Here is an example
`main()` function.
```c
int main()
{
uint8_t hidmsg[64];
uint32_t t1 = 0;
device_init();
memset(hidmsg,0,sizeof(hidmsg));
while(1)
{
if (usbhid_recv(hidmsg) > 0)
{
ctaphid_handle_packet(hidmsg); // pass into libsolo!
memset(hidmsg, 0, sizeof(hidmsg));
}
ctaphid_check_timeouts();
}
}
```
`ctaphid_handle_packet(hidmsg);` is the entrance into the HID layer of libsolo, and will buffer packets and pass them
into FIDO2 or U2F layers.
Everything in the library is cross-platform, but it needs some functions implemented that are usually
platform specific. For example, how should libsolo implement an atomic counter? Where should it save state?
For all of these platform specific functions, the library contains it's own `weak` definition, so the library will compile and run.
LibSolo by default will not try to use an atomic
counter or save data persistently -- that needs to be implemented externally.
If you are using libsolo on another platform,
you should take a look at these possibly platform specific functions. They are listed in `fido2/device.h`.
If you'd like to reimplement any of the functions, then simply implement the function and compile normally.
GCC will replace libsolo's `weak` defined functions (everything in `fido2/device.h`) with your functions. By doing this, you
are replacing the function that is used by libsolo.
To get the library to compile
and run, you only need to implement one function for libsolo: `usbhid_send(uint8_t * send)`, which
is called by the library to send a 64 byte packet over a USB HID endpoint. In essence, you are giving
libsolo a function to write to USB.
The rest of the definitions in `fido2/device.h` are not required to compile and run so you can
immediately hit the ground running and iterative add what else you need. You'll definitely want
to continue implementing other functions in `fido2/device.h`. For example, no data will be stored
persistently until you define how it can be done!
For examples, check out the build for STM32L4 and PC (check out `pc/device` and `targets/stm32l432/src/device.c`).
If there's something that doesn't work for you -- send a pull request! It's better if we can
work together off of the same repo and not fork.

116
docs/programming.md Normal file
View File

@ -0,0 +1,116 @@
# 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](/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
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](/customization/).
## Updating a Hacker to a Secure Solo
Updating a hacker to be a secure build overwrites the [Solo bootloader](/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, application, and attestation key pair (bootloader + firmware + key).
This means using the `bundle-*.hex` file or the `bundle.hex` from your build.
#### *Warning*
* **Any DFU update erases everything! If you overwrite the Solo flash with a missing bootloader, it will be bricked.**
* **If you program bootloader and firmware with no attestation, you will run into FIDO registration issues.**
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 small 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 | bundle.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.

1
docs/repo-readme.md Symbolic link
View File

@ -0,0 +1 @@
../README.md

19
docs/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 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,179 +0,0 @@
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.
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
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`,
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.
- [openocd](http://openocd.org)
- [stlink](https://github.com/texane/stlink)
- [STM32CubeProg](https://www.st.com/en/development-tools/stm32cubeprog.html)
# Compilation
Enter the `stm32l4xx` target directory.
```
cd targets/stm32l432
```
Now build Solo.
```
make build-hacker
```
The `build-hacker` recipe does a few things. First it builds the bootloader, with
signature checking disabled. Then it builds the Solo application with "hacker" features
enabled, like being able to jump to the bootloader on command. It then merges bootloader
and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex`
into `all.hex`.
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`.
### Building with debug messages
If you're developing, you probably want to see debug messages! Solo has a USB
Serial port that it will send debug messages through (from `printf`). You can read them using
a normal serial terminal like `picocom` or `putty`.
Just add `DEBUG=1` or `DEBUG=2` to your build recipe, like this.
```
make build-hacker DEBUG=1
```
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
miss any debug messages.
We recommend using our `solotool.py` as a serial emulator since it will automatically
reconnect each time you program Solo.
```
python tools/solotool.py monitor <serial-port>
```
#### Linux Users:
[See issue 62](https://github.com/solokeys/solo/issues/62).
### Building a Solo release
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
fix any mistakes.
If you're ready to program a full release, run this recipe to build.
```
make build-release-locked
```
Programming `all.hex` will cause the device to permanently lock itself.
# Programming
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

@ -1 +0,0 @@
../../README.md

219
docs/tutorial-getting-started.md Executable file
View File

@ -0,0 +1,219 @@
# Tutorial: Getting started with the solo hacker
This is small guide to let you get started with the solo hacker key. In the end you will have set up everything you need and changed the LED from green to red.
## Some additional ressources
This tutorial will take you through all the necessary steps needed to install and get the solo key running. Before we start, I will just list you additional ressources, which might have important information for you:
* [The git repository](https://github.com/solokeys/solo): Here you will find all the code and a quick readme.
* [The Documenation](https://docs.solokeys.io/solo/building/): The official documentation. Especially the [build instructions](https://docs.solokeys.io/solo/building/) are worth a look, if you got stuck.
## Getting the prerequisites
There are two main tools you will need to work on your solo hacker:
* ARM Compiler tool chain
* Solo python tool
The ARM Compiler is used to compile your C-code to a hex file, which can then be deployed onto your solo hacker. The solo tool helps with deploying, updating etc. of the solo hacker. It is a python3 tool. So make sure, that you got Python3 installed on your system \([pip](https://pip.pypa.io/en/stable/) might also come in handy\).
Besides that, you will also need to get the [solo code](https://github.com/solokeys/solo).
### Get the code
The codebase for the solo hacker and other solo keys, can be found at this [git repository](https://github.com/solokeys/solo). So just clone this into your development folder. Make sure, that all the submodules are loaded by using the following command. I forgot to get all the submoules at my first try and the make command failed \(I got an error message telling me, that no solo.elf target can be found\).
```bash
git clone --recurse-submodules https://github.com/solokeys/solo
```
### Getting the ARM Compiler tool chain
Download the Compiler tool chain for your system [here](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads). After you have downloaded it, you will have to unzip it and add the path to the installation folder.
**Readme**
There is a readme.txt __ in _gcc-arm-none-eabi-x-yyyy-dd-major/share/doc/gcc-arm-none-eabi_. It contains installation guides for Linux, Windows and Mac.
**Installation**
As I used Mac, I will guide you through the installation using MacOS. If you have unpacked the folder already, you can skip the first step.
```bash
#Unzip the tarball
cd $install_dir && tar xjf gcc-arm-none-eabi-*-yyyymmdd-mac.tar.bz2
#Set path
export PATH=$PATH:$install_dir/gcc-arm-none-eabi-*/bin
#Test if it works
arm-none-eabi-gcc
```
If everything worked your output should like this:
```bash
arm-none-eabi-gcc: fatal error: no input files
compilation terminated.
```
### Getting the solo tool
There are several ways, which are listed at the [build instructions](https://docs.solokeys.io/solo/building/). If you are familiar with pip, just use this.
```bash
pip install solo-python
#Or
pip3 install solo-python
```
**Install all other requirements**
To do this either do it in the virtual env or directly on your machine. The requirements can be found in the source folder in requirements.txt.
```bash
#Move to source folder
cd solo
#Install requirements, use pip3 otherwise
pip install -r solo/tools/requirements.txt
```
## Let's get a red light blinking
You will find the code for the key in _/solo/targets/stm32l432_ \(The target might have another id for you, so just use that id\). The LED colors can be found in [_/solo/targets/stm32l432 /src/app.h_](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/app.h)_._ To change the color we will just have to change the hex-value. Out of the box it should look like this:
```c
// 0xRRGGBB
#define LED_INIT_VALUE 0x000800
#define LED_WINK_VALUE 0x000010
#define LED_MAX_SCALER 15
#define LED_MIN_SCALER 1
```
_LED\_INIT\_VALUE_ is the color, that the LED shows whenever it is plugged in. It normally is a green light. So let's change it to red:
```c
// 0xRRGGBB
#define LED_INIT_VALUE 0xFF0800
#define LED_WINK_VALUE 0x000010
#define LED_MAX_SCALER 15
#define LED_MIN_SCALER 1
```
_LED\_WINK\_VALUE_ is the color, which is shown, whenever the bottom is pressed. It normally is a blue tone, but let's change it to a yellow:
```c
// 0xRRGGBB
#define LED_INIT_VALUE 0xFF0800
#define LED_WINK_VALUE 0xFFFF00
#define LED_MAX_SCALER 15
#define LED_MIN_SCALER 1
```
Save the file and then let's try to get the code onto the stick.
## Move code to solo hacker
First we have to build cbor. To do this change into the target folder and use the corresponding command.
```bash
#Change into correct directory
cd solo/targets/stm32l432/
#Make cbor
make cbor
```
You should also make sure to check, that your key has the newest solo firmware installed. To check the firmware on the device, use this command:
```bash
solo key version
```
To update to the newest version, use this command:
```bash
solo key version
```
**Note:** Sometimes the connection between Mac and key seemed to be broken and you might get an error stating: _No solo found_. Just unplug the key and plug it back in.
### General deployment cycle
In general we will always have to go through these steps:
* Compile code and generate new firmware
* Change device into bootloader mode
* Deploy code to device
#### Compile code
To compile the code, we will again have to change into our target directory:
```bash
#Change into correct directory
cd solo/targets/stm32l432/
```
It is important to choose the correct build target. Most explanations focus on the build of the firmware and use:
```bash
make firmware
```
As we are using the solo hacker, we will need to use:
```bash
make build-hacker
```
This will generate a file _solo.hex_, which has the compiled code on it. If you later need to change the bootloader itself, please refer to [the documentation](https://docs.solokeys.io/solo/building/).
#### Deploy code
To deploy the code make sure you are back at the source root.
```bash
cd ../..
```
First we will have to change into bootload modus:
```bash
solo program aux enter-bootloader
```
This is needed to be able to load the new firmware on the device. If we forget this step, the solo tool will do it for us in the next step.
This is the moment of truth. We delete the old firmware and deploy the new one with the changed LED lights to the solo key. For this step we will also stay in the source root.
```bash
solo program bootloader targets/stm32l432/solo.hex
```
If there is another hex-File, that you want to load, you can just exchange the last argument.
And that's it, now your LED should be red.
To summarize, here are again the steps to update your solo:
1. Change code
2. Run these commands
```bash
#Change into correct directory
cd solo/targets/stm32l432/
#Compile code
make build-hacker
#Change to root
cd ../..
#Enter bootload mode
solo program aux enter-bootloader
#Deploy code
solo program bootloader targets/stm32l432/solo.hex
```

View File

@ -0,0 +1,205 @@
# Tutorial: Writing an extension for the solo stick
A short overview about, where and how you should implement your extension into the solo stick code base. In this tutorial we will add a small extension, that will engage in a "ping"-"pong" exchange.
## Make it visible
We need to make it visible, that the key now supports a new extension.
This is done in the function _ctap_get_info_ in [ctap.c](https://github.com/solokeys/solo/blob/master/fido2/ctap.c). This function creates a map with all the information about the solo key. You should therefore add your extension identifier here, too.
```c
uint8_t ctap_get_info(CborEncoder * encoder){
//[...]
ret = cbor_encode_uint(&map, RESP_extensions);
check_ret(ret);
{
ret = cbor_encoder_create_array(&map, &array, 3);
check_ret(ret);
{
ret = cbor_encode_text_stringz(&array, "hmac-secret");
check_ret(ret);
ret = cbor_encode_text_stringz(&array, "credProtect");
check_ret(ret);
//Add it here
}
ret = cbor_encoder_close_container(&map, &array);
check_ret(ret);
}
//[...]
}
```
After you have added your identifier it should look similiar to this:
```c
uint8_t ctap_get_info(CborEncoder * encoder){
//[...]
ret = cbor_encode_uint(&map, RESP_extensions);
check_ret(ret);
{
ret = cbor_encoder_create_array(&map, &array, 3); //This number should reflect the number of supported extensions
check_ret(ret);
{
ret = cbor_encode_text_stringz(&array, "hmac-secret");
check_ret(ret);
ret = cbor_encode_text_stringz(&array, "credProtect");
check_ret(ret);
//Add it here
ret = cbor_encode_text_stringz(&array, "ping-pong");
check_ret(ret);
}
ret = cbor_encoder_close_container(&map, &array);
check_ret(ret);
}
//[...]
}
```
Important: make sure to change the size of the created array to the correct number of elements.
## Let's get our extension parsed
As with all incoming messages, the extension has to be parsed and depending on the incoming message the reply has to be constructed. For this the function _ctap_parse_extensions_ in [ctap_parse.c](https://github.com/solokeys/solo/blob/master/fido2/ctap_parse.c) is used.
In this function the extension identifier is checked. So, if we want to add our ping-pong extension, we need to compare the incoming identifier to our identifier "ping-pong".
```c
uint8_t ctap_parse_extensions(CborValue * val, CTAP_extensions * ext){
//[...]
if (strncmp(key, "hmac-secret",11) == 0){
//[...]
}else if (strncmp(key, "credProtect",11) == 0) {
//[...]
else if (strncmp(key, "ping-pong",9) == 0) {
//Logic should be placed here
}
//[...]
}
```
What happens then, depends on your extension. You should make sure, to check incoming values for correctness, though. As hmac-secret and credProtect are already implemented, you could have a look at their implementations for a kind of guideline.
At this stage we can use the extension struct, which can be found in [ctap.h](https://github.com/solokeys/solo/blob/master/fido2/ctap.h).
```c
typedef struct
{
uint8_t hmac_secret_present;
CTAP_hmac_secret hmac_secret;
uint32_t cred_protect;
} CTAP_extensions;
```
This struct already contains important values for the other extensions, so we are going to add two for our extension. The first "ping_pong_present" should indicate if the key received a message with a ping-pong extension. The response should then contain the correct response.
```c
typedef struct
{
uint8_t hmac_secret_present;
CTAP_hmac_secret hmac_secret;
uint32_t cred_protect;
uint8_t ping_pong_present;
char ping_pong_response[4];
} CTAP_extensions;
```
Now we have to parse our message accordingly.
```c
uint8_t ctap_parse_extensions(CborValue * val, CTAP_extensions * ext){
//[...]
if (strncmp(key, "hmac-secret",11) == 0){
//[...]
}else if (strncmp(key, "credProtect",11) == 0) {
//[...]
else if (strncmp(key, "ping-pong",9) == 0) {
if (cbor_value_get_type(&map) == CborTextStringType)
{
//Cop incoming message
uint8_t txt[5];
sz = sizeof(txt);
ret = cbor_value_copy_text_string(&map, (char *)txt, &sz, NULL);
check_ret(ret);
if(strcmp((const char*)txt, "ping") == 0) {
ext->ping_pong_present = 0x01;
strcpy((char *)ext->ping_pong_response, "pong");
}else if(strcmp((const char*)txt, "pong") == 0) {
ext->ping_pong_present = 0x01;
strcpy((char *)ext->ping_pong_response, "ping");
}else{
printf2(TAG_ERR, "Wrong parameter requested. Got %s.\r\n", txt);
return CTAP2_ERR_INVALID_OPTION;
}
}else{
printf1(TAG_RED, "warning: ping-pong request ignored for being wrong type\r\n");
}
}
//[...]
}
```
Here we are doing the following:
1. Check if we got a message with either "ping" or "pong"
2. Set the correct value, to note, that we received a message using the ping-pong extension
3. Set the correct response ("pong" for "ping" and vice versa)
## Create a reply
Now, that we have parsed the correct message, we have to construct the correct reply. That is done in the function _ctap_make_extensions_ in [ctap.c](https://github.com/solokeys/solo/blob/master/fido2/ctap.c). We will use the before filled _CTAP_extensions_ in here.
We have to do two things here:
1. Check, if a message using the ping-pong extension
2. Set the correct response according to our parsed incoming message
```c
static int ctap_make_extensions(CTAP_extensions * ext, uint8_t * ext_encoder_buf, unsigned int * ext_encoder_buf_size){
//[...]
if (ext->hmac_secret_present == EXT_HMAC_SECRET_PARSED)
{
//[...]
}
else if (ext->hmac_secret_present == EXT_HMAC_SECRET_REQUESTED)
{
//[...]
}
if (ext->cred_protect != EXT_CRED_PROTECT_INVALID) {
//[...]
}
if(ext->ping_pong_present){
extensions_used += 1;
ping_pong_is_valid = 1;
}
if (extensions_used > 0)
{
//[...]
if (hmac_secret_output_is_valid) {
{
//[...]
}
}
if (hmac_secret_requested_is_valid) {
{
//[...]
}
}
if (cred_protect_is_valid) {
{
//[...]
}
}
if (ping_pong_is_valid) {
{
ret = cbor_encode_text_stringz(&extension_output_map, "ping-pong");
check_ret(ret);
//Set the response message
ret = cbor_encode_text_stringz(&extension_output_map, (const char*)ext->ping_pong_response);
check_ret(ret);
}
}
//[...]
}
//[...]
}
```
## Recap
To create a new extension, you would have to take the following three steps:
- Make sure, that the new extension will be made visible through a call of get_info
- Parse incoming messages correctly
- Construct the correct reply

View File

@ -1,17 +1,25 @@
# tl;dr
# Summary
Create [`/etc/udev/rules.d/99-solo.rules`](https://github.com/solokeys/solo/blob/master/99-solo.rules) and add the following (which assumes your user is in group `plugdev`):
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:
- Recent Linux distributions (such as Ubuntu Focal, Fedora 32, [Arch Linux](https://wiki.archlinux.org/index.php/Solo)) with systemd 244 or higher automatically detect FIDO devices (check with `systemctl --version`)
- 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
- [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
- FreeBSD has support in [u2f-devd](https://github.com/solokeys/solo/issues/144#issuecomment-500216020)
If you still need to setup a rule, a simple way to do it is:
```
# Solo
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", SYMLINK+="solokey"
# U2F Zero
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", SYMLINK+="u2fzero"
git clone https://github.com/solokeys/solo.git
cd solo/udev
make setup
```
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
```
@ -50,7 +58,7 @@ This contains rules for Yubico's keys, the U2F Zero, and many others. The releva
```
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
```
It matches on the correct vendor/product IDs of 10c4/8acf, and adds the TAG `uaccess`. Older versions of udev use rules such as
It matches on the correct vendor/product IDs of 10c4/8acf, and adds the TAG `uaccess`. Older versions of udev use rules such as
```
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", MODE="0644", GROUP="plugdev"
```

44
fido2/Makefile Normal file
View File

@ -0,0 +1,44 @@
include version.mk
ifndef APP_CONFIG
APP_CONFIG=example_app.h
endif
INC = -I./ -I./extensions
INC += -I../tinycbor/src
INC += -I../crypto/sha256 -I../crypto/micro-ecc -I../crypto/tiny-AES-c
INC += -I../crypto/cifra/src -I../crypto/cifra/src/ext
INT_CFLAGS = -DAPP_CONFIG=\"$(APP_CONFIG)\"
INT_CFLAGS += $(INC)
INT_CFLAGS += $(SOLO_VERSION_FLAGS)
SRC = apdu.c util.c u2f.c test_power.c
SRC += stubs.c log.c ctaphid.c ctap.c
SRC += ctap_parse.c crypto.c
SRC += device.c
SRC += version.c
SRC += data_migration.c
SRC += extensions/extensions.c extensions/solo.c
SRC += extensions/wallet.c
# Crypto libs
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
OBJ = $(SRC:.c=.o)
all: libsolo.a
libsolo.a: $(OBJ)
$(AR) cqs $@ $^
%.o: %.c
$(CC) $^ $(INT_CFLAGS) $(CFLAGS) -c -o $@
../crypto/micro-ecc/uECC.o: ../crypto/micro-ecc/uECC.c
$(CC) $^ $(INT_CFLAGS) $(ECC_CFLAGS) -c -o $@
clean:
rm -f $(OBJ) libsolo.a

136
fido2/apdu.c Normal file
View File

@ -0,0 +1,136 @@
// 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"
uint16_t 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];
if (len - 7 < extlen)
{
return SW_WRONG_LENGTH;
}
// 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;
}
}
else
{
if ((len > 5) && (len - 5 < hapdu->lc[0]))
{
return SW_WRONG_LENGTH;
}
}
if (!apdu->case_type)
{
return SW_COND_USE_NOT_SATISFIED;
}
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 uint16_t 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_CRV_P256 1
#define COSE_ALG_ES256 -7
#define COSE_ALG_ES256 -7
#define COSE_ALG_ECDH_ES_HKDF_256 -25
#endif

View File

@ -5,29 +5,33 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
/*
* Wrapper for crypto implementation on device
* Wrapper for crypto implementation on device.
*
* Can be replaced with different crypto implementation by
* defining EXTERNAL_SOLO_CRYPTO
*
* */
#ifndef EXTERNAL_SOLO_CRYPTO
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "crypto.h"
#ifdef USE_SOFTWARE_IMPLEMENTATION
#include "sha256.h"
#include "uECC.h"
#include "aes.h"
#include "ctap.h"
#include "device.h"
#include "log.h"
// stuff for SHA512
#include "sha2.h"
#include "blockwise.h"
#include APP_CONFIG
#include "log.h"
#ifdef USING_PC
typedef enum
{
MBEDTLS_ECP_DP_NONE = 0,
@ -44,49 +48,56 @@ typedef enum
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
} mbedtls_ecp_group_id;
#endif
const uint8_t attestation_cert_der[];
const uint16_t attestation_cert_der_size;
const uint8_t attestation_key[];
const uint16_t attestation_key_size;
static SHA256_CTX sha256_ctx;
static cf_sha512_context sha512_ctx;
static const struct uECC_Curve_t * _es256_curve = NULL;
static const uint8_t * _signing_key = NULL;
static int _key_len = 0;
// Secrets for testing only
static uint8_t master_secret[32];
static uint8_t master_secret[64];
static uint8_t transport_secret[32];
void crypto_sha256_init()
void crypto_sha256_init(void)
{
sha256_init(&sha256_ctx);
}
void crypto_reset_master_secret()
void crypto_sha512_init(void)
{
ctap_generate_rng(master_secret, 32);
cf_sha512_init(&sha512_ctx);
}
void crypto_load_master_secret(uint8_t * key)
{
memmove(master_secret, key, 32);
memmove(transport_secret, key+32, 32);
#if KEY_SPACE_BYTES < 96
#error "need more key bytes"
#endif
memmove(master_secret, key, 64);
memmove(transport_secret, key+64, 32);
}
void crypto_reset_master_secret(void)
{
memset(master_secret, 0, 64);
memset(transport_secret, 0, 32);
ctap_generate_rng(master_secret, 64);
ctap_generate_rng(transport_secret, 32);
}
void crypto_sha256_update(uint8_t * data, size_t 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()
{
sha256_update(&sha256_ctx, master_secret, 32);
@ -97,21 +108,32 @@ void crypto_sha256_final(uint8_t * 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)
{
uint8_t buf[64];
int i;
unsigned int i;
memset(buf, 0, sizeof(buf));
if (key == CRYPTO_MASTER_KEY)
{
key = master_secret;
klen = sizeof(master_secret);
klen = sizeof(master_secret)/2;
}
else if (key == CRYPTO_TRANSPORT_KEY)
{
key = transport_secret;
klen = 32;
}
if(klen > 64)
{
printf2(TAG_ERR,"Error, key size must be <= 64\n");
printf2(TAG_ERR, "Error, key size must be <= 64\n");
exit(1);
}
@ -129,19 +151,24 @@ 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)
{
uint8_t buf[64];
int i;
unsigned int i;
crypto_sha256_final(hmac);
memset(buf, 0, sizeof(buf));
if (key == CRYPTO_MASTER_KEY)
{
key = master_secret;
klen = sizeof(master_secret);
klen = sizeof(master_secret)/2;
}
else if (key == CRYPTO_TRANSPORT_KEY2)
{
key = transport_secret;
klen = 32;
}
if(klen > 64)
{
printf2(TAG_ERR,"Error, key size must be <= 64\n");
printf2(TAG_ERR, "Error, key size must be <= 64\n");
exit(1);
}
memmove(buf, key, klen);
@ -158,16 +185,16 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
}
void crypto_ecc256_init()
void crypto_ecc256_init(void)
{
uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
_es256_curve = uECC_secp256r1();
}
void crypto_ecc256_load_attestation_key()
void crypto_ecc256_load_attestation_key(void)
{
_signing_key = attestation_key;
_signing_key = device_get_attestation_key();
_key_len = 32;
}
@ -175,7 +202,7 @@ void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
{
if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0)
{
printf2(TAG_ERR,"error, uECC failed\n");
printf2(TAG_ERR, "error, uECC failed\n");
exit(1);
}
}
@ -212,19 +239,19 @@ void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_I
if (_key_len != 32) goto fail;
break;
default:
printf2(TAG_ERR,"error, invalid ECDSA alg specifier\n");
printf2(TAG_ERR, "error, invalid ECDSA alg specifier\n");
exit(1);
}
if ( uECC_sign(_signing_key, data, len, sig, curve) == 0)
{
printf2(TAG_ERR,"error, uECC failed\n");
printf2(TAG_ERR, "error, uECC failed\n");
exit(1);
}
return;
fail:
printf2(TAG_ERR,"error, invalid key length\n");
printf2(TAG_ERR, "error, invalid key length\n");
exit(1);
}
@ -234,8 +261,11 @@ void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, ui
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
crypto_sha256_update(data, len);
crypto_sha256_update(data2, len2);
crypto_sha256_update(master_secret, 32);
crypto_sha256_update(master_secret, 32); // TODO AES
crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey);
crypto_aes256_init(master_secret + 32, NULL);
crypto_aes256_encrypt(privkey, 32);
}
@ -252,6 +282,11 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
memmove(x,pubkey,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)
{
@ -264,7 +299,7 @@ void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
{
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
{
printf2(TAG_ERR,"Error, uECC_make_key failed\n");
printf2(TAG_ERR, "Error, uECC_make_key failed\n");
exit(1);
}
}
@ -273,7 +308,7 @@ void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey
{
if (uECC_shared_secret(pubkey, privkey, shared_secret, _es256_curve) != 1)
{
printf2(TAG_ERR,"Error, uECC_shared_secret failed\n");
printf2(TAG_ERR, "Error, uECC_shared_secret failed\n");
exit(1);
}
@ -324,42 +359,4 @@ void crypto_aes256_encrypt(uint8_t * buf, int length)
}
const uint8_t attestation_cert_der[] =
"\x30\x82\x01\xfb\x30\x82\x01\xa1\xa0\x03\x02\x01\x02\x02\x01\x00\x30\x0a\x06\x08"
"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e"
"\x06\x03\x55\x04\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x30\x20\x17\x0d\x31\x38"
"\x30\x35\x31\x30\x30\x33\x30\x36\x32\x30\x5a\x18\x0f\x32\x30\x36\x38\x30\x34\x32"
"\x37\x30\x33\x30\x36\x32\x30\x5a\x30\x7c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x0f\x30\x0d"
"\x06\x03\x55\x04\x07\x0c\x06\x4c\x61\x75\x72\x65\x6c\x31\x15\x30\x13\x06\x03\x55"
"\x04\x0a\x0c\x0c\x54\x45\x53\x54\x20\x43\x4f\x4d\x50\x41\x4e\x59\x31\x22\x30\x20"
"\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x6f\x72"
"\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x14\x30\x12\x06\x03\x55\x04"
"\x03\x0c\x0b\x63\x6f\x6e\x6f\x72\x70\x70\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07"
"\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00"
"\x04\x45\xa9\x02\xc1\x2e\x9c\x0a\x33\xfa\x3e\x84\x50\x4a\xb8\x02\xdc\x4d\xb9\xaf"
"\x15\xb1\xb6\x3a\xea\x8d\x3f\x03\x03\x55\x65\x7d\x70\x3f\xb4\x02\xa4\x97\xf4\x83"
"\xb8\xa6\xf9\x3c\xd0\x18\xad\x92\x0c\xb7\x8a\x5a\x3e\x14\x48\x92\xef\x08\xf8\xca"
"\xea\xfb\x32\xab\x20\xa3\x62\x30\x60\x30\x46\x06\x03\x55\x1d\x23\x04\x3f\x30\x3d"
"\xa1\x30\xa4\x2e\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31"
"\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e\x06\x03\x55\x04"
"\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x82\x09\x00\xf7\xc9\xec\x89\xf2\x63\x94"
"\xd9\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55\x1d\x0f\x04"
"\x04\x03\x02\x04\xf0\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00"
"\x30\x45\x02\x20\x18\x38\xb0\x45\x03\x69\xaa\xa7\xb7\x38\x62\x01\xaf\x24\x97\x5e"
"\x7e\x74\x64\x1b\xa3\x7b\xf7\xe6\xd3\xaf\x79\x28\xdb\xdc\xa5\x88\x02\x21\x00\xcd"
"\x06\xf1\xe3\xab\x16\x21\x8e\xd8\xc0\x14\xaf\x09\x4f\x5b\x73\xef\x5e\x9e\x4b\xe7"
"\x35\xeb\xdd\x9b\x6d\x8f\x7d\xf3\xc4\x3a\xd7";
const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1;
const uint8_t attestation_key[] = "\xcd\x67\xaa\x31\x0d\x09\x1e\xd1\x6e\x7e\x98\x92\xaa\x07\x0e\x19\x94\xfc\xd7\x14\xae\x7c\x40\x8f\xb9\x46\xb7\x2e\x5f\xe7\x5d\x30";
const uint16_t attestation_key_size = sizeof(attestation_key)-1;
#else
#error "No crypto implementation defined"
#endif

View File

@ -9,8 +9,6 @@
#include <stddef.h>
#define USE_SOFTWARE_IMPLEMENTATION
void crypto_sha256_init();
void crypto_sha256_update(uint8_t * data, size_t len);
void crypto_sha256_update_secret();
@ -19,9 +17,13 @@ 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_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_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_attestation_key();
@ -34,6 +36,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_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_MASTER_KEY ((uint8_t*)0)
@ -48,10 +51,4 @@ void crypto_reset_master_secret();
void crypto_load_master_secret(uint8_t * key);
extern const uint8_t attestation_cert_der[];
extern const uint16_t attestation_cert_der_size;
extern const uint8_t attestation_key[];
extern const uint16_t attestation_key_size;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -16,12 +16,11 @@
#define CTAP_CLIENT_PIN 0x06
#define CTAP_RESET 0x07
#define GET_NEXT_ASSERTION 0x08
#define CTAP_CBOR_CRED_MGMT 0x0A
#define CTAP_VENDOR_FIRST 0x40
#define CTAP_CBOR_CRED_MGMT_PRE 0x41
#define CTAP_VENDOR_LAST 0xBF
// AAGUID For Solo
#define CTAP_AAGUID ((uint8_t*)"\x88\x76\x63\x1b\xd4\xa0\x42\x7f\x57\x73\x0e\xc7\x1c\x9e\x02\x79")
#define MC_clientDataHash 0x01
#define MC_rp 0x02
#define MC_user 0x03
@ -40,6 +39,19 @@
#define GA_pinAuth 0x06
#define GA_pinProtocol 0x07
#define CM_cmd 0x01
#define CM_cmdMetadata 0x01
#define CM_cmdRPBegin 0x02
#define CM_cmdRPNext 0x03
#define CM_cmdRKBegin 0x04
#define CM_cmdRKNext 0x05
#define CM_cmdRKDelete 0x06
#define CM_subCommandParams 0x02
#define CM_subCommandRpId 0x01
#define CM_subCommandCred 0x02
#define CM_pinProtocol 0x03
#define CM_pinAuth 0x04
#define CP_pinProtocol 0x01
#define CP_subCommand 0x02
#define CP_cmdGetRetries 0x01
@ -54,6 +66,18 @@
#define CP_getKeyAgreement 0x07
#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 EXT_CRED_PROTECT_INVALID 0x00
#define EXT_CRED_PROTECT_OPTIONAL 0x01
#define EXT_CRED_PROTECT_OPTIONAL_WITH_CREDID 0x02
#define EXT_CRED_PROTECT_REQUIRED 0x03
#define RESP_versions 0x1
#define RESP_extensions 0x2
#define RESP_aaguid 0x3
@ -105,6 +129,8 @@
#define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes
#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 CREDENTIAL_IS_SUPPORTED 1
@ -122,6 +148,8 @@
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
#define CTAP2_UP_DELAY_MS 29000
typedef struct
{
uint8_t id[USER_ID_MAX_SIZE];
@ -133,18 +161,35 @@ typedef struct
typedef struct {
uint8_t tag[CREDENTIAL_TAG_SIZE];
uint8_t nonce[CREDENTIAL_NONCE_SIZE];
union {
uint8_t nonce[CREDENTIAL_NONCE_SIZE];
struct {
uint8_t _pad[CREDENTIAL_NONCE_SIZE - 4];
uint32_t value;
}__attribute__((packed)) metadata;
}__attribute__((packed)) entropy;
uint8_t rpIdHash[32];
uint32_t count;
}__attribute__((packed)) CredentialId;
struct Credential {
struct __attribute__((packed)) Credential {
CredentialId id;
CTAP_userEntity user;
};
typedef struct {
CredentialId id;
CTAP_userEntity user;
typedef struct Credential CTAP_residentKey;
// Maximum amount of "extra" space in resident key.
uint8_t rpId[48];
uint8_t rpIdSize;
} __attribute__((packed)) CTAP_residentKey;
typedef struct
{
uint8_t type;
struct Credential credential;
} CTAP_credentialDescriptor;
typedef struct
{
@ -181,34 +226,68 @@ struct rpId
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;
uint32_t cred_protect;
} CTAP_extensions;
typedef struct
{
CTAP_userEntity user;
uint8_t publicKeyCredentialType;
int32_t COSEAlgorithmIdentifier;
uint8_t rk;
} CTAP_credInfo;
typedef struct
{
uint32_t paramsParsed;
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
struct rpId rp;
CTAP_userEntity user;
uint8_t publicKeyCredentialType;
int32_t COSEAlgorithmIdentifier;
CTAP_credInfo credInfo;
CborValue excludeList;
size_t excludeListSize;
uint8_t rk;
uint8_t uv;
uint8_t up;
uint8_t pinAuth[16];
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;
CTAP_extensions extensions;
} CTAP_makeCredential;
typedef struct
{
uint8_t type;
struct Credential credential;
} CTAP_credentialDescriptor;
typedef struct
{
@ -226,26 +305,45 @@ typedef struct
uint8_t pinAuth[16];
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;
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
CTAP_credentialDescriptor * creds;
uint8_t allowListPresent;
CTAP_extensions extensions;
} CTAP_getAssertion;
typedef struct
{
int cmd;
struct {
uint8_t rpIdHash[32];
CTAP_credentialDescriptor credentialDescriptor;
} subCommandParams;
struct {
uint8_t cmd;
uint8_t subCommandParamsCborCopy[sizeof(CTAP_credentialDescriptor) + 16];
} hashed;
uint32_t subCommandParamsCborSize;
uint8_t pinAuth[16];
uint8_t pinAuthPresent;
int pinProtocol;
} CTAP_credMgmt;
typedef struct
{
int pinProtocol;
int subCommand;
struct
{
struct{
uint8_t x[32];
uint8_t y[32];
} pubkey;
int kty;
int crv;
} keyAgreement;
COSE_key keyAgreement;
uint8_t keyAgreementPresent;
uint8_t pinAuth[16];
uint8_t pinAuthPresent;
@ -258,6 +356,24 @@ typedef struct
} CTAP_clientPin;
struct _getAssertionState {
// Room for both authData struct and extensions
struct {
CTAP_authDataHeader authData;
uint8_t extensions[80];
} __attribute__((packed)) buf;
CTAP_extensions extensions;
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);
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp);
@ -299,5 +415,8 @@ uint16_t ctap_key_len(uint8_t index);
extern uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
extern uint8_t KEY_AGREEMENT_PUB[64];
void lock_device_permanently();
void ctap_load_external_keys(uint8_t * keybytes);
#endif

View File

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

View File

@ -9,12 +9,14 @@
#include "cbor.h"
#include "ctap.h"
#include "u2f.h"
#include "ctap_parse.h"
#include "ctap_errors.h"
#include "cose_key.h"
#include "util.h"
#include "log.h"
extern struct _getAssertionState getAssertionState;
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;
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)
{
printf2(TAG_ERR,"Error, USER_ID is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
MC->user.id_size = sz;
printf1(TAG_GREEN,"parsed id_size: %d\r\n", MC->user.id_size);
MC->credInfo.user.id_size = sz;
check_ret(ret);
}
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;
}
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)
{ // Just truncate the name it's okay
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)
{
@ -161,12 +162,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
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)
{ // Just truncate the name it's okay
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)
{
@ -176,12 +177,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
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)
{ // Just truncate the name it's okay
check_ret(ret);
}
MC->user.icon[ICON_LIMIT - 1] = 0;
MC->credInfo.user.icon[ICON_LIMIT - 1] = 0;
}
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)
{
MC->publicKeyCredentialType = cred_type;
MC->COSEAlgorithmIdentifier = alg_type;
MC->credInfo.publicKeyCredentialType = cred_type;
MC->credInfo.COSEAlgorithmIdentifier = alg_type;
MC->paramsParsed |= PARAM_pubKeyCredParams;
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)
{
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;
}
@ -556,6 +557,162 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
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");
check_ret( cbor_value_advance(&map) );
check_ret( 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");
}
}
else if (strncmp(key, "credProtect",11) == 0) {
if (cbor_value_get_type(&map) == CborIntegerType) {
ret = cbor_value_get_int(&map, (int*)&ext->cred_protect);
check_ret(ret);
} else {
printf1(TAG_RED, "warning: credProtect 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)
{
int ret;
@ -566,6 +723,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
CborValue it,map;
memset(MC, 0, sizeof(CTAP_makeCredential));
MC->up = 0xff;
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_retr(ret);
@ -631,8 +789,8 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
ret = parse_user(MC, &map);
printf1(TAG_MC," ID: "); dump_hex1(TAG_MC, MC->user.id, MC->user.id_size);
printf1(TAG_MC," name: %s\n", MC->user.name);
printf1(TAG_MC," ID: "); dump_hex1(TAG_MC, MC->credInfo.user.id, MC->credInfo.user.id_size);
printf1(TAG_MC," name: %s\n", MC->credInfo.user.name);
break;
case MC_pubKeyCredParams:
@ -640,8 +798,8 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
ret = parse_pub_key_cred_params(MC, &map);
printf1(TAG_MC," cred_type: 0x%02x\n", MC->publicKeyCredentialType);
printf1(TAG_MC," alg_type: %d\n", MC->COSEAlgorithmIdentifier);
printf1(TAG_MC," cred_type: 0x%02x\n", MC->credInfo.publicKeyCredentialType);
printf1(TAG_MC," alg_type: %d\n", MC->credInfo.COSEAlgorithmIdentifier);
break;
case MC_excludeList:
@ -665,21 +823,31 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = ctap_parse_extensions(&map, &MC->extensions);
check_retr(ret);
break;
case MC_options:
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);
break;
case MC_pinAuth:
case MC_pinAuth: {
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);
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
{
check_retr(ret);
}
else
{
@ -687,6 +855,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
}
MC->pinAuthPresent = 1;
break;
}
case MC_pinProtocol:
printf1(TAG_MC,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType)
@ -710,7 +879,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
{
return ret;
}
cbor_value_advance(&map);
ret = cbor_value_advance(&map);
check_ret(ret);
}
@ -723,6 +892,8 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
size_t buflen;
char type[12];
CborValue val;
cred->type = 0;
if (cbor_value_get_type(arr) != CborMapType)
{
printf2(TAG_ERR,"Error, CborMapType expected in credential\n");
@ -739,12 +910,22 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
}
buflen = sizeof(CredentialId);
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL);
if (buflen != sizeof(CredentialId))
ret = cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL);
if (buflen == U2F_KEY_HANDLE_SIZE)
{
printf2(TAG_ERR,"Ignoring credential is incorrect length\n");
//return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail?
printf2(TAG_PARSE,"CTAP1 credential\n");
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);
check_ret(ret);
@ -756,11 +937,23 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
}
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)
{
cred->type = PUB_KEY_CRED_PUB_KEY;
if (0 == cred->type)
{
cred->type = PUB_KEY_CRED_PUB_KEY;
}
}
else
{
@ -814,6 +1007,163 @@ uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it)
return 0;
}
static uint8_t parse_cred_mgmt_subcommandparams(CborValue * val, CTAP_credMgmt * CM)
{
size_t map_length;
int key;
int ret;
unsigned int i;
CborValue map;
size_t sz = 32;
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);
const uint8_t * start_byte = cbor_value_get_next_byte(&map) - 1;
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 integer type for 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 CM_subCommandRpId:
ret = cbor_value_copy_byte_string(&map, CM->subCommandParams.rpIdHash, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, map key is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
check_ret(ret);
break;
case CM_subCommandCred:
ret = parse_credential_descriptor(&map, &CM->subCommandParams.credentialDescriptor);
check_ret(ret);;
break;
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
const uint8_t * end_byte = cbor_value_get_next_byte(&map);
uint32_t length = (uint32_t)end_byte - (uint32_t)start_byte;
if (length > sizeof(CM->hashed.subCommandParamsCborCopy))
{
return CTAP2_ERR_LIMIT_EXCEEDED;
}
// Copy the details that were hashed so they can be verified later.
memmove(CM->hashed.subCommandParamsCborCopy, start_byte, length);
CM->subCommandParamsCborSize = length;
return 0;
}
uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length)
{
int ret;
unsigned int i;
int key;
size_t map_length;
CborParser parser;
CborValue it,map;
memset(CM, 0, sizeof(CTAP_credMgmt));
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret);
CborType type = cbor_value_get_type(&it);
if (type != CborMapType)
{
printf2(TAG_ERR,"Error, expecting cbor map\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(&it,&map);
check_ret(ret);
ret = cbor_value_get_map_length(&it, &map_length);
check_ret(ret);
printf1(TAG_PARSE, "CM map has %d elements\n", map_length);
for (i = 0; i < map_length; i++)
{
type = cbor_value_get_type(&map);
if (type != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting int for map key\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int_checked(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
switch(key)
{
case CM_cmd:
printf1(TAG_PARSE, "CM_cmd\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, &CM->cmd);
check_ret(ret);
CM->hashed.cmd = CM->cmd;
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case CM_subCommandParams:
printf1(TAG_PARSE, "CM_subCommandParams\n");
ret = parse_cred_mgmt_subcommandparams(&map, CM);
check_ret(ret);
break;
case CM_pinProtocol:
printf1(TAG_PARSE, "CM_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, &CM->pinProtocol);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case CM_pinAuth:
printf1(TAG_PARSE, "CM_pinAuth\n");
ret = parse_fixed_byte_string(&map, CM->pinAuth, 16);
check_retr(ret);
CM->pinAuthPresent = 1;
break;
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}
uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length)
{
@ -825,6 +1175,9 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
CborValue it,map;
memset(GA, 0, sizeof(CTAP_getAssertion));
GA->creds = getAssertionState.creds; // Save stack memory
GA->up = 0xff;
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret);
@ -886,6 +1239,8 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
break;
case GA_extensions:
printf1(TAG_GA,"GA_extensions\n");
ret = ctap_parse_extensions(&map, &GA->extensions);
check_retr(ret);
break;
case GA_options:
@ -893,9 +1248,18 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up);
check_retr(ret);
break;
case GA_pinAuth:
case GA_pinAuth: {
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);
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
{
@ -911,6 +1275,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
GA->pinAuthPresent = 1;
break;
}
case GA_pinProtocol:
printf1(TAG_GA,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType)
@ -932,7 +1297,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
return ret;
}
cbor_value_advance(&map);
ret = cbor_value_advance(&map);
check_ret(ret);
}
@ -940,15 +1305,15 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
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;
size_t map_length;
int ret,key;
unsigned int i;
int xkey = 0,ykey = 0;
*kty = 0;
*crv = 0;
cose->kty = 0;
cose->crv = 0;
CborType type = cbor_value_get_type(it);
@ -986,7 +1351,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");
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);
}
else
@ -1001,7 +1366,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");
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);
}
else
@ -1011,14 +1376,14 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int
break;
case COSE_KEY_LABEL_X:
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);
xkey = 1;
break;
case COSE_KEY_LABEL_Y:
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);
ykey = 1;
@ -1030,7 +1395,7 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int
ret = cbor_value_advance(&map);
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;
}
@ -1110,7 +1475,7 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
break;
case CP_keyAgreement:
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);
CP->keyAgreementPresent = 1;
break;
@ -1153,11 +1518,21 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
break;
case CP_getKeyAgreement:
printf1(TAG_CP,"CP_getKeyAgreement\n");
if (cbor_value_get_type(&map) != CborBooleanType)
{
printf2(TAG_ERR,"Error, expecting cbor boolean\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_boolean(&map, &CP->getKeyAgreement);
check_ret(ret);
break;
case CP_getRetries:
printf1(TAG_CP,"CP_getRetries\n");
if (cbor_value_get_type(&map) != CborBooleanType)
{
printf2(TAG_ERR,"Error, expecting cbor boolean\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_boolean(&map, &CP->getRetries);
check_ret(ret);
break;

View File

@ -30,11 +30,12 @@ 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_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_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length);
uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length);
uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length);
uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred);

View File

@ -16,6 +16,13 @@
#include "util.h"
#include "log.h"
#include "extensions.h"
#include "version.h"
// move custom SHA512 command out,
// and the following headers too
#include "sha2.h"
#include "crypto.h"
#include APP_CONFIG
typedef enum
@ -268,7 +275,7 @@ static void ctaphid_write(CTAPHID_WRITE_BUFFER * wb, void * _data, int len)
if (wb->offset > 0)
{
memset(wb->buf + wb->offset, 0, HID_MESSAGE_SIZE - wb->offset);
ctaphid_write_block(wb->buf);
usbhid_send(wb->buf);
}
return;
}
@ -297,7 +304,7 @@ static void ctaphid_write(CTAPHID_WRITE_BUFFER * wb, void * _data, int len)
wb->bytes_written += 1;
if (wb->offset == HID_MESSAGE_SIZE)
{
ctaphid_write_block(wb->buf);
usbhid_send(wb->buf);
wb->offset = 0;
}
}
@ -528,11 +535,21 @@ static int ctaphid_buffer_packet(uint8_t * pkt_raw, uint8_t * cmd, uint32_t * ci
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_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE_BUFFER * wb);
extern void solo_lock_if_not_already();
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
{
uint8_t cmd;
uint8_t cmd = 0;
uint32_t cid;
int len;
int len = 0;
#ifndef DISABLE_CTAPHID_CBOR
int status;
#endif
@ -542,6 +559,10 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
CTAP_RESPONSE ctap_resp;
int bufstatus = ctaphid_buffer_packet(pkt_raw, &cmd, &cid, &len);
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = cmd;
if (bufstatus == HID_IGNORE)
{
@ -577,9 +598,6 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
case CTAPHID_PING:
printf1(TAG_HID,"CTAPHID_PING\n");
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_PING;
wb.bcnt = len;
timestamp();
ctaphid_write(&wb, ctap_buffer, len);
@ -592,13 +610,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
case CTAPHID_WINK:
printf1(TAG_HID,"CTAPHID_WINK\n");
ctaphid_write_buffer_init(&wb);
device_wink();
wb.cid = cid;
wb.cmd = CTAPHID_WINK;
ctaphid_write(&wb,NULL,0);
break;
@ -623,10 +637,10 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
ctap_response_init(&ctap_resp);
status = ctap_request(ctap_buffer, len, &ctap_resp);
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_CBOR;
wb.bcnt = (ctap_resp.length+1);
wb.cid = cid;
wb.cmd = cmd;
timestamp();
@ -656,10 +670,10 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
ctap_response_init(&ctap_resp);
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_MSG;
wb.bcnt = (ctap_resp.length);
wb.cid = cid;
wb.cmd = cmd;
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
ctaphid_write(&wb, NULL, 0);
@ -669,60 +683,14 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
printf1(TAG_HID,"CTAPHID_CANCEL\n");
is_busy = 0;
break;
#if defined(IS_BOOTLOADER)
case CTAPHID_BOOT:
printf1(TAG_HID,"CTAPHID_BOOT\n");
ctap_response_init(&ctap_resp);
u2f_set_writeback_buffer(&ctap_resp);
is_busy = bootloader_bridge(len, ctap_buffer);
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_BOOT;
wb.bcnt = (ctap_resp.length + 1);
ctaphid_write(&wb, &is_busy, 1);
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
#endif
#if defined(SOLO_HACKER)
case CTAPHID_ENTERBOOT:
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
boot_solo_bootloader();
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_ENTERBOOT;
wb.bcnt = 0;
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
case CTAPHID_ENTERSTBOOT:
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
boot_st_bootloader();
break;
#endif
#if !defined(IS_BOOTLOADER)
case CTAPHID_GETRNG:
printf1(TAG_HID,"CTAPHID_GETRNG\n");
ctap_response_init(&ctap_resp);
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_GETRNG;
wb.bcnt = ctap_buffer[0];
if (!wb.bcnt)
wb.bcnt = 57;
memset(ctap_buffer,0,wb.bcnt);
ctap_generate_rng(ctap_buffer, wb.bcnt);
ctaphid_write(&wb, &ctap_buffer, wb.bcnt);
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
#endif
default:
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
break;
if (ctaphid_custom_command(len, &ctap_resp, &wb) != 0){
is_busy = 0;
}else{
printf2(TAG_ERR, "error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
}
}
cid_del(cid);
buffer_reset();
@ -732,3 +700,136 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
else return 0;
}
uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE_BUFFER * wb)
{
ctap_response_init(ctap_resp);
#if !defined(IS_BOOTLOADER) && (defined(SOLO_EXPERIMENTAL))
uint32_t param;
#endif
#if defined(IS_BOOTLOADER)
uint8_t is_busy;
#endif
switch(wb->cmd)
{
#if defined(IS_BOOTLOADER)
case CTAPHID_BOOT:
printf1(TAG_HID,"CTAPHID_BOOT\n");
u2f_set_writeback_buffer(ctap_resp);
is_busy = bootloader_bridge(len, ctap_buffer);
wb->bcnt = 1 + ctap_resp->length;
ctaphid_write(wb, &is_busy, 1);
ctaphid_write(wb, ctap_resp->data, ctap_resp->length);
ctaphid_write(wb, NULL, 0);
return 1;
#endif
#if defined(SOLO)
case CTAPHID_ENTERBOOT:
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
boot_solo_bootloader();
wb->bcnt = 0;
ctaphid_write(wb, NULL, 0);
return 1;
#endif
#if defined(SOLO)
case CTAPHID_REBOOT:
device_reboot();
return 1;
#endif
#if !defined(IS_BOOTLOADER)
case CTAPHID_GETRNG:
printf1(TAG_HID,"CTAPHID_GETRNG\n");
wb->bcnt = ctap_buffer[0];
if (!wb->bcnt)
wb->bcnt = 57;
memset(ctap_buffer,0,wb->bcnt);
ctap_generate_rng(ctap_buffer, wb->bcnt);
ctaphid_write(wb, ctap_buffer, wb->bcnt);
ctaphid_write(wb, NULL, 0);
return 1;
break;
#endif
case CTAPHID_GETVERSION:
printf1(TAG_HID,"CTAPHID_GETVERSION\n");
wb->bcnt = 4;
ctap_buffer[0] = SOLO_VERSION_MAJ;
ctap_buffer[1] = SOLO_VERSION_MIN;
ctap_buffer[2] = SOLO_VERSION_PATCH;
#if defined(SOLO)
ctap_buffer[3] = solo_is_locked();
#else
ctap_buffer[3] = 0;
#endif
ctaphid_write(wb, ctap_buffer, 4);
ctaphid_write(wb, NULL, 0);
return 1;
break;
// Remove on next release
#if !defined(IS_BOOTLOADER) && defined(SOLO)
case 0x99:
solo_lock_if_not_already();
wb->bcnt = 0;
ctaphid_write(wb, NULL, 0);
return 1;
break;
#endif
#if !defined(IS_BOOTLOADER) && (defined(SOLO_EXPERIMENTAL))
case CTAPHID_LOADKEY:
/**
* Load external key. Useful for enabling backups.
* bytes: 4 4 96
* payload: version [maj rev patch RFU]| counter_replacement (BE) | master_key |
*
* Counter should be increased by a large amount, e.g. (0x10000000)
* to outdo any previously lost/broken keys.
*/
printf1(TAG_HID,"CTAPHID_LOADKEY\n");
if (len != 104)
{
printf2(TAG_ERR,"Error, invalid length.\n");
ctaphid_send_error(wb->cid, CTAP1_ERR_INVALID_LENGTH);
return 1;
}
param = ctap_buffer[0] << 16;
param |= ctap_buffer[1] << 8;
param |= ctap_buffer[2] << 0;
if (param != 0){
ctaphid_send_error(wb->cid, CTAP2_ERR_UNSUPPORTED_OPTION);
return 1;
}
// Ask for THREE button presses
if (ctap_user_presence_test(8000) > 0)
if (ctap_user_presence_test(2000) > 0)
if (ctap_user_presence_test(2000) > 0)
{
ctap_load_external_keys(ctap_buffer + 8);
param = ctap_buffer[7];
param |= ctap_buffer[6] << 8;
param |= ctap_buffer[5] << 16;
param |= ctap_buffer[4] << 24;
ctap_atomic_count(param);
wb->bcnt = 0;
ctaphid_write(wb, NULL, 0);
return 1;
}
printf2(TAG_ERR, "Error, invalid length.\n");
ctaphid_send_error(wb->cid, CTAP2_ERR_OPERATION_DENIED);
return 1;
#endif
}
return 0;
}

View File

@ -27,7 +27,12 @@
#define CTAPHID_BOOT (TYPE_INIT | 0x50)
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
#define CTAPHID_REBOOT (TYPE_INIT | 0x53)
#define CTAPHID_GETRNG (TYPE_INIT | 0x60)
#define CTAPHID_GETVERSION (TYPE_INIT | 0x61)
#define CTAPHID_LOADKEY (TYPE_INIT | 0x62)
// 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_PAR 0x02
@ -55,6 +60,8 @@
#define CTAP_CAPABILITIES (CAPABILITY_WINK | CAPABILITY_CBOR)
#define HID_MESSAGE_SIZE 64
typedef struct
{
uint32_t cid;

90
fido2/data_migration.c Normal file
View File

@ -0,0 +1,90 @@
// 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.
#include "data_migration.h"
#include "log.h"
#include "device.h"
#include "crypto.h"
// TODO move from macro to function/assert for better readability?
#define check(x) assert(state_prev_0xff->x == state_tmp_ptr->x);
#define check_buf(x) assert(memcmp(state_prev_0xff->x, state_tmp_ptr->x, sizeof(state_tmp_ptr->x)) == 0);
bool migrate_from_FF_to_01(AuthenticatorState_0xFF* state_prev_0xff, AuthenticatorState_0x01* state_tmp_ptr){
// Calculate PIN hash, and replace PIN raw storage with it; add version to structure
// other ingredients do not change
if (state_tmp_ptr->data_version != 0xFF)
return false;
static_assert(sizeof(AuthenticatorState_0xFF) <= sizeof(AuthenticatorState_0x01), "New state structure is smaller, than current one, which is not handled");
if (ctap_generate_rng(state_tmp_ptr->PIN_SALT, sizeof(state_tmp_ptr->PIN_SALT)) != 1) {
printf2(TAG_ERR, "Error, rng failed\n");
return false;
}
if (state_prev_0xff->is_pin_set){
crypto_sha256_init();
crypto_sha256_update(state_prev_0xff->pin_code, state_prev_0xff->pin_code_length);
uint8_t intermediateHash[32];
crypto_sha256_final(intermediateHash);
crypto_sha256_init();
crypto_sha256_update(intermediateHash, 16);
memset(intermediateHash, 0, sizeof(intermediateHash));
crypto_sha256_update(state_tmp_ptr->PIN_SALT, sizeof(state_tmp_ptr->PIN_SALT));
crypto_sha256_final(state_tmp_ptr->PIN_CODE_HASH);
}
assert(state_tmp_ptr->_reserved == state_prev_0xff->pin_code_length);
state_tmp_ptr->_reserved = 0xFF;
state_tmp_ptr->data_version = 1;
check(is_initialized);
check(is_pin_set);
check(remaining_tries);
check(rk_stored);
check_buf(key_lens);
check_buf(key_space);
assert(state_tmp_ptr->data_version != 0xFF);
return true;
}
void save_migrated_state(AuthenticatorState *state_tmp_ptr) {
memmove(&STATE, state_tmp_ptr, sizeof(AuthenticatorState));
authenticator_write_state(state_tmp_ptr);
}
void do_migration_if_required(AuthenticatorState* state_current){
// Currently handles only state structures with the same size, or bigger
// FIXME rework to raw buffers with fixed size to allow state structure size decrease
if(!state_current->is_initialized)
return;
AuthenticatorState state_tmp;
AuthenticatorState state_previous;
authenticator_read_state(&state_previous);
authenticator_read_state(&state_tmp);
if(state_current->data_version == 0xFF){
printf2(TAG_ERR, "Running migration\n");
bool success = migrate_from_FF_to_01((AuthenticatorState_0xFF *) &state_previous, &state_tmp);
if (!success){
printf2(TAG_ERR, "Failed migration from 0xFF to 1\n");
// FIXME discuss migration failure behavior
goto return_cleanup;
}
dump_hex1(TAG_ERR, (void*)&state_tmp, sizeof(state_tmp));
dump_hex1(TAG_ERR, (void*)&state_previous, sizeof(state_previous));
save_migrated_state(&state_tmp);
}
assert(state_current->data_version == STATE_VERSION);
return_cleanup:
memset(&state_tmp, 0, sizeof(AuthenticatorState));
memset(&state_previous, 0, sizeof(AuthenticatorState));
}

15
fido2/data_migration.h Normal file
View File

@ -0,0 +1,15 @@
// 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.
#ifndef FIDO2_PR_DATA_MIGRATION_H
#define FIDO2_PR_DATA_MIGRATION_H
#include "storage.h"
void do_migration_if_required(AuthenticatorState* state_current);
#endif //FIDO2_PR_DATA_MIGRATION_H

225
fido2/device.c Normal file
View File

@ -0,0 +1,225 @@
// 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.
/** device.c
*
* This contains (weak) implementations
* to get FIDO2 working initially on a device. They probably
* aren't what you want to keep, but are designed to be replaced
* with some other platform specific implementation.
*
* For real examples, see the STM32L4 implementation and the PC implementation of device.c.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "ctaphid.h"
#include "log.h"
#include APP_CONFIG
#define RK_NUM 50
struct ResidentKeyStore {
CTAP_residentKey rks[RK_NUM];
} RK_STORE;
static bool _up_disabled = false;
static uint8_t _attestation_cert_der[] =
"\x30\x82\x01\xfb\x30\x82\x01\xa1\xa0\x03\x02\x01\x02\x02\x01\x00\x30\x0a\x06\x08"
"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e"
"\x06\x03\x55\x04\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x30\x20\x17\x0d\x31\x38"
"\x30\x35\x31\x30\x30\x33\x30\x36\x32\x30\x5a\x18\x0f\x32\x30\x36\x38\x30\x34\x32"
"\x37\x30\x33\x30\x36\x32\x30\x5a\x30\x7c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x0f\x30\x0d"
"\x06\x03\x55\x04\x07\x0c\x06\x4c\x61\x75\x72\x65\x6c\x31\x15\x30\x13\x06\x03\x55"
"\x04\x0a\x0c\x0c\x54\x45\x53\x54\x20\x43\x4f\x4d\x50\x41\x4e\x59\x31\x22\x30\x20"
"\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x6f\x72"
"\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x14\x30\x12\x06\x03\x55\x04"
"\x03\x0c\x0b\x63\x6f\x6e\x6f\x72\x70\x70\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07"
"\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00"
"\x04\x45\xa9\x02\xc1\x2e\x9c\x0a\x33\xfa\x3e\x84\x50\x4a\xb8\x02\xdc\x4d\xb9\xaf"
"\x15\xb1\xb6\x3a\xea\x8d\x3f\x03\x03\x55\x65\x7d\x70\x3f\xb4\x02\xa4\x97\xf4\x83"
"\xb8\xa6\xf9\x3c\xd0\x18\xad\x92\x0c\xb7\x8a\x5a\x3e\x14\x48\x92\xef\x08\xf8\xca"
"\xea\xfb\x32\xab\x20\xa3\x62\x30\x60\x30\x46\x06\x03\x55\x1d\x23\x04\x3f\x30\x3d"
"\xa1\x30\xa4\x2e\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31"
"\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e\x06\x03\x55\x04"
"\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x82\x09\x00\xf7\xc9\xec\x89\xf2\x63\x94"
"\xd9\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55\x1d\x0f\x04"
"\x04\x03\x02\x04\xf0\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00"
"\x30\x45\x02\x20\x18\x38\xb0\x45\x03\x69\xaa\xa7\xb7\x38\x62\x01\xaf\x24\x97\x5e"
"\x7e\x74\x64\x1b\xa3\x7b\xf7\xe6\xd3\xaf\x79\x28\xdb\xdc\xa5\x88\x02\x21\x00\xcd"
"\x06\xf1\xe3\xab\x16\x21\x8e\xd8\xc0\x14\xaf\x09\x4f\x5b\x73\xef\x5e\x9e\x4b\xe7"
"\x35\xeb\xdd\x9b\x6d\x8f\x7d\xf3\xc4\x3a\xd7";
__attribute__((weak)) void device_attestation_read_cert_der(uint8_t * dst){
memmove(dst, _attestation_cert_der, device_attestation_cert_der_get_size());
}
__attribute__((weak)) uint8_t * device_get_attestation_key(){
static uint8_t attestation_key[] =
"\xcd\x67\xaa\x31\x0d\x09\x1e\xd1\x6e\x7e\x98\x92\xaa"
"\x07\x0e\x19\x94\xfc\xd7\x14\xae\x7c\x40\x8f\xb9\x46"
"\xb7\x2e\x5f\xe7\x5d\x30";
return attestation_key;
}
__attribute__((weak)) uint16_t device_attestation_cert_der_get_size(){
return sizeof(_attestation_cert_der)-1;
}
__attribute__((weak)) void device_reboot()
{
printf1(TAG_RED, "REBOOT command recieved!\r\n");
exit(100);
}
__attribute__((weak)) void device_set_status(uint32_t status)
{
static uint32_t __device_status = 0;
if (status != CTAPHID_STATUS_IDLE && __device_status != status)
{
ctaphid_update_status(status);
}
__device_status = status;
}
__attribute__((weak)) void usbhid_close(){/**/}
__attribute__((weak)) void device_init(int argc, char *argv[]){/**/}
__attribute__((weak)) void device_disable_up(bool disable)
{
_up_disabled = disable;
}
__attribute__((weak)) int ctap_user_presence_test(uint32_t d)
{
if (_up_disabled)
{
return 2;
}
return 1;
}
__attribute__((weak)) int ctap_user_verification(uint8_t arg)
{
return 1;
}
__attribute__((weak)) uint32_t ctap_atomic_count(uint32_t amount)
{
static uint32_t counter1 = 25;
counter1 += (amount + 1);
return counter1;
}
__attribute__((weak)) int ctap_generate_rng(uint8_t * dst, size_t num)
{
int i;
printf1(TAG_ERR, "Insecure RNG being used.\r\n");
for (i = 0; i < num; i++){
dst[i] = (uint8_t)rand();
}
}
__attribute__((weak)) int device_is_nfc()
{
return 0;
}
__attribute__((weak)) void device_wink()
{
printf1(TAG_GREEN,"*WINK*\n");
}
__attribute__((weak)) void device_set_clock_rate(DEVICE_CLOCK_RATE param){/**/}
static AuthenticatorState _tmp_state = {0};
__attribute__((weak)) int authenticator_read_state(AuthenticatorState * s){
if (_tmp_state.is_initialized != INITIALIZED_MARKER){
return 0;
}
else {
memmove(s, &_tmp_state, sizeof(AuthenticatorState));
return 1;
}
}
__attribute__((weak)) void authenticator_write_state(AuthenticatorState * s){
memmove(&_tmp_state, s, sizeof(AuthenticatorState));
}
__attribute__((weak)) void ctap_reset_rk()
{
memset(&RK_STORE,0xff,sizeof(RK_STORE));
}
__attribute__((weak)) uint32_t ctap_rk_size()
{
return RK_NUM;
}
__attribute__((weak)) void ctap_store_rk(int index, CTAP_residentKey * rk)
{
if (index < RK_NUM)
{
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
}
else
{
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
}
}
__attribute__((weak)) void ctap_delete_rk(int index)
{
CTAP_residentKey rk;
memset(&rk, 0xff, sizeof(CTAP_residentKey));
if (index < RK_NUM)
{
memmove(RK_STORE.rks + index, &rk, sizeof(CTAP_residentKey));
}
else
{
printf1(TAG_ERR,"Out of bounds for delete_rk\r\n");
}
}
__attribute__((weak)) void ctap_load_rk(int index, CTAP_residentKey * rk)
{
memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey));
}
__attribute__((weak)) void ctap_overwrite_rk(int index, CTAP_residentKey * rk)
{
if (index < RK_NUM)
{
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
}
else
{
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
}
}
__attribute__((weak)) void device_read_aaguid(uint8_t * dst){
uint8_t * aaguid = (uint8_t *)"\x00\x76\x63\x1b\xd4\xa0\x42\x7f\x57\x73\x0e\xc7\x1c\x9e\x02\x79";
memmove(dst, aaguid, 16);
}

View File

@ -9,82 +9,218 @@
#include "storage.h"
void device_init();
/** Return a millisecond timestamp. Does not need to be synchronized to anything.
* *Optional* to compile, but will not calculate delays correctly without a correct implementation.
*/
uint32_t millis();
void delay(uint32_t ms);
// HID message size in bytes
#define HID_MESSAGE_SIZE 64
void usbhid_init();
int usbhid_recv(uint8_t * msg);
/** Called by HIDUSB layer to write bytes to the USB HID interface endpoint.
* Will write 64 bytes at a time.
*
* @param msg Pointer to a 64 byte buffer containing a payload to be sent via USB HID.
*
* **Required** to compile and work for FIDO application.
*/
void usbhid_send(uint8_t * msg);
void usbhid_close();
void main_loop_delay();
/** Reboot / power reset the device.
* **Optional** this is not used for FIDO2, and simply won't do anything if not implemented.
*/
void device_reboot();
void heartbeat();
/** Read AuthenticatorState from nonvolatile memory.
* @param s pointer to AuthenticatorState buffer to be overwritten with contents from NV memory.
* @return 0 - state stored is NOT initialized.
* 1 - state stored is initialized.
*
* *Optional* this is required to make persistant updates to FIDO2 State (PIN and device master secret).
* Without it, changes simply won't be persistant.
*/
int authenticator_read_state(AuthenticatorState * s);
void authenticator_read_state(AuthenticatorState * );
void authenticator_read_backup_state(AuthenticatorState * );
// Return 1 yes backup is init'd, else 0
//void authenticator_initialize()
int authenticator_is_backup_initialized();
void authenticator_write_state(AuthenticatorState *, int backup);
// Called each main loop. Doesn't need to do anything.
void device_manage();
/** Store changes in the authenticator state to nonvolatile memory.
* @param s pointer to valid Authenticator state to write to NV memory.
*
* *Optional* this is required to make persistant updates to FIDO2 State (PIN and device master secret).
* Without it, changes simply won't be persistant.
*/
void authenticator_write_state(AuthenticatorState * s);
// sets status that's uses for sending status updates ~100ms.
// A timer should be set up to call `ctaphid_update_status`
/** Updates status of the status of the FIDO2 layer application, which
* can be used for polling updates in the USBHID layer.
*
* @param status is one of the following, which can be used appropriately by USB HID layer.
#define CTAPHID_STATUS_IDLE 0
#define CTAPHID_STATUS_PROCESSING 1
#define CTAPHID_STATUS_UPNEEDED 2
*
* *Optional* to compile and run, but will be required to be used for proper FIDO2 operation with some platforms.
*/
void device_set_status(uint32_t status);
// Returns if button is currently pressed
/** Returns true if button is currently pressed. Debouncing does not need to be handled. Should not block.
* @return 1 if button is currently pressed.
*
* *Optional* to compile and run, but just returns one by default.
*/
int device_is_button_pressed();
// Test for user presence
// Return 1 for user is present, 0 user not present, -1 if cancel is requested.
extern int ctap_user_presence_test();
//
// Return 2 for disabled, 1 for user is present, 0 user not present, -1 if cancel is requested.
/** Test for user presence.
* Perform test that user is present. Returns status on user presence. This is used by FIDO and U2F layer
* to check if an operation should continue, or if the UP flag should be set.
*
* @param delay number of milliseconds to delay waiting for user before timeout.
*
* @return 2 - User presence is disabled. Operation should continue, but UP flag not set.
* 1 - User presence confirmed. Operation should continue, and UP flag is set.
* 0 - User presence is not confirmed. Operation should be denied.
* -1 - Operation was canceled. Do not continue, reset transaction state.
*
* *Optional*, the default implementation will return 1, unless a FIDO2 operation calls for no UP, where this will then return 2.
*/
int ctap_user_presence_test(uint32_t delay);
// Generate @num bytes of random numbers to @dest
// return 1 if success, error otherwise
extern int ctap_generate_rng(uint8_t * dst, size_t num);
/** Disable the next user presence test. This is called by FIDO2 layer when a transaction
* requests UP to be disabled. The next call to ctap_user_presence_test should return 2,
* and then UP should be enabled again.
*
* @param request_active indicate to activate (true) or disable (false) UP.
*
* *Optional*, the default implementation will provide expected behaviour with the default ctap_user_presence_test(...).
*/
void device_disable_up(bool request_active);
// Increment atomic counter and return it.
// Must support two counters, @sel selects counter0 or counter1.
uint32_t ctap_atomic_count(int sel);
/** Generate random numbers. Random numbers should be good enough quality for
* cryptographic use.
*
* @param dst the buffer to write into.
* @param num the number of bytes to generate and write to dst.
*
* @return 1 if successful, or else the RNG failed.
*
* *Optional*, if not implemented, the random numbers will be from rand() and an error will be logged.
*/
int ctap_generate_rng(uint8_t * dst, size_t num);
// Verify the user
// return 1 if user is verified, 0 if not
extern int ctap_user_verification(uint8_t arg);
/** Increment an atomic (non-volatile) counter and return the value.
*
* @param amount a non-zero amount to increment the counter by.
*
* *Optional*, if not implemented, the counter will not be persistant.
*/
uint32_t ctap_atomic_count(uint32_t amount);
// Must be implemented by application
// data is HID_MESSAGE_SIZE long in bytes
extern void ctaphid_write_block(uint8_t * data);
// Resident key
/** Delete all resident keys.
*
* *Optional*, if not implemented, operates on non-persistant RK's.
*/
void ctap_reset_rk();
/** Return the maximum amount of resident keys that can be stored.
* @return max number of resident keys that can be stored, including already stored RK's.
*
* *Optional*, if not implemented, returns 50.
*/
uint32_t ctap_rk_size();
/** Store a resident key into an index between [ 0, ctap_rk_size() ).
* Storage should be in non-volatile memory.
*
* @param index between RK index range.
* @param rk pointer to valid rk structure that should be written to NV memory.
*
* *Optional*, if not implemented, operates on non-persistant RK's.
*/
void ctap_store_rk(int index,CTAP_residentKey * rk);
/** Delete a resident key from an index.
* @param index to delete resident key from. Has no effect if no RK exists at index.
*
* *Optional*, if not implemented, operates on non-persistant RK's.
*/
void ctap_delete_rk(int index);
/** Read a resident key from an index into memory
* @param index to read resident key from.
* @param rk pointer to resident key structure to write into with RK.
*
* *Optional*, if not implemented, operates on non-persistant RK's.
*/
void ctap_load_rk(int index,CTAP_residentKey * rk);
/** Overwrite the RK located in index with a new RK.
* @param index to write resident key to.
* @param rk pointer to valid rk structure that should be written to NV memory, and replace existing RK there.
*
* *Optional*, if not implemented, operates on non-persistant RK's.
*/
void ctap_overwrite_rk(int index,CTAP_residentKey * rk);
// For Solo hacker
void boot_solo_bootloader();
void boot_st_bootloader();
// HID wink command
/** Called by HID layer to indicate that a wink behavior should be performed.
* Should not block, and the wink behavior should occur in parallel to FIDO operations.
*
* *Optional*.
*/
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. This gets called only when the device is running in NFC mode.
* Before Register and authenticate operations, the clock rate will be set to (1), and otherwise back to (0).
* @param param
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.
* *Optional*, by default nothing happens.
*/
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
/** Returns NFC status of the device.
* @return 0 - NFC is not available.
* 1 - NFC is active, and is powering the chip for a transaction.
* 2 - NFC is available, but not currently being used.
*/
int device_is_nfc();
/** Return pointer to attestation key.
* @return pointer to attestation private key, raw encoded. For P256, this is 32 bytes.
*/
uint8_t * device_get_attestation_key();
/** Read the device's attestation certificate into buffer @dst.
* @param dst the destination to write the certificate.
*
* The size of the certificate can be retrieved using `device_attestation_cert_der_get_size()`.
*/
void device_attestation_read_cert_der(uint8_t * dst);
/** Returns the size in bytes of attestation_cert_der.
* @return number of bytes in attestation_cert_der, not including any C string null byte.
*/
uint16_t device_attestation_cert_der_get_size();
/** Read the device's 16 byte AAGUID into a buffer.
* @param dst buffer to write 16 byte AAGUID into.
* */
void device_read_aaguid(uint8_t * dst);
#endif

41
fido2/example_app.h Normal file
View File

@ -0,0 +1,41 @@
// 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.
#ifndef SRC_APP_H_
#define SRC_APP_H_
#include <stdbool.h>
#define USING_DEV_BOARD
#define USING_PC
#define ENABLE_U2F
#define ENABLE_U2F_EXTENSIONS
//#define BRIDGE_TO_WALLET
void printing_init();
extern bool use_udp;
// 0xRRGGBB
#define LED_INIT_VALUE 0x000800
#define LED_WINK_VALUE 0x000008
#define LED_MAX_SCALER 30
#define LED_MIN_SCALER 1
// # of ms between each change in LED
#define HEARTBEAT_PERIOD 100
// Each LED channel will be multiplied by a integer between LED_MAX_SCALER
// and LED_MIN_SCALER to cause the slow pulse. E.g.
// #define LED_INIT_VALUE 0x301000
// #define LED_MAX_SCALER 30
// #define LED_MIN_SCALER 1
// #define HEARTBEAT_PERIOD 8
// Will pulse from 0x301000 to 0x903000 to 0x301000 ...
// Which will take ~8 * (30)*2 ms
#endif /* SRC_APP_H_ */

View File

@ -35,6 +35,28 @@ int extension_needs_atomic_count(uint8_t klen, uint8_t * keyh)
|| ((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)
{
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);
#ifdef IS_BOOTLOADER
ret = bootloader_bridge(klen, keyh);
#elif defined(WALLET_EXTENSION)
ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh);
#else
ret = bridge_u2f_to_solo(sig, keyh, klen);
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)))
{
printf1(TAG_EXT,"IS EXT REQ\r\n");
output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId));
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;
if (req->ins == U2F_AUTHENTICATE)
@ -118,7 +139,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
{
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
{
rcode = U2F_SW_WRONG_PAYLOAD;
rcode = U2F_SW_WRONG_DATA;
printf1(TAG_EXT, "Ignoring U2F auth request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end;

View File

@ -7,8 +7,14 @@
#ifndef EXTENSIONS_H_
#define EXTENSIONS_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);
@ -16,4 +22,8 @@ int bootloader_bridge(int klen, uint8_t * keyh);
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_ */

View File

@ -31,12 +31,15 @@
#include "log.h"
#include APP_CONFIG
// output must be at least 71 bytes
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
{
int8_t ret = 0;
wallet_request * req = (wallet_request *) keyh;
extension_writeback_init(output, 71);
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;
#ifdef ENABLE_WALLET
case WalletSign:
case WalletRegister:
case WalletPin:
case WalletReset:
return bridge_to_wallet(keyh, keylen);
#endif
default:
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
ret = CTAP1_ERR_INVALID_COMMAND;

View File

@ -14,8 +14,8 @@
#include "util.h"
#include "storage.h"
#include "device.h"
#include "extensions.h"
#if defined(USING_PC) || defined(IS_BOOTLOADER)
typedef enum
{
MBEDTLS_ECP_DP_NONE = 0,
@ -32,9 +32,7 @@ typedef enum
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
} mbedtls_ecp_group_id;
#else
#include "ecp.h"
#endif
// 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;
}
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);
break;
case CP_cmdGetRetries:
printf1(TAG_WALLET,"cmdGetRetries\n");
pinTokenEnc[0] = ctap_leftover_pin_attempts();
u2f_response_writeback(pinTokenEnc,1);
extension_writeback(pinTokenEnc,1);
break;
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;
}
if (!ctap_user_presence_test())
if (!ctap_user_presence_test(5000))
{
return CTAP2_ERR_OPERATION_DENIED;
}
@ -97,7 +95,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
if (ret != 0)
return ret;
printf1(TAG_WALLET,"Success. Pin = %s\n", STATE.pin_code);
// printf1(TAG_WALLET,"Success. Pin = %s\n", STATE.pin_code);
break;
case CP_cmdChangePin:
@ -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;
}
if (!ctap_user_presence_test())
if (!ctap_user_presence_test(5000))
{
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;
}
if (!ctap_user_presence_test())
if (!ctap_user_presence_test(5000))
{
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;
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;
@ -159,7 +157,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
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];
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_ecdsa_sign(args[0], lens[0], sig, MBEDTLS_ECP_DP_SECP256K1);
u2f_response_writeback(sig,64);
extension_writeback(sig,64);
break;
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");
ctap_reset();
@ -374,39 +372,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
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:
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);

View File

@ -87,10 +87,7 @@ typedef enum
} WalletOperation;
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 bridge_to_wallet(uint8_t * keyh, uint8_t klen);
void wallet_init();

View File

@ -48,6 +48,10 @@ struct logtag tagtable[] = {
{TAG_STOR,"STOR"},
{TAG_BOOT,"BOOT"},
{TAG_EXT,"EXT"},
{TAG_NFC,"NFC"},
{TAG_NFC_APDU, "NAPDU"},
{TAG_CCID, "CCID"},
{TAG_CM, "CRED_MGMT"},
};
@ -68,7 +72,7 @@ void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...)
{
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;
break;
}

View File

@ -7,7 +7,10 @@
#ifndef _LOG_H
#define _LOG_H
#ifdef APP_CONFIG
#include APP_CONFIG
#endif
#include <stdint.h>
#ifndef DEBUG_LEVEL
@ -23,30 +26,35 @@ void set_logging_tag(uint32_t tag);
typedef enum
{
TAG_GEN = (1 << 0),
TAG_MC = (1 << 1),
TAG_GA = (1 << 2),
TAG_CP = (1 << 3),
TAG_ERR = (1 << 4),
TAG_PARSE= (1 << 5),
TAG_CTAP = (1 << 6),
TAG_U2F = (1 << 7),
TAG_DUMP = (1 << 8),
TAG_GREEN = (1 << 9),
TAG_RED= (1 << 10),
TAG_TIME= (1 << 11),
TAG_HID = (1 << 12),
TAG_USB = (1 << 13),
TAG_WALLET = (1 << 14),
TAG_STOR = (1 << 15),
TAG_DUMP2 = (1 << 16),
TAG_BOOT = (1 << 17),
TAG_EXT = (1 << 18),
TAG_GEN = (1 << 0),
TAG_MC = (1 << 1),
TAG_GA = (1 << 2),
TAG_CP = (1 << 3),
TAG_ERR = (1 << 4),
TAG_PARSE = (1 << 5),
TAG_CTAP = (1 << 6),
TAG_U2F = (1 << 7),
TAG_DUMP = (1 << 8),
TAG_GREEN = (1 << 9),
TAG_RED = (1 << 10),
TAG_TIME = (1 << 11),
TAG_HID = (1 << 12),
TAG_USB = (1 << 13),
TAG_WALLET = (1 << 14),
TAG_STOR = (1 << 15),
TAG_DUMP2 = (1 << 16),
TAG_BOOT = (1 << 17),
TAG_EXT = (1 << 18),
TAG_NFC = (1 << 19),
TAG_NFC_APDU = (1 << 20),
TAG_CCID = (1 << 21),
TAG_CM = (1 << 22),
TAG_FILENO = (1u << 31)
TAG_NO_TAG = (1UL << 30),
TAG_FILENO = (1UL << 31)
} LOG_TAG;
#if DEBUG_LEVEL > 0
#if defined(DEBUG_LEVEL) && DEBUG_LEVEL > 0
void set_logging_mask(uint32_t mask);
#define printf1(tag,fmt, ...) LOG(tag & ~(TAG_FILENO), NULL, 0, fmt, ##__VA_ARGS__)

View File

@ -11,6 +11,9 @@
#define KEY_SPACE_BYTES 128
#define MAX_KEYS (1)
#define PIN_SALT_LEN (32)
#define STATE_VERSION (1)
#define BACKUP_MARKER 0x5A
#define INITIALIZED_MARKER 0xA5
@ -19,20 +22,40 @@
#define ERR_KEY_SPACE_TAKEN (-2)
#define ERR_KEY_SPACE_EMPTY (-2)
typedef struct
{
// Pin information
uint8_t is_initialized;
uint8_t is_pin_set;
uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
int pin_code_length;
int8_t remaining_tries;
uint16_t rk_stored;
uint16_t key_lens[MAX_KEYS];
uint8_t key_space[KEY_SPACE_BYTES];
} AuthenticatorState_0xFF;
typedef struct
{
// Pin information
uint8_t is_initialized;
uint8_t is_pin_set;
uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
int pin_code_length;
uint8_t PIN_CODE_HASH[32];
uint8_t PIN_SALT[PIN_SALT_LEN];
int _reserved;
int8_t remaining_tries;
uint16_t rk_stored;
uint16_t key_lens[MAX_KEYS];
uint8_t key_space[KEY_SPACE_BYTES];
} AuthenticatorState;
uint8_t data_version;
} AuthenticatorState_0x01;
typedef AuthenticatorState_0x01 AuthenticatorState;
typedef struct

View File

@ -7,9 +7,11 @@
#include <stdlib.h>
#include "u2f.h"
#include "ctap.h"
#include "ctaphid.h"
#include "crypto.h"
#include "log.h"
#include "device.h"
#include "apdu.h"
#include "wallet.h"
#ifdef ENABLE_U2F_EXTENSIONS
#include "extensions.h"
@ -24,15 +26,16 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
void u2f_reset_response();
void make_auth_tag(uint8_t * rpIdHash, uint8_t * nonce, uint32_t count, uint8_t * tag);
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;
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
uint8_t byte;
ctap_response_init(resp);
u2f_set_writeback_buffer(resp);
if (req->cla != 0)
@ -42,7 +45,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
goto end;
}
#ifdef ENABLE_U2F_EXTENSIONS
rcode = extend_u2f(req, len);
rcode = extend_u2f(req, payload, len);
#endif
if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything...
{
@ -59,7 +62,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
{
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());
}
@ -67,7 +70,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
case U2F_AUTHENTICATE:
printf1(TAG_U2F, "U2F_AUTHENTICATE\n");
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());
break;
case U2F_VERSION:
@ -94,6 +97,8 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
#endif
}
device_set_status(CTAPHID_STATUS_IDLE);
end:
if (rcode != U2F_SW_NO_ERROR)
{
@ -109,6 +114,22 @@ end:
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;
device_disable_up(true); // disable presence test
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
device_disable_up(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)
{
@ -140,9 +161,9 @@ static void dump_signature_der(uint8_t * sig)
len = ctap_encode_der_sig(sig, sigder);
u2f_response_writeback(sigder, len);
}
static int8_t u2f_load_key(struct u2f_key_handle * kh, uint8_t * appid)
static int8_t u2f_load_key(struct u2f_key_handle * kh, uint8_t khl, uint8_t * appid)
{
crypto_ecc256_load_key((uint8_t*)kh, U2F_KEY_HANDLE_SIZE, NULL, 0);
crypto_ecc256_load_key((uint8_t*)kh, khl, NULL, 0);
return 0;
}
@ -156,7 +177,7 @@ static void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8
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);
u2f_make_auth_tag(kh, appid, kh->tag);
@ -166,24 +187,43 @@ static int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8
}
static int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid)
// Return 1 if authenticate, 0 if not.
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t key_handle_len, uint8_t * appid)
{
printf1(TAG_U2F, "checked CRED SIZE %d. (FIDO2: %d)\n", key_handle_len, sizeof(CredentialId));
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
u2f_make_auth_tag(kh, appid, tag);
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
{
return 0;
}
else
{
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, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
return -1;
}
}
if (key_handle_len == sizeof(CredentialId))
{
printf1(TAG_U2F, "FIDO2 key handle detected.\n");
CredentialId * cred = (CredentialId *) kh;
// FIDO2 credential.
if (memcmp(cred->rpIdHash, appid, 32) != 0)
{
printf1(TAG_U2F, "APPID does not match rpIdHash.\n");
return 0;
}
make_auth_tag(appid, (uint8_t*)&cred->entropy, cred->count, tag);
if (memcmp(cred->tag, tag, CREDENTIAL_TAG_SIZE) == 0){
return 1;
}
}else if (key_handle_len == U2F_KEY_HANDLE_SIZE)
{
u2f_make_auth_tag(kh, appid, tag);
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
{
return 1;
}
}
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, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
return 0;
}
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control)
@ -196,7 +236,8 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
if (control == U2F_AUTHENTICATE_CHECK)
{
if (u2f_appid_eq(&req->kh, req->app) == 0)
printf1(TAG_U2F, "CHECK-ONLY\r\n");
if (u2f_authenticate_credential(&req->kh, req->khl, req->app))
{
return U2F_SW_CONDITIONS_NOT_SATISFIED;
}
@ -206,42 +247,46 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
}
}
if (
control != U2F_AUTHENTICATE_SIGN ||
req->khl != U2F_KEY_HANDLE_SIZE ||
u2f_appid_eq(&req->kh, req->app) != 0 || // Order of checks is important
u2f_load_key(&req->kh, req->app) != 0
(control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) ||
(!u2f_authenticate_credential(&req->kh, req->khl, req->app)) || // Order of checks is important
u2f_load_key(&req->kh, req->khl, req->app) != 0
)
{
return U2F_SW_WRONG_PAYLOAD;
return U2F_SW_WRONG_DATA;
}
// dont-enforce-user-presence-and-sign
if (control == U2F_AUTHENTICATE_SIGN_NO_USER)
up = 0;
if (ctap_user_presence_test() == 0)
{
return U2F_SW_CONDITIONS_NOT_SATISFIED;
}
if(up)
{
if (ctap_user_presence_test(750) == 0)
{
return U2F_SW_CONDITIONS_NOT_SATISFIED;
}
}
count = ctap_atomic_count(0);
hash[0] = 0xff;
hash[0] = (count >> 24) & 0xff;
hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff;
crypto_sha256_init();
crypto_sha256_update(req->app,32);
crypto_sha256_update(&up,1);
crypto_sha256_update(hash,4);
crypto_sha256_update(req->chal,32);
crypto_sha256_update(req->app, 32);
crypto_sha256_update(&up, 1);
crypto_sha256_update(hash, 4);
crypto_sha256_update(req->chal, 32);
crypto_sha256_final(hash);
printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F,hash,32);
printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F, hash, 32);
crypto_ecc256_sign(hash, 32, sig);
u2f_response_writeback(&up,1);
hash[0] = 0xff;
hash[0] = (count >> 24) & 0xff;
hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff;
@ -254,20 +299,25 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
static int16_t u2f_register(struct u2f_register_request * req)
{
uint8_t i[] = {0x0,U2F_EC_FMT_UNCOMPRESSED};
uint8_t cert[1024];
struct u2f_key_handle key_handle;
uint8_t pubkey[64];
uint8_t hash[32];
uint8_t * sig = (uint8_t*)req;
const uint16_t attest_size = attestation_cert_der_size;
const uint16_t attest_size = device_attestation_cert_der_get_size();
if ( ! ctap_user_presence_test())
{
return U2F_SW_CONDITIONS_NOT_SATISFIED;
if (attest_size > sizeof(cert)){
printf2(TAG_ERR,"Certificate is too large for buffer\r\n");
return U2F_SW_INSUFFICIENT_MEMORY;
}
if ( ! ctap_user_presence_test(750))
{
return U2F_SW_CONDITIONS_NOT_SATISFIED;
}
if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1)
{
return U2F_SW_INSUFFICIENT_MEMORY;
@ -296,12 +346,11 @@ static int16_t u2f_register(struct u2f_register_request * req)
u2f_response_writeback(i,1);
u2f_response_writeback((uint8_t*)&key_handle,U2F_KEY_HANDLE_SIZE);
u2f_response_writeback(attestation_cert_der,attest_size);
device_attestation_read_cert_der(cert);
u2f_response_writeback(cert,attest_size);
dump_signature_der(sig);
/*printf1(TAG_U2F, "dersig: "); dump_hex1(TAG_U2F,sig,74);*/
return U2F_SW_NO_ERROR;
}

View File

@ -38,16 +38,16 @@
// U2F Authenticate
#define U2F_AUTHENTICATE_CHECK 0x7
#define U2F_AUTHENTICATE_SIGN 0x3
#define U2F_AUTHENTICATE_SIGN_NO_USER 0x8
// Command status responses
#define U2F_SW_NO_ERROR 0x9000
#define U2F_SW_WRONG_DATA 0x6984
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985
#define U2F_SW_INS_NOT_SUPPORTED 0x6d00
#define U2F_SW_WRONG_LENGTH 0x6700
#define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00
#define U2F_SW_WRONG_PAYLOAD 0x6a80
#define U2F_SW_WRONG_DATA 0x6a80
#define U2F_SW_INSUFFICIENT_MEMORY 0x9210
// Delay in milliseconds to wait for user input
@ -95,9 +95,15 @@ struct u2f_authenticate_request
};
// u2f_request send a U2F message to U2F protocol
// @req U2F message
// @req U2F message
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 key_handle_len, uint8_t * appid);
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
void u2f_reset_response();

18
fido2/version.c Normal file
View File

@ -0,0 +1,18 @@
#include "version.h"
#include "app.h"
const version_t firmware_version
#ifdef SOLO
__attribute__ ((section (".flag"))) __attribute__ ((__used__))
#endif
= {
.major = SOLO_VERSION_MAJ,
.minor = SOLO_VERSION_MIN,
.patch = SOLO_VERSION_PATCH,
.reserved = 0
};
// from tinycbor, for a quick static_assert
#include <compilersupport_p.h>
cbor_static_assert(sizeof(version_t) == 4);

View File

@ -17,5 +17,23 @@
#define SOLO_VERSION __STR(SOLO_VERSION_MAJ) "." __STR(SOLO_VERSION_MIN) "." __STR(SOLO_VERSION_PATCH)
#endif
#include <stdint.h>
#include <stdbool.h>
typedef struct {
union{
uint32_t raw;
struct {
uint8_t major;
uint8_t minor;
uint8_t patch;
uint8_t reserved;
};
};
} version_t;
bool is_newer(const version_t* const newer, const version_t* const older);
const version_t firmware_version ;
#endif

9
fido2/version.mk Normal file
View File

@ -0,0 +1,9 @@
SOLO_VERSION_FULL?=$(shell git describe)
SOLO_VERSION:=$(shell python -c 'print("$(SOLO_VERSION_FULL)".split("-")[0])')
SOLO_VERSION_MAJ:=$(shell python -c 'print("$(SOLO_VERSION)".split(".")[0])')
SOLO_VERSION_MIN:=$(shell python -c 'print("$(SOLO_VERSION)".split(".")[1])')
SOLO_VERSION_PAT:=$(shell python -c 'print("$(SOLO_VERSION)".split(".")[2])')
SOLO_VERSION_FLAGS := -DSOLO_VERSION_MAJ=$(SOLO_VERSION_MAJ) -DSOLO_VERSION_MIN=$(SOLO_VERSION_MIN) \
-DSOLO_VERSION_PATCH=$(SOLO_VERSION_PAT) -DSOLO_VERSION=\"$(SOLO_VERSION_FULL)\"

View File

@ -1,13 +1,10 @@
#!/bin/bash -xe
version=$1
version=${1:-master}
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
cd /solo/targets/stm32l432
git fetch
git checkout ${version}
version=$(git describe)
ls
make cbor
@ -15,13 +12,12 @@ out_dir="/builds"
function build() {
part=${1}
variant=${2}
output=${3:-${part}}
what="${part}-${variant}"
output=${2}
what="${part}"
make full-clean
make ${what}
make ${what} VERSION_FULL=${version}
out_hex="${what}-${version}.hex"
out_sha2="${what}-${version}.sha2"
@ -31,7 +27,27 @@ function build() {
cp ${out_hex} ${out_sha2} ${out_dir}
}
build bootloader nonverifying
build bootloader verifying
build firmware hacker solo
build firmware secure solo
build bootloader-nonverifying bootloader
build bootloader-verifying bootloader
build firmware solo
build firmware-debug-1 solo
build firmware-debug-2 solo
build firmware solo
cd ${out_dir}
bundle="bundle-hacker-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-${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-debug-1-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-hacker-debug-2-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-debug-2-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-secure-non-solokeys-${version}"
/opt/conda/bin/solo mergehex --lock bootloader-verifying-${version}.hex firmware-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2

View File

@ -15,11 +15,13 @@
"authenticationAlgorithm": 1,
"publicKeyAlgAndEncoding": 260,
"attestationTypes": [
15879,
15880
15879
],
"userVerificationDetails": [
[
{
"userVerification": 1
},
{
"userVerification": 4
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

35
mkdocs.yml Normal file → Executable file
View File

@ -1,27 +1,36 @@
site_name: Solo Technical Documentation
site_author: SoloKeys
site_description: 'Documentation for the SoloKeys solo software'
site_url: 'https://docs.solokeys.io/solo/'
site_url: 'https://docs.solokeys.dev/'
repo_url: 'https://github.com/solokeys/solo'
repo_name: 'solokeys/solo'
copyright: 'Copyright &copy; 2018 - 2019 SoloKeys'
nav:
- Home: solo/index.md
- FIDO2 Implementation: solo/fido2-impl.md
- Metadata Statements: solo/metadata-statements.md
- Build instructions: solo/building.md
- Signed update process: solo/signed-updates.md
- Code documentation: solo/code-overview.md
- Contributing Code: solo/contributing.md
- Contributing Docs: solo/documenting.md
- udev Rules: solo/udev.md
- About: solo/repo-readme.md
- Home: index.md
- FIDO2 Implementation: fido2-impl.md
- Metadata Statements: metadata-statements.md
- Build instructions: building.md
- Programming instructions: programming.md
- Bootloader mode: bootloader-mode.md
- Customization: customization.md
- Solo Extras: solo-extras.md
- Application Ideas: application-ideas.md
- Running on Nucleo32 board: nucleo32-board.md
- Signed update process: signed-updates.md
- Usage and Porting guide: porting.md
- Tutorial Getting Started: tutorial-getting-started.md
- Tutorial - Writing extensions: tutorial-writing-extensions.md
- Code documentation: code-overview.md
- Contributing Code: contributing.md
- Contributing Docs: documenting.md
- udev Rules: udev.md
- About: repo-readme.md
theme:
name: material
logo: 'solo/images/logo.svg'
favicon: 'solo/images/favicon.ico'
logo: 'images/logo.svg'
favicon: 'images/favicon.ico'
markdown_extensions:
- markdown_include.include

View File

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

View File

@ -11,10 +11,10 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include "device.h"
#include "cbor.h"
@ -22,20 +22,16 @@
#include "log.h"
#include "ctaphid.h"
#define RK_NUM 50
static bool use_udp = true;
struct ResidentKeyStore {
CTAP_residentKey rks[RK_NUM];
} RK_STORE;
void authenticator_initialize();
uint32_t __device_status = 0;
void device_set_status(uint32_t status)
{
if (status != CTAPHID_STATUS_IDLE && __device_status != status)
{
ctaphid_update_status(status);
}
__device_status = status;
}
int udp_server()
{
@ -95,6 +91,7 @@ int udp_recv(int fd, uint8_t * buf, int size)
perror( "recvfrom failed" );
exit(1);
}
printf1(TAG_DUMP, ">>"); dump_hex1(TAG_DUMP, buf, length);
return length;
}
@ -111,15 +108,11 @@ void udp_send(int fd, uint8_t * buf, int size)
perror( "sendto failed" );
exit(1);
}
}
void udp_close(int fd)
{
close(fd);
printf1(TAG_DUMP, "<<"); dump_hex1(TAG_DUMP, buf, size);
}
uint32_t millis()
{
struct timeval te;
@ -129,35 +122,80 @@ uint32_t millis()
}
static int serverfd = 0;
static int fd = 0;
void usbhid_init()
{
// just bridge to UDP for now for pure software testing
serverfd = udp_server();
if (use_udp)
{
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
int usbhid_recv(uint8_t * msg)
{
int l = udp_recv(serverfd, msg, HID_MESSAGE_SIZE);
/*if (l && l != HID_MESSAGE_SIZE)*/
/*{*/
/*printf("Error, recv'd message of wrong size %d", l);*/
/*exit(1);*/
/*}*/
int l = 0;
if (use_udp)
{
l = udp_recv(fd, msg, HID_MESSAGE_SIZE);
}
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;
}
// Send 64 byte USB HID message
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()
{
udp_close(serverfd);
close(fd);
}
void int_handler(int i)
@ -167,64 +205,66 @@ void int_handler(int i)
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);
printf1(TAG_GREEN, "Using %s backing\n", use_udp ? "UDP" : "hidg");
usbhid_init();
authenticator_initialize();
ctaphid_init();
ctap_init( 1 );
}
void main_loop_delay()
void delay(uint32_t ms)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 1000*1000*25;
ts.tv_nsec = 1000*1000*ms;
nanosleep(&ts,NULL);
}
void heartbeat()
{
}
void ctaphid_write_block(uint8_t * data)
{
/*printf("<< "); dump_hex(data, 64);*/
usbhid_send(data);
}
int ctap_user_presence_test()
{
return 1;
}
int ctap_user_verification(uint8_t arg)
{
return 1;
}
uint32_t ctap_atomic_count(int sel)
{
static uint32_t counter1 = 25;
/*return 713;*/
if (sel == 0)
{
printf1(TAG_RED,"counter1: %d\n", counter1);
return counter1++;
}
else
{
printf2(TAG_ERR,"counter2 not imple\n");
exit(1);
}
}
int ctap_generate_rng(uint8_t * dst, size_t num)
{
int ret;
@ -246,9 +286,9 @@ int ctap_generate_rng(uint8_t * dst, size_t num)
const char * state_file = "authenticator_state.bin";
const char * backup_file = "authenticator_state2.bin";
const char * rk_file = "resident_keys.bin";
void authenticator_read_state(AuthenticatorState * state)
int authenticator_read_state(AuthenticatorState * state)
{
FILE * f;
int ret;
@ -267,105 +307,54 @@ void authenticator_read_state(AuthenticatorState * state)
perror("fwrite");
exit(1);
}
if (state->is_initialized == INITIALIZED_MARKER)
return 1;
else
return 0;
}
void authenticator_read_backup_state(AuthenticatorState * state )
void authenticator_write_state(AuthenticatorState * state)
{
FILE * f;
int ret;
f = fopen(backup_file, "rb");
f = fopen(state_file, "wb+");
if (f== NULL)
{
perror("fopen");
exit(1);
}
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
fclose(f);
if (ret != sizeof(AuthenticatorState))
{
perror("fwrite");
exit(1);
}
}
static void sync_rk()
{
FILE * f = fopen(rk_file, "wb+");
if (f== NULL)
{
perror("fopen");
exit(1);
}
ret = fread(state, 1, sizeof(AuthenticatorState), f);
int ret = fwrite(&RK_STORE, 1, sizeof(RK_STORE), f);
fclose(f);
if(ret != sizeof(AuthenticatorState))
if (ret != sizeof(RK_STORE))
{
perror("fwrite");
exit(1);
}
}
void authenticator_write_state(AuthenticatorState * state, int backup)
{
FILE * f;
int ret;
if (! backup)
{
f = fopen(state_file, "wb+");
if (f== NULL)
{
perror("fopen");
exit(1);
}
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
fclose(f);
if (ret != sizeof(AuthenticatorState))
{
perror("fwrite");
exit(1);
}
}
else
{
f = fopen(backup_file, "wb+");
if (f== NULL)
{
perror("fopen");
exit(1);
}
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
fclose(f);
if (ret != sizeof(AuthenticatorState))
{
perror("fwrite");
exit(1);
}
}
}
// Return 1 yes backup is init'd, else 0
int authenticator_is_backup_initialized()
{
uint8_t header[16];
AuthenticatorState * state = (AuthenticatorState*) header;
FILE * f;
int ret;
printf("state file exists\n");
f = fopen(backup_file, "rb");
if (f== NULL)
{
printf("Warning, backup file doesn't exist\n");
return 0;
}
ret = fread(header, 1, sizeof(header), f);
fclose(f);
if(ret != sizeof(header))
{
perror("fwrite");
exit(1);
}
return state->is_initialized == INITIALIZED_MARKER;
}
// Return 1 yes backup is init'd, else 0
/*int authenticator_is_initialized()*/
/*{*/
/*}*/
void authenticator_initialize()
{
uint8_t header[16];
@ -389,6 +378,22 @@ void authenticator_initialize()
perror("fwrite");
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
{
@ -410,54 +415,68 @@ void authenticator_initialize()
exit(1);
}
f = fopen(backup_file, "wb+");
if (f== NULL)
{
perror("fopen");
exit(1);
}
mem = malloc(sizeof(AuthenticatorState));
memset(mem,0xff,sizeof(AuthenticatorState));
ret = fwrite(mem, 1, sizeof(AuthenticatorState), f);
free(mem);
fclose(f);
if (ret != sizeof(AuthenticatorState))
{
perror("fwrite");
exit(1);
}
// resident_keys
memset(&RK_STORE,0xff,sizeof(RK_STORE));
sync_rk();
}
}
void device_manage()
{
}
void ctap_reset_rk()
{
memset(&RK_STORE,0xff,sizeof(RK_STORE));
sync_rk();
}
uint32_t ctap_rk_size()
{
printf("Warning: rk not implemented\n");
return 0;
}
void ctap_store_rk(int index,CTAP_residentKey * rk)
{
printf("Warning: rk not implemented\n");
}
void ctap_load_rk(int index,CTAP_residentKey * rk)
{
printf("Warning: rk not implemented\n");
}
void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
{
printf("Warning: rk not implemented\n");
return RK_NUM;
}
void device_wink()
void ctap_store_rk(int index, CTAP_residentKey * rk)
{
printf("*WINK*\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_delete_rk(int index)
{
CTAP_residentKey rk;
memset(&rk, 0xff, sizeof(CTAP_residentKey));
memmove(RK_STORE.rks + index, &rk, sizeof(CTAP_residentKey));
}
void ctap_load_rk(int index, CTAP_residentKey * rk)
{
memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey));
}
void ctap_overwrite_rk(int index, CTAP_residentKey * rk)
{
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");
}
}

View File

@ -7,6 +7,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
#include "cbor.h"
#include "device.h"
@ -15,61 +18,50 @@
#include "util.h"
#include "log.h"
#include "ctap.h"
#include APP_CONFIG
#include "app.h"
#if !defined(TEST)
int main()
void device_init(int argc, char *argv[]);
int usbhid_recv(uint8_t * msg);
int main(int argc, char *argv[])
{
uint8_t hidmsg[64];
uint32_t t1 = 0;
set_logging_mask(
/*0*/
// TAG_GEN|
// TAG_MC |
// TAG_GA |
TAG_WALLET |
TAG_STOR |
// TAG_CP |
// TAG_CTAP|
// TAG_HID|
/*TAG_U2F|*/
// TAG_PARSE |
// TAG_TIME|
// TAG_DUMP|
TAG_GREEN|
TAG_RED|
TAG_ERR
);
/*0*/
// TAG_GEN|
// TAG_MC |
// TAG_GA |
TAG_WALLET |
TAG_STOR |
//TAG_NFC_APDU |
TAG_NFC |
// TAG_CP |
// TAG_CTAP|
// TAG_HID|
TAG_U2F|
// TAG_PARSE |
//TAG_TIME|
// TAG_DUMP|
// TAG_DUMP2|
TAG_GREEN|
TAG_RED|
TAG_EXT|
TAG_CCID|
TAG_ERR
);
device_init();
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");
device_init(argc, argv);
memset(hidmsg,0,sizeof(hidmsg));
printf1(TAG_GEN,"recv'ing hid msg \n");
while(1)
{
if (millis() - t1 > HEARTBEAT_PERIOD)
{
heartbeat();
t1 = millis();
}
device_manage();
if (usbhid_recv(hidmsg) > 0)
{
@ -79,13 +71,16 @@ int main()
else
{
}
ctaphid_check_timeouts();
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 1000*1000*10;
nanosleep(&ts,NULL);
}
// Should never get here
usbhid_close();
printf1(TAG_GREEN, "done\n");
return 0;
}
#endif

@ -1 +0,0 @@
Subproject commit 329434fdd476870ff0a73196b6de8a963409235f

13
shell.nix Normal file
View File

@ -0,0 +1,13 @@
let
nixpkgs_tar = fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/20.03.tar.gz"; sha256 = "0182ys095dfx02vl2a20j1hz92dx3mfgz2a6fhn31bqlp1wa8hlq"; };
pkgs = import "${nixpkgs_tar}" {};
pyPackages = (python-packages: with python-packages; ([
solo-python pytest
] ++ (with builtins; map (d: getAttr d python-packages) (filter (d: stringLength d > 0) (pkgs.lib.splitString "\n" (builtins.readFile ./tools/requirements.txt))))));
python-with-my-packages = pkgs.python3.withPackages pyPackages;
in
with pkgs;
stdenv.mkDerivation {
name = "solo";
buildInputs = [ gnumake gcc gcc-arm-embedded-8 python-with-my-packages ];
}

View File

@ -2,21 +2,25 @@ ifndef DEBUG
DEBUG=0
endif
APPMAKE=build/application.mk
BOOTMAKE=build/bootloader.mk
VERSION_FULL?=$(shell git describe)
APPMAKE=build/application.mk VERSION_FULL=${VERSION_FULL}
BOOTMAKE=build/bootloader.mk VERSION_FULL=${VERSION_FULL}
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
# The following are the main targets for reproducible builds.
# TODO: better explanation
firmware-hacker:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0
firmware-secure:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2'
firmware-debug-1:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1
firmware-debug-2:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2
bootloader-nonverifying:
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0
@ -53,7 +57,6 @@ boot-no-sig:
build-release-locked: cbor clean2 boot-sig-checking clean all-locked
$(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
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
@ -82,11 +85,15 @@ flash_dfu: solo.hex bootloader.hex
# STM32_Programmer_CLI -c port=usb1 -halt -e all --readunprotect
STM32_Programmer_CLI -c port=usb1 -halt -rdu -d all.hex
flashboot: solo.hex bootloader.hex
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
flashboot: bootloader.hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
flash-firmware:
$(SZ) -A solo.elf
solo program aux enter-bootloader
solo program bootloader solo.hex
# tell ST DFU to enter application
detach:
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

@ -1,4 +1,4 @@
# STM32L432 Solo
Check out our [official documentation](https://docs.solokeys.io/solo/building/)
Check out our [official documentation](https://docs.solokeys.dev/building/)
for instructions on building and programming!

View File

@ -19,6 +19,12 @@
#include "ctap_errors.h"
#include "log.h"
volatile version_t current_firmware_version __attribute__ ((section (".flag2"))) __attribute__ ((__used__)) = {
.major = SOLO_VERSION_MAJ,
.minor = SOLO_VERSION_MIN,
.patch = SOLO_VERSION_PATCH,
.reserved = 0
};
extern uint8_t REBOOT_FLAG;
@ -44,20 +50,21 @@ typedef struct {
uint8_t payload[255 - 10];
} __attribute__((packed)) BootloaderReq;
uint8_t * last_written_app_address = 0;
/**
* Erase all application pages. **APPLICATION_END_PAGE excluded**.
*/
static void erase_application()
{
int page;
last_written_app_address = (uint8_t*) 0;
for(page = APPLICATION_START_PAGE; page < APPLICATION_END_PAGE; page++)
{
flash_erase_page(page);
}
}
#define LAST_ADDR (APPLICATION_END_ADDR-2048 + 8)
#define LAST_PAGE (APPLICATION_END_PAGE-1)
static void disable_bootloader()
{
// Clear last 4 bytes of the last application page-1, which is 108th
@ -103,6 +110,41 @@ int is_bootloader_disabled()
return *auth == 0;
}
#include "version.h"
bool is_firmware_version_newer_or_equal()
{
if (last_written_app_address == 0) {
return false;
}
printf1(TAG_BOOT,"Current firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved,
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved
);
volatile version_t * new_version = ((volatile version_t *) (last_written_app_address-8+4));
printf1(TAG_BOOT,"Uploaded firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
new_version->major, new_version->minor, new_version->patch, new_version->reserved,
new_version->major, new_version->minor, new_version->patch, new_version->reserved
);
const bool allowed = is_newer((const version_t *)new_version, (const version_t *)&current_firmware_version) || current_firmware_version.raw == 0xFFFFFFFF;
if (allowed){
printf1(TAG_BOOT, "Update allowed, setting new firmware version as current.\r\n");
// current_firmware_version.raw = new_version.raw;
uint8_t page[PAGE_SIZE];
memmove(page, (uint8_t*)BOOT_VERSION_ADDR, PAGE_SIZE);
memmove(page, (version_t *)new_version, 4);
printf1(TAG_BOOT, "Writing\r\n");
flash_erase_page(BOOT_VERSION_PAGE);
flash_write(BOOT_VERSION_ADDR, page, PAGE_SIZE);
printf1(TAG_BOOT, "Finish\r\n");
} else {
printf1(TAG_BOOT, "Firmware older - update not allowed.\r\n");
}
return allowed;
}
/**
* Execute bootloader commands
* @param klen key length - length of the bootloader request
@ -125,10 +167,7 @@ int bootloader_bridge(int klen, uint8_t * keyh)
return CTAP1_ERR_INVALID_LENGTH;
}
#ifndef SOLO_HACKER
uint8_t * pubkey = (uint8_t*)"\xd2\xa4\x2f\x8f\xb2\x31\x1c\xc1\xf7\x0c\x7e\x64\x32\xfb\xbb\xb4\xa3\xdd\x32\x20"
"\x0f\x1b\x88\x9c\xda\x62\xc2\x83\x25\x93\xdd\xb8\x75\x9d\xf9\x86\xee\x03\x6c\xce"
"\x34\x47\x71\x36\xb3\xb2\xad\x6d\x12\xb7\xbe\x49\x3e\x20\xa4\x61\xac\xc7\x71\xc7"
"\x1f\xa8\x14\xf2";
extern uint8_t *pubkey_boot;
const struct uECC_Curve_t * curve = NULL;
#endif
@ -137,6 +176,7 @@ int bootloader_bridge(int klen, uint8_t * keyh)
uint32_t addr = ((*((uint32_t*)req->addr)) & 0xffffff) | 0x8000000;
uint32_t * ptr = (uint32_t *)addr;
uint32_t current_address;
switch(req->op){
case BootWrite:
@ -163,14 +203,20 @@ int bootloader_bridge(int klen, uint8_t * keyh)
printf2(TAG_ERR, "Error, boot check bypassed\n");
exit(1);
}
current_address = addr + len;
if (current_address < (uint32_t) last_written_app_address) {
printf2(TAG_ERR, "Error, only ascending writes allowed.\n");
has_erased = 0;
return CTAP2_ERR_NOT_ALLOWED;
}
last_written_app_address = (uint8_t*) current_address;
// Do the actual write
flash_write((uint32_t)ptr,req->payload, len);
break;
case BootDone:
// Writing to flash finished. Request code validation.
printf1(TAG_BOOT, "BootDone: ");
printf1(TAG_BOOT, "BootDone: \r\n");
#ifndef SOLO_HACKER
if (len != 64)
{
@ -185,17 +231,23 @@ int bootloader_bridge(int klen, uint8_t * keyh)
crypto_sha256_final(hash);
curve = uECC_secp256r1();
// Verify incoming signature made over the SHA256 hash
if (! uECC_verify(pubkey,
hash,
32,
req->payload,
curve))
if (
!uECC_verify(pubkey_boot, hash, 32, req->payload, curve)
)
{
printf1(TAG_BOOT, "Signature invalid\r\n");
return CTAP2_ERR_OPERATION_DENIED;
}
if (!is_firmware_version_newer_or_equal()){
printf1(TAG_BOOT, "Firmware older - update not allowed.\r\n");
printf1(TAG_BOOT, "Rebooting...\r\n");
REBOOT_FLAG = 1;
return CTAP2_ERR_OPERATION_DENIED;
}
#endif
// Set the application validated, and mark for reboot.
authorize_application();
REBOOT_FLAG = 1;
break;
case BootCheck:
@ -218,6 +270,7 @@ int bootloader_bridge(int klen, uint8_t * keyh)
break;
case BootReboot:
printf1(TAG_BOOT, "BootReboot.\r\n");
printf1(TAG_BOOT, "Application authorized: %d.\r\n", is_authorized_to_boot());
REBOOT_FLAG = 1;
break;
case BootDisable:
@ -277,3 +330,10 @@ void bootloader_heartbeat()
led_rgb(((val * g)<<8) | ((val*r) << 16) | (val*b));
}
uint32_t ctap_atomic_count(uint32_t amount)
{
static uint32_t count = 1000;
count += (amount + 1);
return count;
}

View File

@ -9,7 +9,7 @@
#define _APP_H_
#include <stdint.h>
#include "version.h"
#include "solo.h"
#define DEBUG_UART USART1
#ifndef DEBUG_LEVEL
@ -21,6 +21,7 @@
#define BOOT_TO_DFU 0
#define SOLO 1
#define IS_BOOTLOADER 1
#define ENABLE_U2F_EXTENSIONS
@ -55,7 +56,7 @@
#define SOLO_PRODUCT_NAME "Solo Bootloader " SOLO_VERSION
void printing_init();
void hw_init(void);
void hw_init(int lf);
// Trigger software reset
void device_reboot();
@ -64,4 +65,9 @@ int is_authorized_to_boot();
int is_bootloader_disabled();
void bootloader_heartbeat();
// Return 1 if Solo is secure/locked.
int solo_is_locked();
#endif

View File

@ -8,6 +8,10 @@
#include <stdlib.h>
#include <stdint.h>
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx.h"
#include "cbor.h"
#include "device.h"
#include "ctaphid.h"
@ -17,14 +21,14 @@
#include "ctap.h"
#include "app.h"
#include "memory_layout.h"
#include "stm32l4xx_ll_rcc.h"
#include "init.h"
#include "stm32l4xx.h"
uint8_t REBOOT_FLAG = 0;
void SystemClock_Config(void);
void BOOT_boot(void)
void BOOT_boot(void)
{
typedef void (*pFunction)(void);
@ -42,9 +46,7 @@ int main()
{
uint8_t hidmsg[64];
uint32_t t1 = 0;
#ifdef SOLO_HACKER
uint32_t stboot_time = 0;
#endif
uint32_t boot = 1;
set_logging_mask(
@ -69,7 +71,18 @@ int main()
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");
t1 = millis();
@ -83,7 +96,6 @@ int main()
}
#ifdef SOLO_HACKER
if (!is_bootloader_disabled())
{
stboot_time = millis();
@ -93,7 +105,6 @@ int main()
goto start_bootloader;
}
}
#endif
if (is_authorized_to_boot() && (boot || is_bootloader_disabled()))
{
@ -104,10 +115,15 @@ int main()
printf1(TAG_RED,"Not authorized to boot (%08x == %08lx)\r\n", AUTH_WORD_ADDR, *(uint32_t*)AUTH_WORD_ADDR);
}
#ifdef SOLO_HACKER
start_bootloader:
#endif
SystemClock_Config();
init_gpio();
init_millisecond_timer(0);
init_pwm();
init_rng();
usbhid_init();
printf1(TAG_GEN,"init usb\n");
ctaphid_init();
@ -117,6 +133,14 @@ int main()
printf1(TAG_GEN,"recv'ing hid msg \n");
extern volatile version_t current_firmware_version;
printf1(TAG_BOOT,"Current firmware version address: %p\r\n", &current_firmware_version);
printf1(TAG_BOOT,"Current firmware version: %d.%d.%d.%d (%02x.%02x.%02x.%02x)\r\n",
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved,
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved
);
dump_hex1(TAG_BOOT, (uint8_t*)(&current_firmware_version) - 16, 32);
while(1)
{

View File

@ -0,0 +1,6 @@
#include "stdint.h"
uint8_t * pubkey_boot = (uint8_t*)"\xd2\xa4\x2f\x8f\xb2\x31\x1c\xc1\xf7\x0c\x7e\x64\x32\xfb\xbb\xb4\xa3\xdd\x32\x20"
"\x0f\x1b\x88\x9c\xda\x62\xc2\x83\x25\x93\xdd\xb8\x75\x9d\xf9\x86\xee\x03\x6c\xce"
"\x34\x47\x71\x36\xb3\xb2\xad\x6d\x12\xb7\xbe\x49\x3e\x20\xa4\x61\xac\xc7\x71\xc7"
"\x1f\xa8\x14\xf2";

View File

@ -0,0 +1,8 @@
#include "version.h"
// FIXME test version check function
bool is_newer(const version_t* const newer, const version_t* const older){
return (newer->major > older->major) ||
(newer->major == older->major && newer->minor > older->minor) ||
(newer->major == older->major && newer->minor == older->minor && newer->patch >= older->patch);
}

View File

@ -2,25 +2,32 @@ include build/common.mk
# 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/fifo.c src/crypto.c src/attestation.c
SRC += src/fifo.c src/attestation.c src/nfc.c src/ams.c src/sense.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(DRIVER_LIBS) $(USB_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/ctap_parse.c ../../fido2/main.c
SRC += ../../fido2/ctap_parse.c ../../fido2/crypto.c
SRC += ../../fido2/version.c
SRC += ../../fido2/data_migration.c
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
SRC += ../../fido2/extensions/wallet.c
# Crypto libs
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)
OBJ=$(OBJ1:.s=.o)
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/
INC+= -I../../fido2/ -I../../fido2/extensions
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
INC += -I../../crypto/tiny-AES-c
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
SEARCH=-L../../tinycbor/lib
@ -41,12 +48,14 @@ DEBUG=0
endif
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)
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -u _printf_float -lnosys
CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections \
-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
ECC_CFLAGS = $(CFLAGS) -DuECC_PLATFORM=5 -DuECC_OPTIMIZATION_LEVEL=4 -DuECC_SQUARE_FUNC=1 -DuECC_SUPPORT_COMPRESSED_POINT=0
.PRECIOUS: %.o
@ -57,15 +66,14 @@ all: $(TARGET).elf
$(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 $@
$(CC) $^ $(HW) -O3 $(ECC_CFLAGS) -o $@
%.elf: $(OBJ)
$(CC) $^ $(HW) $(LDFLAGS) -o $@
@echo "Built version: $(VERSION_FLAGS)"
%.hex: %.elf
$(SZ) $^
$(CP) -O ihex $^ $(TARGET).hex
clean:
@ -76,4 +84,5 @@ cbor:
cd ../../tinycbor/ && make clean
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
LDFLAGS="$(LDFLAGS_LIB)" \
CFLAGS="$(CFLAGS)"
CFLAGS="$(CFLAGS) -Os -DCBOR_PARSER_MAX_RECURSIONS=3"

View File

@ -2,17 +2,20 @@ include build/common.mk
# ST related
SRC = bootloader/main.c bootloader/bootloader.c
SRC += bootloader/pubkey_bootloader.c bootloader/version_check.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/attestation.c src/sense.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(DRIVER_LIBS) $(USB_LIB)
# FIDO2 lib
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/extensions/extensions.c
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
SRC += ../../fido2/crypto.c
# Crypto libs
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)
OBJ=$(OBJ1:.s=.o)
@ -21,6 +24,7 @@ OBJ=$(OBJ1:.s=.o)
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../../crypto/tiny-AES-c
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
ifndef LDSCRIPT
LDSCRIPT=linker/bootloader_stm32l4xx.ld
@ -63,6 +67,7 @@ all: $(TARGET).elf
%.elf: $(OBJ)
$(CC) $^ $(HW) $(LDFLAGS) -o $@
$(SZ) $@
%.hex: %.elf
$(CP) -O ihex $^ $(TARGET).hex

View File

@ -1,28 +1,35 @@
include ../../fido2/version.mk
CC=$(PREFIX)arm-none-eabi-gcc
CP=$(PREFIX)arm-none-eabi-objcopy
SZ=$(PREFIX)arm-none-eabi-size
AR=$(PREFIX)arm-none-eabi-ar
AS=$(PREFIX)arm-none-eabi-as
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_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 \
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \
lib/usbd/usbd_ccid.c
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_FULL?=$(SOLO_VERSION_FULL)
VERSION:=$(SOLO_VERSION)
VERSION_MAJ:=$(SOLO_VERSION_MAJ)
VERSION_MIN:=$(SOLO_VERSION_MIN)
VERSION_PAT:=$(SOLO_VERSION_PAT)
VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
_all:
echo $(VERSION_FULL)
echo $(VERSION_MAJ)
echo $(VERSION_MIN)
echo $(VERSION_PAT)
echo $(SOLO_VERSION_FULL)
echo $(SOLO_VERSION_MAJ)
echo $(SOLO_VERSION_MIN)
echo $(SOLO_VERSION_PAT)
%.o: %.s
$(AS) -o $@ $^

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

@ -0,0 +1,319 @@
#include <stdint.h>
#include "usbd_ccid.h"
#include "usbd_ctlreq.h"
#include "usbd_conf.h"
#include "usbd_core.h"
#include "log.h"
static uint8_t USBD_CCID_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
static uint8_t USBD_CCID_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
static uint8_t USBD_CCID_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req);
static uint8_t USBD_CCID_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum);
static uint8_t USBD_CCID_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum);
static uint8_t USBD_CCID_EP0_RxReady (USBD_HandleTypeDef *pdev);
USBD_ClassTypeDef USBD_CCID =
{
USBD_CCID_Init,
USBD_CCID_DeInit,
USBD_CCID_Setup,
NULL, /* EP0_TxSent, */
USBD_CCID_EP0_RxReady,
USBD_CCID_DataIn,
USBD_CCID_DataOut,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static uint8_t ccidmsg_buf[CCID_DATA_PACKET_SIZE];
static uint8_t USBD_CCID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
uint8_t ret = 0U;
USBD_CCID_HandleTypeDef *hcdc;
//Y
USBD_LL_OpenEP(pdev, CCID_IN_EP, USBD_EP_TYPE_BULK,
CCID_DATA_PACKET_SIZE);
USBD_LL_OpenEP(pdev, CCID_OUT_EP, USBD_EP_TYPE_BULK,
CCID_DATA_PACKET_SIZE);
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 1U;
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 1U;
USBD_LL_OpenEP(pdev, CCID_CMD_EP, USBD_EP_TYPE_INTR, CCID_DATA_PACKET_SIZE);
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 1U;
// dump_pma_header("ccid.c");
static USBD_CCID_HandleTypeDef mem;
pdev->pClassData = &mem;
hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
// init transfer states
hcdc->TxState = 0U;
hcdc->RxState = 0U;
USBD_LL_PrepareReceive(&Solo_USBD_Device, CCID_OUT_EP, ccidmsg_buf,
CCID_DATA_PACKET_SIZE);
return ret;
}
static uint8_t USBD_CCID_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
uint8_t ret = 0U;
//N
USBD_LL_CloseEP(pdev, CCID_IN_EP);
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 0U;
USBD_LL_CloseEP(pdev, CCID_OUT_EP);
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 0U;
USBD_LL_CloseEP(pdev, CCID_CMD_EP);
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 0U;
/* DeInit physical Interface components */
if(pdev->pClassData != NULL)
{
pdev->pClassData = NULL;
}
return ret;
}
/**
* @brief USBD_CDC_Setup
* Handle the CDC specific requests
* @param pdev: instance
* @param req: usb requests
* @retval status
*/
static uint8_t USBD_CCID_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
uint8_t ifalt = 0U;
uint16_t status_info = 0U;
uint8_t ret = USBD_OK;
//N
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
if (req->wLength)
{
if (req->bmRequest & 0x80U)
{
USBD_CtlSendData (pdev, (uint8_t *)(void *)hcdc->data, req->wLength);
}
else
{
hcdc->CmdOpCode = req->bRequest;
hcdc->CmdLength = (uint8_t)req->wLength;
USBD_CtlPrepareRx (pdev, (uint8_t *)(void *)hcdc->data, req->wLength);
}
}
else
{
}
break;
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_STATUS:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
USBD_CtlSendData (pdev, (uint8_t *)(void *)&status_info, 2U);
}
else
{
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_GET_INTERFACE:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
USBD_CtlSendData (pdev, &ifalt, 1U);
}
else
{
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_SET_INTERFACE:
if (pdev->dev_state != USBD_STATE_CONFIGURED)
{
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_GET_DESCRIPTOR:
break;
default:
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
break;
}
break;
default:
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
break;
}
return ret;
}
/**
* @brief USBD_CDC_DataIn
* Data sent on non-control IN endpoint
* @param pdev: device instance
* @param epnum: endpoint number
* @retval status
*/
static uint8_t USBD_CCID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
return USBD_OK;
}
static uint8_t USBD_CCID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*)pdev->pClassData;
hcdc->TxState = 0U;
return USBD_OK;
}
uint8_t USBD_CCID_TransmitPacket(uint8_t * msg, int len)
{
/* Update the packet total length */
Solo_USBD_Device.ep_in[CCID_IN_EP & 0xFU].total_length = len;
while (PCD_GET_EP_TX_STATUS(USB, CCID_IN_EP & 0x0f) == USB_EP_TX_VALID)
;
/* Transmit next packet */
USBD_LL_Transmit(&Solo_USBD_Device, CCID_IN_EP, msg,
len);
printf1(TAG_CCID,"<< ");
dump_hex1(TAG_CCID, msg, len);
return USBD_OK;
}
void ccid_send_status(CCID_HEADER * c, uint8_t status)
{
uint8_t msg[CCID_HEADER_SIZE];
memset(msg,0,sizeof(msg));
msg[0] = CCID_SLOT_STATUS_RES;
msg[6] = c->seq;
msg[7] = status;
USBD_CCID_TransmitPacket(msg, sizeof(msg));
}
void ccid_send_data_block(CCID_HEADER * c, uint8_t status)
{
uint8_t msg[CCID_HEADER_SIZE];
memset(msg,0,sizeof(msg));
msg[0] = CCID_DATA_BLOCK_RES;
msg[6] = c->seq;
msg[7] = status;
USBD_CCID_TransmitPacket(msg, sizeof(msg));
}
void handle_ccid(uint8_t * msg, int len)
{
CCID_HEADER * h = (CCID_HEADER *) msg;
switch(h->type)
{
case CCID_SLOT_STATUS:
ccid_send_status(h, CCID_STATUS_ON);
break;
case CCID_POWER_ON:
ccid_send_data_block(h, CCID_STATUS_ON);
break;
case CCID_POWER_OFF:
ccid_send_status(h, CCID_STATUS_OFF);
break;
default:
ccid_send_status(h, CCID_STATUS_ON);
break;
}
}
/**
* @brief USBD_CDC_DataOut
* Data received on non-control Out endpoint
* @param pdev: device instance
* @param epnum: endpoint number
* @retval status
*/
uint8_t usb_ccid_recieve_callback(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
/* Get the received data length */
hcdc->RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
printf1(TAG_CCID, ">> ");
dump_hex1(TAG_CCID, ccidmsg_buf, hcdc->RxLength);
handle_ccid(ccidmsg_buf, hcdc->RxLength);
USBD_LL_PrepareReceive(&Solo_USBD_Device, CCID_OUT_EP, ccidmsg_buf,
CCID_DATA_PACKET_SIZE);
return USBD_OK;
}
/**
* @brief USBD_CDC_EP0_RxReady
* Handle EP0 Rx Ready event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_CCID_EP0_RxReady (USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}

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