Compare commits
985 Commits
fido2-cert
...
master
Author | SHA1 | Date | |
---|---|---|---|
ba6da64605 | |||
393051f407 | |||
c9894ab68a | |||
65dc8de490 | |||
d0124c615a | |||
![]() |
8b91ec7c53 | ||
![]() |
b86f0ee4e5 | ||
![]() |
13c882b532 | ||
![]() |
483edcb56d | ||
![]() |
b7b5d51cc2 | ||
![]() |
c52af54e8f | ||
![]() |
cc4cd340da | ||
![]() |
ca885941f0 | ||
![]() |
dc27b48101 | ||
![]() |
1bf071f8b4 | ||
![]() |
cc3d3c63ec | ||
![]() |
c248b5d569 | ||
![]() |
85cf25559c | ||
![]() |
299e91b91b | ||
![]() |
cbf40f4ec7 | ||
![]() |
8d93f88631 | ||
![]() |
5f8a9a44fc | ||
![]() |
8aa1f4ad01 | ||
![]() |
04cffb6509 | ||
![]() |
f002d08071 | ||
![]() |
e53b83257d | ||
![]() |
05e149fb17 | ||
![]() |
530e175ad1 | ||
![]() |
6cd3873b37 | ||
![]() |
241f58657b | ||
![]() |
3b42289cce | ||
![]() |
b3712b57fc | ||
![]() |
37769bb735 | ||
![]() |
d677f8c346 | ||
![]() |
98bcf647c4 | ||
![]() |
682a443f4e | ||
![]() |
a28a05673f | ||
![]() |
3a70ee0ec6 | ||
![]() |
872a320abc | ||
![]() |
3cbf7ec451 | ||
![]() |
748c552eea | ||
![]() |
98f996fcfe | ||
![]() |
97eb6bba8a | ||
![]() |
fdc5a68fcd | ||
![]() |
1c1005a0e8 | ||
![]() |
4831410111 | ||
![]() |
05bc8bee55 | ||
![]() |
7112633779 | ||
![]() |
79b43a90fd | ||
![]() |
ec7a6fd740 | ||
![]() |
f2d6698066 | ||
![]() |
3c9315e34c | ||
![]() |
8ed7157bfe | ||
![]() |
28a1b1cc06 | ||
![]() |
5738bcc7a3 | ||
![]() |
4fb166631d | ||
![]() |
1b862d3b0c | ||
![]() |
094420b32b | ||
![]() |
349cbc39f2 | ||
![]() |
e294cb3458 | ||
![]() |
da31f984dd | ||
![]() |
9d3e8c06fc | ||
![]() |
b378bbf61d | ||
![]() |
04b89a9739 | ||
![]() |
0d28a7bcf6 | ||
![]() |
aeafd09007 | ||
![]() |
8b6148ac90 | ||
![]() |
15a4fdfa66 | ||
![]() |
e713daba26 | ||
![]() |
b78f2cd2e7 | ||
![]() |
601c98000a | ||
![]() |
ab1c9417b1 | ||
![]() |
f6d96013e1 | ||
![]() |
f74dba7ff0 | ||
![]() |
794accf3dc | ||
![]() |
2ca0ced808 | ||
![]() |
17b430fd44 | ||
![]() |
0d4197fb2c | ||
![]() |
f74a77d80b | ||
![]() |
5f1d61a3ba | ||
![]() |
46f2920e63 | ||
![]() |
53427c4279 | ||
![]() |
ac10933379 | ||
![]() |
8a44d14fef | ||
![]() |
1d59bbfdd4 | ||
![]() |
54c66d80b6 | ||
![]() |
6217fc34b9 | ||
![]() |
af23e84a8d | ||
![]() |
9650d99b34 | ||
![]() |
145b04750e | ||
![]() |
078acbc4b4 | ||
![]() |
670a4e5d62 | ||
![]() |
de55e521cc | ||
![]() |
bbfe51499f | ||
![]() |
6cb15a6482 | ||
![]() |
85ddc40036 | ||
![]() |
1d63154699 | ||
![]() |
ee55bf3ba0 | ||
![]() |
3b4b6dd4fe | ||
![]() |
28e607ddac | ||
![]() |
dcd256faf4 | ||
![]() |
85365c635d | ||
![]() |
a388607dab | ||
![]() |
d266e7927c | ||
![]() |
0ac074e8a8 | ||
![]() |
67eb721da2 | ||
![]() |
6b5d353501 | ||
![]() |
bacce7d978 | ||
![]() |
975cdf02f2 | ||
![]() |
21f3a0d10f | ||
![]() |
b535b41d92 | ||
![]() |
fd32cc0761 | ||
![]() |
78dd2a10d3 | ||
![]() |
fa1bb0dce5 | ||
![]() |
169dfd2f0d | ||
![]() |
dafd974d93 | ||
![]() |
712fde6858 | ||
![]() |
fcc2e86a6d | ||
![]() |
8b146c4a16 | ||
![]() |
a1a79b05fd | ||
![]() |
c0df8b680d | ||
![]() |
9ac2aa90c3 | ||
![]() |
d33749fc16 | ||
![]() |
96a2cbcb41 | ||
![]() |
7212982385 | ||
![]() |
89e218e561 | ||
![]() |
666cd6a0ba | ||
![]() |
b4f59ec355 | ||
![]() |
b7d74cc99f | ||
![]() |
375a607356 | ||
![]() |
ea8409c072 | ||
![]() |
04f06b3b0d | ||
![]() |
a57c5170e1 | ||
![]() |
aaffce4021 | ||
![]() |
463a8b444d | ||
![]() |
44ed3ceea5 | ||
![]() |
30f73b41e4 | ||
![]() |
6f6e831fba | ||
![]() |
9fd608d3ee | ||
![]() |
765dc27b15 | ||
![]() |
48147a39df | ||
![]() |
6c48d75e44 | ||
![]() |
fca1e9d405 | ||
![]() |
0fbc28fbc1 | ||
![]() |
2a02d0de33 | ||
![]() |
00b09e0d40 | ||
![]() |
26db2b3f6b | ||
![]() |
ff88660027 | ||
![]() |
9ecfda02c5 | ||
![]() |
9158453830 | ||
![]() |
08658eb11e | ||
![]() |
49d79fa5da | ||
![]() |
69a7191860 | ||
![]() |
a2fd507f45 | ||
![]() |
a58658e35d | ||
![]() |
bb2929b28f | ||
![]() |
8e0eda8ed4 | ||
![]() |
0ebe0ff502 | ||
![]() |
7bcb7ea840 | ||
![]() |
811a57f7ab | ||
![]() |
5168afa16e | ||
![]() |
208d26be89 | ||
![]() |
45293fe998 | ||
![]() |
a1a42fec5c | ||
![]() |
8c256298ae | ||
![]() |
01b928c0ec | ||
![]() |
018a4d394c | ||
![]() |
7a75fba6d3 | ||
![]() |
c61f15a090 | ||
![]() |
f072561899 | ||
![]() |
6652feb4a2 | ||
![]() |
fc7ea68d4a | ||
![]() |
cb116efcc9 | ||
![]() |
80b9df3e04 | ||
![]() |
194ef5edcf | ||
![]() |
006117bb6b | ||
![]() |
75c75fa897 | ||
![]() |
2969d09ffa | ||
![]() |
b871e10d08 | ||
![]() |
18d39a7047 | ||
![]() |
a9bbdee35b | ||
![]() |
321bbe3691 | ||
![]() |
1ce191343f | ||
![]() |
9041e5903c | ||
![]() |
689d471688 | ||
![]() |
8b9e44c3ed | ||
![]() |
83dd92d9ba | ||
![]() |
a5e1dc2a0c | ||
![]() |
a053bbc669 | ||
![]() |
3621f2ed4f | ||
![]() |
3c7bf5a264 | ||
![]() |
8bf1921263 | ||
![]() |
e3ff136196 | ||
![]() |
74181406fe | ||
![]() |
987b04523d | ||
![]() |
8023347c8e | ||
![]() |
9dae7b2e7c | ||
![]() |
cb13fb65de | ||
![]() |
7fddd58704 | ||
![]() |
3a1ea275cc | ||
![]() |
22293f82f2 | ||
![]() |
40c3c13b07 | ||
![]() |
7042b0b656 | ||
![]() |
ea803aab95 | ||
![]() |
1100b159a9 | ||
![]() |
9ddba5dfc3 | ||
![]() |
35e52f4968 | ||
![]() |
efddd2f3a8 | ||
![]() |
17ceb7b9e8 | ||
![]() |
188a34d1da | ||
![]() |
9248c6462c | ||
![]() |
118e129152 | ||
![]() |
beb5a5892c | ||
![]() |
d618081dd0 | ||
![]() |
e4e0a3a84e | ||
![]() |
3ba9b671fc | ||
![]() |
69c34f9ca9 | ||
![]() |
3b4c154fd1 | ||
![]() |
ccd9a04146 | ||
![]() |
bde4c09c21 | ||
![]() |
5d3914bc5e | ||
![]() |
abe306a649 | ||
![]() |
41ceb78f6c | ||
![]() |
8e192f2363 | ||
![]() |
affc256ca2 | ||
![]() |
b3ac739a35 | ||
![]() |
3b53537077 | ||
![]() |
3fad9a7a7d | ||
![]() |
8973608f59 | ||
![]() |
8af6505f6d | ||
![]() |
d39d7978fd | ||
![]() |
c972a13034 | ||
![]() |
a95e62e2ea | ||
![]() |
c79b7abfb6 | ||
![]() |
dfb124dc8b | ||
![]() |
972760eb78 | ||
![]() |
0d621d13f9 | ||
![]() |
32f920e372 | ||
![]() |
a5aff478dd | ||
![]() |
728acc1671 | ||
![]() |
62b4418dac | ||
![]() |
8059a9765f | ||
![]() |
b743d5fac5 | ||
![]() |
dccfb0d1b3 | ||
![]() |
a72f0ede05 | ||
![]() |
adcbd3aeb8 | ||
![]() |
d931954a13 | ||
![]() |
b706cc30b0 | ||
![]() |
57fe39704b | ||
![]() |
4b6619b705 | ||
![]() |
a5877f518f | ||
![]() |
5a0cc0d02c | ||
![]() |
b452e3dfe4 | ||
![]() |
7f82233d17 | ||
![]() |
8e3753e711 | ||
![]() |
816ca21f08 | ||
![]() |
6c60a37e8a | ||
![]() |
ee351421cb | ||
![]() |
bac576f3a0 | ||
![]() |
6e637299e5 | ||
![]() |
43b3e93854 | ||
![]() |
5a448d636c | ||
![]() |
7be0553377 | ||
![]() |
095b08e3d9 | ||
![]() |
89e021003a | ||
![]() |
4f3d4b09eb | ||
![]() |
3f4843b03a | ||
![]() |
26af0c423e | ||
![]() |
19422d9daa | ||
![]() |
b7a4cf001a | ||
![]() |
3927aec06d | ||
![]() |
f5794481ae | ||
![]() |
caac9d0cc1 | ||
![]() |
ffadab05a3 | ||
![]() |
2423154fee | ||
![]() |
cf79b7865d | ||
![]() |
6f0cf99c92 | ||
![]() |
7ef68fd5d3 | ||
![]() |
3be8611fcf | ||
![]() |
21489658a7 | ||
![]() |
a07a3dee8d | ||
![]() |
416da63a9a | ||
![]() |
027fa791a3 | ||
![]() |
3e52d7b42b | ||
![]() |
301e18c6a2 | ||
![]() |
44205141eb | ||
![]() |
6e1110ca9b | ||
![]() |
9105b988e2 | ||
![]() |
14c94ea8f5 | ||
![]() |
435b908c17 | ||
![]() |
78280e570b | ||
![]() |
36aec9f20b | ||
![]() |
b5d3276df6 | ||
![]() |
ffd854a303 | ||
![]() |
349a84dcec | ||
![]() |
6c6a9bc5b6 | ||
![]() |
e1528cb248 | ||
![]() |
e0955c190e | ||
![]() |
ef1e9bc1a1 | ||
![]() |
f6c7dbdbdd | ||
![]() |
ea1969ca94 | ||
![]() |
c14bc76ddf | ||
![]() |
f7fd30b9ae | ||
![]() |
11763b6502 | ||
![]() |
ae5d341c72 | ||
![]() |
afed99bae9 | ||
![]() |
d6078ce015 | ||
![]() |
d630254224 | ||
![]() |
b2ac7b5479 | ||
![]() |
c050b82210 | ||
![]() |
ba8119b370 | ||
![]() |
d350f9a638 | ||
![]() |
53275e0182 | ||
![]() |
2e14ac5b11 | ||
![]() |
a760bed29f | ||
![]() |
e854184a11 | ||
![]() |
87c2076107 | ||
![]() |
9be192b82f | ||
![]() |
e95233bb5f | ||
![]() |
2a2145b7f2 | ||
![]() |
7cfd0ccb19 | ||
![]() |
7d84caa754 | ||
![]() |
f7dd595d84 | ||
![]() |
04570aaf15 | ||
![]() |
1a3aad9761 | ||
![]() |
9545dacc5d | ||
![]() |
b5e592adc9 | ||
![]() |
1cd6692246 | ||
![]() |
17884505b4 | ||
![]() |
c2312fa69a | ||
![]() |
832f06b6b4 | ||
![]() |
4ab5477f96 | ||
![]() |
434f2f89ec | ||
![]() |
9174c00abf | ||
![]() |
46111e27e3 | ||
![]() |
763995763f | ||
![]() |
4f317863e9 | ||
![]() |
8f9aeebb9b | ||
![]() |
86c6b3cbc8 | ||
![]() |
a53dfb2812 | ||
![]() |
04d6cffcb6 | ||
![]() |
76e46605e3 | ||
![]() |
dc94e73c62 | ||
![]() |
018311cfab | ||
![]() |
c37638d4cb | ||
![]() |
81a67eda24 | ||
![]() |
70c176e9ef | ||
![]() |
7e39425e98 | ||
![]() |
25bf9d8e54 | ||
![]() |
2e67a5f772 | ||
![]() |
66befb96b8 | ||
![]() |
257f6d1ed5 | ||
![]() |
b4b59a6d4d | ||
![]() |
c18a08b14b | ||
![]() |
c249148d80 | ||
![]() |
02a51454b7 | ||
![]() |
4e3420f19f | ||
![]() |
6b8e575fac | ||
![]() |
28788d1eeb | ||
![]() |
1ee031ae9c | ||
![]() |
6dfe42e486 | ||
![]() |
29b2032dae | ||
![]() |
f9f1e96c73 | ||
![]() |
e2738d11d3 | ||
![]() |
a8c7c43e14 | ||
![]() |
db479850a6 | ||
![]() |
09d450ed02 | ||
![]() |
be37ed46f7 | ||
![]() |
420d052ac9 | ||
![]() |
3698c942a2 | ||
![]() |
17a170bb90 | ||
![]() |
d4e61421b6 | ||
![]() |
690d7c716a | ||
![]() |
78e3b291c2 | ||
![]() |
b47854c335 | ||
![]() |
2af747ddaa | ||
![]() |
9ead11de8d | ||
![]() |
f17faca689 | ||
![]() |
ca66b6e43b | ||
![]() |
1cd1b3c295 | ||
![]() |
df2cff2350 | ||
![]() |
f5d50e001d | ||
![]() |
235785b225 | ||
![]() |
303c42901a | ||
![]() |
df2f950e69 | ||
![]() |
10bf4242e1 | ||
![]() |
9e95b0075c | ||
![]() |
ddbe31776c | ||
![]() |
645ca6a5a0 | ||
![]() |
15fc39faed | ||
![]() |
a1eedc0048 | ||
![]() |
89e00482e4 | ||
![]() |
533ce39237 | ||
![]() |
63ee003535 | ||
![]() |
fa9408d5d6 | ||
![]() |
ed9689435d | ||
![]() |
24a006068d | ||
![]() |
315b6564ab | ||
![]() |
4d9285085f | ||
![]() |
2272e69e15 | ||
![]() |
151e1d0e9b | ||
![]() |
d1df8b8b77 | ||
![]() |
cb76c34ed2 | ||
![]() |
f2ebaf6abe | ||
![]() |
4845d2c172 | ||
![]() |
75b1d9cd01 | ||
![]() |
26bc8a2889 | ||
![]() |
88a8eba424 | ||
![]() |
d2c85881e6 | ||
![]() |
236498ee03 | ||
![]() |
a51c9192b1 | ||
![]() |
4dc6bcf771 | ||
![]() |
cce81b23d9 | ||
![]() |
8c2e2386a9 | ||
![]() |
c783a1442a | ||
![]() |
b61e5db736 | ||
![]() |
b41cd5d5b8 | ||
![]() |
b42e990f67 | ||
![]() |
ff53bb1e32 | ||
![]() |
2d72e02051 | ||
![]() |
91c77da179 | ||
![]() |
795cf5c4a1 | ||
![]() |
d1722b85af | ||
![]() |
2c500fe25a | ||
![]() |
751b2fd69c | ||
![]() |
c2216929a9 | ||
![]() |
a51417bf61 | ||
![]() |
3f225f362f | ||
![]() |
dd4ff920ad | ||
![]() |
bddd60c080 | ||
![]() |
ba581db49c | ||
![]() |
3a5cd786dc | ||
![]() |
5f878ff022 | ||
![]() |
14f91a6e15 | ||
![]() |
4fad28ea47 | ||
![]() |
0ff9870612 | ||
![]() |
cd29a0e0fe | ||
![]() |
46b7f9a778 | ||
![]() |
31328fe7e7 | ||
![]() |
035b1a8632 | ||
![]() |
b1563dbe94 | ||
![]() |
2a9e3ac576 | ||
![]() |
e1474e8e8e | ||
![]() |
1564df5305 | ||
![]() |
1f3db3fe51 | ||
![]() |
36876e1528 | ||
![]() |
0f50ae7d63 | ||
![]() |
4854192c63 | ||
![]() |
e105afd647 | ||
![]() |
9fb02d4da3 | ||
![]() |
e402d36bf1 | ||
![]() |
54792b345c | ||
![]() |
84740f3d6a | ||
![]() |
4ac61f7f18 | ||
![]() |
30cfa46186 | ||
![]() |
aca28fde61 | ||
![]() |
60e3d01e0d | ||
![]() |
aff8d10432 | ||
![]() |
898d45f871 | ||
![]() |
2b2835b823 | ||
![]() |
f9202b2b6a | ||
![]() |
1b74f6a93b | ||
![]() |
0dfda6fce2 | ||
![]() |
09b73d694f | ||
![]() |
9ab5e761c3 | ||
![]() |
b3604f49ba | ||
![]() |
6ae1cd3865 | ||
![]() |
f9d3b9561d | ||
![]() |
ec98af115f | ||
![]() |
fecf258116 | ||
![]() |
437f691d12 | ||
![]() |
55aadfd78e | ||
![]() |
813eb97d2f | ||
![]() |
32afdccfb3 | ||
![]() |
41ae0e4a2c | ||
![]() |
b0baace2e7 | ||
![]() |
6ff4200f5d | ||
![]() |
1fab0b8f1f | ||
![]() |
ce96fffddd | ||
![]() |
4fb25e165a | ||
![]() |
8fc0da7934 | ||
![]() |
494e856198 | ||
![]() |
472b094acb | ||
![]() |
e0ce23034f | ||
![]() |
5f3974a4e6 | ||
![]() |
26adac1730 | ||
![]() |
eab8b81c95 | ||
![]() |
325396d518 | ||
![]() |
6d04c86018 | ||
![]() |
56d6624e4e | ||
![]() |
3094c87b0a | ||
![]() |
212f98e384 | ||
![]() |
73f538dd0e | ||
![]() |
a5f794c0ff | ||
![]() |
f28cf9c6d0 | ||
![]() |
6068fb9868 | ||
![]() |
6a288243c1 | ||
![]() |
955d4f76ef | ||
![]() |
74cbe00e3b | ||
![]() |
7e490f17fc | ||
![]() |
9bb706987f | ||
![]() |
88a759566d | ||
![]() |
44fa3bbb8e | ||
![]() |
89e9296825 | ||
![]() |
873d65b823 | ||
![]() |
eb8e3ed46a | ||
![]() |
8b97276e32 | ||
![]() |
78579c27dc | ||
![]() |
ca80329b4c | ||
![]() |
7a49169492 | ||
![]() |
46dd4fe818 | ||
![]() |
c71bbd8689 | ||
![]() |
7068be9cd5 | ||
![]() |
f8635f1682 | ||
![]() |
ffa9ad4923 | ||
![]() |
5fc8d214fd | ||
![]() |
5f49f4680e | ||
![]() |
86393c46b4 | ||
![]() |
4cc72bcd97 | ||
![]() |
5e0edf3e11 | ||
![]() |
bd810fff87 | ||
![]() |
d9fb508949 | ||
![]() |
c2b7acb6aa | ||
![]() |
4690a7ce65 | ||
![]() |
61f24d142d | ||
![]() |
f5c6f99423 | ||
![]() |
96de4f0850 | ||
![]() |
331ebdfccf | ||
![]() |
a6a6d653ad | ||
![]() |
928bc0216d | ||
![]() |
6d52c9ede7 | ||
![]() |
89769ecc18 | ||
![]() |
3b3f47bfcf | ||
![]() |
6fa443b0bc | ||
![]() |
893d4131b2 | ||
![]() |
4e21c0bd8f | ||
![]() |
251eb6bf64 | ||
![]() |
08e236df69 | ||
![]() |
d2091563ab | ||
![]() |
54a6a82ca0 | ||
![]() |
40b9dae38a | ||
![]() |
98a209e330 | ||
![]() |
d3b5fb68ee | ||
![]() |
74a1f0e21b | ||
![]() |
e21172fff8 | ||
![]() |
9d3144e9b1 | ||
![]() |
a2a774125f | ||
![]() |
349ea5343a | ||
![]() |
c851807376 | ||
![]() |
84d1629aa3 | ||
![]() |
8f6ae29163 | ||
![]() |
a0d27c2c56 | ||
![]() |
3a10427bd9 | ||
![]() |
f3b591e570 | ||
![]() |
175f59d206 | ||
![]() |
f5ff6a11f0 | ||
![]() |
d979420324 | ||
![]() |
5076af1be4 | ||
![]() |
0a7845459c | ||
![]() |
c4262b0f5b | ||
![]() |
53fb0059a7 | ||
![]() |
a1a75e4ab5 | ||
![]() |
d68011ef04 | ||
![]() |
02e83073e0 | ||
![]() |
3a48756f96 | ||
![]() |
946e932b1e | ||
![]() |
142d4002e5 | ||
![]() |
dbe5283e1f | ||
![]() |
2d233f164e | ||
![]() |
b62e9906c7 | ||
![]() |
e22e636475 | ||
![]() |
074225d87a | ||
![]() |
bb9b2ea9d4 | ||
![]() |
e8d5bc5829 | ||
![]() |
850381a633 | ||
![]() |
ce3ad0e56f | ||
![]() |
00d86379e5 | ||
![]() |
6098810167 | ||
![]() |
821880a8d6 | ||
![]() |
44f96f5843 | ||
![]() |
6ec9fb962a | ||
![]() |
c9bfe001ee | ||
![]() |
5e46fd96ac | ||
![]() |
103cc3cfb0 | ||
![]() |
9544330dc3 | ||
![]() |
0964ff69b7 | ||
![]() |
e4a2b9e1ca | ||
![]() |
d29fa34da1 | ||
![]() |
6ed2610a5c | ||
![]() |
3b9d4e5023 | ||
![]() |
2da083c18a | ||
![]() |
50bfbc1eff | ||
![]() |
86739df7a1 | ||
![]() |
c7f0d050d7 | ||
![]() |
b79670a447 | ||
![]() |
169ba59ed4 | ||
![]() |
f3003c58c9 | ||
![]() |
084e518018 | ||
![]() |
6674f0a8ff | ||
![]() |
f704851419 | ||
![]() |
0d5e1ee872 | ||
![]() |
5cb81c753d | ||
![]() |
b0b0564df9 | ||
![]() |
195dc2a8ae | ||
![]() |
4982b13f64 | ||
![]() |
63a93f6ec2 | ||
![]() |
7b8ec18e76 | ||
![]() |
67faef0117 | ||
![]() |
0b9f0af3c7 | ||
![]() |
880d54a4f0 | ||
![]() |
1507758ad1 | ||
![]() |
e883c5aa6e | ||
![]() |
afc85e0d2e | ||
![]() |
a40dcf3f17 | ||
![]() |
4b82e80d7a | ||
![]() |
246dea8a44 | ||
![]() |
7a98764a5b | ||
![]() |
dc946f5b35 | ||
![]() |
0232893611 | ||
![]() |
5995f84822 | ||
![]() |
1ff00895b1 | ||
![]() |
83641b3789 | ||
![]() |
9b356076c5 | ||
![]() |
6c96521c7d | ||
![]() |
35707c3797 | ||
![]() |
e31e703afd | ||
![]() |
3a8be9eef7 | ||
![]() |
e2b30ec087 | ||
![]() |
495e10f3a1 | ||
![]() |
11ca6bd517 | ||
![]() |
a265da09fb | ||
![]() |
1b4d1be9ee | ||
![]() |
32f2436380 | ||
![]() |
7255c4f8db | ||
![]() |
4e215db42a | ||
![]() |
a1ad641076 | ||
![]() |
daf56b0cc7 | ||
![]() |
5859073cb8 | ||
![]() |
ff5207ba77 | ||
![]() |
324b4a89cc | ||
![]() |
9f60caf9c1 | ||
![]() |
0865f2a660 | ||
![]() |
b1c72c9d94 | ||
![]() |
5e70c11b54 | ||
![]() |
46ada5a8b9 | ||
![]() |
0eac67259d | ||
![]() |
9399a5f195 | ||
![]() |
47aa287480 | ||
![]() |
865b698bed | ||
![]() |
14974e0ebe | ||
![]() |
1ed7833c9f | ||
![]() |
e8d0ad5e7c | ||
![]() |
e2ca7f52db | ||
![]() |
c97b9f9b8f | ||
![]() |
ecf994b647 | ||
![]() |
347d0942b1 | ||
![]() |
ff0d42c8d5 | ||
![]() |
a6673b0917 | ||
![]() |
0c296bba30 | ||
![]() |
57930aaa13 | ||
![]() |
1a6895ca25 | ||
![]() |
54241ecd42 | ||
![]() |
e537d00173 | ||
![]() |
a195408a11 | ||
![]() |
54b7f42056 | ||
![]() |
6128e86da2 | ||
![]() |
fed9f473aa | ||
![]() |
f6ff3c1b87 | ||
![]() |
afd3218358 | ||
![]() |
ed6da0ba1e | ||
![]() |
46d7be865d | ||
![]() |
596c6c1077 | ||
![]() |
6c3014575f | ||
![]() |
190ecc8fd8 | ||
![]() |
0d2e03a5a9 | ||
![]() |
991530f88b | ||
![]() |
de31924be3 | ||
![]() |
6b97807f51 | ||
![]() |
35022775cd | ||
![]() |
6fecb3c035 | ||
![]() |
3fed8cebdf | ||
![]() |
c81bc9fb98 | ||
![]() |
99f09790f1 | ||
![]() |
6745c9a0cb | ||
![]() |
0651316da5 | ||
![]() |
f48becc6dc | ||
![]() |
85c58e9d5b | ||
![]() |
c9862977bf | ||
![]() |
1a40299dcb | ||
![]() |
8f9ff17bef | ||
![]() |
9e9d26e604 | ||
![]() |
b3d76d56e0 | ||
![]() |
13424fdbcd | ||
![]() |
2327247c29 | ||
![]() |
85004370b7 | ||
![]() |
8f6f8a34e1 | ||
![]() |
f0f0aaaaa4 | ||
![]() |
5fddde240f | ||
![]() |
b212c71da6 | ||
![]() |
1ea4a2776b | ||
![]() |
41f1d5efed | ||
![]() |
6e497ad04e | ||
![]() |
34fb8c9c24 | ||
![]() |
8386ae56d2 | ||
![]() |
d38d3a8342 | ||
![]() |
ce364e5e87 | ||
![]() |
c482d6cc74 | ||
![]() |
2cb96cb793 | ||
![]() |
a32bea2697 | ||
![]() |
7df402a20a | ||
![]() |
650e0b26cc | ||
![]() |
831976f3a2 | ||
![]() |
e7e83820a9 | ||
![]() |
8dd211d557 | ||
![]() |
747d9a194d | ||
![]() |
bfd8827073 | ||
![]() |
ce92c7634e | ||
![]() |
f97d9ab34f | ||
![]() |
a2611fb013 | ||
![]() |
3b320e0aeb | ||
![]() |
f2d0e3d275 | ||
![]() |
c1631c7172 | ||
![]() |
259020ece0 | ||
![]() |
589b17c596 | ||
![]() |
ad4e526497 | ||
![]() |
f005ea438c | ||
![]() |
2615fd39ac | ||
![]() |
eba9ce8475 | ||
![]() |
a4f01c3f23 | ||
![]() |
c2342834dd | ||
![]() |
be212fd8b1 | ||
![]() |
ee817ea8bb | ||
![]() |
6c6f0a0068 | ||
![]() |
5862a8a5ac | ||
![]() |
a966ea3a58 | ||
![]() |
eed418ea33 | ||
![]() |
9a037279c8 | ||
![]() |
727e1f2fd9 | ||
![]() |
5afdef463e | ||
![]() |
1dd835d698 | ||
![]() |
400b37a96a | ||
![]() |
23c140fd99 | ||
![]() |
894f6f7ee1 | ||
![]() |
b9e6d552f8 | ||
![]() |
828a8fc0b5 | ||
![]() |
45eaef2663 | ||
![]() |
ed676151f1 | ||
![]() |
45da2f0b32 | ||
![]() |
6c23532f08 | ||
![]() |
bc8984aac3 | ||
![]() |
020fe21546 | ||
![]() |
9957a83746 | ||
![]() |
72bca0765a | ||
![]() |
ba4f9ed7ae | ||
![]() |
eb2d377ffb | ||
![]() |
8303bb04d3 | ||
![]() |
d23bf0a144 | ||
![]() |
a6446e67bc | ||
![]() |
529b879c08 | ||
![]() |
2893cd7ce3 | ||
![]() |
0634510b92 | ||
![]() |
858545c0c8 | ||
![]() |
120fb95541 | ||
![]() |
665e84d183 | ||
![]() |
13d9885da4 | ||
![]() |
e230a9464e | ||
![]() |
342af18b1f | ||
![]() |
be9bd941c8 | ||
![]() |
0f6be6740b | ||
![]() |
9054736e0e | ||
![]() |
c6d946136e | ||
![]() |
32400c8d09 | ||
![]() |
587c9aad14 | ||
![]() |
c624a32ef6 | ||
![]() |
3005a63938 | ||
![]() |
f470e9a9cd | ||
![]() |
e3971a5e0f | ||
![]() |
2ed8667f18 | ||
![]() |
765d532f82 | ||
![]() |
ca05385513 | ||
![]() |
5328610ff1 | ||
![]() |
bc1bb3509f | ||
![]() |
375db69e3a | ||
![]() |
771fffe329 | ||
![]() |
4611f05051 | ||
![]() |
e657e26886 | ||
![]() |
3ffcc47374 | ||
![]() |
102f2f261b | ||
![]() |
24d8abf820 | ||
![]() |
449faea7d3 | ||
![]() |
1b5e230d45 | ||
![]() |
81a89ed6aa | ||
![]() |
ca2074de36 | ||
![]() |
ee98340a03 | ||
![]() |
3d0d91fa5c | ||
![]() |
38171dba06 | ||
![]() |
4ba57ccc85 | ||
![]() |
c3bddee814 | ||
![]() |
b7bc50bc4f | ||
![]() |
19627a959a | ||
![]() |
429e4b2a77 | ||
![]() |
6e5de7bd6b | ||
![]() |
c6daa4acc9 | ||
![]() |
ab01d0c73d | ||
![]() |
0ef42b2df7 | ||
![]() |
f6e2bfa683 | ||
![]() |
5c8acdd666 | ||
![]() |
e996d470f9 | ||
![]() |
4c36a752cb | ||
![]() |
e2e29492e6 | ||
![]() |
5f637992b1 | ||
![]() |
91d092a27a | ||
![]() |
23cbfde312 | ||
![]() |
cce25b2a1c | ||
![]() |
f24058d2e8 | ||
![]() |
4c941997b4 | ||
![]() |
37f1790028 | ||
![]() |
91066292ae | ||
![]() |
1ffe85f083 | ||
![]() |
2049020b92 | ||
![]() |
7a6abdfd0c | ||
![]() |
ff4cb32bc3 | ||
![]() |
1857482617 | ||
![]() |
2feef8b043 | ||
![]() |
3eddfbf8a9 | ||
![]() |
a662a9a619 | ||
![]() |
1a656d60e4 | ||
![]() |
e235402fb8 | ||
![]() |
6ca9f1946b | ||
![]() |
df671775ba | ||
![]() |
3ba83f6407 | ||
![]() |
ffa4225827 | ||
![]() |
cde6bc107a | ||
![]() |
15de8dc4a6 | ||
![]() |
94fe58d020 | ||
![]() |
e8634a2d61 | ||
![]() |
67b0abde4b | ||
![]() |
d713167ec4 | ||
![]() |
45888c9a25 | ||
![]() |
d02206ba09 | ||
![]() |
ad9186c13b | ||
![]() |
4e0dc15dfd | ||
![]() |
a75d272f4a | ||
![]() |
15c3383249 | ||
![]() |
c556fcd8c3 | ||
![]() |
b4bfe5e3b9 | ||
![]() |
29d4d88259 | ||
![]() |
7bd5f29a79 | ||
![]() |
a72f5029dc | ||
![]() |
81e58a92f2 | ||
![]() |
c3b4806e85 | ||
![]() |
dffc1833cb | ||
![]() |
31538faab1 | ||
![]() |
1866d366fb | ||
![]() |
dcf7940b3d | ||
![]() |
1874e11fba | ||
![]() |
302ce75ce6 | ||
![]() |
178c25710b | ||
![]() |
62cd7cc728 | ||
![]() |
20f8aac768 | ||
![]() |
5806b25fd1 | ||
![]() |
4110434e33 | ||
![]() |
8c103be5c0 | ||
![]() |
9ff52fcdb4 | ||
![]() |
e7f01f4e55 | ||
![]() |
04a85db303 | ||
![]() |
61ad141830 | ||
![]() |
f38b29256b | ||
![]() |
121070822f | ||
![]() |
96f65be9c2 | ||
![]() |
78c40976c3 | ||
![]() |
8eacfa6717 | ||
![]() |
aa978abfc7 | ||
![]() |
80f2b487f0 | ||
![]() |
a0f8b27841 | ||
![]() |
b7c0e4ea92 | ||
![]() |
d89fe933f3 | ||
![]() |
794c231b0d | ||
![]() |
6ffba7d472 | ||
![]() |
c330346c31 | ||
![]() |
eda26e3c93 | ||
![]() |
fa4da6e9d7 | ||
![]() |
6d3313bd3f | ||
![]() |
ea210320c6 | ||
![]() |
bdc4c8f9df | ||
![]() |
8c1d716632 | ||
![]() |
ca27b26c6b | ||
![]() |
600b2a61fe | ||
![]() |
2f61c061b7 | ||
![]() |
44077a4f2f | ||
![]() |
ba4ca96253 | ||
![]() |
a48a962653 | ||
![]() |
4c6f0969c1 | ||
![]() |
ccac725b7f | ||
![]() |
41ed68eb44 | ||
![]() |
3d9dd08208 | ||
![]() |
83d59dfc54 | ||
![]() |
ce11e4173f | ||
![]() |
f15ba1d3dc | ||
![]() |
c0a2b677f0 | ||
![]() |
f8f895df4f | ||
![]() |
de3d6fd5ba | ||
![]() |
4072a51a5b | ||
![]() |
5f3c50e690 | ||
![]() |
6ca7076fe5 | ||
![]() |
dd320d049f | ||
![]() |
a8e1060eee | ||
![]() |
8210e9ecd9 | ||
![]() |
59503c775e | ||
![]() |
2f9987a28a | ||
![]() |
cbc422b817 | ||
![]() |
c7f1aecd61 | ||
![]() |
f2f71e2cbf | ||
![]() |
a1d3205011 | ||
![]() |
b01b37d86b | ||
![]() |
e63462cd86 | ||
![]() |
4136853e76 | ||
![]() |
c58c8300ac | ||
![]() |
89de3738c0 | ||
![]() |
6a5449b8cb | ||
![]() |
b2c78ca7c0 | ||
![]() |
fa810ff54d | ||
![]() |
de900dec2c | ||
![]() |
9565ae4cda | ||
![]() |
b8a27eadca | ||
![]() |
a4d79d12dd | ||
![]() |
8e8d74c5ad | ||
![]() |
1f380b0264 | ||
![]() |
58605fd278 | ||
![]() |
d726465b67 | ||
![]() |
4fe98ef560 | ||
![]() |
ea7ab508bc | ||
![]() |
f2a04ff1ff | ||
![]() |
c8531d3870 | ||
![]() |
ff2600a1fc | ||
![]() |
a4f0744a6e | ||
![]() |
71fbf37f69 | ||
![]() |
a219b4f7d9 | ||
![]() |
00ad1dd0ce | ||
![]() |
2144816e0b | ||
![]() |
80934f3e3b | ||
![]() |
05d99120cd | ||
![]() |
57879291cc | ||
![]() |
fbddf051c8 | ||
![]() |
ebd24e6181 | ||
![]() |
bbc61d5743 | ||
![]() |
ab06837628 | ||
![]() |
2a8498210c | ||
![]() |
db0642eeab | ||
![]() |
a96ff8eb63 | ||
![]() |
94140a0aa9 | ||
![]() |
09778c7c51 | ||
![]() |
5dd3355bd8 | ||
![]() |
51cf2d5ec9 | ||
![]() |
15a1fb1e5b | ||
![]() |
e360fa0097 | ||
![]() |
827a7da443 | ||
![]() |
1a07b4a73a | ||
![]() |
beedc24839 | ||
![]() |
b9ebde22e5 | ||
![]() |
cbf021c7a8 | ||
![]() |
5ee91048e2 | ||
![]() |
173b8833ce | ||
![]() |
b475c8391a | ||
![]() |
5a636d1ebe | ||
![]() |
97b715881b | ||
![]() |
b0cc9cf582 | ||
![]() |
5a96e82f4d | ||
![]() |
9b4b18e1a4 | ||
![]() |
e107a9aa86 | ||
![]() |
aece05b2e8 | ||
![]() |
eb39e0f2c4 | ||
![]() |
bfa2d2830d | ||
![]() |
0c461bb5d8 | ||
![]() |
9ff5dc6373 | ||
![]() |
ac7950f4c4 | ||
![]() |
93d4112bc3 | ||
![]() |
5ba11b1c40 | ||
![]() |
673470540d | ||
![]() |
1a9548c0f0 | ||
![]() |
50f565895f | ||
![]() |
296d2e6c74 | ||
![]() |
d402df42e2 | ||
![]() |
eb4a29edc6 | ||
![]() |
ff682d6b5e |
228
.all-contributorsrc
Normal file
228
.all-contributorsrc
Normal 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"
|
||||
}
|
19
.editorconfig
Normal file
19
.editorconfig
Normal file
@ -0,0 +1,19 @@
|
||||
https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties
|
||||
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -34,7 +34,8 @@
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
targets/*/*.hex
|
||||
targets/*/*.sha2
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
@ -75,7 +76,13 @@ tools/python-fido2/*
|
||||
site/
|
||||
_site/
|
||||
venv/
|
||||
env2/
|
||||
env3/
|
||||
.project
|
||||
.tags*
|
||||
targets/*/docs/
|
||||
main
|
||||
|
||||
builds/*
|
||||
tools/testing/.idea/*
|
||||
tools/testing/tests/__pycache__/*
|
||||
|
8
.gitmodules
vendored
8
.gitmodules
vendored
@ -1,9 +1,6 @@
|
||||
[submodule "tinycbor"]
|
||||
path = tinycbor
|
||||
url = https://github.com/intel/tinycbor
|
||||
[submodule "python-fido2"]
|
||||
path = python-fido2
|
||||
url = https://github.com/SoloKeysSec/python-fido2
|
||||
[submodule "crypto/micro-ecc"]
|
||||
path = crypto/micro-ecc
|
||||
url = https://github.com/kmackay/micro-ecc.git
|
||||
@ -12,4 +9,7 @@
|
||||
url = https://github.com/kokke/tiny-AES-c
|
||||
[submodule "targets/stm32l442/dfuse-tool"]
|
||||
path = targets/stm32l442/dfuse-tool
|
||||
url = https://github.com/SoloKeysSec/dfuse-tool
|
||||
url = https://github.com/solokeys/dfuse-tool
|
||||
[submodule "crypto/cifra"]
|
||||
path = crypto/cifra
|
||||
url = https://github.com/solokeys/cifra.git
|
||||
|
16
.travis.yml
16
.travis.yml
@ -1,4 +1,4 @@
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
language: c
|
||||
compiler: gcc
|
||||
addons:
|
||||
@ -6,7 +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 python3-venv
|
||||
script:
|
||||
- export CC=gcc-7
|
||||
- make test
|
||||
- export CC=gcc-8
|
||||
- pyenv shell 3.6.7
|
||||
- make travis
|
||||
|
1
99-solo.rules
Symbolic link
1
99-solo.rules
Symbolic link
@ -0,0 +1 @@
|
||||
udev/70-solokeys-access.rules
|
1
ALPHA_VERSION
Normal file
1
ALPHA_VERSION
Normal file
@ -0,0 +1 @@
|
||||
2.0.0
|
38
Dockerfile
Normal file
38
Dockerfile
Normal file
@ -0,0 +1,38 @@
|
||||
FROM debian:9.11-slim
|
||||
MAINTAINER SoloKeys <hello@solokeys.com>
|
||||
|
||||
# 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/*
|
||||
|
||||
# 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;
|
||||
|
||||
# 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
|
||||
|
||||
# solo-python (Python3.7 script for merging etc.)
|
||||
RUN pip install -U solo-python
|
20
LICENSE
20
LICENSE
@ -1,19 +1 @@
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Apache-2.0 OR MIT
|
||||
|
201
LICENSE-APACHE
Normal file
201
LICENSE-APACHE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
23
LICENSE-MIT
Normal file
23
LICENSE-MIT
Normal file
@ -0,0 +1,23 @@
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
160
Makefile
160
Makefile
@ -1,3 +1,5 @@
|
||||
include fido2/version.mk
|
||||
|
||||
#define uECC_arch_other 0
|
||||
#define uECC_x86 1
|
||||
#define uECC_x86_64 2
|
||||
@ -6,41 +8,35 @@
|
||||
#define uECC_arm_thumb2 5
|
||||
#define uECC_arm64 6
|
||||
#define uECC_avr 7
|
||||
ecc_platform=2
|
||||
|
||||
platform=2
|
||||
src = pc/device.c pc/main.c
|
||||
|
||||
EFM32_DEBUGGER= -s 440083537 --device EFM32JG1B200F128GM32
|
||||
#EFM32_DEBUGGER= -s 440121060 #dev board
|
||||
|
||||
src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard crypto/sha256/*.c) crypto/tiny-AES-c/aes.c
|
||||
obj = $(src:.c=.o) uECC.o
|
||||
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
|
||||
CFLAGS += -DAES256=1 -DSOLO_EXPERIMENTAL=1 -DDEBUG_LEVEL=1
|
||||
|
||||
name = main
|
||||
|
||||
.PHONY: all
|
||||
all: python-fido2 main
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(MAKE) -C . main
|
||||
$(MAKE) -C . testgcm
|
||||
./testgcm
|
||||
.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:
|
||||
git submodule update --init
|
||||
@ -48,72 +44,96 @@ tinycbor/Makefile crypto/tiny-AES-c/aes.c:
|
||||
.PHONY: cbor
|
||||
cbor: $(LIBCBOR)
|
||||
|
||||
$(LIBCBOR): tinycbor/Makefile
|
||||
cd tinycbor/ && $(MAKE) clean && $(MAKE) -j8
|
||||
$(LIBCBOR):
|
||||
cd tinycbor/ && $(MAKE) LDFLAGS='' -j8
|
||||
|
||||
.PHONY: efm8prog
|
||||
efm8prog:
|
||||
cd './targets/efm8\Keil 8051 v9.53 - Debug' && $(MAKE) all
|
||||
flashefm8.exe -part EFM8UB10F8G -sn 440105518 -erase
|
||||
flashefm8.exe -part EFM8UB10F8G -sn 440105518 -upload './targets/efm8/Keil 8051 v9.53 - Debug/efm8.hex'
|
||||
$(LIBSOLO):
|
||||
cd fido2/ && $(MAKE) CFLAGS="$(CFLAGS)" ECC_CFLAGS="$(ECC_CFLAGS)" APP_CONFIG=app.h -j8
|
||||
|
||||
.PHONY: efm32com efm32prog efm32read efm32bootprog
|
||||
efm32com:
|
||||
cd './targets/efm32/GNU ARM v7.2.1 - Debug' && $(MAKE) all
|
||||
efm32prog: efm32com
|
||||
commander flash './targets/efm32/GNU ARM v7.2.1 - Debug/EFM32.hex' $(EFM32_DEBUGGER) -p "0x1E7FC:0x00000000:4"
|
||||
efm32read: efm32com
|
||||
commander swo read $(EFM32_DEBUGGER)
|
||||
efm32bootprog: efm32com
|
||||
commander flash './efm32boot/GNU ARM v7.2.1 - Debug/efm32boot.hex' $(EFM32_DEBUGGER) --masserase
|
||||
version:
|
||||
@git describe
|
||||
|
||||
$(name): $(obj) $(LIBCBOR)
|
||||
test: venv
|
||||
$(MAKE) clean
|
||||
$(MAKE) -C . main
|
||||
$(MAKE) clean
|
||||
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" VERSION_FULL=${SOLO_VERSION_FULL}
|
||||
$(MAKE) clean
|
||||
$(MAKE) cppcheck
|
||||
|
||||
$(name): $(obj) $(LIBCBOR) $(LIBSOLO)
|
||||
$(CC) $(LDFLAGS) -o $@ $(obj) $(LDFLAGS)
|
||||
|
||||
crypto/aes-gcm/aes_gcm.o:
|
||||
$(CC) -c crypto/aes-gcm/aes_gcm.c $(CFLAGS) -DTEST -o crypto/aes-gcm/aes_gcm.o
|
||||
|
||||
testgcm: $(obj) $(LIBCBOR) crypto/aes-gcm/aes_gcm.o
|
||||
$(CC) -c fido2/main.c $(CFLAGS) -DTEST -o fido2/main.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
uECC.o: ./crypto/micro-ecc/uECC.c
|
||||
$(CC) -c -o $@ $^ -O2 -fdata-sections -ffunction-sections -DuECC_PLATFORM=$(platform) -I./crypto/micro-ecc/
|
||||
|
||||
|
||||
# python virtualenv
|
||||
|
||||
venv:
|
||||
@if ! which virtualenv >/dev/null ; then \
|
||||
echo "ERR: Sorry, no python virtualenv found. Please consider installing " ;\
|
||||
echo " it via something like:" ;\
|
||||
echo " sudo apt install python-virtualenv" ;\
|
||||
echo " or maybe:" ;\
|
||||
echo " pip install virtualenv" ;\
|
||||
fi
|
||||
virtualenv venv
|
||||
./venv/bin/pip install wheel
|
||||
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
|
||||
|
||||
.PHONY: python-fido2
|
||||
python-fido2: venv
|
||||
cd python-fido2/ && ../venv/bin/python setup.py install
|
||||
# selectively reformat our own code
|
||||
black: venv
|
||||
venv/bin/black --skip-string-normalization --check tools/
|
||||
|
||||
venv/bin/mkdocs: venv
|
||||
./venv/bin/pip install mkdocs mkdocs-material
|
||||
wink: venv
|
||||
venv/bin/solo key wink
|
||||
|
||||
.PHONY: docsrv
|
||||
docsrv: venv/bin/mkdocs
|
||||
./venv/bin/mkdocs serve
|
||||
fido2-test: venv
|
||||
venv/bin/python tools/ctap_test.py
|
||||
|
||||
.PHONY: fido2-test
|
||||
fido2-test:
|
||||
./venv/bin/python tools/ctap_test.py
|
||||
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):/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
|
||||
|
||||
cppcheck:
|
||||
cppcheck $(CPPCHECK_FLAGS) crypto/aes-gcm
|
||||
cppcheck $(CPPCHECK_FLAGS) crypto/sha256
|
||||
cppcheck $(CPPCHECK_FLAGS) fido2
|
||||
cppcheck $(CPPCHECK_FLAGS) pc
|
||||
|
||||
clean:
|
||||
rm -f *.o main.exe main testgcm $(obj)
|
||||
rm -f *.o main.exe main $(obj)
|
||||
for f in crypto/tiny-AES-c/Makefile tinycbor/Makefile ; do \
|
||||
if [ -f "$$f" ]; then \
|
||||
(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) test-docker
|
||||
$(MAKE) black
|
277
README.md
277
README.md
@ -1,145 +1,218 @@
|
||||

|
||||
[](https://solokeys.com/kickstarter)
|
||||
[](https://travis-ci.com/SoloKeysSec/solo)
|
||||
[](https://discourse.solokeys.com)
|
||||
[](https://update.solokeys.com/)
|
||||
[](https://keybase.io/team/solokeys.public)
|
||||
[](https://travis-ci.com/solokeys/solo)
|
||||
|
||||
Solo is an open source security key, and you can get one at [solokeys.com](https://solokeys.com).
|
||||
|
||||
# Solo
|
||||
[<img src="https://static.solokeys.com/images/photos/hero-on-white-cropped.png" width="600">](https://solokeys.com)
|
||||
|
||||
Solo is an affordable security key that implements FIDO2/U2F and supports USB, NFC, and extensions. Extensions
|
||||
include SSH, GPG, and cryptocurrency. Solo is an upgrade to [U2F Zero](https://github.com/conorpp/u2f-zero) and is a work in progress.
|
||||
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.
|
||||
|
||||
> Technical documentation for this project is contained in [docs/](https://github.com/SoloKeysSec/solo/tree/master/docs), built with [MkDocs](https://solo.solokeys.io/documenting/) and deployed automatically to <https://solo.solokeys.io>, part of our technical documentation suite hosted at <https://docs.solokeys.io>.
|
||||
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.
|
||||
|
||||
The Solo FIDO2/U2F code base is designed to be easily ported to different embedded systems.
|
||||
Right now, it has been ported to the NRF52840 and EFM32J. Soon to be supported is the STM32L442.
|
||||
|
||||
No hardware is needed for development. You can run and extend the FIDO2 code base
|
||||
using just your PC.
|
||||
|
||||
# Security
|
||||
|
||||
Solo is based on the STM32L442 microcontroller. It offers the following security features.
|
||||
Solo is based on the STM32L432 microcontroller. It offers the following security features.
|
||||
|
||||
- True random number generation to guarantee random keys.
|
||||
- Firewall feature for code and secret data isolation.
|
||||
- Locked flash
|
||||
|
||||
It also has up to 256 KB of memory, meaning it has room for side channel and fault resistant crypto implementations, plus other features.
|
||||
|
||||
Each chip ships with a read-only USB bootloader, put in place by ST. This can be leveraged to completely reset and reprogram the device, to make sure you can trust it's running the right code. The bootloader can be disabled.
|
||||
|
||||
# How do I get one?
|
||||
|
||||
We are still working on open sourcing an implementation that anyone can cheaply
|
||||
build and program, just like with U2F Zero. This will be released soon. It will be easy to solder :)
|
||||
|
||||
In the meantime, you can port the code to your favorite microcontroller, or support
|
||||
us by [signing up for our Kickstarter](https://solokeys.com/kickstarter). Our aim is to crowdfund enough to make an economic
|
||||
bulk order and provide open source security tokens for everyone that is interested. We will offer
|
||||
"hackable" tokens that come with USB bootloaders and are reprogrammable.
|
||||
|
||||
[Sign up here](https://solokeys.com/kickstarter)!
|
||||
- Security isolation so only simple & secure parts of code can handle keys.
|
||||
- Flash protection from both external use and untrusted code segments.
|
||||
- 256 KB of memory to support hardened crypto implementations and, later, additional features such as OpenPGP or SSH.
|
||||
- No NDA needed to develop for.
|
||||
|
||||
|
||||
# Setting up
|
||||
# Solo for Hackers
|
||||
|
||||
Clone solo and build it
|
||||
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.
|
||||
|
||||
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.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
|
||||
git clone --recurse-submodules https://github.com/SoloKeysSec/solo
|
||||
cd solo/
|
||||
# Build the toolchain container
|
||||
make docker-build-toolchain
|
||||
|
||||
git submodules init
|
||||
git submodules update
|
||||
# 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
|
||||
cd ../..
|
||||
|
||||
make venv
|
||||
source venv/bin/activate
|
||||
solo program aux enter-bootloader
|
||||
solo program bootloader targets/stm32l432/solo.hex
|
||||
```
|
||||
|
||||
# Developing Solo (No Hardware Needed)
|
||||
|
||||
Clone Solo and build it
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules https://github.com/solokeys/solo
|
||||
cd solo
|
||||
make all
|
||||
```
|
||||
|
||||
This builds our FIDO 2.0 and the U2F authenticator, as well as making a virtualenv in venv/
|
||||
that has our python-fido2 fork installed.
|
||||
This builds Solo as a standalone application. Solo application is set up to send and recv USB HID messages over UDP to ease development and reduce need for hardware.
|
||||
|
||||
Note that our python-fido2 fork will only connect to the software FIDO2 application,
|
||||
not a hardware authenticator. Install Yubico's fork to do that.
|
||||
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
|
||||
pip install -r tools/requirements.txt
|
||||
```
|
||||
|
||||
# Testing and development
|
||||
|
||||
The application is set up to send and recv USB HID messages over UDP to ease
|
||||
development and reduce need for hardware.
|
||||
|
||||
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.
|
||||
|
||||
Run FIDO 2 / U2F application.
|
||||
|
||||
Run the Solo application:
|
||||
```bash
|
||||
./main
|
||||
```
|
||||
|
||||
Run example client software. This runs through a registration and authentication.
|
||||
In another shell, you can run our [test suite](https://github.com/solokeys/fido2-tests).
|
||||
|
||||
```
|
||||
./venv/bin/python python-fido2/examples/credential.py
|
||||
```
|
||||
You can find more details in our [documentation](https://docs.solokeys.dev/), including how to build on the the NUCLEO-L432KC development board.
|
||||
|
||||
Run the FIDO2 tests.
|
||||
|
||||
```
|
||||
make fido2-test
|
||||
```
|
||||
|
||||
Follow specifications to really dig in.
|
||||
|
||||
[https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html](https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html)
|
||||
|
||||
## Extensions
|
||||
|
||||
Extensions can be added to FIDO2/U2F to support things like SSH, GPG, and cryptocurrency.
|
||||
Right now, an experimental cryptocurrency extension can be found in `fido2/extensions` and `web/index.html`.
|
||||
More documentation to come.
|
||||
|
||||
The main goal is to expose an extensible API on Solo, like the following:
|
||||
- Command to store private key
|
||||
- Command to sign arbitrary hash
|
||||
- Command to derive a public key
|
||||
- Commands for setting/changing/authenticating a pin code (like in FIDO2)
|
||||
- Command to expose entropy from TRNG.
|
||||
|
||||
Using these generic commands, various external programs can be implemented for the security key.
|
||||
Since FIDO2/U2F are implemented, these programs can potentially work in the browser on desktops
|
||||
and mobile devices, with no drivers needed to be installed.
|
||||
|
||||
|
||||
## Porting
|
||||
|
||||
The main code base is in `fido2/`. See `targets/nrf52840`, `targets/efm32/src`, and `pc/`
|
||||
for examples of FIDO2/U2F ports. In essence, you just need to reimplement `device.c`. Optionally you can
|
||||
re-implement `crypto.c` to accelerate operations and/or add other security features.
|
||||
|
||||
|
||||
More documentation to come.
|
||||
|
||||
# Documentation
|
||||
|
||||
Check out our [official documentation](https://solo.solokeys.io/).
|
||||
Check out our [official documentation](https://docs.solokeys.dev/).
|
||||
|
||||
# Contributors
|
||||
|
||||
Contributors are welcome. The ultimate goal is to have a FIDO 2 hardware token
|
||||
capable of USB, Bluetooth, and NFC interfaces. There could be multiple tokens
|
||||
for each interface.
|
||||
# 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.
|
||||
|
||||
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.
|
||||
|
||||
This is an upgrade to [U2F Zero](https://github.com/conorpp/u2f-zero).
|
||||
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
|
||||
|
||||
Everything in this repo is open source and licensed under the MIT License.
|
||||
Solo is fully open source.
|
||||
|
||||
All software, unless otherwise noted, is dual licensed under Apache 2.0 and MIT.
|
||||
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
|
||||
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_large)
|
||||
|
||||
# Where To Buy Solo
|
||||
|
||||
You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solokeys.com).
|
||||
|
||||
<br/>
|
||||
<hr/>
|
||||
<br/>
|
||||
|
||||
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
||||
[](#contributors)
|
||||
[](https://travis-ci.com/solokeys/solo)
|
||||
[](https://discourse.solokeys.com)
|
||||
[](https://keybase.io/team/solokeys.public)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_shield)
|
||||
|
||||
[](https://github.com/solokeys/solo/releases)
|
||||
[](https://github.com/solokeys/solo/commits/master)
|
||||
[](https://github.com/solokeys/solo/commits/master)
|
||||
[](https://github.com/solokeys/solo/commits/master)
|
||||
[](https://github.com/solokeys/solo/graphs/contributors)
|
||||
|
32
SECURITY.md
Normal file
32
SECURITY.md
Normal 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
1
STABLE_VERSION
Normal file
@ -0,0 +1 @@
|
||||
4.0.0
|
0
builds/.gitkeep
Normal file
0
builds/.gitkeep
Normal file
1
crypto/cifra
Submodule
1
crypto/cifra
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d04dd318609733d809904d4f2973597240655cde
|
27
default.nix
Normal file
27
default.nix
Normal 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
1
docs/_redirects
Normal file
@ -0,0 +1 @@
|
||||
/solo/* /:splat 302
|
147
docs/application-ideas.md
Normal file
147
docs/application-ideas.md
Normal 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
53
docs/bootloader-mode.md
Normal 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.
|
147
docs/building.md
147
docs/building.md
@ -1,28 +1,137 @@
|
||||
To build, develop and debug the firmware for the STM32L442 (WIP!) via cross-compilation on Linux, no vendor-specific software is necessary.
|
||||
# Building solo
|
||||
|
||||
There exists a development board [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) you can use; the L432 chip differs from the L442 used for Solo only in that it lacks a cryptographic accelerator. 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)).
|
||||
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.
|
||||
|
||||
You will need the following packages (naming given for Arch Linux):
|
||||
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)).
|
||||
|
||||
- arm-none-eabi-gcc
|
||||
- arm-none-eabi-newlib
|
||||
- arm-none-eabi-binutils
|
||||
## Prerequisites
|
||||
|
||||
and one of
|
||||
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.
|
||||
|
||||
- [openocd](http://openocd.org)
|
||||
- [stlink](https://github.com/texane/stlink)
|
||||
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`.
|
||||
|
||||
If you remove the `.exe` extensions in the [Makefile](https://github.com/SoloKeysSec/solo/blob/master/targets/stm32l442/Makefile), and possibly add a `-g` flag, compilation runs through.
|
||||
Install `solo-python` usually with `pip3 install solo-python`. The `solo` python application may also be used for [programming](#programming).
|
||||
|
||||
To flash and step through the code:
|
||||
## Obtain source code and solo tool
|
||||
|
||||
* connect the Nucleo to your PC
|
||||
* attach one of the debuggers: `st-util` (for stlink), or `openocd -f interface/stlink-v2-1.cfg -f target/stm32l4x.cfg` (for openocd)
|
||||
* launch `gdb` via `arm-none-eabi-gdb -q solo.elf`
|
||||
* connect gdb to the debugger via `target extended-remote :4242` (for stlink), or `target remote :3333` (for openocd)
|
||||
* flash the firmware via `load`
|
||||
* optionally set a breakpoint via `break main`
|
||||
* `continue`, and start stepping 🙌
|
||||
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).
|
||||
|
||||
Note that the code for `targets/stm32l442` currently consists of only a blinky hello world...
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
We are very open to contributions!
|
||||
|
||||
[Currently](https://github.com/solokeyssec/solo/issues), most work will go towards
|
||||
[Currently](https://github.com/solokeys/solo/issues), most work will go towards
|
||||
|
||||
* implementing STM32L442
|
||||
* ~~implementing STM32L432~~
|
||||
* implementing NFC
|
||||
* adding documentation and improving accessability of the code
|
||||
|
||||
In the future, we would love to see creative plugins/extensions, putting the TRNG and other features of the STM32L442 to good use!
|
||||
In the future, we would love to see creative plugins/extensions, putting the TRNG and other features of the STM32L432 to good use!
|
||||
|
||||
Feel free to send a [pull request](https://github.com/SoloKeysSec/solo/pulls) at any time, we don't currently have a formal contribution process.
|
||||
Feel free to send a [pull request](https://github.com/solokeys/solo/pulls) at any time, please note that we do require a lightweight copyright license agreement in order to accept contributions. Reason and procedure: <https://solokeys.com/legal/contributors/>.
|
||||
|
||||
If you want to discuss your plans in quasi-realtime beforehand, you can also join our [solokeys.public](https://keybase.io/team/solokeys.public) Keybase team.
|
||||
|
||||
But first: [join our mailing list!](https://solokeys.us19.list-manage.com/subscribe/post?u=cc0c298fb99cd136bdec8294b&id=b9cb3de62d)
|
||||
But first: [join our mailing list!](https://solokeys.us19.list-manage.com/subscribe/post?u=cc0c298fb99cd136bdec8294b&id=6550fc947a)
|
||||
|
142
docs/customization.md
Normal file
142
docs/customization.md
Normal 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.
|
@ -3,9 +3,9 @@ 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
|
||||
```
|
||||
|
||||
`make docsrv` and visit [localhost:8000](http://localhost:8000).
|
||||
`mkdocs serve` and visit [localhost:8000](http://localhost:8000).
|
||||
|
||||
The file `runtime.txt` is necessary to tell Netlify to use Python3.
|
||||
|
@ -15,13 +15,15 @@ A master secret, `M`, is generated at initialization. This is only used for
|
||||
all key generation and derivation in FIDO2. Solo uses a key wrapping method
|
||||
for FIDO2 operation.
|
||||
|
||||
** NOTE: The masked implementation of AES is planned, but not yet implemented. Currently it is normal AES. **
|
||||
|
||||
## Key wrapping
|
||||
|
||||
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
|
||||
@ -37,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)`.
|
||||
@ -55,6 +57,8 @@ keys which are then used for FIDO2/U2F. -->
|
||||
|
||||
## Key derivation
|
||||
|
||||
** Planned, but not yet implemented. **
|
||||
|
||||
Master secret `M` consists of 64 bytes, split into equal parts `M1` and `M2`.
|
||||
In theory, we should only need 32 bytes to achieve 256 security, but we also
|
||||
plan to have side channel security hence the added bytes.
|
||||
|
BIN
docs/images/conforms.PNG
Normal file
BIN
docs/images/conforms.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
BIN
docs/images/favicon.ico
Normal file
BIN
docs/images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
docs/images/solo_conforms.PNG
Normal file
BIN
docs/images/solo_conforms.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 129 KiB |
@ -1,4 +1,4 @@
|
||||
Welcome to the technical documentation for [solokeyssec/solo](https://github.com/solokeyssec/solo).
|
||||
Welcome to the technical documentation for [solokeys/solo](https://github.com/solokeys/solo).
|
||||
|
||||
For now, you can read the repository `README.md`, more documentation to come!
|
||||
Use the table of contents on the left to browse this documentation.
|
||||
|
||||
|
12
docs/metadata-statements.md
Normal file
12
docs/metadata-statements.md
Normal file
@ -0,0 +1,12 @@
|
||||
For information on what this is, see the [spec](https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-metadata-statement-v2.0-rd-20180702.html#fido2-example).
|
||||
## CTAP2
|
||||
|
||||
```
|
||||
{!metadata/Solo-FIDO2-CTAP2-Authenticator.json!}
|
||||
```
|
||||
|
||||
## U2F
|
||||
|
||||
```
|
||||
{!metadata/Solo-FIDO2-U2F-Authenticator.json!}
|
||||
```
|
257
docs/nucleo32-board.md
Normal file
257
docs/nucleo32-board.md
Normal 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]:
|
||||
|
||||
```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
60
docs/porting.md
Normal 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
116
docs/programming.md
Normal 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.
|
||||
|
Binary file not shown.
@ -2,7 +2,7 @@
|
||||
Solo has a bootloader that's fixed in memory to allow for signed firmware updates. It is not a built-in bootloader provided by the chip
|
||||
manufacturer, it is our own. We plan to use Ed25519 signatures, which have [efficient constant-time implementations on Cortex-M4 chips](http://www.cs.haifa.ac.il/~orrd/LC17/paper39.pdf).
|
||||
|
||||
On the STM32L442, there is 256 KB of memory. The first 14 KB of memory is reserved for the bootloader.
|
||||
On the STM32L432, there is 256 KB of memory. The first 14 KB of memory is reserved for the bootloader.
|
||||
The bootloader is the first thing that boots, and if the button of the device is not held for 2 seconds, the
|
||||
application is immediately booted.
|
||||
|
||||
@ -22,5 +22,5 @@ In order to boot the application, a valid signature must be provided to the boot
|
||||
signature using a public key stored in the bootloader section, and the data in the application section. If the signature
|
||||
is valid, the boot flag in the data section will be changed to allow boot.
|
||||
|
||||
Signature checks and checks to the data section boot flag are made redundantly to make glitching attacks more difficult. Random delays
|
||||
between redundant checks are also made.
|
||||
We are working to make the signature checking process redundantly to make glitching attacks more difficult. Also random delays
|
||||
between redundant checks.
|
||||
|
19
docs/solo-extras.md
Normal file
19
docs/solo-extras.md
Normal 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
|
||||
```
|
219
docs/tutorial-getting-started.md
Executable file
219
docs/tutorial-getting-started.md
Executable 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
|
||||
```
|
205
docs/tutorial-writing-extensions.md
Executable file
205
docs/tutorial-writing-extensions.md
Executable 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
|
38
docs/udev.md
38
docs/udev.md
@ -1,16 +1,27 @@
|
||||
# tl;dr
|
||||
# Summary
|
||||
|
||||
Create `/etc/udev/fido.rules` and add the following.
|
||||
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:
|
||||
|
||||
```
|
||||
# U2F Zero
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
|
||||
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):
|
||||
```
|
||||
udevadm trigger
|
||||
sudo udevadm control --reload-rules && sudo udevadm trigger
|
||||
```
|
||||
|
||||
# How do udev rules work and why are they needed
|
||||
@ -30,13 +41,13 @@ You can either compare `ls /dev` before and after inserting, or use the `udevadm
|
||||
```
|
||||
udevadm monitor --environment --udev | grep DEVNAME
|
||||
```
|
||||
Typically, you will detect `/dev/hidraw0`.
|
||||
Typically, you will detect `/dev/hidraw0`. Using the symlinks above, you can follow symlinks from `/dev/solokey` and `/dev/u2fzero`.
|
||||
|
||||
## How do you know if your system is configured correctly?
|
||||
Try reading and writing to the device node you identified in the previous step. Assuming the node is called `/dev/hidraw0`:
|
||||
|
||||
* read: try `cat /dev/hidraw0`, if you don't get "permission denied", you can access.
|
||||
* write: try `echo "hello, Solo" > /dev/hidraw0`. Again, if you don't get denied permission, you're OK.
|
||||
* read: try `cat /dev/solokey`, if you don't get "permission denied", you can access.
|
||||
* write: try `echo "hello, Solo" > /dev/solokey`. Again, if you don't get denied permission, you're OK.
|
||||
|
||||
## Which rule should I use, and how do I do it?
|
||||
Simplest is probably to copy [Yubico's rule file](https://github.com/Yubico/libu2f-host/blob/master/70-u2f.rules) to `/etc/udev/rules.d/fido.rules` on your system, for instance:
|
||||
@ -60,7 +71,10 @@ udevadm trigger
|
||||
```
|
||||
|
||||
## What about vendor and product ID for Solo?
|
||||
Current prototypes reuse the IDs of the U2F Zero (10c4/8acf). The final Solo will probably be assigned new IDs; read about it here first :)
|
||||
| Key | Vendor ID | Product ID |
|
||||
| --- | --- | --- |
|
||||
| Solo | 0483 | a2ca |
|
||||
| U2F Zero | 10c4 | 8acf |
|
||||
|
||||
## You got this all wrong, I can't believe it!
|
||||
Are you suffering from [us being wrong](https://xkcd.com/386/)? Please, send us a [pull request](https://github.com/SoloKeysSec/solo/pulls) and prove us wrong :D
|
||||
Are you suffering from [us being wrong](https://xkcd.com/386/)? Please, send us a [pull request](https://github.com/solokeys/solo/pulls) and prove us wrong :D
|
||||
|
44
fido2/Makefile
Normal file
44
fido2/Makefile
Normal 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
136
fido2/apdu.c
Normal 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
63
fido2/apdu.h
Normal 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_
|
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _COSE_KEY_H
|
||||
#define _COSE_KEY_H
|
||||
|
||||
@ -31,7 +16,7 @@
|
||||
#define COSE_KEY_KTY_EC2 2
|
||||
#define COSE_KEY_CRV_P256 1
|
||||
|
||||
|
||||
#define COSE_ALG_ES256 -7
|
||||
#define COSE_ALG_ECDH_ES_HKDF_256 -25
|
||||
|
||||
#endif
|
||||
|
158
fido2/crypto.c
158
fido2/crypto.c
@ -1,26 +1,37 @@
|
||||
// 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.
|
||||
/*
|
||||
* 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 "app.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,
|
||||
@ -37,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);
|
||||
@ -90,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)
|
||||
{
|
||||
printf("Error, key size must be <= 64\n");
|
||||
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -122,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)
|
||||
{
|
||||
printf("Error, key size must be <= 64\n");
|
||||
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||
exit(1);
|
||||
}
|
||||
memmove(buf, key, klen);
|
||||
@ -151,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;
|
||||
}
|
||||
|
||||
@ -168,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)
|
||||
{
|
||||
printf("error, uECC failed\n");
|
||||
printf2(TAG_ERR, "error, uECC failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -205,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:
|
||||
printf("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)
|
||||
{
|
||||
printf("error, uECC failed\n");
|
||||
printf2(TAG_ERR, "error, uECC failed\n");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
printf("error, invalid key length\n");
|
||||
printf2(TAG_ERR, "error, invalid key length\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -227,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);
|
||||
}
|
||||
|
||||
|
||||
@ -245,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)
|
||||
{
|
||||
@ -257,7 +299,7 @@ void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
|
||||
{
|
||||
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
|
||||
{
|
||||
printf("Error, uECC_make_key failed\n");
|
||||
printf2(TAG_ERR, "Error, uECC_make_key failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -266,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)
|
||||
{
|
||||
printf("Error, uECC_shared_secret failed\n");
|
||||
printf2(TAG_ERR, "Error, uECC_shared_secret failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -317,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
|
||||
|
@ -1,31 +1,14 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _CRYPTO_H
|
||||
#define _CRYPTO_H
|
||||
|
||||
#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();
|
||||
@ -34,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();
|
||||
@ -49,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)
|
||||
|
||||
@ -63,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
|
||||
|
1626
fido2/ctap.c
1626
fido2/ctap.c
File diff suppressed because it is too large
Load Diff
198
fido2/ctap.h
198
fido2/ctap.h
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _CTAP_H
|
||||
#define _CTAP_H
|
||||
|
||||
@ -31,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
|
||||
@ -55,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
|
||||
@ -69,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
|
||||
@ -120,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
|
||||
@ -137,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];
|
||||
@ -148,18 +161,35 @@ typedef struct
|
||||
|
||||
typedef struct {
|
||||
uint8_t tag[CREDENTIAL_TAG_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
|
||||
{
|
||||
@ -196,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
|
||||
{
|
||||
@ -241,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;
|
||||
@ -273,13 +356,31 @@ 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);
|
||||
|
||||
// Encodes R,S signature to 2 der sequence of two integers. Sigder must be at least 72 bytes.
|
||||
// @return length of der signature
|
||||
int ctap_encode_der_sig(uint8_t * sigbuf, uint8_t * sigder);
|
||||
int ctap_encode_der_sig(uint8_t const * const in_sigbuf, uint8_t * const out_sigder);
|
||||
|
||||
// Run ctap related power-up procedures (init pinToken, generate shared secret)
|
||||
void ctap_init();
|
||||
@ -314,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
|
||||
|
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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.
|
||||
#define CTAP1_ERR_SUCCESS 0x00
|
||||
#define CTAP1_ERR_INVALID_COMMAND 0x01
|
||||
#define CTAP1_ERR_INVALID_PARAMETER 0x02
|
||||
@ -64,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
|
||||
|
@ -1,35 +1,22 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 <stdint.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
@ -94,7 +81,7 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||
size_t sz, map_length;
|
||||
uint8_t key[24];
|
||||
int ret;
|
||||
int i;
|
||||
unsigned int i;
|
||||
CborValue map;
|
||||
|
||||
|
||||
@ -143,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)
|
||||
@ -161,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)
|
||||
{
|
||||
@ -176,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)
|
||||
{
|
||||
@ -191,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
|
||||
@ -285,7 +271,7 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
|
||||
uint8_t cred_type;
|
||||
int32_t alg_type;
|
||||
int ret;
|
||||
int i;
|
||||
unsigned int i;
|
||||
CborValue arr;
|
||||
|
||||
|
||||
@ -320,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;
|
||||
}
|
||||
@ -334,7 +320,7 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
|
||||
return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
|
||||
}
|
||||
|
||||
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len)
|
||||
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, unsigned int len)
|
||||
{
|
||||
size_t sz;
|
||||
int ret;
|
||||
@ -359,7 +345,7 @@ uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len)
|
||||
|
||||
uint8_t parse_verify_exclude_list(CborValue * val)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
CborValue arr;
|
||||
size_t size;
|
||||
@ -408,7 +394,7 @@ uint8_t parse_rp(struct rpId * rp, CborValue * val)
|
||||
size_t sz, map_length;
|
||||
char key[8];
|
||||
int ret;
|
||||
int i;
|
||||
unsigned int i;
|
||||
CborValue map;
|
||||
|
||||
|
||||
@ -496,7 +482,7 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
|
||||
size_t sz, map_length;
|
||||
char key[8];
|
||||
int ret;
|
||||
int i;
|
||||
unsigned int i;
|
||||
_Bool b;
|
||||
CborValue map;
|
||||
|
||||
@ -536,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;
|
||||
}
|
||||
|
||||
@ -571,16 +557,173 @@ 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;
|
||||
int i;
|
||||
unsigned int i;
|
||||
int key;
|
||||
size_t map_length;
|
||||
CborParser parser;
|
||||
CborValue it,map;
|
||||
|
||||
memset(MC, 0, sizeof(CTAP_makeCredential));
|
||||
MC->up = 0xff;
|
||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||
check_retr(ret);
|
||||
|
||||
@ -646,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:
|
||||
@ -655,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:
|
||||
@ -680,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
|
||||
{
|
||||
@ -702,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)
|
||||
@ -725,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);
|
||||
}
|
||||
|
||||
@ -738,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");
|
||||
@ -754,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);
|
||||
@ -771,12 +937,24 @@ 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)
|
||||
{
|
||||
if (0 == cred->type)
|
||||
{
|
||||
cred->type = PUB_KEY_CRED_PUB_KEY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cred->type = PUB_KEY_CRED_UNKNOWN;
|
||||
@ -790,7 +968,8 @@ uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it)
|
||||
{
|
||||
CborValue arr;
|
||||
size_t len;
|
||||
int i,ret;
|
||||
int ret;
|
||||
unsigned int i;
|
||||
CTAP_credentialDescriptor * cred;
|
||||
|
||||
if (cbor_value_get_type(it) != CborArrayType)
|
||||
@ -828,17 +1007,177 @@ 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)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
unsigned int i;
|
||||
int key;
|
||||
size_t map_length;
|
||||
CborParser parser;
|
||||
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);
|
||||
|
||||
@ -900,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:
|
||||
@ -907,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
|
||||
{
|
||||
@ -925,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)
|
||||
@ -946,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);
|
||||
}
|
||||
|
||||
@ -954,14 +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 i,ret,key;
|
||||
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);
|
||||
@ -999,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
|
||||
@ -1014,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
|
||||
@ -1024,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;
|
||||
|
||||
@ -1043,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;
|
||||
}
|
||||
@ -1053,7 +1405,7 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int
|
||||
uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
unsigned int i;
|
||||
int key;
|
||||
size_t map_length;
|
||||
size_t sz;
|
||||
@ -1123,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;
|
||||
@ -1166,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;
|
||||
|
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _CTAP_PARSE_H
|
||||
#define _CTAP_PARSE_H
|
||||
|
||||
@ -39,17 +24,18 @@ const char * cbor_value_get_type_string(const CborValue *value);
|
||||
uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val);
|
||||
uint8_t parse_pub_key_cred_param(CborValue * val, uint8_t * cred_type, int32_t * alg_type);
|
||||
uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val);
|
||||
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len);
|
||||
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, unsigned int len);
|
||||
uint8_t parse_rp_id(struct rpId * rp, CborValue * val);
|
||||
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);
|
||||
|
||||
|
242
fido2/ctaphid.c
242
fido2/ctaphid.c
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -30,7 +15,15 @@
|
||||
#include "time.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "app.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
|
||||
{
|
||||
@ -112,7 +105,7 @@ static uint32_t get_new_cid()
|
||||
|
||||
static int8_t add_cid(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
uint32_t i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (!CIDS[i].busy)
|
||||
@ -128,7 +121,7 @@ static int8_t add_cid(uint32_t cid)
|
||||
|
||||
static int8_t cid_exists(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
uint32_t i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (CIDS[i].cid == cid)
|
||||
@ -141,7 +134,7 @@ static int8_t cid_exists(uint32_t cid)
|
||||
|
||||
static int8_t cid_refresh(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
uint32_t i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (CIDS[i].cid == cid)
|
||||
@ -156,7 +149,7 @@ static int8_t cid_refresh(uint32_t cid)
|
||||
|
||||
static int8_t cid_del(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
uint32_t i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (CIDS[i].cid == cid)
|
||||
@ -282,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;
|
||||
}
|
||||
@ -311,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;
|
||||
}
|
||||
}
|
||||
@ -394,7 +387,7 @@ static int ctaphid_buffer_packet(uint8_t * pkt_raw, uint8_t * cmd, uint32_t * ci
|
||||
printf1(TAG_HID, "Recv packet\n");
|
||||
printf1(TAG_HID, " CID: %08x \n", pkt->cid);
|
||||
printf1(TAG_HID, " cmd: %02x\n", pkt->pkt.init.cmd);
|
||||
if (!is_cont_pkt(pkt)) printf1(TAG_HID, " length: %d\n", ctaphid_packet_len(pkt));
|
||||
if (!is_cont_pkt(pkt)) {printf1(TAG_HID, " length: %d\n", ctaphid_packet_len(pkt));}
|
||||
|
||||
int ret;
|
||||
uint32_t oldcid;
|
||||
@ -542,20 +535,34 @@ 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
|
||||
|
||||
static uint8_t is_busy = 0;
|
||||
static CTAPHID_WRITE_BUFFER wb;
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
|
||||
uint32_t t1,t2;
|
||||
|
||||
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)
|
||||
{
|
||||
@ -591,25 +598,20 @@ 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;
|
||||
t1 = millis();
|
||||
timestamp();
|
||||
ctaphid_write(&wb, ctap_buffer, len);
|
||||
ctaphid_write(&wb, NULL,0);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"PING writeback: %d ms\n",(uint32_t)(t2-t1));
|
||||
printf1(TAG_TIME,"PING writeback: %d ms\n",timestamp());
|
||||
|
||||
break;
|
||||
#endif
|
||||
#ifndef DISABLE_CTAPHID_WINK
|
||||
case CTAPHID_WINK:
|
||||
printf1(TAG_HID,"CTAPHID_WINK\n");
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_WINK;
|
||||
device_wink();
|
||||
|
||||
ctaphid_write(&wb,NULL,0);
|
||||
|
||||
@ -635,18 +637,17 @@ 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;
|
||||
|
||||
|
||||
t1 = millis();
|
||||
|
||||
timestamp();
|
||||
ctaphid_write(&wb, &status, 1);
|
||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"CBOR writeback: %d ms\n",(uint32_t)(t2-t1));
|
||||
printf1(TAG_TIME,"CBOR writeback: %d ms\n",timestamp());
|
||||
is_busy = 0;
|
||||
break;
|
||||
#endif
|
||||
@ -669,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);
|
||||
@ -682,10 +683,14 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
||||
is_busy = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cid_del(cid);
|
||||
buffer_reset();
|
||||
@ -695,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;
|
||||
}
|
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _CTAPHID_H_H
|
||||
#define _CTAPHID_H_H
|
||||
|
||||
@ -38,6 +23,17 @@
|
||||
#define CTAPHID_ERROR (TYPE_INIT | 0x3f)
|
||||
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3b)
|
||||
|
||||
// Custom commands between 0x40-0x7f
|
||||
#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
|
||||
#define ERR_INVALID_SEQ 0x04
|
||||
@ -64,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
90
fido2/data_migration.c
Normal 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
15
fido2/data_migration.h
Normal 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
225
fido2/device.c
Normal 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);
|
||||
}
|
||||
|
259
fido2/device.h
259
fido2/device.h
@ -1,93 +1,226 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _DEVICE_H
|
||||
#define _DEVICE_H
|
||||
|
||||
#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`
|
||||
void device_set_status(int status);
|
||||
|
||||
// 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();
|
||||
/** 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);
|
||||
|
||||
// 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);
|
||||
/** 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();
|
||||
|
||||
// Increment atomic counter and return it.
|
||||
// Must support two counters, @sel selects counter0 or counter1.
|
||||
uint32_t ctap_atomic_count(int sel);
|
||||
//
|
||||
// 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);
|
||||
|
||||
// Verify the user
|
||||
// return 1 if user is verified, 0 if not
|
||||
extern int ctap_user_verification(uint8_t arg);
|
||||
/** 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);
|
||||
|
||||
// Must be implemented by application
|
||||
// data is HID_MESSAGE_SIZE long in bytes
|
||||
extern void ctaphid_write_block(uint8_t * data);
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
/** 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
41
fido2/example_app.h
Normal 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_ */
|
@ -1,35 +1,121 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
// 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.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "extensions.h"
|
||||
#include "u2f.h"
|
||||
#include "ctap.h"
|
||||
#include "wallet.h"
|
||||
#include "solo.h"
|
||||
#include "device.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
|
||||
#define htonl(x) (((x & 0xff) << 24) | ((x & 0xff00) << 8) \
|
||||
| ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24) )
|
||||
|
||||
int is_extension_request(uint8_t * kh, int len)
|
||||
{
|
||||
wallet_request * req = (wallet_request *) kh;
|
||||
|
||||
if (len < WALLET_MIN_LENGTH)
|
||||
return 0;
|
||||
|
||||
return memcmp(req->tag, WALLET_TAG, sizeof(WALLET_TAG)-1) == 0;
|
||||
}
|
||||
|
||||
|
||||
int extension_needs_atomic_count(uint8_t klen, uint8_t * keyh)
|
||||
{
|
||||
return ((wallet_request *) keyh)->operation == WalletRegister
|
||||
|| ((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;
|
||||
uint32_t count;
|
||||
uint8_t up = 1;
|
||||
uint8_t sig[72];
|
||||
if (extension_needs_atomic_count(klen, keyh))
|
||||
{
|
||||
count = htonl(ctap_atomic_count(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
count = htonl(10);
|
||||
}
|
||||
|
||||
u2f_response_writeback(&up,1);
|
||||
u2f_response_writeback((uint8_t *)&count,4);
|
||||
u2f_response_writeback((uint8_t *)&ret,1);
|
||||
#ifdef IS_BOOTLOADER
|
||||
ret = bootloader_bridge(klen, keyh);
|
||||
#else
|
||||
ret = bridge_u2f_to_solo(sig, keyh, klen);
|
||||
u2f_response_writeback(sig,72);
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
u2f_reset_response();
|
||||
u2f_response_writeback(&up,1);
|
||||
u2f_response_writeback((uint8_t *)&count,4);
|
||||
|
||||
memset(sig,0,sizeof(sig));
|
||||
sig[0] = ret;
|
||||
u2f_response_writeback(sig,72);
|
||||
}
|
||||
|
||||
return U2F_SW_NO_ERROR;
|
||||
}
|
||||
|
||||
// Returns 1 if this is a extension request.
|
||||
// Else 0 if nothing is done.
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -37,7 +123,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
|
||||
if (req->p1 == U2F_AUTHENTICATE_CHECK)
|
||||
{
|
||||
|
||||
if (is_wallet_device((uint8_t *) &auth->kh, auth->khl)) // Pin requests
|
||||
if (is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
|
||||
{
|
||||
rcode = U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
@ -45,23 +131,25 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
|
||||
{
|
||||
rcode = U2F_SW_WRONG_DATA;
|
||||
}
|
||||
printf1(TAG_WALLET,"Ignoring U2F request\n");
|
||||
printf1(TAG_EXT,"Ignoring U2F check request\n");
|
||||
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! is_wallet_device((uint8_t *) &auth->kh, auth->khl)) // Pin requests
|
||||
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
|
||||
{
|
||||
rcode = U2F_SW_WRONG_PAYLOAD;
|
||||
printf1(TAG_WALLET,"Ignoring U2F request\n");
|
||||
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;
|
||||
}
|
||||
rcode = bridge_u2f_to_wallet(auth->chal, auth->app, auth->khl, (uint8_t*)&auth->kh);
|
||||
rcode = bridge_u2f_to_extensions(auth->chal, auth->app, auth->khl, (uint8_t*)&auth->kh);
|
||||
}
|
||||
}
|
||||
else if (req->ins == U2F_VERSION)
|
||||
{
|
||||
printf1(TAG_U2F, "U2F_VERSION\n");
|
||||
printf1(TAG_EXT, "U2F_VERSION\n");
|
||||
if (len)
|
||||
{
|
||||
rcode = U2F_SW_WRONG_LENGTH;
|
||||
|
@ -1,28 +1,29 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 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);
|
||||
|
||||
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_ */
|
||||
|
84
fido2/extensions/solo.c
Normal file
84
fido2/extensions/solo.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2018 SoloKeys, Inc. <https://solokeys.com/>
|
||||
*
|
||||
* This file is part of Solo.
|
||||
*
|
||||
* Solo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Solo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Solo. If not, see <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This code is available under licenses for commercial use.
|
||||
* Please contact SoloKeys for more information.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "extensions.h"
|
||||
#include "u2f.h"
|
||||
#include "wallet.h"
|
||||
#include "device.h"
|
||||
#include "ctap.h"
|
||||
#include "ctap_errors.h"
|
||||
|
||||
#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);
|
||||
|
||||
switch(req->operation)
|
||||
{
|
||||
case WalletVersion:
|
||||
output[0] = SOLO_VERSION_MAJ;
|
||||
output[1] = SOLO_VERSION_MIN;
|
||||
output[2] = SOLO_VERSION_PATCH;
|
||||
break;
|
||||
case WalletRng:
|
||||
printf1(TAG_WALLET,"SoloRng\n");
|
||||
|
||||
ret = ctap_generate_rng(output, 71);
|
||||
if (ret != 1)
|
||||
{
|
||||
printf1(TAG_WALLET,"Rng failed\n");
|
||||
ret = CTAP2_ERR_PROCESSING;
|
||||
goto cleanup;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
return ret;
|
||||
}
|
27
fido2/extensions/solo.h
Normal file
27
fido2/extensions/solo.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2018 SoloKeys, Inc. <https://solokeys.com/>
|
||||
*
|
||||
* This file is part of Solo.
|
||||
*
|
||||
* Solo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Solo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Solo. If not, see <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This code is available under licenses for commercial use.
|
||||
* Please contact SoloKeys for more information.
|
||||
*/
|
||||
#ifndef SOLO_H_
|
||||
#define SOLO_H_
|
||||
|
||||
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen);
|
||||
|
||||
#endif
|
@ -1,26 +1,11 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 "wallet.h"
|
||||
#include "app.h"
|
||||
#include APP_CONFIG
|
||||
#include "ctap.h"
|
||||
#include "ctap_errors.h"
|
||||
#include "crypto.h"
|
||||
@ -29,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,
|
||||
@ -47,30 +32,8 @@ 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
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WalletSign = 0x10,
|
||||
WalletRegister = 0x11,
|
||||
WalletPin = 0x12,
|
||||
WalletReset= 0x13,
|
||||
WalletVersion= 0x14,
|
||||
WalletRng = 0x15,
|
||||
} WalletOperation;
|
||||
|
||||
int is_wallet_device(uint8_t * kh, int len)
|
||||
{
|
||||
wallet_request * req = (wallet_request *) kh;
|
||||
|
||||
if (len < WALLET_MIN_LENGTH)
|
||||
return 0;
|
||||
|
||||
return memcmp(req->tag, WALLET_TAG, sizeof(WALLET_TAG)-1) == 0;
|
||||
}
|
||||
|
||||
// return 1 if hash is valid, 0 otherwise
|
||||
int check_pinhash(uint8_t * pinAuth, uint8_t * msg, uint8_t len)
|
||||
@ -105,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:
|
||||
@ -122,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;
|
||||
}
|
||||
@ -132,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:
|
||||
@ -148,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;
|
||||
}
|
||||
@ -170,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;
|
||||
}
|
||||
@ -180,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;
|
||||
|
||||
@ -194,14 +157,13 @@ 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;
|
||||
int i;
|
||||
int8_t ret = 0;
|
||||
uint32_t count;
|
||||
uint8_t up = 1;
|
||||
|
||||
uint8_t sig[200];
|
||||
|
||||
uint8_t * args[5] = {NULL,NULL,NULL,NULL,NULL};
|
||||
@ -222,21 +184,6 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
||||
|
||||
printf1(TAG_WALLET, "u2f2wallet [%d]: ",reqlen); dump_hex1(TAG_WALLET, msg_buf,reqlen);
|
||||
|
||||
if (req->operation == WalletRegister || req->operation == WalletSign)
|
||||
{
|
||||
count = ctap_atomic_count(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 10;
|
||||
}
|
||||
|
||||
u2f_response_writeback(&up,1);
|
||||
u2f_response_writeback((uint8_t *)&count,4);
|
||||
u2f_response_writeback((uint8_t *)&ret,1);
|
||||
|
||||
#ifndef IS_BOOTLOADER
|
||||
|
||||
int offset = 0;
|
||||
for (i = 0; i < MIN(5,req->numArgs); i++)
|
||||
{
|
||||
@ -310,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:
|
||||
@ -348,8 +295,6 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
||||
memmove(chksum, args[0] + lens[0] - 4, 4);
|
||||
lens[0] -= 4;
|
||||
|
||||
/*printf("chksum: "); dump_hex1(TAG_WALLET, chksum, 4);*/
|
||||
|
||||
// perform integrity check
|
||||
/*printf1(TAG_WALLET,"shasum on [%d]: ",lens[0]); dump_hex1(TAG_WALLET, args[0], lens[0]);*/
|
||||
crypto_sha256_init();
|
||||
@ -414,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();
|
||||
@ -427,63 +372,15 @@ 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);
|
||||
ret = CTAP1_ERR_INVALID_COMMAND;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
ret = bootloader_bridge(klen, keyh);
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
if (ret != 0)
|
||||
{
|
||||
u2f_reset_response();
|
||||
u2f_response_writeback(&up,1);
|
||||
u2f_response_writeback((uint8_t *)&count,4);
|
||||
|
||||
memset(sig,0,sizeof(sig));
|
||||
sig[0] = ret;
|
||||
u2f_response_writeback(sig,72);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*u2f_response_writeback(sig,sizeof(sig));*/
|
||||
}
|
||||
return U2F_SW_NO_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,25 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// 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 WALLET_H_
|
||||
#define WALLET_H_
|
||||
|
||||
@ -92,10 +76,18 @@ typedef struct
|
||||
}__attribute__((packed)) wallet_request;
|
||||
|
||||
|
||||
int16_t bridge_u2f_to_wallet(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh);
|
||||
typedef enum
|
||||
{
|
||||
WalletSign = 0x10,
|
||||
WalletRegister = 0x11,
|
||||
WalletPin = 0x12,
|
||||
WalletReset= 0x13,
|
||||
WalletVersion= 0x14,
|
||||
WalletRng = 0x15,
|
||||
} WalletOperation;
|
||||
|
||||
// return 1 if request is a wallet request
|
||||
int is_wallet_device(uint8_t * req, int len);
|
||||
|
||||
int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen);
|
||||
|
||||
void wallet_init();
|
||||
|
||||
|
54
fido2/log.c
54
fido2/log.c
@ -1,36 +1,27 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "device.h"
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
|
||||
static uint32_t LOGMASK = TAG_FILENO;
|
||||
|
||||
|
||||
void set_logging_mask(uint32_t mask)
|
||||
{
|
||||
LOGMASK = mask;
|
||||
}
|
||||
|
||||
|
||||
struct logtag
|
||||
{
|
||||
uint32_t tagn;
|
||||
@ -55,6 +46,12 @@ struct logtag tagtable[] = {
|
||||
{TAG_TIME,"[1;33mTIME[0m"},
|
||||
{TAG_WALLET,"[1;34mWALLET[0m"},
|
||||
{TAG_STOR,"[1;35mSTOR[0m"},
|
||||
{TAG_BOOT,"[1;36mBOOT[0m"},
|
||||
{TAG_EXT,"[1;37mEXT[0m"},
|
||||
{TAG_NFC,"[1;38mNFC[0m"},
|
||||
{TAG_NFC_APDU, "NAPDU"},
|
||||
{TAG_CCID, "CCID"},
|
||||
{TAG_CM, "CRED_MGMT"},
|
||||
};
|
||||
|
||||
|
||||
@ -65,7 +62,7 @@ __attribute__((weak)) void set_logging_tag(uint32_t tag)
|
||||
|
||||
void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
if (((tag & 0x7fffffff) & LOGMASK) == 0)
|
||||
{
|
||||
@ -75,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;
|
||||
}
|
||||
@ -107,3 +104,14 @@ void LOG_HEX(uint32_t tag, uint8_t * data, int length)
|
||||
set_logging_tag(tag);
|
||||
dump_hex(data,length);
|
||||
}
|
||||
|
||||
uint32_t timestamp()
|
||||
{
|
||||
static uint32_t t1 = 0;
|
||||
uint32_t t2 = millis();
|
||||
uint32_t diff = t2 - t1;
|
||||
t1 = t2;
|
||||
return diff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
56
fido2/log.h
56
fido2/log.h
@ -1,28 +1,16 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
#include "app.h"
|
||||
#ifdef APP_CONFIG
|
||||
#include APP_CONFIG
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
@ -33,7 +21,7 @@
|
||||
|
||||
void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...);
|
||||
void LOG_HEX(uint32_t tag, uint8_t * data, int length);
|
||||
void set_logging_mask(uint32_t mask);
|
||||
|
||||
void set_logging_tag(uint32_t tag);
|
||||
|
||||
typedef enum
|
||||
@ -55,24 +43,36 @@ typedef enum
|
||||
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 = (1<<31)
|
||||
TAG_NO_TAG = (1UL << 30),
|
||||
TAG_FILENO = (1UL << 31)
|
||||
} LOG_TAG;
|
||||
|
||||
#if DEBUG_LEVEL == 1
|
||||
#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__)
|
||||
#define printf2(tag,fmt, ...) LOG(tag | TAG_FILENO,__FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
#define printf3(tag,fmt, ...) LOG(tag | TAG_FILENO,__FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define dump_hex1(tag,data,len) LOG_HEX(tag,data,len)
|
||||
|
||||
uint32_t timestamp();
|
||||
|
||||
#else
|
||||
|
||||
#define printf1(fmt, ...)
|
||||
#define printf2(fmt, ...)
|
||||
#define printf3(fmt, ...)
|
||||
#define set_logging_mask(mask)
|
||||
#define printf1(tag,fmt, ...)
|
||||
#define printf2(tag,fmt, ...)
|
||||
#define printf3(tag,fmt, ...)
|
||||
#define dump_hex1(tag,data,len)
|
||||
#define timestamp()
|
||||
|
||||
#endif
|
||||
|
||||
|
103
fido2/main.c
103
fido2/main.c
@ -1,103 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
//#include "bsp.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
#include "app.h"
|
||||
|
||||
#if !defined(TEST)
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
device_init();
|
||||
printf1(TAG_GEN,"init device\n");
|
||||
|
||||
printf1(TAG_GEN,"init ctaphid\n");
|
||||
ctaphid_init();
|
||||
|
||||
printf1(TAG_GEN,"init ctap\n");
|
||||
ctap_init();
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
printf1(TAG_GEN,"recv'ing hid msg \n");
|
||||
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (millis() - t1 > 100)
|
||||
{
|
||||
/*printf("heartbeat %ld\n", beat++);*/
|
||||
heartbeat();
|
||||
t1 = millis();
|
||||
}
|
||||
|
||||
device_manage();
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
ctaphid_handle_packet(hidmsg);
|
||||
memset(hidmsg, 0, sizeof(hidmsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
ctaphid_check_timeouts();
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
usbhid_close();
|
||||
printf1(TAG_GREEN, "done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _STORAGE_H
|
||||
#define _STORAGE_H
|
||||
|
||||
@ -26,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
|
||||
@ -47,7 +35,27 @@ typedef struct
|
||||
|
||||
uint16_t key_lens[MAX_KEYS];
|
||||
uint8_t key_space[KEY_SPACE_BYTES];
|
||||
} AuthenticatorState;
|
||||
} AuthenticatorState_0xFF;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Pin information
|
||||
uint8_t is_initialized;
|
||||
uint8_t is_pin_set;
|
||||
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];
|
||||
uint8_t data_version;
|
||||
} AuthenticatorState_0x01;
|
||||
|
||||
typedef AuthenticatorState_0x01 AuthenticatorState;
|
||||
|
||||
|
||||
typedef struct
|
||||
|
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 <stdio.h>
|
||||
#include "device.h"
|
||||
#include "util.h"
|
||||
@ -31,18 +16,18 @@
|
||||
|
||||
void ctap_init()
|
||||
{
|
||||
printf("STUB: ctap_init\n");
|
||||
printf1(TAG_GEN,"STUB: ctap_init\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STUB_CTAPHID)
|
||||
void ctaphid_init()
|
||||
{
|
||||
printf("STUB: ctaphid_init\n");
|
||||
printf1(TAG_GEN,"STUB: ctaphid_init\n");
|
||||
}
|
||||
void ctaphid_handle_packet(uint8_t * hidmsg)
|
||||
{
|
||||
printf("STUB: ctaphid_handle_packet\n");
|
||||
printf1(TAG_GEN,"STUB: ctaphid_handle_packet\n");
|
||||
}
|
||||
|
||||
void ctaphid_check_timeouts()
|
||||
@ -57,7 +42,7 @@ void ctaphid_check_timeouts()
|
||||
|
||||
void ctap_reset_state()
|
||||
{
|
||||
printf("STUB: ctap_reset_state\n");
|
||||
printf1(TAG_GEN,"STUB: ctap_reset_state\n");
|
||||
}
|
||||
|
||||
void ctap_response_init(CTAP_RESPONSE * resp)
|
||||
@ -66,12 +51,12 @@ void ctap_response_init(CTAP_RESPONSE * resp)
|
||||
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
{
|
||||
printf("STUB: u2f_request\n");
|
||||
printf1(TAG_GEN,"STUB: u2f_request\n");
|
||||
}
|
||||
|
||||
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
{
|
||||
printf("STUB: ctap_request\n");
|
||||
printf1(TAG_GEN,"STUB: ctap_request\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -1,25 +1,10 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "app.h"
|
||||
// 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 APP_CONFIG
|
||||
#ifdef TEST_POWER
|
||||
|
||||
/*
|
||||
|
186
fido2/u2f.c
186
fido2/u2f.c
@ -1,49 +1,42 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 <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"
|
||||
#include "app.h"
|
||||
#ifdef ENABLE_U2F_EXTENSIONS
|
||||
#include "extensions.h"
|
||||
#endif
|
||||
#include APP_CONFIG
|
||||
|
||||
// void u2f_response_writeback(uint8_t * buf, uint8_t len);
|
||||
#ifdef ENABLE_U2F
|
||||
static int16_t u2f_register(struct u2f_register_request * req);
|
||||
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control);
|
||||
#endif
|
||||
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;
|
||||
uint64_t t1,t2;
|
||||
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
|
||||
uint8_t byte;
|
||||
|
||||
_u2f_resp = resp;
|
||||
ctap_response_init(resp);
|
||||
u2f_set_writeback_buffer(resp);
|
||||
|
||||
if (req->cla != 0)
|
||||
{
|
||||
@ -52,9 +45,9 @@ 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) // If the extension didn't do anything...
|
||||
if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything...
|
||||
{
|
||||
#ifdef ENABLE_U2F
|
||||
switch(req->ins)
|
||||
@ -67,18 +60,18 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = millis();
|
||||
rcode = u2f_register((struct u2f_register_request*)req->payload);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"u2f_register time: %d ms\n", t2-t1);
|
||||
|
||||
timestamp();
|
||||
rcode = u2f_register((struct u2f_register_request*)payload);
|
||||
printf1(TAG_TIME,"u2f_register time: %d ms\n", timestamp());
|
||||
|
||||
}
|
||||
break;
|
||||
case U2F_AUTHENTICATE:
|
||||
printf1(TAG_U2F, "U2F_AUTHENTICATE\n");
|
||||
t1 = millis();
|
||||
rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", t2-t1);
|
||||
timestamp();
|
||||
rcode = u2f_authenticate((struct u2f_authenticate_request*)payload, req->p1);
|
||||
printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", timestamp());
|
||||
break;
|
||||
case U2F_VERSION:
|
||||
printf1(TAG_U2F, "U2F_VERSION\n");
|
||||
@ -104,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)
|
||||
{
|
||||
@ -119,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)
|
||||
{
|
||||
@ -137,7 +148,12 @@ void u2f_reset_response()
|
||||
ctap_response_init(_u2f_resp);
|
||||
}
|
||||
|
||||
void u2f_set_writeback_buffer(CTAP_RESPONSE * resp)
|
||||
{
|
||||
_u2f_resp = resp;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_U2F
|
||||
static void dump_signature_der(uint8_t * sig)
|
||||
{
|
||||
uint8_t sigder[72];
|
||||
@ -145,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;
|
||||
}
|
||||
|
||||
@ -161,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);
|
||||
@ -171,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];
|
||||
|
||||
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 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;
|
||||
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)
|
||||
@ -201,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;
|
||||
}
|
||||
@ -211,30 +247,37 @@ 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)
|
||||
if(up)
|
||||
{
|
||||
if (ctap_user_presence_test(750) == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
count = ctap_atomic_count(0);
|
||||
|
||||
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((uint8_t *)&count,4);
|
||||
crypto_sha256_update(hash, 4);
|
||||
crypto_sha256_update(req->chal, 32);
|
||||
|
||||
crypto_sha256_final(hash);
|
||||
@ -243,7 +286,11 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
||||
crypto_ecc256_sign(hash, 32, sig);
|
||||
|
||||
u2f_response_writeback(&up,1);
|
||||
u2f_response_writeback((uint8_t *)&count,4);
|
||||
hash[0] = (count >> 24) & 0xff;
|
||||
hash[1] = (count >> 16) & 0xff;
|
||||
hash[2] = (count >> 8) & 0xff;
|
||||
hash[3] = (count >> 0) & 0xff;
|
||||
u2f_response_writeback(hash,4);
|
||||
dump_signature_der(sig);
|
||||
|
||||
return U2F_SW_NO_ERROR;
|
||||
@ -252,16 +299,21 @@ 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())
|
||||
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;
|
||||
}
|
||||
@ -284,8 +336,6 @@ static int16_t u2f_register(struct u2f_register_request * req)
|
||||
|
||||
crypto_ecc256_load_attestation_key();
|
||||
|
||||
/*printf("check key handle size: %d vs %d\n", U2F_KEY_HANDLE_SIZE, sizeof(struct u2f_key_handle));*/
|
||||
|
||||
printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F,hash,32);
|
||||
crypto_ecc256_sign(hash, 32, sig);
|
||||
|
||||
@ -296,15 +346,15 @@ 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
int16_t u2f_version()
|
||||
{
|
||||
|
38
fido2/u2f.h
38
fido2/u2f.h
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _U2F_H_
|
||||
#define _U2F_H_
|
||||
|
||||
@ -53,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
|
||||
@ -113,9 +98,16 @@ struct u2f_authenticate_request
|
||||
// @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();
|
||||
void u2f_set_writeback_buffer(CTAP_RESPONSE * resp);
|
||||
|
||||
int16_t u2f_version();
|
||||
|
||||
|
29
fido2/util.c
29
fido2/util.c
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@ -30,5 +15,3 @@ void dump_hex(uint8_t * buf, int size)
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
|
27
fido2/util.h
27
fido2/util.h
@ -1,24 +1,9 @@
|
||||
/*
|
||||
Copyright 2018 Conor Patrick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// 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 _UTIL_H
|
||||
#define _UTIL_H
|
||||
|
||||
|
18
fido2/version.c
Normal file
18
fido2/version.c
Normal 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);
|
39
fido2/version.h
Normal file
39
fido2/version.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef _VERSION_H_
|
||||
#define _VERSION_H_
|
||||
|
||||
|
||||
#ifndef SOLO_VERSION_MAJ
|
||||
|
||||
#define SOLO_VERSION_MAJ 0
|
||||
#define SOLO_VERSION_MIN 0
|
||||
#define SOLO_VERSION_PATCH 0
|
||||
|
||||
#endif
|
||||
|
||||
#define __STR_HELPER(x) #x
|
||||
#define __STR(x) __STR_HELPER(x)
|
||||
|
||||
#ifndef SOLO_VERSION
|
||||
#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
9
fido2/version.mk
Normal 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)\"
|
53
in-docker-build.sh
Executable file
53
in-docker-build.sh
Executable file
@ -0,0 +1,53 @@
|
||||
#!/bin/bash -xe
|
||||
version=$1
|
||||
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
|
||||
|
||||
cd /solo/targets/stm32l432
|
||||
ls
|
||||
|
||||
make cbor
|
||||
|
||||
out_dir="/builds"
|
||||
|
||||
function build() {
|
||||
part=${1}
|
||||
output=${2}
|
||||
what="${part}"
|
||||
|
||||
make full-clean
|
||||
|
||||
make ${what} VERSION_FULL=${version}
|
||||
|
||||
out_hex="${what}-${version}.hex"
|
||||
out_sha2="${what}-${version}.sha2"
|
||||
|
||||
mv ${output}.hex ${out_hex}
|
||||
sha256sum ${out_hex} > ${out_sha2}
|
||||
cp ${out_hex} ${out_sha2} ${out_dir}
|
||||
}
|
||||
|
||||
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
|
41
metadata/Solo-FIDO2-CTAP2-Authenticator.json
Normal file
41
metadata/Solo-FIDO2-CTAP2-Authenticator.json
Normal file
File diff suppressed because one or more lines are too long
37
metadata/Solo-FIDO2-U2F-Authenticator.json
Normal file
37
metadata/Solo-FIDO2-U2F-Authenticator.json
Normal file
File diff suppressed because one or more lines are too long
41
metadata/SoloTap-FIDO2-CTAP2-Authenticator.json
Normal file
41
metadata/SoloTap-FIDO2-CTAP2-Authenticator.json
Normal file
File diff suppressed because one or more lines are too long
41
metadata/Somu-FIDO2-CTAP2-Authenticator.json
Normal file
41
metadata/Somu-FIDO2-CTAP2-Authenticator.json
Normal file
File diff suppressed because one or more lines are too long
29
mkdocs.yml
Normal file → Executable file
29
mkdocs.yml
Normal file → Executable file
@ -1,21 +1,36 @@
|
||||
site_name: Solo
|
||||
site_name: Solo Technical Documentation
|
||||
site_author: SoloKeys
|
||||
site_description: 'Documentation for the SoloKeys solo software'
|
||||
repo_url: 'https://github.com/solokeyssec/solo'
|
||||
repo_name: 'solokeyssec/solo'
|
||||
copyright: 'Copyright © 2018 SoloKeys'
|
||||
site_url: 'https://docs.solokeys.dev/'
|
||||
repo_url: 'https://github.com/solokeys/solo'
|
||||
repo_name: 'solokeys/solo'
|
||||
copyright: 'Copyright © 2018 - 2019 SoloKeys'
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- README.md: repo-readme.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
|
||||
- Building: building.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
|
||||
- What the udev?!: udev.md
|
||||
- udev Rules: udev.md
|
||||
- About: repo-readme.md
|
||||
|
||||
theme:
|
||||
name: material
|
||||
logo: 'images/logo.svg'
|
||||
favicon: 'images/favicon.ico'
|
||||
|
||||
markdown_extensions:
|
||||
- markdown_include.include
|
||||
|
33
pc/app.h
33
pc/app.h
@ -1,12 +1,13 @@
|
||||
/*
|
||||
* app.h
|
||||
*
|
||||
* Created on: Jun 26, 2018
|
||||
* Author: conor
|
||||
*/
|
||||
// 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
|
||||
|
||||
@ -15,10 +16,28 @@
|
||||
#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
|
||||
#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_ */
|
||||
|
380
pc/device.c
380
pc/device.c
@ -1,3 +1,9 @@
|
||||
// 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 <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@ -5,22 +11,35 @@
|
||||
#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"
|
||||
#include "util.h"
|
||||
#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();
|
||||
|
||||
|
||||
int udp_server()
|
||||
{
|
||||
int fd;
|
||||
static bool run_already = false;
|
||||
static int fd = -1;
|
||||
if (run_already && fd >= 0) return fd;
|
||||
run_already = true;
|
||||
|
||||
if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
|
||||
perror( "socket failed" );
|
||||
return 1;
|
||||
@ -72,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;
|
||||
}
|
||||
|
||||
@ -88,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;
|
||||
@ -106,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)
|
||||
@ -144,64 +205,66 @@ void int_handler(int i)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void device_init()
|
||||
|
||||
|
||||
void usage(const char * cmd)
|
||||
{
|
||||
signal(SIGINT, int_handler);
|
||||
|
||||
usbhid_init();
|
||||
|
||||
authenticator_initialize();
|
||||
fprintf(stderr, "Usage: %s [-b udp|hidg]\n", cmd);
|
||||
fprintf(stderr, " -b backing implementation: udp(default) or hidg\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void main_loop_delay()
|
||||
void device_init(int argc, char *argv[])
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000*1000*25;
|
||||
nanosleep(&ts,NULL);
|
||||
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'b':
|
||||
if (strcmp("udp", optarg) == 0)
|
||||
{
|
||||
use_udp = true;
|
||||
}
|
||||
|
||||
|
||||
void heartbeat()
|
||||
else if (strcmp("hidg", optarg) == 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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++;
|
||||
use_udp = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf2(TAG_ERR,"counter2 not imple\n");
|
||||
exit(1);
|
||||
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 delay(uint32_t ms)
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000*1000*ms;
|
||||
nanosleep(&ts,NULL);
|
||||
}
|
||||
|
||||
|
||||
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||
{
|
||||
int ret;
|
||||
@ -211,24 +274,21 @@ int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
ret = fread(dst, 1, num, urand);
|
||||
fclose(urand);
|
||||
|
||||
if (ret != num)
|
||||
if (fread(dst, 1, num, urand) != num)
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
perror("fread");
|
||||
}
|
||||
/*memset(dst,0xaa,num);*/
|
||||
|
||||
fclose(urand);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@ -247,37 +307,19 @@ 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");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = fread(state, 1, sizeof(AuthenticatorState), f);
|
||||
fclose(f);
|
||||
if(ret != sizeof(AuthenticatorState))
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -291,60 +333,27 @@ void authenticator_write_state(AuthenticatorState * state, int backup)
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
f = fopen(backup_file, "wb+");
|
||||
}
|
||||
|
||||
|
||||
static void sync_rk()
|
||||
{
|
||||
FILE * f = fopen(rk_file, "wb+");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
ret = fwrite(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
@ -369,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
|
||||
{
|
||||
@ -390,27 +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 manage_device()
|
||||
|
||||
void ctap_reset_rk()
|
||||
{
|
||||
memset(&RK_STORE,0xff,sizeof(RK_STORE));
|
||||
sync_rk();
|
||||
}
|
||||
|
||||
uint32_t ctap_rk_size()
|
||||
{
|
||||
return RK_NUM;
|
||||
}
|
||||
|
||||
|
||||
void ctap_store_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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
86
pc/main.c
Normal file
86
pc/main.c
Normal file
@ -0,0 +1,86 @@
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
//#include "bsp.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
#include "app.h"
|
||||
|
||||
|
||||
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_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(argc, argv);
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
ctaphid_handle_packet(hidmsg);
|
||||
memset(hidmsg, 0, sizeof(hidmsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
ctaphid_check_timeouts();
|
||||
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000*1000*10;
|
||||
nanosleep(&ts,NULL);
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
printf1(TAG_GREEN, "done\n");
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
Subproject commit 329434fdd476870ff0a73196b6de8a963409235f
|
13
shell.nix
Normal file
13
shell.nix
Normal 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 ];
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>EFM32</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>com.silabs.ss.framework.ide.project.sls.core.SLSProjectNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>crypto</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-2-PROJECT_LOC%7D/crypto</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>fido2</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-2-PROJECT_LOC%7D/fido2</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>CMSIS/EFM32JG1B/startup_gcc_efm32jg1b.s</name>
|
||||
<type>1</type>
|
||||
<locationURI>STUDIO_SDK_LOC/platform/Device/SiliconLabs/EFM32JG1B/Source/GCC/startup_efm32jg1b.S</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>CMSIS/EFM32JG1B/system_efm32jg1b.c</name>
|
||||
<type>1</type>
|
||||
<locationURI>STUDIO_SDK_LOC/platform/Device/SiliconLabs/EFM32JG1B/Source/system_efm32jg1b.c</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
</projectDescription>
|
@ -1,2 +0,0 @@
|
||||
copiedFilesOriginState={}
|
||||
eclipse.preferences.version=1
|
@ -1,70 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.cdt.codan.checkers.errnoreturn=Warning
|
||||
org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
|
||||
org.eclipse.cdt.codan.checkers.errreturnvalue=Error
|
||||
org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.checkers.nocommentinside=-Error
|
||||
org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.checkers.nolinecomment=-Error
|
||||
org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.checkers.noreturn=Error
|
||||
org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
|
||||
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")}
|
||||
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
@ -1,317 +0,0 @@
|
||||
/* @file startup_efm32pg1b.S
|
||||
* @brief startup file for Silicon Labs EFM32PG1B devices.
|
||||
* For use with GCC for ARM Embedded Processors
|
||||
* @version 5.2.2
|
||||
* Date: 12 June 2014
|
||||
*
|
||||
*/
|
||||
/* Copyright (c) 2011 - 2014 ARM LIMITED
|
||||
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
- 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.
|
||||
- Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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.
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
.syntax unified
|
||||
.arch armv7-m
|
||||
.section .stack
|
||||
.align 3
|
||||
#ifdef __STACK_SIZE
|
||||
.equ Stack_Size, __STACK_SIZE
|
||||
#else
|
||||
.equ Stack_Size, 0x00000400
|
||||
#endif
|
||||
.globl __StackTop
|
||||
.globl __StackLimit
|
||||
__StackLimit:
|
||||
.space Stack_Size
|
||||
.size __StackLimit, . - __StackLimit
|
||||
__StackTop:
|
||||
.size __StackTop, . - __StackTop
|
||||
|
||||
.section .heap
|
||||
.align 3
|
||||
#ifdef __HEAP_SIZE
|
||||
.equ Heap_Size, __HEAP_SIZE
|
||||
#else
|
||||
.equ Heap_Size, 0x00000C00
|
||||
#endif
|
||||
.globl __HeapBase
|
||||
.globl __HeapLimit
|
||||
__HeapBase:
|
||||
.if Heap_Size
|
||||
.space Heap_Size
|
||||
.endif
|
||||
.size __HeapBase, . - __HeapBase
|
||||
__HeapLimit:
|
||||
.size __HeapLimit, . - __HeapLimit
|
||||
|
||||
.section .vectors
|
||||
.align 2
|
||||
.globl __Vectors
|
||||
__Vectors:
|
||||
.long __StackTop /* Top of Stack */
|
||||
.long Reset_Handler /* Reset Handler */
|
||||
.long NMI_Handler /* NMI Handler */
|
||||
.long HardFault_Handler /* Hard Fault Handler */
|
||||
.long MemManage_Handler /* MPU Fault Handler */
|
||||
.long BusFault_Handler /* Bus Fault Handler */
|
||||
.long UsageFault_Handler /* Usage Fault Handler */
|
||||
.long Default_Handler /* Reserved */
|
||||
.long Default_Handler /* Reserved */
|
||||
.long Default_Handler /* Reserved */
|
||||
.long Default_Handler /* Reserved */
|
||||
.long SVC_Handler /* SVCall Handler */
|
||||
.long DebugMon_Handler /* Debug Monitor Handler */
|
||||
.long Default_Handler /* Reserved */
|
||||
.long PendSV_Handler /* PendSV Handler */
|
||||
.long SysTick_Handler /* SysTick Handler */
|
||||
|
||||
/* External interrupts */
|
||||
.long EMU_IRQHandler /* 0 - EMU */
|
||||
.long Default_Handler /* 1 - Reserved */
|
||||
.long WDOG0_IRQHandler /* 2 - WDOG0 */
|
||||
.long Default_Handler /* 3 - Reserved */
|
||||
.long Default_Handler /* 4 - Reserved */
|
||||
.long Default_Handler /* 5 - Reserved */
|
||||
.long Default_Handler /* 6 - Reserved */
|
||||
.long Default_Handler /* 7 - Reserved */
|
||||
.long LDMA_IRQHandler /* 8 - LDMA */
|
||||
.long GPIO_EVEN_IRQHandler /* 9 - GPIO_EVEN */
|
||||
.long TIMER0_IRQHandler /* 10 - TIMER0 */
|
||||
.long USART0_RX_IRQHandler /* 11 - USART0_RX */
|
||||
.long USART0_TX_IRQHandler /* 12 - USART0_TX */
|
||||
.long ACMP0_IRQHandler /* 13 - ACMP0 */
|
||||
.long ADC0_IRQHandler /* 14 - ADC0 */
|
||||
.long IDAC0_IRQHandler /* 15 - IDAC0 */
|
||||
.long I2C0_IRQHandler /* 16 - I2C0 */
|
||||
.long GPIO_ODD_IRQHandler /* 17 - GPIO_ODD */
|
||||
.long TIMER1_IRQHandler /* 18 - TIMER1 */
|
||||
.long USART1_RX_IRQHandler /* 19 - USART1_RX */
|
||||
.long USART1_TX_IRQHandler /* 20 - USART1_TX */
|
||||
.long LEUART0_IRQHandler /* 21 - LEUART0 */
|
||||
.long PCNT0_IRQHandler /* 22 - PCNT0 */
|
||||
.long CMU_IRQHandler /* 23 - CMU */
|
||||
.long MSC_IRQHandler /* 24 - MSC */
|
||||
.long CRYPTO_IRQHandler /* 25 - CRYPTO */
|
||||
.long LETIMER0_IRQHandler /* 26 - LETIMER0 */
|
||||
.long Default_Handler /* 27 - Reserved */
|
||||
.long Default_Handler /* 28 - Reserved */
|
||||
.long RTCC_IRQHandler /* 29 - RTCC */
|
||||
.long Default_Handler /* 30 - Reserved */
|
||||
.long CRYOTIMER_IRQHandler /* 31 - CRYOTIMER */
|
||||
.long Default_Handler /* 32 - Reserved */
|
||||
.long FPUEH_IRQHandler /* 33 - FPUEH */
|
||||
|
||||
|
||||
.size __Vectors, . - __Vectors
|
||||
|
||||
.text
|
||||
.thumb
|
||||
.thumb_func
|
||||
.align 2
|
||||
.globl Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
#ifndef __NO_SYSTEM_INIT
|
||||
ldr r0, =SystemInit
|
||||
blx r0
|
||||
#endif
|
||||
|
||||
/* Firstly it copies data from read only memory to RAM. There are two schemes
|
||||
* to copy. One can copy more than one sections. Another can only copy
|
||||
* one section. The former scheme needs more instructions and read-only
|
||||
* data to implement than the latter.
|
||||
* Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */
|
||||
|
||||
#ifdef __STARTUP_COPY_MULTIPLE
|
||||
/* Multiple sections scheme.
|
||||
*
|
||||
* Between symbol address __copy_table_start__ and __copy_table_end__,
|
||||
* there are array of triplets, each of which specify:
|
||||
* offset 0: LMA of start of a section to copy from
|
||||
* offset 4: VMA of start of a section to copy to
|
||||
* offset 8: size of the section to copy. Must be multiply of 4
|
||||
*
|
||||
* All addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r4, =__copy_table_start__
|
||||
ldr r5, =__copy_table_end__
|
||||
|
||||
.L_loop0:
|
||||
cmp r4, r5
|
||||
bge .L_loop0_done
|
||||
ldr r1, [r4]
|
||||
ldr r2, [r4, #4]
|
||||
ldr r3, [r4, #8]
|
||||
|
||||
.L_loop0_0:
|
||||
subs r3, #4
|
||||
ittt ge
|
||||
ldrge r0, [r1, r3]
|
||||
strge r0, [r2, r3]
|
||||
bge .L_loop0_0
|
||||
|
||||
adds r4, #12
|
||||
b .L_loop0
|
||||
|
||||
.L_loop0_done:
|
||||
#else
|
||||
/* Single section scheme.
|
||||
*
|
||||
* The ranges of copy from/to are specified by following symbols
|
||||
* __etext: LMA of start of the section to copy from. Usually end of text
|
||||
* __data_start__: VMA of start of the section to copy to
|
||||
* __data_end__: VMA of end of the section to copy to
|
||||
*
|
||||
* All addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r1, =__etext
|
||||
ldr r2, =__data_start__
|
||||
ldr r3, =__data_end__
|
||||
|
||||
.L_loop1:
|
||||
cmp r2, r3
|
||||
ittt lt
|
||||
ldrlt r0, [r1], #4
|
||||
strlt r0, [r2], #4
|
||||
blt .L_loop1
|
||||
#endif /*__STARTUP_COPY_MULTIPLE */
|
||||
|
||||
/* This part of work usually is done in C library startup code. Otherwise,
|
||||
* define this macro to enable it in this startup.
|
||||
*
|
||||
* There are two schemes too. One can clear multiple BSS sections. Another
|
||||
* can only clear one section. The former is more size expensive than the
|
||||
* latter.
|
||||
*
|
||||
* Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former.
|
||||
* Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later.
|
||||
*/
|
||||
#ifdef __STARTUP_CLEAR_BSS_MULTIPLE
|
||||
/* Multiple sections scheme.
|
||||
*
|
||||
* Between symbol address __zero_table_start__ and __zero_table_end__,
|
||||
* there are array of tuples specifying:
|
||||
* offset 0: Start of a BSS section
|
||||
* offset 4: Size of this BSS section. Must be multiply of 4
|
||||
*/
|
||||
ldr r3, =__zero_table_start__
|
||||
ldr r4, =__zero_table_end__
|
||||
|
||||
.L_loop2:
|
||||
cmp r3, r4
|
||||
bge .L_loop2_done
|
||||
ldr r1, [r3]
|
||||
ldr r2, [r3, #4]
|
||||
movs r0, 0
|
||||
|
||||
.L_loop2_0:
|
||||
subs r2, #4
|
||||
itt ge
|
||||
strge r0, [r1, r2]
|
||||
bge .L_loop2_0
|
||||
adds r3, #8
|
||||
b .L_loop2
|
||||
.L_loop2_done:
|
||||
#elif defined (__STARTUP_CLEAR_BSS)
|
||||
/* Single BSS section scheme.
|
||||
*
|
||||
* The BSS section is specified by following symbols
|
||||
* __bss_start__: start of the BSS section.
|
||||
* __bss_end__: end of the BSS section.
|
||||
*
|
||||
* Both addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r1, =__bss_start__
|
||||
ldr r2, =__bss_end__
|
||||
|
||||
movs r0, 0
|
||||
.L_loop3:
|
||||
cmp r1, r2
|
||||
itt lt
|
||||
strlt r0, [r1], #4
|
||||
blt .L_loop3
|
||||
#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */
|
||||
|
||||
#ifndef __START
|
||||
#define __START _start
|
||||
#endif
|
||||
bl __START
|
||||
|
||||
.pool
|
||||
.size Reset_Handler, . - Reset_Handler
|
||||
|
||||
.align 1
|
||||
.thumb_func
|
||||
.weak Default_Handler
|
||||
.type Default_Handler, %function
|
||||
Default_Handler:
|
||||
b .
|
||||
.size Default_Handler, . - Default_Handler
|
||||
|
||||
/* Macro to define default handlers. Default handler
|
||||
* will be weak symbol and just dead loops. They can be
|
||||
* overwritten by other handlers */
|
||||
.macro def_irq_handler handler_name
|
||||
.weak \handler_name
|
||||
.set \handler_name, Default_Handler
|
||||
.endm
|
||||
|
||||
def_irq_handler NMI_Handler
|
||||
def_irq_handler HardFault_Handler
|
||||
def_irq_handler MemManage_Handler
|
||||
def_irq_handler BusFault_Handler
|
||||
def_irq_handler UsageFault_Handler
|
||||
def_irq_handler SVC_Handler
|
||||
def_irq_handler DebugMon_Handler
|
||||
def_irq_handler PendSV_Handler
|
||||
def_irq_handler SysTick_Handler
|
||||
|
||||
|
||||
def_irq_handler EMU_IRQHandler
|
||||
def_irq_handler WDOG0_IRQHandler
|
||||
def_irq_handler LDMA_IRQHandler
|
||||
def_irq_handler GPIO_EVEN_IRQHandler
|
||||
def_irq_handler TIMER0_IRQHandler
|
||||
def_irq_handler USART0_RX_IRQHandler
|
||||
def_irq_handler USART0_TX_IRQHandler
|
||||
def_irq_handler ACMP0_IRQHandler
|
||||
def_irq_handler ADC0_IRQHandler
|
||||
def_irq_handler IDAC0_IRQHandler
|
||||
def_irq_handler I2C0_IRQHandler
|
||||
def_irq_handler GPIO_ODD_IRQHandler
|
||||
def_irq_handler TIMER1_IRQHandler
|
||||
def_irq_handler USART1_RX_IRQHandler
|
||||
def_irq_handler USART1_TX_IRQHandler
|
||||
def_irq_handler LEUART0_IRQHandler
|
||||
def_irq_handler PCNT0_IRQHandler
|
||||
def_irq_handler CMU_IRQHandler
|
||||
def_irq_handler MSC_IRQHandler
|
||||
def_irq_handler CRYPTO_IRQHandler
|
||||
def_irq_handler LETIMER0_IRQHandler
|
||||
def_irq_handler RTCC_IRQHandler
|
||||
def_irq_handler CRYOTIMER_IRQHandler
|
||||
def_irq_handler FPUEH_IRQHandler
|
||||
|
||||
.end
|
@ -1,389 +0,0 @@
|
||||
/***************************************************************************//**
|
||||
* @file system_efm32pg1b.c
|
||||
* @brief CMSIS Cortex-M3/M4 System Layer for EFM32 devices.
|
||||
* @version 5.2.2
|
||||
******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2017 Silicon Laboratories, Inc. http://www.silabs.com</b>
|
||||
******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.@n
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.@n
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Laboratories, Inc.
|
||||
* has no obligation to support this Software. Silicon Laboratories, Inc. is
|
||||
* providing the Software "AS IS", with no express or implied warranties of any
|
||||
* kind, including, but not limited to, any implied warranties of
|
||||
* merchantability or fitness for any particular purpose or warranties against
|
||||
* infringement of any proprietary rights of a third party.
|
||||
*
|
||||
* Silicon Laboratories, Inc. will not be liable for any consequential,
|
||||
* incidental, or special damages, or any other relief, or for any claim by
|
||||
* any third party, arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "em_device.h"
|
||||
|
||||
/*******************************************************************************
|
||||
****************************** DEFINES ************************************
|
||||
******************************************************************************/
|
||||
|
||||
/** LFRCO frequency, tuned to below frequency during manufacturing. */
|
||||
#define EFM32_LFRCO_FREQ (32768UL)
|
||||
/** ULFRCO frequency */
|
||||
#define EFM32_ULFRCO_FREQ (1000UL)
|
||||
|
||||
/*******************************************************************************
|
||||
************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
/* System oscillator frequencies. These frequencies are normally constant */
|
||||
/* for a target, but they are made configurable in order to allow run-time */
|
||||
/* handling of different boards. The crystal oscillator clocks can be set */
|
||||
/* compile time to a non-default value by defining respective EFM_nFXO_FREQ */
|
||||
/* values according to board design. By defining the EFM_nFXO_FREQ to 0, */
|
||||
/* one indicates that the oscillator is not present, in order to save some */
|
||||
/* SW footprint. */
|
||||
|
||||
#ifndef EFM32_HFRCO_MAX_FREQ
|
||||
/** Maximum HFRCO frequency */
|
||||
#define EFM32_HFRCO_MAX_FREQ (38000000UL)
|
||||
#endif
|
||||
|
||||
#ifndef EFM32_HFXO_FREQ
|
||||
/** HFXO frequency */
|
||||
#define EFM32_HFXO_FREQ (40000000UL)
|
||||
#endif
|
||||
|
||||
#ifndef EFM32_HFRCO_STARTUP_FREQ
|
||||
/** HFRCO startup frequency */
|
||||
#define EFM32_HFRCO_STARTUP_FREQ (19000000UL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Do not define variable if HF crystal oscillator not present */
|
||||
#if (EFM32_HFXO_FREQ > 0UL)
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
/** System HFXO clock. */
|
||||
static uint32_t SystemHFXOClock = EFM32_HFXO_FREQ;
|
||||
/** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */
|
||||
#endif
|
||||
|
||||
#ifndef EFM32_LFXO_FREQ
|
||||
/** LFXO frequency */
|
||||
#define EFM32_LFXO_FREQ (EFM32_LFRCO_FREQ)
|
||||
#endif
|
||||
/* Do not define variable if LF crystal oscillator not present */
|
||||
#if (EFM32_LFXO_FREQ > 0UL)
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
/** System LFXO clock. */
|
||||
static uint32_t SystemLFXOClock = 32768UL;
|
||||
/** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL VARIABLES *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* System System Clock Frequency (Core Clock).
|
||||
*
|
||||
* @details
|
||||
* Required CMSIS global variable that must be kept up-to-date.
|
||||
*/
|
||||
uint32_t SystemCoreClock = EFM32_HFRCO_STARTUP_FREQ;
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* System HFRCO frequency
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary variable, not part of the CMSIS definition.
|
||||
*
|
||||
* @details
|
||||
* Frequency of the system HFRCO oscillator
|
||||
*/
|
||||
uint32_t SystemHfrcoFreq = EFM32_HFRCO_STARTUP_FREQ;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the current core clock frequency.
|
||||
*
|
||||
* @details
|
||||
* Calculate and get the current core clock frequency based on the current
|
||||
* configuration. Assuming that the SystemCoreClock global variable is
|
||||
* maintained, the core clock frequency is stored in that variable as well.
|
||||
* This function will however calculate the core clock based on actual HW
|
||||
* configuration. It will also update the SystemCoreClock global variable.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @return
|
||||
* The current core clock frequency in Hz.
|
||||
******************************************************************************/
|
||||
uint32_t SystemCoreClockGet(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint32_t presc;
|
||||
|
||||
ret = SystemHFClockGet();
|
||||
presc = (CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK) >>
|
||||
_CMU_HFCOREPRESC_PRESC_SHIFT;
|
||||
ret /= (presc + 1);
|
||||
|
||||
/* Keep CMSIS system clock variable up-to-date */
|
||||
SystemCoreClock = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the maximum core clock frequency.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @return
|
||||
* The maximum core clock frequency in Hz.
|
||||
******************************************************************************/
|
||||
uint32_t SystemMaxCoreClockGet(void)
|
||||
{
|
||||
return (EFM32_HFRCO_MAX_FREQ > EFM32_HFXO_FREQ ? \
|
||||
EFM32_HFRCO_MAX_FREQ : EFM32_HFXO_FREQ);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the current HFCLK frequency.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @return
|
||||
* The current HFCLK frequency in Hz.
|
||||
******************************************************************************/
|
||||
uint32_t SystemHFClockGet(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
switch (CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK)
|
||||
{
|
||||
case CMU_HFCLKSTATUS_SELECTED_LFXO:
|
||||
#if (EFM32_LFXO_FREQ > 0)
|
||||
ret = SystemLFXOClock;
|
||||
#else
|
||||
/* We should not get here, since core should not be clocked. May */
|
||||
/* be caused by a misconfiguration though. */
|
||||
ret = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case CMU_HFCLKSTATUS_SELECTED_LFRCO:
|
||||
ret = EFM32_LFRCO_FREQ;
|
||||
break;
|
||||
|
||||
case CMU_HFCLKSTATUS_SELECTED_HFXO:
|
||||
#if (EFM32_HFXO_FREQ > 0)
|
||||
ret = SystemHFXOClock;
|
||||
#else
|
||||
/* We should not get here, since core should not be clocked. May */
|
||||
/* be caused by a misconfiguration though. */
|
||||
ret = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
default: /* CMU_HFCLKSTATUS_SELECTED_HFRCO */
|
||||
ret = SystemHfrcoFreq;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret / (1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
|
||||
>> _CMU_HFPRESC_PRESC_SHIFT));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @brief
|
||||
* Get high frequency crystal oscillator clock frequency for target system.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @return
|
||||
* HFXO frequency in Hz.
|
||||
*****************************************************************************/
|
||||
uint32_t SystemHFXOClockGet(void)
|
||||
{
|
||||
/* External crystal oscillator present? */
|
||||
#if (EFM32_HFXO_FREQ > 0)
|
||||
return SystemHFXOClock;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @brief
|
||||
* Set high frequency crystal oscillator clock frequency for target system.
|
||||
*
|
||||
* @note
|
||||
* This function is mainly provided for being able to handle target systems
|
||||
* with different HF crystal oscillator frequencies run-time. If used, it
|
||||
* should probably only be used once during system startup.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @param[in] freq
|
||||
* HFXO frequency in Hz used for target.
|
||||
*****************************************************************************/
|
||||
void SystemHFXOClockSet(uint32_t freq)
|
||||
{
|
||||
/* External crystal oscillator present? */
|
||||
#if (EFM32_HFXO_FREQ > 0)
|
||||
SystemHFXOClock = freq;
|
||||
|
||||
/* Update core clock frequency if HFXO is used to clock core */
|
||||
if ((CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK) == CMU_HFCLKSTATUS_SELECTED_HFXO)
|
||||
{
|
||||
/* The function will update the global variable */
|
||||
SystemCoreClockGet();
|
||||
}
|
||||
#else
|
||||
(void)freq; /* Unused parameter */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @brief
|
||||
* Initialize the system.
|
||||
*
|
||||
* @details
|
||||
* Do required generic HW system init.
|
||||
*
|
||||
* @note
|
||||
* This function is invoked during system init, before the main() routine
|
||||
* and any data has been initialized. For this reason, it cannot do any
|
||||
* initialization of variables etc.
|
||||
*****************************************************************************/
|
||||
void SystemInit(void)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
/* Set floating point coprosessor access mode. */
|
||||
SCB->CPACR |= ((3UL << 10*2) | /* set CP10 Full Access */
|
||||
(3UL << 11*2) ); /* set CP11 Full Access */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @brief
|
||||
* Get low frequency RC oscillator clock frequency for target system.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @return
|
||||
* LFRCO frequency in Hz.
|
||||
*****************************************************************************/
|
||||
uint32_t SystemLFRCOClockGet(void)
|
||||
{
|
||||
/* Currently we assume that this frequency is properly tuned during */
|
||||
/* manufacturing and is not changed after reset. If future requirements */
|
||||
/* for re-tuning by user, we can add support for that. */
|
||||
return EFM32_LFRCO_FREQ;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @brief
|
||||
* Get ultra low frequency RC oscillator clock frequency for target system.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @return
|
||||
* ULFRCO frequency in Hz.
|
||||
*****************************************************************************/
|
||||
uint32_t SystemULFRCOClockGet(void)
|
||||
{
|
||||
/* The ULFRCO frequency is not tuned, and can be very inaccurate */
|
||||
return EFM32_ULFRCO_FREQ;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @brief
|
||||
* Get low frequency crystal oscillator clock frequency for target system.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @return
|
||||
* LFXO frequency in Hz.
|
||||
*****************************************************************************/
|
||||
uint32_t SystemLFXOClockGet(void)
|
||||
{
|
||||
/* External crystal oscillator present? */
|
||||
#if (EFM32_LFXO_FREQ > 0)
|
||||
return SystemLFXOClock;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @brief
|
||||
* Set low frequency crystal oscillator clock frequency for target system.
|
||||
*
|
||||
* @note
|
||||
* This function is mainly provided for being able to handle target systems
|
||||
* with different HF crystal oscillator frequencies run-time. If used, it
|
||||
* should probably only be used once during system startup.
|
||||
*
|
||||
* @note
|
||||
* This is an EFM32 proprietary function, not part of the CMSIS definition.
|
||||
*
|
||||
* @param[in] freq
|
||||
* LFXO frequency in Hz used for target.
|
||||
*****************************************************************************/
|
||||
void SystemLFXOClockSet(uint32_t freq)
|
||||
{
|
||||
/* External crystal oscillator present? */
|
||||
#if (EFM32_LFXO_FREQ > 0)
|
||||
SystemLFXOClock = freq;
|
||||
|
||||
/* Update core clock frequency if LFXO is used to clock core */
|
||||
if ((CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK) == CMU_HFCLKSTATUS_SELECTED_LFXO)
|
||||
{
|
||||
/* The function will update the global variable */
|
||||
SystemCoreClockGet();
|
||||
}
|
||||
#else
|
||||
(void)freq; /* Unused parameter */
|
||||
#endif
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
<?xml version="1.0" encoding="ASCII"?>
|
||||
<device:XMLDevice xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:device="http://www.silabs.com/ss/hwconfig/document/device.ecore" name="EFM32PG1B200F256GM48" partId="mcu.arm.efm32.pg1.efm32pg1b200f256gm48" contextId="%DEFAULT%">
|
||||
<mode name="DefaultMode">
|
||||
<property object="ADC0" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CMU" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CMU" propertyId="clocksettings.hfrcosettings.hfrcofrequency" value="38 MHz"/>
|
||||
<property object="CMU" propertyId="clocksettings.lfclocksettings.ulfrcorequired" value="Yes"/>
|
||||
<property object="CRYOTIMER" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CRYOTIMER" propertyId="cryotimer.clocking.clocksourceforcryotimer" value="ULFRCO"/>
|
||||
<property object="CRYOTIMER" propertyId="cryotimer.clocking.eventafterevery" value="1 cycle"/>
|
||||
<property object="CRYPTO" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="DefaultMode" propertyId="mode.diagramLocation" value="100, 100"/>
|
||||
<property object="EMU" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="GPIO" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="PA0" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PA1" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PA1" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PA1" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PA1" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PA1" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PA3" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PA4" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PA4" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PA4" propertyId="ports.settings.pinmode" value="Wired-and pullup filter"/>
|
||||
<property object="PA4" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PA4" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PA5" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PA5" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PA5" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PA5" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PA5" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PB13" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PB13" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PB13" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PB13" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PB13" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PC10" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PC10" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PC10" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PC10" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PC10" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PC6" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PC6" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PC6" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PC6" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PC6" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PC7" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PC7" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PC7" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PC7" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PC7" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PC8" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PC8" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PC8" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PC8" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PC8" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PC9" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PC9" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PC9" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PC9" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PC9" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD10" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD10" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD10" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD10" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD10" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD15" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD15" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD15" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD15" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD15" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PF2" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PF2" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PF2" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PF2" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PF2" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PF3" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PF3" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PF3" propertyId="ports.settings.pinmode" value="Wired-and pullup filter"/>
|
||||
<property object="PF3" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PF3" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PF4" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PF5" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PF6" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PF6" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PF6" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PF6" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PF6" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.i2c0.location.i2c0_sclloc" value="3"/>
|
||||
<property object="PORTIO" propertyId="portio.i2c0.location.i2c0_sdaloc" value="27"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.cts" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.rts" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.rx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.tx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.location.usart0_ctsloc" value="30"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.location.usart0_rtsloc" value="30"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.enable.clk" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.enable.rx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.enable.tx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.location.usart1_clkloc" value="11"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.location.usart1_rxloc" value="11"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.location.usart1_txloc" value="11"/>
|
||||
<property object="TIMER0" propertyId="timer.clocksettings.clockselection" value="TIM0_CC1 input"/>
|
||||
<property object="USART0" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="USART0" propertyId="usart.outputsettings.clockselect" value="Disabled"/>
|
||||
<property object="USART1" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="USART1" propertyId="usart.mode.usartmode" value="Synchronous Mode (SPI / I2S)"/>
|
||||
<property object="USART1" propertyId="usart.outputsettings.clockselect" value="Disabled"/>
|
||||
<property object="USART1" propertyId="usart.synchronoussettings.baudrate" value="130000"/>
|
||||
<property object="USART1" propertyId="usart.synchronoussettings.clockpolarityphasemode" value="Clock idle low, sample on falling edge"/>
|
||||
</mode>
|
||||
<modeTransition>
|
||||
<property object="RESET → DefaultMode" propertyId="modeTransition.source" value="RESET"/>
|
||||
<property object="RESET → DefaultMode" propertyId="modeTransition.target" value="DefaultMode"/>
|
||||
</modeTransition>
|
||||
</device:XMLDevice>
|
@ -1,107 +0,0 @@
|
||||
<?xml version="1.0" encoding="ASCII"?>
|
||||
<device:XMLDevice xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:device="http://www.silabs.com/ss/hwconfig/document/device.ecore" name="EFM32JG1B200F128GM32" partId="mcu.arm.efm32.jg1.efm32jg1b200f128gm32" contextId="%DEFAULT%">
|
||||
<mode name="DefaultMode">
|
||||
<property object="ADC0" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CMU" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CMU" propertyId="clocksettings.hfrcosettings.hfrcofrequency" value="38 MHz"/>
|
||||
<property object="CMU" propertyId="clocksettings.lfclocksettings.ulfrcorequired" value="Yes"/>
|
||||
<property object="CRYOTIMER" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="CRYOTIMER" propertyId="cryotimer.clocking.clocksourceforcryotimer" value="ULFRCO"/>
|
||||
<property object="CRYOTIMER" propertyId="cryotimer.clocking.eventafterevery" value="1 cycle"/>
|
||||
<property object="CRYPTO" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="DefaultMode" propertyId="mode.diagramLocation" value="100, 100"/>
|
||||
<property object="EMU" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="EMU" propertyId="emu.powerconfiguration.externalpowercircuitwiring" value="Not wired for DCDC"/>
|
||||
<property object="GPIO" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="PA0" propertyId="ports.settings.pinmode" value="Input"/>
|
||||
<property object="PA1" propertyId="ports.settings.pinmode" value="Input"/>
|
||||
<property object="PB11" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PB11" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PB11" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PB11" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PB11" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PB12" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PB12" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PB12" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PB12" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PB12" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PB13" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PB13" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PB13" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PB13" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PB13" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PB15" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PB15" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PB15" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PB15" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PB15" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD10" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD10" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD10" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD10" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD10" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD11" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD11" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD11" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PD11" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD11" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD12" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD12" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD12" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD12" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD12" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD13" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD13" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD13" propertyId="ports.settings.pinmode" value="Input pull"/>
|
||||
<property object="PD13" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD13" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD14" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD14" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD14" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD14" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD14" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD15" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD15" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD15" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD15" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD15" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PD9" propertyId="ports.settings.dout" value="1"/>
|
||||
<property object="PD9" propertyId="ports.settings.filter" value="Enabled"/>
|
||||
<property object="PD9" propertyId="ports.settings.pinmode" value="Push-pull"/>
|
||||
<property object="PD9" propertyId="ports.settings.pulldirection" value="Pullup"/>
|
||||
<property object="PD9" propertyId="ports.settings.pullup" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.timer0.enable.cc0" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.timer0.enable.cc1" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.timer0.enable.cc2" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.timer0.location.timer0_cc0loc" value="18"/>
|
||||
<property object="PORTIO" propertyId="portio.timer0.location.timer0_cc1loc" value="16"/>
|
||||
<property object="PORTIO" propertyId="portio.timer0.location.timer0_cc2loc" value="20"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.rx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.enable.tx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart0.location.usart0_txloc" value="20"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.enable.clk" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.enable.rx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.enable.tx" value="Enabled"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.location.usart1_rxloc" value="6"/>
|
||||
<property object="PORTIO" propertyId="portio.usart1.location.usart1_txloc" value="8"/>
|
||||
<property object="TIMER0" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="TIMER0" propertyId="timer.capturecomparech0.ccmode" value="PWM"/>
|
||||
<property object="TIMER0" propertyId="timer.capturecomparech0.countermatchoutputaction" value="Toggle on event"/>
|
||||
<property object="TIMER0" propertyId="timer.capturecomparech1.ccmode" value="PWM"/>
|
||||
<property object="TIMER0" propertyId="timer.capturecomparech1.countermatchoutputaction" value="Toggle on event"/>
|
||||
<property object="TIMER0" propertyId="timer.capturecomparech2.ccmode" value="PWM"/>
|
||||
<property object="TIMER0" propertyId="timer.capturecomparech2.countermatchoutputaction" value="Toggle on event"/>
|
||||
<property object="TIMER0" propertyId="timer.clocksettings.hfperprescaler" value="Divide by 512"/>
|
||||
<property object="USART0" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="USART0" propertyId="usart.outputsettings.clockselect" value="Disabled"/>
|
||||
<property object="USART1" propertyId="ABPeripheral.included" value="true"/>
|
||||
<property object="USART1" propertyId="usart.asynchronoussettings.baudrate" value="130000"/>
|
||||
<property object="USART1" propertyId="usart.mode.usartmode" value="Synchronous Mode (SPI / I2S)"/>
|
||||
<property object="USART1" propertyId="usart.outputsettings.clockselect" value="Disabled"/>
|
||||
<property object="USART1" propertyId="usart.synchronoussettings.baudrate" value="130000"/>
|
||||
</mode>
|
||||
<modeTransition>
|
||||
<property object="RESET → DefaultMode" propertyId="modeTransition.source" value="RESET"/>
|
||||
<property object="RESET → DefaultMode" propertyId="modeTransition.target" value="DefaultMode"/>
|
||||
</modeTransition>
|
||||
</device:XMLDevice>
|
@ -1,23 +0,0 @@
|
||||
|
||||
CC=arm-none-eabi-gcc
|
||||
|
||||
all:
|
||||
cd 'GNU ARM v7.2.1 - Debug' && make all
|
||||
|
||||
|
||||
#arm-none-eabi-gcc -g -gdwarf-2 -mcpu=cortex-m4 -mthumb -std=c99 '-DDEBUG=1' '-DEFM32PG1B200F256GM48=1' -IC:/Users/conor/Desktop/u2f-one/crypto/sha256 -IC:/Users/conor/Desktop/u2f-one/crypto/micro-ecc -IC:/Users/conor/Desktop/u2f-one/crypto/tiny-AES-c -I"C:\Users\conor\Desktop\u2f-one\efm32\inc" -IC:/Users/conor/Desktop/u2f-one/fido2 -IC:/Users/conor/Desktop/u2f-one/tinycbor/src -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//platform/CMSIS/Include" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//hardware/kit/common/drivers" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//hardware/kit/SLSTK3401A_EFM32PG/config" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//platform/Device/SiliconLabs/EFM32PG1B/Include" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//platform/emlib/inc" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//hardware/kit/common/bsp" -O0 -Wall -c -fmessage-length=0 -mno-sched-prolog -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -MMD -MP -MF"src/device.d" -MT"src/device.o" -o "src/device.o" "../src/device.c"
|
||||
|
||||
|
||||
#arm-none-eabi-gcc -g -gdwarf-2 -mcpu=cortex-m4 -mthumb -T "EFM32.ld" -Xlinker --gc-sections -Xlinker -Map="EFM32.map" -mfpu=fpv4-sp-d16 -mfloat-abi=softfp --specs=nano.specs -o EFM32.axf "./CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.o" "./CMSIS/EFM32PG1B/system_efm32pg1b.o" "./crypto/micro-ecc/uECC.o" "./crypto/sha256/sha256.o" "./crypto/tiny-AES-c/aes.o" "./emlib/em_assert.o" "./emlib/em_cmu.o" "./emlib/em_emu.o" "./emlib/em_gpio.o" "./emlib/em_system.o" "./emlib/em_usart.o" "./fido2/crypto.o" "./fido2/ctap.o" "./fido2/ctap_parse.o" "./fido2/ctaphid.o" "./fido2/log.o" "./fido2/main.o" "./fido2/stubs.o" "./fido2/test_power.o" "./fido2/u2f.o" "./fido2/util.o" "./src/InitDevice.o" "./src/device.o" "./src/main.o" "./src/printing.o" "./src/retargetio.o" -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group
|
||||
|
||||
|
||||
cbor:
|
||||
cd ../tinycbor/ && make clean
|
||||
cd ../tinycbor/ && make CC="$(CC)" \
|
||||
LDFLAGS="-lgcc -lc -lnosys --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -mthumb " \
|
||||
CFLAGS="-g -gdwarf-2 -mcpu=cortex-m4 -mthumb -std=c99 -DEFM32PG1B200F256GM48=1 -O3 -Wall -c -fmessage-length=0 -mno-sched-prolog -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -MMD -MP "
|
||||
|
||||
|
||||
|
||||
clean:
|
||||
cd 'GNU ARM v7.2.1 - Debug' && make clean
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user