mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
481 Commits
DROPBEAR_2
...
coverity
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ea2e3463d | ||
|
|
ddb6751ab4 | ||
|
|
3727b099c5 | ||
|
|
45294b458a | ||
|
|
d51e4a75cd | ||
|
|
e9f2815144 | ||
|
|
2771fab0fa | ||
|
|
a7a67585cb | ||
|
|
366f01252e | ||
|
|
1490c0c3a6 | ||
|
|
3f5c106a88 | ||
|
|
10e119f638 | ||
|
|
5b68d117c2 | ||
|
|
58106b1615 | ||
|
|
1e10af850b | ||
|
|
ee4b4db816 | ||
|
|
ab9cfce00d | ||
|
|
2b8106b14e | ||
|
|
78c5daee52 | ||
|
|
2301b6ac0b | ||
|
|
a27e8b053e | ||
|
|
6145289e0d | ||
|
|
d14ebdbf0e | ||
|
|
4b305c5721 | ||
|
|
615885be01 | ||
|
|
6b823d617c | ||
|
|
ec993dbdbc | ||
|
|
ad1e9b7e3c | ||
|
|
846b8cdbf7 | ||
|
|
b0243b0e7b | ||
|
|
4faf06aae7 | ||
|
|
07d46f9907 | ||
|
|
413eaf1ba1 | ||
|
|
3b359050b4 | ||
|
|
a015cc7594 | ||
|
|
dc12be0cfe | ||
|
|
89e98a2f83 | ||
|
|
5027bc4db1 | ||
|
|
630f6aa6b9 | ||
|
|
8048473eb9 | ||
|
|
4216c984ae | ||
|
|
6abf756e51 | ||
|
|
b4bd23b4d2 | ||
|
|
724e61f8ae | ||
|
|
49667a82de | ||
|
|
a57114e7fa | ||
|
|
cfe90bc6bd | ||
|
|
0aefec6c89 | ||
|
|
6a3bc73a78 | ||
|
|
73aa4f0de9 | ||
|
|
9e25854b41 | ||
|
|
d277f140ba | ||
|
|
61267f8503 | ||
|
|
d3d0d60076 | ||
|
|
91e537e427 | ||
|
|
fb9a78c3ee | ||
|
|
8f8a3dff70 | ||
|
|
c917807b1c | ||
|
|
701d43b859 | ||
|
|
79bedc90a1 | ||
|
|
545cc62671 | ||
|
|
331d4a714f | ||
|
|
2a81289ed3 | ||
|
|
5acee497bf | ||
|
|
972d723484 | ||
|
|
7dc2f36c3e | ||
|
|
90cfbe1f7a | ||
|
|
b681570899 | ||
|
|
201e359363 | ||
|
|
fa4c4646d8 | ||
|
|
6f6aa9db5a | ||
|
|
e35d0784a8 | ||
|
|
cc6fa57a41 | ||
|
|
a26ad21c0a | ||
|
|
002b79e2f9 | ||
|
|
3d12521735 | ||
|
|
b2007beeb0 | ||
|
|
8f123fb618 | ||
|
|
c71258625d | ||
|
|
615ed4e46a | ||
|
|
fa116e983b | ||
|
|
8c6aaf8d36 | ||
|
|
cae6e6af10 | ||
|
|
f89c5b0390 | ||
|
|
4318631dd6 | ||
|
|
7bc6280613 | ||
|
|
e9231f73c2 | ||
|
|
4fd40e61f7 | ||
|
|
71f818262c | ||
|
|
07f790db5a | ||
|
|
78a3388b98 | ||
|
|
6e3c3c8c51 | ||
|
|
6fecc91d10 | ||
|
|
ef080502f8 | ||
|
|
8b4f60a7a1 | ||
|
|
01cd1bd11f | ||
|
|
f6df3e1fec | ||
|
|
553087b7a6 | ||
|
|
16fb0b0d53 | ||
|
|
493ab8fd81 | ||
|
|
0afcfafbb9 | ||
|
|
0af22aa8e4 | ||
|
|
2fd3b9f560 | ||
|
|
2de3bc9353 | ||
|
|
28b6111db0 | ||
|
|
a0aa274981 | ||
|
|
b016ebedfd | ||
|
|
cb945f9f67 | ||
|
|
df0f1297eb | ||
|
|
fe992bf4ea | ||
|
|
ffde4a524f | ||
|
|
7e03e4d443 | ||
|
|
02ffdd09dc | ||
|
|
6f6ef4834c | ||
|
|
d2e71ade72 | ||
|
|
892c5fc1c8 | ||
|
|
e7504b3311 | ||
|
|
ad3eacf3d6 | ||
|
|
52adbb34c3 | ||
|
|
90f04384ee | ||
|
|
195934be96 | ||
|
|
fdbdbe5703 | ||
|
|
d740dc5489 | ||
|
|
76933e6c0a | ||
|
|
38c9408cf8 | ||
|
|
397af3e6a6 | ||
|
|
933bc5f8a7 | ||
|
|
ba94bcd2e8 | ||
|
|
56855744b8 | ||
|
|
b4b11c8155 | ||
|
|
f82933108d | ||
|
|
27828c742c | ||
|
|
ed4c38ba46 | ||
|
|
e9edbe8bb2 | ||
|
|
4fd3160179 | ||
|
|
a60725740b | ||
|
|
5d065258da | ||
|
|
149b21d7cf | ||
|
|
145fb96989 | ||
|
|
084ff9b4c8 | ||
|
|
6b05aa4275 | ||
|
|
366fc8f335 | ||
|
|
35f479bd87 | ||
|
|
9d11cad5dc | ||
|
|
0233dcebb4 | ||
|
|
f7dedab4a7 | ||
|
|
129c440362 | ||
|
|
abee8093b3 | ||
|
|
2583b180c9 | ||
|
|
1e1e477d85 | ||
|
|
85eda7d943 | ||
|
|
4b36e24735 | ||
|
|
921592d37e | ||
|
|
a5eac0a065 | ||
|
|
7f15910541 | ||
|
|
625b38d7af | ||
|
|
b9edf939f4 | ||
|
|
257bba00ac | ||
|
|
8d0b48f165 | ||
|
|
ce1f9cdf7c | ||
|
|
e612aec5d9 | ||
|
|
5bd0c0d25a | ||
|
|
26ad6853d2 | ||
|
|
8a4f7fe4f8 | ||
|
|
294e98c397 | ||
|
|
c1a2dcb25d | ||
|
|
a0972e0ac6 | ||
|
|
8062a4e8d6 | ||
|
|
a0ab5e86b5 | ||
|
|
a1dcaf82a0 | ||
|
|
78e17f6ee9 | ||
|
|
5ebc48b3f2 | ||
|
|
1ae4237920 | ||
|
|
5ca12d8332 | ||
|
|
7f8702d3d6 | ||
|
|
5f2447edbb | ||
|
|
c658b275fd | ||
|
|
9bbce01e1b | ||
|
|
bbe02dc3cf | ||
|
|
3d76aecaa6 | ||
|
|
64bd345a5d | ||
|
|
152c507499 | ||
|
|
e2ae628b17 | ||
|
|
6eabc0fe87 | ||
|
|
bf6f04cbe6 | ||
|
|
e0c86670e2 | ||
|
|
7840691420 | ||
|
|
96e1a7e6da | ||
|
|
5df73215f8 | ||
|
|
04a02730bc | ||
|
|
3996e93a20 | ||
|
|
246f24eda8 | ||
|
|
4aa72b96c1 | ||
|
|
0fc20c70af | ||
|
|
ebc915baae | ||
|
|
7435369615 | ||
|
|
2e836bb553 | ||
|
|
36ccfd21e7 | ||
|
|
44c323872a | ||
|
|
094972ea84 | ||
|
|
2707f054a5 | ||
|
|
4c95d595c0 | ||
|
|
573838a027 | ||
|
|
05f4e29a52 | ||
|
|
dbc0520992 | ||
|
|
7efe873d73 | ||
|
|
4058574cfa | ||
|
|
d17dedfa4f | ||
|
|
dcce2cfd8d | ||
|
|
4768351e89 | ||
|
|
3f3f399231 | ||
|
|
316c923188 | ||
|
|
8fdaf0268d | ||
|
|
f2d86ae7d3 | ||
|
|
34ee326075 | ||
|
|
1656db9e58 | ||
|
|
802dace05e | ||
|
|
c2f2f2b817 | ||
|
|
dcb41e91eb | ||
|
|
67111efdad | ||
|
|
5fd677af76 | ||
|
|
b080f5a047 | ||
|
|
7e8094d53a | ||
|
|
c8d852caf6 | ||
|
|
00a1290173 | ||
|
|
f042eb41ab | ||
|
|
017e2f07a7 | ||
|
|
3a923b72a4 | ||
|
|
5bf1214859 | ||
|
|
2ef1ab0753 | ||
|
|
c218af6ea7 | ||
|
|
e0748b1970 | ||
|
|
3ee685ad1c | ||
|
|
17be46e229 | ||
|
|
370d4c7cd5 | ||
|
|
1700987bfc | ||
|
|
a1aa161527 | ||
|
|
9a7972dcb8 | ||
|
|
191f22e11a | ||
|
|
93632660bb | ||
|
|
84d415fb66 | ||
|
|
ad9db51434 | ||
|
|
1a37d7aa48 | ||
|
|
22eb197d6c | ||
|
|
3953018c2d | ||
|
|
cfe99a79bd | ||
|
|
a3a0b26581 | ||
|
|
276197b404 | ||
|
|
ee812daf69 | ||
|
|
df66daa26a | ||
|
|
484d1e9b81 | ||
|
|
8013009880 | ||
|
|
95b99cc86a | ||
|
|
6a713ad834 | ||
|
|
278a3e43e5 | ||
|
|
c81e530d3c | ||
|
|
2df2117388 | ||
|
|
4b021ae6f0 | ||
|
|
a36f182b36 | ||
|
|
d8bb6a7816 | ||
|
|
57d474e183 | ||
|
|
d7e12aadbe | ||
|
|
c0df3902b7 | ||
|
|
4f2eb1914b | ||
|
|
d72f50ff32 | ||
|
|
debb208553 | ||
|
|
f581ef9453 | ||
|
|
b65354d237 | ||
|
|
e4ac7ea1ca | ||
|
|
9c7ecf6d14 | ||
|
|
917722257d | ||
|
|
3d61b6eab6 | ||
|
|
e64e25e4d6 | ||
|
|
f7a664f127 | ||
|
|
89bdf3b0b9 | ||
|
|
597f7eb5e9 | ||
|
|
ba23b823dc | ||
|
|
fa3b0dd3ca | ||
|
|
dd8988220e | ||
|
|
cc803ee802 | ||
|
|
598056d168 | ||
|
|
89e64c631e | ||
|
|
5cd003d9e6 | ||
|
|
468656b4aa | ||
|
|
22037d5fba | ||
|
|
4b7105dfea | ||
|
|
a5ec3aca7d | ||
|
|
785459d31b | ||
|
|
a9a3746d09 | ||
|
|
74ace058a6 | ||
|
|
96382d52ab | ||
|
|
ddbc8113a9 | ||
|
|
65115b9159 | ||
|
|
e255101299 | ||
|
|
187fc95deb | ||
|
|
a94338dc67 | ||
|
|
6ac5ea2a9f | ||
|
|
364fb6019c | ||
|
|
a79b61517b | ||
|
|
99361f54ca | ||
|
|
82c06dd76b | ||
|
|
17a9b8802f | ||
|
|
9b6f7fc9af | ||
|
|
57690891ce | ||
|
|
5896a4941d | ||
|
|
5ac4a71000 | ||
|
|
521e63529c | ||
|
|
24b446705b | ||
|
|
3c5ed47804 | ||
|
|
b967dc1fa5 | ||
|
|
af2caaab72 | ||
|
|
2cbe70ba34 | ||
|
|
8e1ea0f27b | ||
|
|
e3246ceb7e | ||
|
|
169f41a43c | ||
|
|
88ce30beb6 | ||
|
|
d260d5148e | ||
|
|
723ec19eed | ||
|
|
44f36d57e6 | ||
|
|
7ab8f61974 | ||
|
|
4bba3268d5 | ||
|
|
5f76e4c1ed | ||
|
|
b75a033787 | ||
|
|
92c4f20089 | ||
|
|
acfd372808 | ||
|
|
6054483dc7 | ||
|
|
25931bc1e6 | ||
|
|
9250c58013 | ||
|
|
4f226ab36a | ||
|
|
33e28fb96b | ||
|
|
206b9cea0d | ||
|
|
9dcb04a1e0 | ||
|
|
08543d0c76 | ||
|
|
937e6cb91e | ||
|
|
6c43be767c | ||
|
|
81b64ea0b5 | ||
|
|
ea0e23c172 | ||
|
|
4d07aa315b | ||
|
|
2e298b25e4 | ||
|
|
c38927da47 | ||
|
|
25607c04a7 | ||
|
|
cbd5be1b82 | ||
|
|
924b8469cb | ||
|
|
f24d93d4e4 | ||
|
|
65baa71b58 | ||
|
|
b8fa712847 | ||
|
|
095b067857 | ||
|
|
87c4586d61 | ||
|
|
b17254925d | ||
|
|
cf2c4f44a2 | ||
|
|
2bc55ff428 | ||
|
|
ee5769f31f | ||
|
|
3a8517b06f | ||
|
|
0363d3c32e | ||
|
|
a582c4cdb6 | ||
|
|
a43b6b0323 | ||
|
|
84a143a605 | ||
|
|
114438e669 | ||
|
|
50bde9976b | ||
|
|
18ea116827 | ||
|
|
0ab0687a3a | ||
|
|
72f85ad90f | ||
|
|
fb4e07f7a8 | ||
|
|
6e0b539e9c | ||
|
|
83b2c899f5 | ||
|
|
eb7ca20379 | ||
|
|
30d3ccd419 | ||
|
|
fb8fb7fed0 | ||
|
|
1abd239b9d | ||
|
|
9f1c8b2f8f | ||
|
|
c169423051 | ||
|
|
fdc6f32392 | ||
|
|
ea984cfb95 | ||
|
|
e7cdb2ebe5 | ||
|
|
4dae8edb76 | ||
|
|
a3e01b8884 | ||
|
|
6d33a2b0bb | ||
|
|
423be0d5e6 | ||
|
|
f7d38a1b9c | ||
|
|
45b27b0194 | ||
|
|
2a921c2c25 | ||
|
|
4c759cde1f | ||
|
|
c3984c89f7 | ||
|
|
96dfbc882d | ||
|
|
d3883e54b8 | ||
|
|
beaff53a79 | ||
|
|
b9b308f2fe | ||
|
|
a7bfd792f7 | ||
|
|
06fd9e3771 | ||
|
|
fb719e3d0b | ||
|
|
9f24cdf74c | ||
|
|
d7471c4f87 | ||
|
|
5d2cb48f46 | ||
|
|
597f12c44a | ||
|
|
9f674382d5 | ||
|
|
6830a65923 | ||
|
|
0d9c3fe70b | ||
|
|
2e38ac7504 | ||
|
|
f208d7920c | ||
|
|
ecb4a6173d | ||
|
|
37a66fa5b6 | ||
|
|
f9e6bc2aec | ||
|
|
81a0240491 | ||
|
|
b4d31b492c | ||
|
|
32df924d02 | ||
|
|
c60a65bc93 | ||
|
|
68b3ef0734 | ||
|
|
4222251d6f | ||
|
|
c6e912f9e2 | ||
|
|
1df5c97144 | ||
|
|
b840a0f500 | ||
|
|
9f40bbba29 | ||
|
|
0086e1d7ca | ||
|
|
4732de71c6 | ||
|
|
8db9415f2a | ||
|
|
dd19d73db4 | ||
|
|
91450c7a95 | ||
|
|
1d20df627d | ||
|
|
4a10b1961c | ||
|
|
100cbc5f3f | ||
|
|
e0c6e819c2 | ||
|
|
9025cd9b72 | ||
|
|
2b891f5eb3 | ||
|
|
01bde8ff94 | ||
|
|
eed0e2e431 | ||
|
|
bda3bc4c8d | ||
|
|
93f3c31807 | ||
|
|
3aeb557196 | ||
|
|
8c7ebc02a0 | ||
|
|
1152e47b52 | ||
|
|
32a28d0d9c | ||
|
|
d6daad29fc | ||
|
|
4664ce2c35 | ||
|
|
171456c683 | ||
|
|
2c73fd6fbf | ||
|
|
0ee860a011 | ||
|
|
5127943673 | ||
|
|
3ee9656250 | ||
|
|
c0f63ee100 | ||
|
|
8fd720c3e3 | ||
|
|
4f5d0756c2 | ||
|
|
64e6e3aca9 | ||
|
|
8174300429 | ||
|
|
a453b06168 | ||
|
|
103036c546 | ||
|
|
ac9a4c839f | ||
|
|
3d2ddd15f8 | ||
|
|
ea4ab22017 | ||
|
|
d58e0497cc | ||
|
|
af10eb8346 | ||
|
|
8e93ac9925 | ||
|
|
6d5b27715a | ||
|
|
f295fbe0b2 | ||
|
|
575f0e5f92 | ||
|
|
85374c5ba2 | ||
|
|
83f3f55280 | ||
|
|
b2beb2c2da | ||
|
|
48ad370a19 | ||
|
|
c36f94a322 | ||
|
|
6493bbb7e7 | ||
|
|
3ec2737d54 | ||
|
|
72ccfda5b2 | ||
|
|
003ec5d356 | ||
|
|
f91d66448a | ||
|
|
ccfdf7e039 | ||
|
|
95ce05da40 | ||
|
|
c5d53cf81c | ||
|
|
5574460d25 | ||
|
|
233fd96994 | ||
|
|
d1b29336b1 | ||
|
|
fa5eb62464 | ||
|
|
0b48a4f879 | ||
|
|
00ef081fcf | ||
|
|
dabeaec461 | ||
|
|
d4ed2fffe4 | ||
|
|
0533b87b1a | ||
|
|
7504cd1a1a | ||
|
|
482dc0eff4 | ||
|
|
fc34d02427 | ||
|
|
5ce5fbcba0 | ||
|
|
31d2311537 |
27
.gitignore
vendored
Normal file
27
.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
*~
|
||||
*.o
|
||||
*.a
|
||||
*.da
|
||||
*.bb
|
||||
*.bbg
|
||||
*.prof
|
||||
.*.swp
|
||||
/autom4te.cache
|
||||
/config.log
|
||||
/config.status
|
||||
/dbclient
|
||||
/dropbear
|
||||
/dropbearconvert
|
||||
/dropbearkey
|
||||
/dropbearmulti
|
||||
/fuzzcorpus
|
||||
/fuzzer-*
|
||||
/fuzzer-*.options
|
||||
/scp
|
||||
/scp-progress
|
||||
Makefile
|
||||
config.h
|
||||
config.h.in
|
||||
configure
|
||||
default_options_guard.h
|
||||
tags
|
||||
7
.hgsigs
7
.hgsigs
@@ -20,3 +20,10 @@ af074dbcb68ff8670b3818e0d66d5dc6f1bd5877 0 iQIcBAABCgAGBQJWVdQfAAoJEPSYMBLCC7qs+
|
||||
5bb5976e6902a0c9fba974a880c68c9487ee1e77 0 iQIcBAABCgAGBQJWVyIKAAoJEESTFJTynGdzQosP/0k5bVTerpUKZLjyNuMU8o0eyc7njkX8EyMOyGbtcArKpzO2opSBTRsuCT9Zsk1iiQ1GMTY1quKD7aNr86Hipqo4th/+ZXmLe9mmaCDukKjD0ZYC4dBVUy6RSUAMvdkDP9sZs7CMTO/22a9SqOsKTv3s2NN6XnsBGnmNbvVx5hkAk5hMVNFrjKIaexzI/7bWQIDRo2HQCaWaL06JvWEDSEQd2mynGSXxT/+m4hBnuGg6qxn2pd4XfG0g10tDAFx64HQkWgZqSB+F8z71Cvfjondy1zjJYgtABqNlwCKQJZhRUW2+PblqQnz08TUy83XN2vtisOju4avGcHSaBgBbMvg8Wx4ZtM7sPP9pLrhhOTd5ceERHeTceTJy+iI1SQFvccjrRfs5aJ0zAQX5q6f4bV0zp5SmxkvnZUEkZIoetkM8VrPOYugqx31LtHAWfVT9NM+VkV/rrxLhk6J0giIQvC9MPWxRDileFVDszPiOgTLcxWjOziOLT+xijcj7dtx1b/f2bNCduN5G7i+icjjTlCNtyRPRqhBqn705W7F+xESP2gsscM/1BjQ7TGidU5m1njdkUjbrqm3+Qic6iqkG7SfETHmQB9mHqpJ0hACRPvZlhwB7oimNHllkrlw8UJw9f0SiuLjfERIgVS2EOp+mAia0RU7MlTt19o017M1ffEYL
|
||||
926e7275cef4f4f2a4251597ee4814748394824c 0 iQIcBAABCgAGBQJWYES4AAoJEESTFJTynGdzdT0P/0O/1frevtr698DwMe6kmJx35P6Bqq8szntMxYucv0HROTfr85JRcCCSvl/2SflDS215QmOxdvYLGLUWPJNz/gURCLpzsT88KLF68Y1tC72nl4Fj+LGIOlsWsvwEqQqw0v4iQkHIfcxI6q7g1r9Hfldf/ju4bzQ4HnKLxm6KNcLLoAsuehVpQ+njHpLmlLAGHU5a84B7xeXHFR+U/EBPxSdm637rNhmpLpkuK2Mym/Mzv7BThKDstpB8lhFHIwAVNqi3Cy4nGYxFZOJpooUN9pDornqAwuzHmOAMs9+49L8GZ1de5PBRGyFKibzjBIUWPEU9EIkfJVaVwTlqYK8Q/IRi9HjITPx6GpE8cZhdSvAibrQdb6BbIDrZ8eCvD9vnod6Uk0Jb9/ui6nCF9x+CN/3Qez4epV5+JCMYsqCiXFkVPm9Lab6L2eGZis7Q2TXImA/sSV+E4BGfH2urpkKlnuXTTtDp4XRG+lOISkIBXgjVY+uy8soVKNdx1gv+LeY8hu/oQ2NyOlaOeL47aSQ3who4Pk6pVRUOl6zfcKo9Vs6xDWm35A3Z6x/mrAENaXasB0JrfY5nIbefJUpbeSmi76fYldU98HdQNHPHCSeiKVYl7v/B6gi2JXp5xngLZz/5VVAurago7sRmpIp7G/AqU6LNE85IUzG8aQz8AfR0d1dW
|
||||
fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzuOcP/j6tvB2WRwSj39KoJuRcRebFWWv4ZHiQXYMXWa3X0Ppzz52r9W0cXDjjlp5FyGdovCQsK+IXmjPo5cCvWBrZJYA6usFr9ssnUtTC+45lvPxPYwj47ZGPngCXDt7LD+v08XhqCu4LsctXIP/zejd30KVS1eR2RHI+tnEyaIKC0Xaa0igcv74MZX7Q8/U+B730QMX5adfYAHoeyRhoctRWaxVV3To7Vadd9jNXP45MRY5auhRcK7XyQcS85vJeCRoysfDUas4ERRQWYkX+68GyzO9GrkYFle931Akw2K6ZZfUuiC2TrF5xv1eRP1Zm2GX481U4ZGFTI8IzZL8sVQ6tvzq2Mxsecu589JNui9aB2d8Gp2Su/E2zn0h0ShIRmviGzf2HiBt+Bnji5X2h/fJKWbLaWge0MdOU5Jidfyh9k0YT7xo4piJLJYSaZ3nv+j4jTYnTfL7uYvuWbYkJ1T32aQVCan7Eup3BFAgQjzbWYi1XQVg6fvu8uHPpS3tNNA9EAMeeyTyg1l6zI2EIU5gPfd/dKmdyotY2lZBkFZNJqFkKRZuzjWekcw7hAxS+Bd68GKklt/DGrQiVycAgimqwXrfkzzQagawq2fXL2uXB8ghlsyxKLSQPnAtBF2Jcn5FH2z7HOQ+e18ZrFfNy0cYa/4OdH6K5aK1igTzhZZP2Urn0
|
||||
70705edee9dd29cd3d410f19fbd15cc3489313e2 0 iQIcBAABCgAGBQJW7CQRAAoJEESTFJTynGdzTj0QAJL38CKSZthBAeI9c6B+IlwIeT6kPZaPqk1pkycCTWOe87NiNU9abrsF+JrjTuRQiO1EpM2IvfQEIXTijUcMxvld3PnzrZDDv6UvBLtOkn3i++HSVRO0MOuTKI8gFDEPUxRtcaCKXEbqYnf1OTK25FT09Vb//qP9mK1thvlLJmbV+D2a9MkMK66rom1d1h+347IsuwsM+ycHjB80VVAQLA7VYLC5YIwmL17dSmcQLvetfikAMwwmUE+KES4qiLSaqOcAWcKcU67RZzgMMv5o0rESlQmv1nj0mHZtHoUR71sd21emPaRXLOr0oT5YogWUphKq2qVthRn2B06+vd3hPdtn92CmJw9j7zT2jl4OeSjNm9qfAajsRzHIANssFxkGAb7w/LxcMoO29JC+01iUUJMdOVm+4Ns6wGI7qxssWPKdB+VbQUDlHrXLR+sopO524uhkYoWB6DVfTj4R6tImaHtj5/VXON0lsYaLGj8cSH60emL6nNQ0lYV/bSlk6l0s+0x3uXGZnp9oKA+vqMzHfG3vJeMm6KUqtFVjUsYx+q8nHm5/SlWxj1EwnkH8s8ELKZAUXjd76nWEwJ7JFRNRSQWvjOUh3/rsOo4JopzZXPsjCjm+Vql9TG0X6hB21noai32oD5RvfhtR/NX6sXNS5TKZz/j/cMsMnAAsSKb6W7Jm
|
||||
9030ffdbe5625e35ed7189ab84a41dfc8d413e9c 0 iQIcBAABCgAGBQJXkOg0AAoJEESTFJTynGdzc1kP/3vSKCnhOOvjCjnpTQadYcCUq8vTNnfLHYVu0R4ItPa/jT6RmxoaYP+lZnLnnBx9+aX7kzwHsa9BUX3MbMEyLrOzX2I+bDJbNPhQyupyCuPYlf5Q9KVcO9YlpbsC4q5XBzCn3j2+pT8kSfi9uD8fgY3TgE4w9meINrfQAealfjwMLT8S/I49/ni0r+usSfk/dnSShJYDUO7Ja0VWbJea/GkkZTu30bCnMUZPjRApipU3hPP63WFjkSMT1rp2mAXbWqyr9lf8z32yxzM9nMSjq4ViRFzFlkGtE3EVRJ4PwkO7JuiWAMPJpiQcEr+r52cCsmWhiGyHuINo01MwoMO9/n6uL1WVa3mJcE9se3xBOvfgDu2FRFGCAdm1tef+AGVo9EG1uJXi0sX2yUc6DMeuYaRWrXMMlZh7zp9cuNU9Y/lLui9RFmq66yeXG3Z2B72doju3Ig5QGrNNw2AOsSzeHdAtOp6ychqPcl9QfIeJQG18KyPSefZKM3G8YRKBRIwXFEH6iZJe5ZIP4iXrHDMn2JqtTRtDqKR8VNDAgb9z4Ffx8QRxFyj5JzTTMM1GddHb9udLvTQlO0ULYG7hCSMRNzvUBE2aTw8frjLRyfyyg3QpDu/hz8op8s1ecE8rTCD8RuX9DiiylNozypPtGNS+UDbAmkc1PCWaRpPVl+9K6787
|
||||
5c9207ceedaea794f958224c19214d66af6e2d56 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlkdtooACgkQRJMUlPKcZ3P6ZxAAmLy/buZB/d96DJF/pViRWt/fWdjQFC4MqWfeSLW02OZ8Qkm1vPL3ln6WPHC2thy3xZWVg2uan3pLk/XXnsIFu8Q7r1EAfFFpvlMUmdl7asE8V6ilaeqmiI7bIvGMFbf4cZkQliLjiFkJX56tFHRCNi+rb7WgRuru3/GzPXUq2AvXZvFpFJgik0B72TxVlmCKeBRZq1FvP0UhAH48RJWYJksdEyzh2paMfjX9ZO5Q2SFFrmPw6k2ArdJFC1AYcgceZC84y06RKJ0WiSntUPlEUXgQbQVVWbtQDhjfJXMr/beuroNdT/vsRraLVkAzvhaDXNnHlAJNLQxci+AcLpnzZhxMW+ax7RRtrpXGxRN4cs0lBGUcSkaDybFqMYXwEjXAE8w6fdJRWCIlxctkAW/iNEO4kAG97hI2Qwcw5oU2Ymnv09zyGR+XJE35pJqPulJHExdwanJHvmjH0QF7TNFS82yxS5dKnP954cj3Lu9SWGYWjxQJRmLtOwb+lqqol4VTxG7Ois4uef9/Tpp9skeMZXVeNlpn2wrp6iFcX3uiiVDg9VKkl3ig6UqCiqQSuiIN87RXwUOeHXlCnW3adz3Xei0ziBrwLSql7lBIHGEAlUUNmJ3CrR8IwQtcynGEMKfNIeZ/XK+uNlm9cJIqZf1fzqc8KexlyS9AS0i/kiYZTr4=
|
||||
2f0c3f3361d3ea4eb9129ed8810699fda7e7a8ee 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlqVb+IACgkQRJMUlPKcZ3OENA//R9HsOUJQB2QZjRgAvqgLn2AMLUvmWb2etTZEc3Nps957Fw1F4kjh6VGfIpWuytfsDx1W8qRx09ikTdb3YteMWCuX8/aFreSPrioYmzrAEcxkZdA7B/jciqU0iXuHiJ9saKk5TR70aNp+iRy0hjAgiYEsVMF9YKHzULOJcHr70x9XVKquubQkwNqJA+/b2JbK2j46wM5nVK/alGSI2kMmEzXmAHQxsvf1OLMvgH8ou/l0xsg/CuFEK299XKfZAbsFEXrjuoWZ1aSa6rTeOWsWli5T+czyyJHI4Eu0Sz/gaR8+MPhJSYes8YjvzEdv32rRMDVOdBq4e+HoTgFt/THYABP6/R1H5fX3Lm4K8u9F9SwJbb/YKRAIrfWDob8ApnGFHk2dyYO20Fskbbg6b1pC7ulDWsufu8lYkQyMlTc3dR6P4eTB6mKO4x+gMG6tIYZ60fiULoEnMJCgegPtevmz+TG1rzdjh3ljiw9Dxz5lNtL+W7sBKKHwhyG0u+bavgmvBMKNL/rdHEM+0yCIz1U6Lb8sVaST1E4zbdm7cWHbSozBij3G0GBSkLFEq7ZLlh8wco9rELRh0Y9fFsWY9j6H/PTOu0GfHrYluFb9WGywHAquQY8j2croRx+MrvTbR1wZrbevPNm9gqk3vgOiDWu7KwxLLqcj+dEQ7tccptVYtbM=
|
||||
07b0d56d186d7eeef4106137a3eba554959ba0e3 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlyWOo8ACgkQRJMUlPKcZ3O+MQ//c5oeDUvZuFiI4FHZqfIK/59YAciTP+9TQmoWDVSuOdkd9ZYJA7b7DCusqP2TWFEIl9M7i5hTLTMD21xuEQQtfOSP6EXpUw6JNdh/lsJs7EDlFANtwkdEozAQozFKnXbJEV3y9WldEWUlmPFjt4fJQIuG10SU7MTJHcSaQddJCh3I1//F4EvgRe+OqyrFwKekGiFdvfjcIFN3lQmk6K1Sc0MgyIO/VVZm/AQpBi0Dlg0yOl+EDcxxlmeSInbvLceWSP6op35I4dE5YWH1UetjzIsr5AIM15/k3viAKDDefY1EMAzK9b7YAF4BLw0a6XoQu0apvcWaALE/bJzWNSg/QbCm2JAZzk21WLLvR+AELzPfKXrHX3o0h51lpQ4rs7EWKUm43dJPoWkcFNOU+BDsNzffcJgChbRs48ut89DYLiGmSxhRxE77VPbA+klgTGdctOTLd8psseRlGYCuGe8zeota80bV9fUZ9WJZHwNgEWGowKUoTjy6l5k9OH3iQuQX3OXoy78ufRgWDulE7noVTMhXurQ8a0Jf2k/MW9dcnqGVkWitCFKPEvZwVmWyW2AWsdMcBJnFFGzDsNSxWTtCF9XcxieDO1IB8vGwYcb1TwEVuVzvR/wwvc3PgVikF+4Qv2NqdoQc1yn2PkocY2hwXyIZUAwz7erNumlTbeC/JK8=
|
||||
ebcdb893992d286d363e60f5353d6e1401e7084b 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlybhXAACgkQRJMUlPKcZ3O7pQ//QuNJfBVa7ROaOJOR2H/xr6PRn1Fnc6rr/GCF9cqWrbGP6wNo24dRjcu5LxviqPvzfwRXIMXwVz8L/y61/sm6XcA7VFP4+MBoltfeUOdMbfBdtwEUo3WMBdP1w2q5GgYj8ZY6MawiLEqFba5aua7dokTNBOQM3Yebj+9I16MiWEaRSnuwYPoieHW2Fo6oftcIgs/GCXwT2xYzc0n3FpYAbK7u6sEkpL16EstV0Y/G70+X1/4Mg3GM96S5fl9Zbun47W7/+gT4AQVQjE+UnPNDudObAe+2BaOZLFvEbd7iJBBcqtjpBktuP58IEAb3A3srUCy49LNLWk43lj+PtoslK/U6TShKQ2vAgfd//bbn6ieXFJY8N+wYPpJo1m7zpTiEtS7J7wu6vkGGZlqUAj6MHXZj223CgazhSAlg/XFPs9oz3Y96c33Tnd4jB9iEXNNt5jzCAMImx2huSGgnP0JFAbcniq/ug5tl1VWaracvSuJl7fmf17DbmehsLbvtZBoMlePY7Ssfb5IokfVvptt4zRpRZnjtWfHCjtC6zYhtvXTmXH/bqWwx9MMjOf5WPfZoCMvXfMqdVI15FVbxU15WnqjvdvKUCkdz1aMFzxqc4MXgyvjtB9CvO/8WwBOJ2m2nDdiZfh8/H8SawYqEHgB61FX5xA5aXecgXcjQnqWDDxw=
|
||||
4877afd51e041eca7749cc46b57fd80aa23815b4 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAl7nmREACgkQRJMUlPKcZ3PG1BAAnUl0/nTnQ3CMM3S72DT1JQ1eDxZa14r6r1xEPngU83hNNzmPcnfiMDts+Vz1M3PLxNNOXVVt/MTw04+V9joPhhSWEe8O1pd3lAqTPswL7hhIEbVwZwyFCuAV4iAm+tHKzKLjtjgZfMgij6XylOmw18VBw5R+suoOMclJqeHlJ5m0Mq2wRLDE+RdVCAkulTqhGYjJNQUXMMNPx/cxUo3NHsto9pWL3d1285vBByP6BQSaeYlO012InvJRlQuEkK3lnIyzq6voIc6+tMli0q9iyBz+2GIloBQNAnb6EGaXxqAOBW5NRc+/Oauiu8Yf/6JoFlkAIcPXmGRtxiAiynJImhiTaCFdgdxaXLFzjBvq+tcwVXvvNM52fOZ4Z3QgMDu6EgNWfma0lsg4T3ar2ml2/evuWeLVut5ZmYFHarTFX+/pTVy9nAZK/F5ROJM1prTNYI18PZV4qvULta8spGV2Be0rCkQQubp9RWdKHNGZE70lrX5OnNIwE/D3g2QE04243i0IGBwhlDEpYjqujLyHk8W6XE1CORx0hQ0fUjzKZsRvOB7XyMAFpQUVOhoMFcnk5XHDW6B/U7NAxzqNqO+gbHO/UIeuy/KOVlMNJCmtRL/HYNGZ6SCZbRpyX3d8Ow0sasNfJkZrT6a0Tf6lZktWOxtPkoEDLfuCzudzn4JxGQM=
|
||||
|
||||
7
.hgtags
7
.hgtags
@@ -52,3 +52,10 @@ cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
|
||||
79a6ef02307d05cb9dda10465cb5b807baa8f62e DROPBEAR_2015.70
|
||||
9a944a243f08be6b22d32f166a0690eb4872462b DROPBEAR_2015.71
|
||||
78b12b6549be08b0bea3da329b2578060a76ca31 DROPBEAR_2016.72
|
||||
309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73
|
||||
0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
|
||||
c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
|
||||
1c66ca4f3791c82501c88e7637312182c7294978 DROPBEAR_2018.76
|
||||
6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77
|
||||
009d52ae26d35f3381c801e02318fa9be34be93c DROPBEAR_2019.78
|
||||
e2e4929d057b09422f2ea4556fb64209aff58161 DROPBEAR_2020.79
|
||||
|
||||
59
.travis.yml
59
.travis.yml
@@ -1,28 +1,19 @@
|
||||
language: c
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror
|
||||
- BUNDLEDLIBTOM=--enable-bundled-libtom
|
||||
- MULTI=1
|
||||
- NOWRITEV=1
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: "F4rKQrHK/u58vPo3F9+x0WYXAeMFJvvtH9BIGZqx9yw8bUnL+gk0Ge9wnHHTXRcgCTqoc7B35uMS5njpH+Su/esVjrLAq85f/AmQctlRpmApwGK9LyxkIvx3UJN0nqfeeDXA90/8FUZ+n/qnCydXmYCEgqSaBCNydDxW1oqYUIc="
|
||||
- BUNDLEDLIBTOM=--enable-bundled-libtom
|
||||
- MULTI=1
|
||||
|
||||
# TODO: remove this section when libtomcrypt compiles on OSX: https://github.com/libtom/libtomcrypt/issues/82
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror
|
||||
before_install:
|
||||
- echo -n | openssl s_client -connect https://scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
# container-based builds
|
||||
sudo: false
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
@@ -30,22 +21,16 @@ addons:
|
||||
- zlib1g-dev
|
||||
- libtomcrypt-dev
|
||||
- libtommath-dev
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "mkj/dropbear"
|
||||
description: "Dropbear SSH"
|
||||
notification_email: matt@ucc.asn.au
|
||||
build_command_prepend: autoconf && autoheader && ./configure --enable-bundled-libtom CFLAGS='-O2 -Wall -Wno-pointer-sign' --prefix=$HOME/inst
|
||||
build_command: make MULTI=1
|
||||
branch_pattern: coverity
|
||||
|
||||
|
||||
before_install:
|
||||
- if [ "$CC" = "clang" ]; then WEXTRAFLAGS="$WEXTRAFLAGS -Wno-error=incompatible-library-redeclaration" ; fi # workaround
|
||||
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$BUNDLEDLIBTOM" = "--disable-bundled-libtom" ]; then brew update > /dev/null && brew install libtomcrypt libtommath ; fi
|
||||
|
||||
script:
|
||||
- autoconf && autoheader && ./configure "$BUNDLEDLIBTOM" CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix="$HOME/inst"
|
||||
- if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
|
||||
- make -j3 install
|
||||
|
||||
after_success:
|
||||
- ~/inst/bin/dropbearkey -t rsa -f testrsa
|
||||
- ~/inst/bin/dropbearkey -t dss -f testdss
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- coverity
|
||||
|
||||
283
CHANGES
283
CHANGES
@@ -1,3 +1,280 @@
|
||||
2020.80 - 26 June 2020
|
||||
|
||||
- Don't block authorized_keys logins with no-X11-forwarding or no-agent-forwarding
|
||||
restrictions when X11 or agent forwarding are disabled at compile time.
|
||||
This is more of a problem now X11 is disabled by default, reported by Guilhem Moulin
|
||||
|
||||
- Reduce binary size by 4kB (x64) when using bundled libtommath
|
||||
|
||||
- Define GNU_SOURCE for getrandom() on uclibc, reported by Laurent Bercot and
|
||||
Fabrice Fontaine
|
||||
|
||||
- Improve checking libtomcrypt version compatibility
|
||||
|
||||
- Add some style notes to DEVELOPING.md
|
||||
|
||||
2020.79 - 15 June 2020
|
||||
|
||||
- Support ed25519 hostkeys and authorized_keys, many thanks to Vladislav Grishenko.
|
||||
This also replaces curve25519 with a TweetNaCl implementation that reduces code size.
|
||||
|
||||
- Add chacha20-poly1305 authenticated cipher. This will perform faster than AES
|
||||
on many platforms. Thanks to Vladislav Grishenko
|
||||
|
||||
- Support using rsa-sha2 signatures. No changes are needed to hostkeys/authorized_keys
|
||||
entries, existing RSA keys can be used with the new signature format (signatures
|
||||
are ephemeral within a session). Old ssh-rsa signatures will no longer
|
||||
be supported by OpenSSH in future so upgrading is recommended.
|
||||
|
||||
- Use getrandom() call on Linux to ensure sufficient entropy has been gathered at startup.
|
||||
Dropbear now avoids reading from the random source at startup, instead waiting until
|
||||
the first connection. It is possible that some platforms were running without enough
|
||||
entropy previously, those could potentially block at first boot generating host keys.
|
||||
The dropbear "-R" option is one way to avoid that.
|
||||
|
||||
- Upgrade libtomcrypt to 1.18.2 and libtommath to 1.2.0, many thanks to Steffen Jaeckel for
|
||||
updating Dropbear to use the current API. Dropbear's configure script will check
|
||||
for sufficient system library versions, otherwise using the bundled versions.
|
||||
|
||||
- CBC ciphers, 3DES, hmac-sha1-96, and x11 forwarding are now disabled by default.
|
||||
They can be set in localoptions.h if required.
|
||||
Blowfish has been removed.
|
||||
|
||||
- Support AES GCM, patch from Vladislav Grishenko. This is disabled by default,
|
||||
Dropbear doesn't currently use hardware accelerated AES.
|
||||
|
||||
- Added an API for specifying user public keys as an authorized_keys replacement.
|
||||
See pubkeyapi.h for details, thanks to Fabrizio Bertocci
|
||||
|
||||
- Fix idle detection clashing with keepalives, thanks to jcmathews
|
||||
|
||||
- Include IP addresses in more early exit messages making it easier for fail2ban
|
||||
processing. Patch from Kevin Darbyshire-Bryant
|
||||
|
||||
- scp fix for CVE-2018-20685 where a server could modify name of output files
|
||||
|
||||
- SSH_ORIGINAL_COMMAND is set for "dropbear -c" forced command too
|
||||
|
||||
- Fix writing key files on systems without hard links, from Matt Robinson
|
||||
|
||||
- Compatibility fixes for IRIX from Kazuo Kuroi
|
||||
|
||||
- Re-enable printing MOTD by default, was lost moving from options.h. Thanks to zciendor
|
||||
|
||||
- Call fsync() is called on parent directory when writing key files to ensure they are flushed
|
||||
|
||||
- Fix "make install" for manpages in out-of-tree builds, from Gabor Z. Papp
|
||||
|
||||
- Some notes are added in DEVELOPING.md
|
||||
|
||||
2019.78 - 27 March 2019
|
||||
|
||||
- Fix dbclient regression in 2019.77. After exiting the terminal would be left
|
||||
in a bad state. Reported by Ryan Woodsmall
|
||||
|
||||
2019.77 - 23 March 2019
|
||||
|
||||
- Fix server -R option with ECDSA - only advertise one key size which will be accepted.
|
||||
Reported by Peter Krefting, 2018.76 regression.
|
||||
|
||||
- Fix server regression in 2018.76 where multiple client -R forwards were all forwarded
|
||||
to the first destination. Reported by Iddo Samet.
|
||||
|
||||
- Make failure delay more consistent to avoid revealing valid usernames, set server password
|
||||
limit of 100 characters. Problem reported by usd responsible disclosure team
|
||||
|
||||
- Change handling of failed authentication to avoid disclosing valid usernames,
|
||||
CVE-2018-15599.
|
||||
|
||||
- Fix dbclient to reliably return the exit code from the remote server.
|
||||
Reported by W. Mike Petullo
|
||||
|
||||
- Fix export of 521-bit ECDSA keys, from Christian Hohnstädt
|
||||
|
||||
- Add -o Port=xxx option to work with sshfs, from xcko
|
||||
|
||||
- Merged fuzzing code, see FUZZER-NOTES.md
|
||||
|
||||
- Add a DROPBEAR_SVR_MULTIUSER=0 compile option to run on
|
||||
single-user Linux kernels (CONFIG_MULTIUSER disabled). From Patrick Stewart
|
||||
|
||||
- Increase allowed username to 100 characters, reported by W. Mike Petullo
|
||||
|
||||
- Update config.sub and config.guess, should now work with RISC-V
|
||||
|
||||
- Cygwin compile fix from karel-m
|
||||
|
||||
- Don't require GNU sed (accidentally in 2018.76), reported by Samuel Hsu
|
||||
|
||||
- Fix for IRIX and writev(), reported by Kazuo Kuroi
|
||||
|
||||
- Other fixes and cleanups from François Perrad, Andre McCurdy, Konstantin Demin,
|
||||
Michael Jones, Pawel Rapkiewicz
|
||||
|
||||
|
||||
2018.76 - 27 February 2018
|
||||
|
||||
> > > Configuration/compatibility changes
|
||||
IMPORTANT
|
||||
Custom configuration is now specified in localoptions.h rather than options.h
|
||||
Available options and defaults can be seen in default_options.h
|
||||
|
||||
To migrate your configuration, compare your customised options.h against the
|
||||
upstream options.h from your relevant version. Any customised options should
|
||||
be put in localoptions.h in the build directory.
|
||||
|
||||
- "configure --enable-static" should now be used instead of "make STATIC=1"
|
||||
This will avoid 'hardened build' flags that conflict with static binaries
|
||||
|
||||
- Set 'hardened build' flags by default if supported by the compiler.
|
||||
These can be disabled with configure --disable-harden if needed.
|
||||
-Wl,-pie
|
||||
-Wl,-z,now -Wl,-z,relro
|
||||
-fstack-protector-strong
|
||||
-D_FORTIFY_SOURCE=2
|
||||
# spectre v2 mitigation
|
||||
-mfunction-return=thunk
|
||||
-mindirect-branch=thunk
|
||||
|
||||
Spectre patch from Loganaden Velvindron
|
||||
|
||||
- "dropbear -r" option for hostkeys no longer attempts to load the default
|
||||
hostkey paths as well. If desired these can be specified manually.
|
||||
Patch from CamVan Nguyen
|
||||
|
||||
- group1-sha1 key exchange is disabled in the server by default since
|
||||
the fixed 1024-bit group may be susceptible to attacks
|
||||
|
||||
- twofish ciphers are now disabled in the default configuration
|
||||
|
||||
- Default generated ECDSA key size is now 256 (rather than 521)
|
||||
for better interoperability
|
||||
|
||||
- Minimum RSA key length has been increased to 1024 bits
|
||||
|
||||
> > > Other features and fixes
|
||||
|
||||
- Add runtime -T max_auth_tries option from Kevin Darbyshire-Bryant
|
||||
|
||||
- Add 'dbclient -J &fd' to allow dbclient to connect over an existing socket.
|
||||
See dbclient manpage for a socat example. Patch from Harald Becker
|
||||
|
||||
- Add "-c forced_command" option. Patch from Jeremy Kerr
|
||||
|
||||
- Restricted group -G option added with patch from stellarpower
|
||||
|
||||
- Support server-chosen TCP forwarding ports, patch from houseofkodai
|
||||
|
||||
- Allow choosing outgoing address for dbclient with -b [bind_address][:bind_port]
|
||||
Patch from houseofkodai
|
||||
|
||||
- Makefile will now rebuild object files when header files are modified
|
||||
|
||||
- Add group14-256 and group16 key exchange options
|
||||
|
||||
- curve25519-sha256 also supported without @libssh.org suffix
|
||||
|
||||
- Update bundled libtomcrypt to 1.18.1, libtommath to 1.0.1
|
||||
This fixes building with some recent versions of clang
|
||||
|
||||
- Set PAM_RHOST which is needed by modules such as pam_abl
|
||||
|
||||
- Improvements to DSS and RSA public key validation, found by OSS-Fuzz.
|
||||
|
||||
- Don't exit when an authorized_keys file has malformed entries. Found by OSS-Fuzz
|
||||
|
||||
- Fix null-pointer crash with malformed ECDSA or DSS keys. Found by OSS-Fuzz
|
||||
|
||||
- Numerous code cleanups and small issues fixed by Francois Perrad
|
||||
|
||||
- Test for pkt_sched.h rather than SO_PRIORITY which was problematic with some musl
|
||||
platforms. Reported by Oliver Schneider and Andrew Bainbridge
|
||||
|
||||
- Fix some platform portability problems, from Ben Gardner
|
||||
|
||||
- Add EXEEXT filename suffix for building dropbearmulti, from William Foster
|
||||
|
||||
- Support --enable-<option> properly for configure, from Stefan Hauser
|
||||
|
||||
- configure have_openpty result can be cached, from Eric Bénard
|
||||
|
||||
- handle platforms that return close() < -1 on failure, from Marco Wenzel
|
||||
|
||||
- Build and configuration cleanups from Michael Witten
|
||||
|
||||
- Fix libtomcrypt/libtommath linking order, from Andre McCurdy
|
||||
|
||||
- Fix old Linux platforms that have SYS_clock_gettime but not CLOCK_MONOTONIC
|
||||
|
||||
- Update curve25519-donna implementation to current version
|
||||
|
||||
2017.75 - 18 May 2017
|
||||
|
||||
- Security: Fix double-free in server TCP listener cleanup
|
||||
A double-free in the server could be triggered by an authenticated user if
|
||||
dropbear is running with -a (Allow connections to forwarded ports from any host)
|
||||
This could potentially allow arbitrary code execution as root by an authenticated user.
|
||||
Affects versions 2013.56 to 2016.74. Thanks to Mark Shepard for reporting the crash.
|
||||
CVE-2017-9078 https://secure.ucc.asn.au/hg/dropbear/rev/c8114a48837c
|
||||
|
||||
- Security: Fix information disclosure with ~/.ssh/authorized_keys symlink.
|
||||
Dropbear parsed authorized_keys as root, even if it were a symlink. The fix
|
||||
is to switch to user permissions when opening authorized_keys
|
||||
|
||||
A user could symlink their ~/.ssh/authorized_keys to a root-owned file they
|
||||
couldn't normally read. If they managed to get that file to contain valid
|
||||
authorized_keys with command= options it might be possible to read other
|
||||
contents of that file.
|
||||
This information disclosure is to an already authenticated user.
|
||||
Thanks to Jann Horn of Google Project Zero for reporting this.
|
||||
CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123
|
||||
|
||||
- Generate hostkeys with dropbearkey atomically and flush to disk with fsync
|
||||
Thanks to Andrei Gherzan for a patch
|
||||
|
||||
- Fix out of tree builds with bundled libtom
|
||||
Thanks to Henrik Nordström and Peter Krefting for patches.
|
||||
|
||||
2016.74 - 21 July 2016
|
||||
|
||||
- Security: Message printout was vulnerable to format string injection.
|
||||
|
||||
If specific usernames including "%" symbols can be created on a system
|
||||
(validated by getpwnam()) then an attacker could run arbitrary code as root
|
||||
when connecting to Dropbear server.
|
||||
|
||||
A dbclient user who can control username or host arguments could potentially
|
||||
run arbitrary code as the dbclient user. This could be a problem if scripts
|
||||
or webpages pass untrusted input to the dbclient program.
|
||||
CVE-2016-7406
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb
|
||||
|
||||
- Security: dropbearconvert import of OpenSSH keys could run arbitrary code as
|
||||
the local dropbearconvert user when parsing malicious key files
|
||||
CVE-2016-7407
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e
|
||||
|
||||
- Security: dbclient could run arbitrary code as the local dbclient user if
|
||||
particular -m or -c arguments are provided. This could be an issue where
|
||||
dbclient is used in scripts.
|
||||
CVE-2016-7408
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6
|
||||
|
||||
- Security: dbclient or dropbear server could expose process memory to the
|
||||
running user if compiled with DEBUG_TRACE and running with -v
|
||||
CVE-2016-7409
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04
|
||||
|
||||
The security issues were reported by an anonymous researcher working with
|
||||
Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html
|
||||
|
||||
- Fix port forwarding failure when connecting to domains that have both
|
||||
IPv4 and IPv6 addresses. The bug was introduced in 2015.68
|
||||
|
||||
- Fix 100% CPU use while waiting for rekey to complete. Thanks to Zhang Hui P
|
||||
for the patch
|
||||
|
||||
|
||||
2016.73 - 18 March 2016
|
||||
|
||||
- Support syslog in dbclient, option -o usesyslog=yes. Patch from Konstantin Tokarev
|
||||
@@ -32,6 +309,7 @@
|
||||
|
||||
- Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions,
|
||||
found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff
|
||||
|
||||
2015.71 - 3 December 2015
|
||||
|
||||
@@ -265,6 +543,8 @@ kernels, from Steve Dover
|
||||
|
||||
2013.61test - Thursday 14 November 2013
|
||||
|
||||
- Default generated RSA key size changed from 1024 to 2048 bits
|
||||
|
||||
- ECC (elliptic curve) support. Supports ECDSA hostkeys (requires new keys to
|
||||
be generated) and ECDH for setting up encryption keys (no intervention
|
||||
required). This is significantly faster.
|
||||
@@ -310,9 +590,11 @@ kernels, from Steve Dover
|
||||
- Limit the size of decompressed payloads, avoids memory exhaustion denial
|
||||
of service
|
||||
Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f
|
||||
|
||||
- Avoid disclosing existence of valid users through inconsistent delays
|
||||
Thanks to Logan Lamb for reporting. CVE-2013-4434
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a
|
||||
|
||||
- Update config.guess and config.sub for newer architectures
|
||||
|
||||
@@ -415,6 +697,7 @@ though probably will be soon
|
||||
This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
|
||||
Thanks to Danny Fullerton of Mantor Organization for reporting
|
||||
the bug.
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749
|
||||
|
||||
- Compile fix, only apply IPV6 socket options if they are available in headers
|
||||
Thanks to Gustavo Zacarias for the patch
|
||||
|
||||
75
DEVELOPING.md
Normal file
75
DEVELOPING.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Developer Notes
|
||||
|
||||
## Building
|
||||
|
||||
See [INSTALL](INSTALL) for build instructions.
|
||||
[SMALL](SMALL) has hints for building smaller binaries, also see comments
|
||||
in default_options.h.
|
||||
|
||||
## Debug printing
|
||||
|
||||
Set `#define DEBUG_TRACE 1` in localoptions.h to enable a `-v` option
|
||||
for dropbear and dbclient. That prints various details of the session. For
|
||||
development running `dropbear -F -E` is useful to run in the foreground. You
|
||||
can set `#define DEBUG_NOFORK 1` to make dropbear a one-shot server, easy to
|
||||
run under a debugger.
|
||||
|
||||
## Random sources
|
||||
|
||||
Most cryptography requires a good random entropy source, both to generate secret
|
||||
keys and in the course of a session. Dropbear uses the Linux kernel's
|
||||
`getrandom()` syscall to ensure that the system RNG has been initialised before
|
||||
using it. On some systems there is insufficient entropy gathered during early
|
||||
boot - generating hostkeys then will block for some amount of time.
|
||||
Dropbear has a `-R` option to generate hostkeys upon the first connection
|
||||
as required - that will allow the system more time to gather entropy.
|
||||
|
||||
## Algorithms
|
||||
|
||||
Default algorithm lists are specified in [common-algo.c](common-algo.c).
|
||||
They are in priority order, the client's first matching choice is used
|
||||
(see rfc4253).
|
||||
Dropbear client has `-c` and `-m` arguments to choose which are enabled at
|
||||
runtime (doesn't work for server as of June 2020).
|
||||
|
||||
Enabling/disabling algorithms is done in [localoptions.h](localoptions.h),
|
||||
see [default_options.h](default_options.h).
|
||||
|
||||
## Style
|
||||
|
||||
Source code is indented with tabs, width set to 4 (though width shouldn't
|
||||
matter much). Braces are on the same line as functions/loops/if - try
|
||||
to keep consistency with existing code.
|
||||
|
||||
All `if` statements should have braces, no exceptions.
|
||||
|
||||
Avoid using pointer arithmetic, instead the functions in
|
||||
[buffer.h](buffer.h) should be used.
|
||||
|
||||
Some Dropbear platforms have old compilers.
|
||||
Variable declarations must be at the top of a scope and
|
||||
comments must be `/* */` rather than `//`.
|
||||
|
||||
Pointer variables should be initialised to NULL - it can reduce the
|
||||
severity of bugs.
|
||||
|
||||
## Third party code
|
||||
|
||||
Libtomcrypt and libtommath are periodically synced from upstream, so
|
||||
avoid making changes to that code which will need to be maintained.
|
||||
Improvements can be sent upstream to the libtom project.
|
||||
|
||||
## Non-root user
|
||||
|
||||
Dropbear server will run fine as a non-root user, allowing logins only for
|
||||
that user. Password authentication probably won't work (can't read shadow
|
||||
passwords). You will need to create hostkeys that are readable.
|
||||
|
||||
## Connection setup
|
||||
|
||||
Dropbear implements first_kex_packet_follows to reduce
|
||||
handshake latency (rfc 4253 7.1). Some less common implementations don't
|
||||
handle that, it can be a cause of problems connecting. Note also that
|
||||
Dropbear may send several ssh packets within a single TCP packet - it's just a
|
||||
stream.
|
||||
|
||||
77
FUZZER-NOTES.md
Normal file
77
FUZZER-NOTES.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Fuzzing Dropbear
|
||||
|
||||
Dropbear is process-per-session so it assumes calling `dropbear_exit()`
|
||||
is fine at any point to clean up. This makes fuzzing a bit trickier.
|
||||
A few pieces of wrapping infrastructure are used to work around this.
|
||||
|
||||
The [libfuzzer](http://llvm.org/docs/LibFuzzer.html#fuzz-target) harness
|
||||
expects a long running process to continually run a test function with
|
||||
a string of crafted input. That process should not leak resources or exit.
|
||||
|
||||
## longjmp
|
||||
|
||||
When dropbear runs in fuzz mode it sets up a
|
||||
[`setjmp()`](http://man7.org/linux/man-pages/man3/setjmp.3.html) target prior
|
||||
to launching the code to be fuzzed, and then [`dropbear_exit()`](dbutil.c#L125)
|
||||
calls `longjmp()` back there. This avoids exiting though it doesn't free
|
||||
memory or other resources.
|
||||
|
||||
## malloc Wrapper
|
||||
|
||||
Dropbear normally uses a [`m_malloc()`](dbmalloc.c) function that is the same as `malloc()` but
|
||||
exits if allocation fails. In fuzzing mode this is replaced with a tracking allocator
|
||||
that stores all allocations in a linked list. After the `longjmp()` occurs the fuzzer target
|
||||
calls [`m_malloc_free_epoch(1, 1)`](dbmalloc.c) to clean up any unreleased memory.
|
||||
|
||||
If the fuzz target runs to completion it calls `m_malloc_free_epoch(1, 0)` which will reset
|
||||
the tracked allocations but will not free memory - that allows libfuzzer's leak checking
|
||||
to detect leaks in normal operation.
|
||||
|
||||
## File Descriptor Input
|
||||
|
||||
As a network process Dropbear reads and writes from a socket. The wrappers for
|
||||
`read()`/`write()`/`select()` in [fuzz-wrapfd.c](fuzz-wrapfd.c) will read from the
|
||||
fuzzer input that has been set up with `wrapfd_add()`. `write()` output is
|
||||
currently discarded.
|
||||
These also test error paths such as EINTR and short reads with certain probabilities.
|
||||
|
||||
This allows running the entire dropbear server process with network input provided by the
|
||||
fuzzer, without many modifications to the main code. At the time of writing this
|
||||
only runs the pre-authentication stages, though post-authentication could be run similarly.
|
||||
|
||||
## Encryption and Randomness
|
||||
|
||||
When running in fuzzing mode Dropbear uses a [fixed seed](dbrandom.c#L185)
|
||||
every time so that failures can be reproduced.
|
||||
|
||||
Since the fuzzer cannot generate valid encrypted input the packet decryption and
|
||||
message authentication calls are disabled, see [packet.c](packet.c).
|
||||
MAC failures are set to occur with a low probability to test that error path.
|
||||
|
||||
## Fuzzers
|
||||
|
||||
Current fuzzers are
|
||||
|
||||
- [fuzzer-preauth](fuzzer-preauth.c) - the fuzzer input is treated as a stream of session input. This will
|
||||
test key exchange, packet ordering, authentication attempts etc.
|
||||
|
||||
- [fuzzer-preauth_nomaths](fuzzer-preauth_nomaths.c) - the same as fuzzer-preauth but with asymmetric crypto
|
||||
routines replaced with dummies for faster runtime. corpora are shared
|
||||
between fuzzers by [oss-fuzz](https://github.com/google/oss-fuzz) so this
|
||||
will help fuzzer-preauth too.
|
||||
|
||||
- [fuzzer-verify](fuzzer-verify.c) - read a key and signature from fuzzer input and verify that signature.
|
||||
It would not be expected to pass, though some keys with bad parameters are
|
||||
able to validate with a trivial signature - extra checks are added for that.
|
||||
|
||||
- [fuzzer-pubkey](fuzzer-pubkey.c) - test parsing of an `authorized_keys` line.
|
||||
|
||||
- [fuzzer-kexdh](fuzzer-kexdh.c) - test Diffie-Hellman key exchange where the fuzz input is the
|
||||
ephemeral public key that would be received over the network. This is testing `mp_expt_mod()`
|
||||
and and other libtommath routines.
|
||||
|
||||
- [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh.
|
||||
This is testing libtommath ECC routines.
|
||||
|
||||
- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange
|
||||
like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines.
|
||||
34
INSTALL
34
INSTALL
@@ -1,28 +1,42 @@
|
||||
Basic Dropbear build instructions:
|
||||
|
||||
- Edit options.h to set which features you want.
|
||||
- Edit debug.h if you want any debug options (not usually required).
|
||||
- Edit localoptions.h to set which features you want. Available options
|
||||
are described in default_options.h, these will be overridden by
|
||||
anything set in localoptions.h
|
||||
localoptions.h should be located in the build directory if you are
|
||||
building out of tree.
|
||||
|
||||
(If using a non-tarball copy, "autoconf; autoheader")
|
||||
- If using a Mercurial or Git checkout, "autoconf; autoheader"
|
||||
|
||||
./configure (optionally with --disable-zlib or --disable-syslog,
|
||||
- Configure for your system:
|
||||
./configure (optionally with --disable-zlib or --disable-syslog,
|
||||
or --help for other options)
|
||||
|
||||
Now compile:
|
||||
- Compile:
|
||||
|
||||
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
|
||||
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
|
||||
|
||||
And install (/usr/local/bin is usual default):
|
||||
- Optionally install, or copy the binaries another way
|
||||
|
||||
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install
|
||||
make install (/usr/local/bin is usual default):
|
||||
|
||||
or
|
||||
|
||||
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install
|
||||
|
||||
(you can leave items out of the PROGRAMS list to avoid compiling them. If you
|
||||
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
|
||||
recompiling - bad things will happen otherwise)
|
||||
|
||||
DEVELOPING.md has some notes on other developer topics, including debugging.
|
||||
|
||||
See MULTI for instructions on making all-in-one binaries.
|
||||
|
||||
If you want to compile statically, add "STATIC=1" to the make command-line.
|
||||
If you want to compile statically use ./configure --enable-static
|
||||
|
||||
By default Dropbear adds various build flags that improve robustness
|
||||
against programming bugs (good for security). If these cause problems
|
||||
they can be disabled with ./configure --disable-harden
|
||||
|
||||
Binaries can be stripped with "make strip"
|
||||
|
||||
@@ -44,7 +58,7 @@ Compiling for uClibc should be the same as normal, just set CC to the magic
|
||||
uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
|
||||
You can use "make STATIC=1" to make statically linked binaries, and it is
|
||||
advisable to strip the binaries too. If you're looking to make a small binary,
|
||||
you should remove unneeded ciphers and MD5, by editing options.h
|
||||
you should remove unneeded ciphers and MD5, by editing localoptions.h
|
||||
|
||||
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
|
||||
subdirectory (ie zlibincludes), and
|
||||
|
||||
73
LICENSE
73
LICENSE
@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
|
||||
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
|
||||
same license:
|
||||
|
||||
Copyright (c) 2002-2015 Matt Johnston
|
||||
Copyright (c) 2002-2020 Matt Johnston
|
||||
Portions copyright (c) 2004 Mihnea Stoenescu
|
||||
All rights reserved.
|
||||
|
||||
@@ -32,7 +32,8 @@ SOFTWARE.
|
||||
|
||||
=====
|
||||
|
||||
LibTomCrypt and LibTomMath are written by Tom St Denis, and are Public Domain.
|
||||
LibTomCrypt and LibTomMath are written by Tom St Denis and others, see
|
||||
libtomcrypt/LICENSE and libtommath/LICENSE.
|
||||
|
||||
=====
|
||||
|
||||
@@ -90,52 +91,24 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
=====
|
||||
|
||||
curve25519-donna:
|
||||
curve25519.c:
|
||||
|
||||
/* Copyright 2008, Google Inc.
|
||||
* 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 Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* More information about curve25519 can be found here
|
||||
* http://cr.yp.to/ecdh.html
|
||||
*
|
||||
* djb's sample implementation of curve25519 is written in a special assembly
|
||||
* language called qhasm and uses the floating point registers.
|
||||
*
|
||||
* This is, almost, a clean room reimplementation from the curve25519 paper. It
|
||||
* uses many of the tricks described therein. Only the crecip function is taken
|
||||
* from the sample implementation.
|
||||
*/
|
||||
Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
https://tweetnacl.cr.yp.to/
|
||||
|
||||
Contributors (alphabetical order)
|
||||
Daniel J. Bernstein, University of Illinois at Chicago and Technische
|
||||
Universiteit Eindhoven
|
||||
Bernard van Gastel, Radboud Universiteit Nijmegen
|
||||
Wesley Janssen, Radboud Universiteit Nijmegen
|
||||
Tanja Lange, Technische Universiteit Eindhoven
|
||||
Peter Schwabe, Radboud Universiteit Nijmegen
|
||||
Sjaak Smetsers, Radboud Universiteit Nijmegen
|
||||
|
||||
Acknowledgments
|
||||
This work was supported by the U.S. National Science Foundation under grant
|
||||
1018836. "Any opinions, findings, and conclusions or recommendations expressed
|
||||
in this material are those of the author(s) and do not necessarily reflect the
|
||||
views of the National Science Foundation."
|
||||
This work was supported by the Netherlands Organisation for Scientific
|
||||
Research (NWO) under grant 639.073.005 and Veni 2013 project 13114.
|
||||
|
||||
182
Makefile.in
182
Makefile.in
@@ -2,12 +2,11 @@
|
||||
# @configure_input@
|
||||
|
||||
# invocation:
|
||||
# make PROGRAMS="dropbear dbclient scp" MULTI=1 STATIC=1 SCPPROGRESS=1
|
||||
# make PROGRAMS="dropbear dbclient scp" MULTI=1 SCPPROGRESS=1
|
||||
#
|
||||
# to make a multiple-program statically linked binary "staticdropbearmulti".
|
||||
# to make a multiple-program binary "dropbearmulti".
|
||||
# This example will include dropbear, scp, dropbearkey, dropbearconvert, and
|
||||
# dbclient functionality, and includes the progress-bar functionality in scp.
|
||||
# Hopefully that seems intuitive.
|
||||
|
||||
ifndef PROGRAMS
|
||||
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
|
||||
@@ -20,8 +19,15 @@ LIBTOM_LIBS=@LIBTOM_LIBS@
|
||||
|
||||
ifeq (@BUNDLED_LIBTOM@, 1)
|
||||
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
LIBTOM_CLEAN=ltc-clean ltm-clean
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
endif
|
||||
|
||||
OPTION_HEADERS = default_options_guard.h sysoptions.h
|
||||
ifneq ($(wildcard localoptions.h),)
|
||||
CFLAGS+=-DLOCALOPTIONS_H_EXISTS
|
||||
OPTION_HEADERS += localoptions.h
|
||||
endif
|
||||
|
||||
COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
|
||||
@@ -30,7 +36,9 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o \
|
||||
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
|
||||
gensignkey.o gendss.o genrsa.o
|
||||
curve25519.o ed25519.o \
|
||||
dbmalloc.o \
|
||||
gensignkey.o gendss.o genrsa.o gened25519.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
@@ -45,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
tcp-accept.o listener.o process-packet.o dh_groups.o \
|
||||
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
|
||||
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
|
||||
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
@@ -53,18 +61,34 @@ CONVERTOBJS=dropbearconvert.o keyimport.o
|
||||
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
|
||||
|
||||
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
dss.h bignum.h signkey.h rsa.h dbrandom.h service.h auth.h \
|
||||
debug.h channel.h chansession.h config.h queue.h sshpty.h \
|
||||
termcodes.h gendss.h genrsa.h runopts.h includes.h \
|
||||
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
|
||||
listener.h fake-rfc2553.h ecc.h ecdsa.h
|
||||
ifeq (@DROPBEAR_FUZZ@, 1)
|
||||
allobjs = $(COMMONOBJS) fuzz-common.o fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
|
||||
allobjs:=$(subst svr-main.o, ,$(allobjs))
|
||||
allobjs:=$(subst cli-main.o, ,$(allobjs))
|
||||
allobjs:=$(sort $(allobjs))
|
||||
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
scpobjs=$(SCPOBJS)
|
||||
dropbearobjs=$(allobjs) svr-main.o
|
||||
dbclientobjs=$(allobjs) cli-main.o
|
||||
dropbearkeyobjs=$(allobjs) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
|
||||
# CXX only set when fuzzing
|
||||
CXX=@CXX@
|
||||
else
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
scpobjs=$(SCPOBJS)
|
||||
endif
|
||||
|
||||
ifeq (@DROPBEAR_PLUGIN@, 1)
|
||||
# rdynamic makes all the global symbols of dropbear available to all the loaded shared libraries
|
||||
# this allow a plugin to reuse existing crypto/utilities like base64_decode/base64_encode without
|
||||
# the need to rewrite them.
|
||||
PLUGIN_LIBS=-ldl -rdynamic
|
||||
else
|
||||
PLUGIN_LIBS=
|
||||
endif
|
||||
|
||||
VPATH=@srcdir@
|
||||
srcdir=@srcdir@
|
||||
@@ -76,6 +100,8 @@ bindir=@bindir@
|
||||
sbindir=@sbindir@
|
||||
mandir=@mandir@
|
||||
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
CC=@CC@
|
||||
AR=@AR@
|
||||
RANLIB=@RANLIB@
|
||||
@@ -88,9 +114,10 @@ LDFLAGS=@LDFLAGS@
|
||||
|
||||
EXEEXT=@EXEEXT@
|
||||
|
||||
STATIC=@STATIC@
|
||||
|
||||
# whether we're building client, server, or both for the common objects.
|
||||
# evilness so we detect 'dropbear' by itself as a word
|
||||
space:= $(empty) $(empty)
|
||||
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z))))
|
||||
CFLAGS+= -DDROPBEAR_SERVER
|
||||
endif
|
||||
@@ -98,7 +125,6 @@ ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z)
|
||||
CFLAGS+= -DDROPBEAR_CLIENT
|
||||
endif
|
||||
|
||||
|
||||
# these are exported so that libtomcrypt's makefile will use them
|
||||
export CC
|
||||
export CFLAGS
|
||||
@@ -109,7 +135,7 @@ ifeq ($(STATIC), 1)
|
||||
endif
|
||||
|
||||
ifeq ($(MULTI), 1)
|
||||
TARGETS=dropbearmulti
|
||||
TARGETS=dropbearmulti$(EXEEXT)
|
||||
else
|
||||
TARGETS=$(PROGRAMS)
|
||||
endif
|
||||
@@ -121,24 +147,35 @@ endif
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
# for simplicity assume all source depends on all headers
|
||||
HEADERS=$(wildcard $(srcdir)/*.h *.h) $(OPTION_HEADERS)
|
||||
%.o : %.c $(HEADERS)
|
||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
|
||||
default_options_guard.h: default_options.h
|
||||
@echo Creating $@
|
||||
@printf "/*\n > > > Do not edit this file (default_options_guard.h) < < <\nGenerated from "$^"\nLocal customisation goes in localoptions.h\n*/\n\n" > $@.tmp
|
||||
@$(srcdir)/ifndef_wrapper.sh < $^ >> $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
strip: $(TARGETS)
|
||||
$(STRIP) $(addsuffix $(EXEEXT), $(TARGETS))
|
||||
|
||||
install: $(addprefix inst_, $(TARGETS))
|
||||
|
||||
insmultidropbear: dropbearmulti
|
||||
insmultidropbear: dropbearmulti$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
insmulti%: dropbearmulti
|
||||
insmulti%: dropbearmulti$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
# dropbear should go in sbin, so it needs a separate rule
|
||||
inst_dropbear: dropbear
|
||||
@@ -151,11 +188,10 @@ inst_%: %
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
|
||||
|
||||
|
||||
# for some reason the rule further down doesn't like $($@objs) as a prereq.
|
||||
dropbear: $(dropbearobjs)
|
||||
dbclient: $(dbclientobjs)
|
||||
@@ -163,13 +199,13 @@ dropbearkey: $(dropbearkeyobjs)
|
||||
dropbearconvert: $(dropbearconvertobjs)
|
||||
|
||||
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ $(PLUGIN_LIBS)
|
||||
|
||||
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
|
||||
dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS)
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
|
||||
# scp doesn't use the libs so is special.
|
||||
scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
@@ -194,32 +230,104 @@ link%:
|
||||
-rm -f $*$(EXEEXT)
|
||||
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
|
||||
|
||||
$(STATIC_LTC): options.h
|
||||
cd libtomcrypt && $(MAKE)
|
||||
$(STATIC_LTC): $(OPTION_HEADERS)
|
||||
$(MAKE) -C libtomcrypt
|
||||
|
||||
$(STATIC_LTM): options.h
|
||||
cd libtommath && $(MAKE)
|
||||
$(STATIC_LTM): $(OPTION_HEADERS)
|
||||
$(MAKE) -C libtommath
|
||||
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint
|
||||
|
||||
ltc-clean:
|
||||
cd libtomcrypt && $(MAKE) clean
|
||||
$(MAKE) -C libtomcrypt clean
|
||||
|
||||
ltm-clean:
|
||||
cd libtommath && $(MAKE) clean
|
||||
$(MAKE) -C libtommath clean
|
||||
|
||||
sizes: dropbear
|
||||
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
|
||||
|
||||
clean: ltc-clean ltm-clean thisclean
|
||||
clean: $(LIBTOM_CLEAN) thisclean
|
||||
|
||||
thisclean:
|
||||
-rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress \
|
||||
dropbearmulti *.o *.da *.bb *.bbg *.prof
|
||||
-rm -f dropbear$(EXEEXT) dbclient$(EXEEXT) dropbearkey$(EXEEXT) \
|
||||
dropbearconvert$(EXEEXT) scp$(EXEEXT) scp-progress$(EXEEXT) \
|
||||
dropbearmulti$(EXEEXT) *.o *.da *.bb *.bbg *.prof
|
||||
|
||||
distclean: clean tidy
|
||||
-rm -f config.h
|
||||
-rm -f Makefile
|
||||
-rm -f default_options_guard.h
|
||||
|
||||
tidy:
|
||||
-rm -f *~ *.gcov */*~
|
||||
|
||||
lint:
|
||||
cd $(srcdir); ./dropbear_lint.sh
|
||||
|
||||
## Fuzzing targets
|
||||
|
||||
# list of fuzz targets
|
||||
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519
|
||||
|
||||
FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
|
||||
|
||||
list-fuzz-targets:
|
||||
@echo $(FUZZ_TARGETS)
|
||||
|
||||
# fuzzers that don't use libfuzzer, just a standalone harness that feeds inputs
|
||||
fuzzstandalone: FUZZLIB=fuzz-harness.o
|
||||
fuzzstandalone: fuzz-harness.o fuzz-targets
|
||||
|
||||
# exclude svr-main.o to avoid duplicate main
|
||||
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
|
||||
|
||||
fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
|
||||
|
||||
# build all the fuzzers. This will require fail to link unless built with
|
||||
# make fuzz-targets FUZZLIB=-lFuzzer.a
|
||||
# or similar - the library provides main().
|
||||
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
|
||||
|
||||
fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-verify: fuzzer-verify.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-%.options: Makefile
|
||||
echo "[libfuzzer]" > $@
|
||||
echo "max_len = 50000" >> $@
|
||||
|
||||
# run this to update hardcoded hostkeys for for fuzzing.
|
||||
# hostkeys.c is checked in to hg.
|
||||
fuzz-hostkeys:
|
||||
dropbearkey -t rsa -f keyr
|
||||
dropbearkey -t dss -f keyd
|
||||
dropbearkey -t ecdsa -size 256 -f keye
|
||||
dropbearkey -t ed25519 -f keyed25519
|
||||
echo > hostkeys.c
|
||||
/usr/bin/xxd -i -a keyr >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keye >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keyd >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keyed25519 >> hostkeys.c
|
||||
|
||||
# to make coverity happy?
|
||||
test:
|
||||
true
|
||||
|
||||
|
||||
7
README
7
README
@@ -8,8 +8,8 @@ which performs multiple tasks, to save disk space)
|
||||
|
||||
SMALL has some tips on creating small binaries.
|
||||
|
||||
See TODO for a few of the things I know need looking at, and please contact
|
||||
me if you have any questions/bugs found/features/ideas/comments etc :)
|
||||
Please contact me if you have any questions/bugs found/features/ideas/comments etc :)
|
||||
There is also a mailing list http://lists.ucc.gu.uwa.edu.au/mailman/listinfo/dropbear
|
||||
|
||||
Matt Johnston
|
||||
matt@ucc.asn.au
|
||||
@@ -51,10 +51,11 @@ dropbearkey's '-y' option.
|
||||
|
||||
============================================================================
|
||||
|
||||
To run the server, you need to server keys, this is one-off:
|
||||
To run the server, you need to generate server keys, this is one-off:
|
||||
./dropbearkey -t rsa -f dropbear_rsa_host_key
|
||||
./dropbearkey -t dss -f dropbear_dss_host_key
|
||||
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
|
||||
./dropbearkey -t ed25519 -f dropbear_ed25519_host_key
|
||||
|
||||
or alternatively convert OpenSSH keys to Dropbear:
|
||||
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
|
||||
|
||||
27
TODO
27
TODO
@@ -1,27 +0,0 @@
|
||||
Current:
|
||||
|
||||
Things which might need doing:
|
||||
|
||||
- default private dbclient keys
|
||||
|
||||
- Make options.h generated from configure perhaps?
|
||||
|
||||
- handle /etc/environment in AIX
|
||||
|
||||
- check that there aren't timing issues with valid/invalid user authentication
|
||||
feedback.
|
||||
|
||||
- Binding to different interfaces
|
||||
|
||||
- CTR mode
|
||||
- SSH_MSG_IGNORE sending to improve CBC security
|
||||
- DH Group Exchange possibly, or just add group14 (whatever it's called today)
|
||||
|
||||
- fix scp.c for IRIX
|
||||
|
||||
- Be able to use OpenSSH keys for the client? or at least have some form of
|
||||
encrypted keys.
|
||||
|
||||
- Client agent forwarding
|
||||
|
||||
- Handle restrictions in ~/.ssh/authorized_keys ?
|
||||
17
agentfwd.h
17
agentfwd.h
@@ -30,7 +30,10 @@
|
||||
#include "auth.h"
|
||||
#include "list.h"
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
|
||||
/* From OpenSSH authfd.h */
|
||||
#define SSH_AGENT_RSA_SHA2_256 0x02
|
||||
|
||||
/* An agent reply can be reasonably large, as it can
|
||||
* contain a list of all public keys held by the agent.
|
||||
@@ -40,8 +43,8 @@
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
buffer *data_buf);
|
||||
void cli_setup_agent(struct Channel *channel);
|
||||
const buffer *data_buf, enum signature_type type);
|
||||
void cli_setup_agent(const struct Channel *channel);
|
||||
|
||||
#ifdef __hpux
|
||||
#define seteuid(a) setresuid(-1, (a), -1)
|
||||
@@ -50,14 +53,14 @@ void cli_setup_agent(struct Channel *channel);
|
||||
|
||||
extern const struct ChanType cli_chan_agent;
|
||||
|
||||
#endif /* ENABLE_CLI_AGENTFWD */
|
||||
#endif /* DROPBEAR_CLI_AGENTFWD */
|
||||
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
#if DROPBEAR_SVR_AGENTFWD
|
||||
|
||||
int svr_agentreq(struct ChanSess * chansess);
|
||||
void svr_agentcleanup(struct ChanSess * chansess);
|
||||
void svr_agentset(struct ChanSess *chansess);
|
||||
void svr_agentset(const struct ChanSess *chansess);
|
||||
|
||||
#endif /* ENABLE_SVR_AGENTFWD */
|
||||
#endif /* DROPBEAR_SVR_AGENTFWD */
|
||||
|
||||
#endif /* DROPBEAR_AGENTFWD_H_ */
|
||||
|
||||
40
algo.h
40
algo.h
@@ -47,7 +47,7 @@ typedef struct Algo_Type algo_type;
|
||||
|
||||
/* lists mapping ssh types of algorithms to internal values */
|
||||
extern algo_type sshkex[];
|
||||
extern algo_type sshhostkey[];
|
||||
extern algo_type sigalgs[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type ssh_compress[];
|
||||
@@ -72,6 +72,14 @@ struct dropbear_cipher_mode {
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*decrypt)(const unsigned char *ct, unsigned char *pt,
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*aead_crypt)(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
void *cipher_state, int direction);
|
||||
int (*aead_getlength)(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, void *cipher_state);
|
||||
const struct dropbear_hash *aead_mac;
|
||||
};
|
||||
|
||||
struct dropbear_hash {
|
||||
@@ -83,9 +91,15 @@ struct dropbear_hash {
|
||||
};
|
||||
|
||||
enum dropbear_kex_mode {
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
DROPBEAR_KEX_NORMAL_DH,
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
DROPBEAR_KEX_ECDH,
|
||||
#endif
|
||||
#if DROPBEAR_CURVE25519
|
||||
DROPBEAR_KEX_CURVE25519,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct dropbear_kex {
|
||||
@@ -96,7 +110,7 @@ struct dropbear_kex {
|
||||
const int dh_p_len;
|
||||
|
||||
/* elliptic curve DH KEX */
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECDH
|
||||
const struct dropbear_ecc_curve *ecc_curve;
|
||||
#else
|
||||
const void* dummy;
|
||||
@@ -106,26 +120,22 @@ struct dropbear_kex {
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
};
|
||||
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]);
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
|
||||
|
||||
enum kexguess2_used {
|
||||
KEXGUESS2_LOOK,
|
||||
KEXGUESS2_NO,
|
||||
KEXGUESS2_YES,
|
||||
};
|
||||
/* Includes all algorithms is useall is set */
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall);
|
||||
/* Includes "usable" algorithms */
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
|
||||
|
||||
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
|
||||
#define KEXGUESS2_ALGO_ID 99
|
||||
|
||||
|
||||
int buf_has_algo(buffer *buf, const char *algo);
|
||||
algo_type * first_usable_algo(algo_type algos[]);
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess);
|
||||
int kexguess2, int *goodguess);
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
const char *algo_desc);
|
||||
char * algolist_string(algo_type algos[]);
|
||||
char * algolist_string(const algo_type algos[]);
|
||||
#endif
|
||||
|
||||
enum {
|
||||
|
||||
29
atomicio.c
29
atomicio.c
@@ -1,6 +1,8 @@
|
||||
/* $OpenBSD: atomicio.c,v 1.17 2006/04/01 05:51:34 djm Exp $ */
|
||||
/*
|
||||
* Copied from OpenSSH 3.6.1p2.
|
||||
* Copied from OpenSSH/OpenBSD.
|
||||
*
|
||||
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
|
||||
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -25,39 +27,32 @@
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* RCSID("OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp "); */
|
||||
#include "includes.h"
|
||||
|
||||
#include "atomicio.h"
|
||||
|
||||
/*
|
||||
* ensure all of data on socket comes through. f==read || f==write
|
||||
* ensure all of data on socket comes through. f==read || f==vwrite
|
||||
*/
|
||||
ssize_t
|
||||
atomicio(f, fd, _s, n)
|
||||
ssize_t (*f) ();
|
||||
int fd;
|
||||
void *_s;
|
||||
size_t n;
|
||||
size_t
|
||||
atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
|
||||
{
|
||||
char *s = _s;
|
||||
ssize_t res;
|
||||
size_t pos = 0;
|
||||
ssize_t res;
|
||||
|
||||
while (n > pos) {
|
||||
res = (f) (fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
#ifdef EWOULDBLOCK
|
||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
#else
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
#endif
|
||||
continue;
|
||||
/* FALLTHROUGH */
|
||||
return 0;
|
||||
case 0:
|
||||
return (res);
|
||||
errno = EPIPE;
|
||||
return pos;
|
||||
default:
|
||||
pos += res;
|
||||
pos += (size_t)res;
|
||||
}
|
||||
}
|
||||
return (pos);
|
||||
|
||||
13
atomicio.h
13
atomicio.h
@@ -1,8 +1,7 @@
|
||||
/* $OpenBSD: atomicio.h,v 1.7 2006/03/25 22:22:42 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copied from OpenSSH 3.6.1p2, required for loginrec.c
|
||||
*
|
||||
* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $
|
||||
* Copied from OpenSSH/OpenBSD, required for loginrec.c
|
||||
*
|
||||
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
|
||||
* All rights reserved.
|
||||
@@ -28,9 +27,9 @@
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/*
|
||||
* Ensure all of data on socket comes through. f==read || f==write
|
||||
* Ensure all of data on socket comes through. f==read || f==vwrite
|
||||
*/
|
||||
ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
|
||||
size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
|
||||
|
||||
#define vwrite (ssize_t (*)(int, void *, size_t))write
|
||||
|
||||
27
auth.h
27
auth.h
@@ -36,12 +36,12 @@ void cli_authinitialise(void);
|
||||
void recv_msg_userauth_request(void);
|
||||
void send_msg_userauth_failure(int partial, int incrfail);
|
||||
void send_msg_userauth_success(void);
|
||||
void send_msg_userauth_banner(buffer *msg);
|
||||
void svr_auth_password(void);
|
||||
void svr_auth_pubkey(void);
|
||||
void svr_auth_pam(void);
|
||||
void send_msg_userauth_banner(const buffer *msg);
|
||||
void svr_auth_password(int valid_user);
|
||||
void svr_auth_pubkey(int valid_user);
|
||||
void svr_auth_pam(int valid_user);
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
int svr_pubkey_allows_agentfwd(void);
|
||||
int svr_pubkey_allows_tcpfwd(void);
|
||||
int svr_pubkey_allows_x11fwd(void);
|
||||
@@ -74,11 +74,11 @@ void cli_pubkeyfail(void);
|
||||
void cli_auth_password(void);
|
||||
int cli_auth_pubkey(void);
|
||||
void cli_auth_interactive(void);
|
||||
char* getpass_or_cancel(char* prompt);
|
||||
char* getpass_or_cancel(const char* prompt);
|
||||
void cli_auth_pubkey_cleanup(void);
|
||||
|
||||
|
||||
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
|
||||
#define MAX_USERNAME_LEN 100 /* arbitrary for the moment */
|
||||
|
||||
#define AUTH_TYPE_NONE 1
|
||||
#define AUTH_TYPE_PUBKEY (1 << 1)
|
||||
@@ -105,12 +105,17 @@ struct AuthState {
|
||||
unsigned char authtypes; /* Flags indicating which auth types are still
|
||||
valid */
|
||||
unsigned int failcount; /* Number of (failed) authentication attempts.*/
|
||||
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||
unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||
client and server (though has differing
|
||||
meanings). */
|
||||
unsigned perm_warn : 1; /* Server only, set if bad permissions on
|
||||
|
||||
unsigned int perm_warn; /* Server only, set if bad permissions on
|
||||
~/.ssh/authorized_keys have already been
|
||||
logged. */
|
||||
unsigned int checkusername_failed; /* Server only, set if checkusername
|
||||
has already failed */
|
||||
struct timespec auth_starttime; /* Server only, time of receiving current
|
||||
SSH_MSG_USERAUTH_REQUEST */
|
||||
|
||||
/* These are only used for the server */
|
||||
uid_t pw_uid;
|
||||
@@ -119,12 +124,12 @@ struct AuthState {
|
||||
char *pw_shell;
|
||||
char *pw_name;
|
||||
char *pw_passwd;
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
struct PubKeyOptions* pubkey_options;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
struct PubKeyOptions;
|
||||
struct PubKeyOptions {
|
||||
/* Flags */
|
||||
|
||||
18
bignum.c
18
bignum.c
@@ -68,9 +68,25 @@ void m_mp_alloc_init_multi(mp_int **mp, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void m_mp_free_multi(mp_int **mp, ...)
|
||||
{
|
||||
mp_int** cur_arg = mp;
|
||||
va_list args;
|
||||
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
if (*cur_arg) {
|
||||
mp_clear(*cur_arg);
|
||||
}
|
||||
m_free(*cur_arg);
|
||||
cur_arg = va_arg(args, mp_int**);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
|
||||
if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
if (mp_from_ubin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
1
bignum.h
1
bignum.h
@@ -30,6 +30,7 @@
|
||||
void m_mp_init(mp_int *mp);
|
||||
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
|
||||
void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
|
||||
void m_mp_free_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp);
|
||||
|
||||
58
buffer.c
58
buffer.c
@@ -67,7 +67,7 @@ void buf_free(buffer* buf) {
|
||||
}
|
||||
|
||||
/* overwrite the contents of the buffer to clear it */
|
||||
void buf_burn(buffer* buf) {
|
||||
void buf_burn(const buffer* buf) {
|
||||
|
||||
m_burn(buf->data, buf->size);
|
||||
|
||||
@@ -91,7 +91,7 @@ buffer* buf_resize(buffer *buf, unsigned int newsize) {
|
||||
|
||||
/* Create a copy of buf, allocating required memory etc. */
|
||||
/* The new buffer is sized the same as the length of the source buffer. */
|
||||
buffer* buf_newcopy(buffer* buf) {
|
||||
buffer* buf_newcopy(const buffer* buf) {
|
||||
|
||||
buffer* ret;
|
||||
|
||||
@@ -109,6 +109,7 @@ void buf_setlen(buffer* buf, unsigned int len) {
|
||||
dropbear_exit("Bad buf_setlen");
|
||||
}
|
||||
buf->len = len;
|
||||
buf->pos = MIN(buf->pos, buf->len);
|
||||
}
|
||||
|
||||
/* Increment the length of the buffer */
|
||||
@@ -141,9 +142,10 @@ void buf_incrwritepos(buffer* buf, unsigned int incr) {
|
||||
/* increment the position by incr, negative values are allowed, to
|
||||
* decrement the pos*/
|
||||
void buf_incrpos(buffer* buf, int incr) {
|
||||
if (incr > BUF_MAX_INCR ||
|
||||
(unsigned int)((int)buf->pos + incr) > buf->len
|
||||
|| ((int)buf->pos + incr) < 0) {
|
||||
if (incr > BUF_MAX_INCR
|
||||
|| incr < -BUF_MAX_INCR
|
||||
|| (unsigned int)((int)buf->pos + incr) > buf->len
|
||||
|| ((int)buf->pos + incr) < 0) {
|
||||
dropbear_exit("Bad buf_incrpos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
@@ -182,9 +184,9 @@ void buf_putbyte(buffer* buf, unsigned char val) {
|
||||
|
||||
/* returns an in-place pointer to the buffer, checking that
|
||||
* the next len bytes from that position can be used */
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len) {
|
||||
unsigned char* buf_getptr(const buffer* buf, unsigned int len) {
|
||||
|
||||
if (buf->pos + len > buf->len) {
|
||||
if (len > BUF_MAX_INCR || buf->pos + len > buf->len) {
|
||||
dropbear_exit("Bad buf_getptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
@@ -192,9 +194,9 @@ unsigned char* buf_getptr(buffer* buf, unsigned int len) {
|
||||
|
||||
/* like buf_getptr, but checks against total size, not used length.
|
||||
* This allows writing past the used length, but not past the size */
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
|
||||
unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len) {
|
||||
|
||||
if (buf->pos + len > buf->size) {
|
||||
if (len > BUF_MAX_INCR || buf->pos + len > buf->size) {
|
||||
dropbear_exit("Bad buf_getwriteptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
@@ -207,6 +209,7 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
unsigned int len;
|
||||
char* ret;
|
||||
void* src = NULL;
|
||||
len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
@@ -215,8 +218,9 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
if (retlen != NULL) {
|
||||
*retlen = len;
|
||||
}
|
||||
src = buf_getptr(buf, len);
|
||||
ret = m_malloc(len+1);
|
||||
memcpy(ret, buf_getptr(buf, len), len);
|
||||
memcpy(ret, src, len);
|
||||
buf_incrpos(buf, len);
|
||||
ret[len] = '\0';
|
||||
|
||||
@@ -224,19 +228,37 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
static buffer * buf_getstringbuf_int(buffer *buf, int incllen) {
|
||||
buffer *ret = NULL;
|
||||
unsigned int len = buf_getint(buf);
|
||||
int extra = 0;
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
ret = buf_new(len);
|
||||
if (incllen) {
|
||||
extra = 4;
|
||||
}
|
||||
ret = buf_new(len+extra);
|
||||
if (incllen) {
|
||||
buf_putint(ret, len);
|
||||
}
|
||||
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
buf_incrlen(ret, len);
|
||||
buf_setpos(ret, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 0);
|
||||
}
|
||||
|
||||
/* Returns a string in a new buffer, including the length */
|
||||
buffer * buf_getbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 1);
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
@@ -285,18 +307,18 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
/* for our purposes we only need positive (or 0) numbers, so will
|
||||
* fail if we get negative numbers */
|
||||
void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
|
||||
size_t written;
|
||||
unsigned int len, pad = 0;
|
||||
TRACE2(("enter buf_putmpint"))
|
||||
|
||||
dropbear_assert(mp != NULL);
|
||||
|
||||
if (SIGN(mp) == MP_NEG) {
|
||||
if (mp_isneg(mp)) {
|
||||
dropbear_exit("negative bignum");
|
||||
}
|
||||
|
||||
/* zero check */
|
||||
if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
|
||||
if (mp_iszero(mp)) {
|
||||
len = 0;
|
||||
} else {
|
||||
/* SSH spec requires padding for mpints with the MSB set, this code
|
||||
@@ -317,10 +339,10 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
if (pad) {
|
||||
buf_putbyte(buf, 0x00);
|
||||
}
|
||||
if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
|
||||
if (mp_to_ubin(mp, buf_getwriteptr(buf, len-pad), len-pad, &written) != MP_OKAY) {
|
||||
dropbear_exit("mpint error");
|
||||
}
|
||||
buf_incrwritepos(buf, len-pad);
|
||||
buf_incrwritepos(buf, written);
|
||||
}
|
||||
|
||||
TRACE2(("leave buf_putmpint"))
|
||||
@@ -348,7 +370,7 @@ int buf_getmpint(buffer* buf, mp_int* mp) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
if (mp_from_ubin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
9
buffer.h
9
buffer.h
@@ -44,8 +44,8 @@ buffer * buf_new(unsigned int size);
|
||||
/* Possibly returns a new buffer*, like realloc() */
|
||||
buffer * buf_resize(buffer *buf, unsigned int newsize);
|
||||
void buf_free(buffer* buf);
|
||||
void buf_burn(buffer* buf);
|
||||
buffer* buf_newcopy(buffer* buf);
|
||||
void buf_burn(const buffer* buf);
|
||||
buffer* buf_newcopy(const buffer* buf);
|
||||
void buf_setlen(buffer* buf, unsigned int len);
|
||||
void buf_incrlen(buffer* buf, unsigned int incr);
|
||||
void buf_setpos(buffer* buf, unsigned int pos);
|
||||
@@ -54,10 +54,11 @@ void buf_incrwritepos(buffer* buf, unsigned int incr);
|
||||
unsigned char buf_getbyte(buffer* buf);
|
||||
unsigned char buf_getbool(buffer* buf);
|
||||
void buf_putbyte(buffer* buf, unsigned char val);
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getptr(const buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len);
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
buffer * buf_getbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len);
|
||||
|
||||
148
chachapoly.c
Normal file
148
chachapoly.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 "includes.h"
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
#include "chachapoly.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
#define CHACHA20_KEY_LEN 32
|
||||
#define CHACHA20_BLOCKSIZE 8
|
||||
#define POLY1305_KEY_LEN 32
|
||||
#define POLY1305_TAG_LEN 16
|
||||
|
||||
static const struct ltc_cipher_descriptor dummy = {.name = NULL};
|
||||
|
||||
static const struct dropbear_hash dropbear_chachapoly_mac =
|
||||
{NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN};
|
||||
|
||||
const struct dropbear_cipher dropbear_chachapoly =
|
||||
{&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
|
||||
|
||||
static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
const unsigned char *key, int keylen,
|
||||
int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_start"))
|
||||
|
||||
if (keylen != CHACHA20_KEY_LEN*2) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->chacha, key,
|
||||
CHACHA20_KEY_LEN, 20)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN,
|
||||
CHACHA20_KEY_LEN, 20) != CRYPT_OK)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_start"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_crypt(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
dropbear_chachapoly_state *state, int direction) {
|
||||
poly1305_state poly;
|
||||
unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_crypt"))
|
||||
|
||||
if (len < 4 || taglen != POLY1305_TAG_LEN) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
poly1305_init(&poly, key, sizeof(key));
|
||||
if (direction == LTC_DECRYPT) {
|
||||
poly1305_process(&poly, in, len);
|
||||
poly1305_done(&poly, tag, &taglen);
|
||||
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1);
|
||||
if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direction == LTC_ENCRYPT) {
|
||||
poly1305_process(&poly, out, len);
|
||||
poly1305_done(&poly, out + len, &taglen);
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_crypt"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_getlength(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, dropbear_chachapoly_state *state) {
|
||||
unsigned char seqbuf[8], buf[4];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_getlength"))
|
||||
|
||||
if (len < sizeof(buf)) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LOAD32H(*outlen, buf);
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_getlength"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_chachapoly =
|
||||
{(void *)dropbear_chachapoly_start, NULL, NULL,
|
||||
(void *)dropbear_chachapoly_crypt,
|
||||
(void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac};
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
44
chachapoly.h
Normal file
44
chachapoly.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. */
|
||||
|
||||
#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
typedef struct {
|
||||
chacha_state chacha;
|
||||
chacha_state header;
|
||||
} dropbear_chachapoly_state;
|
||||
|
||||
extern const struct dropbear_cipher dropbear_chachapoly;
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_chachapoly;
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */
|
||||
31
channel.h
31
channel.h
@@ -69,10 +69,6 @@ struct Channel {
|
||||
int sent_close, recv_close;
|
||||
int recv_eof, sent_eof;
|
||||
|
||||
/* Set after running the ChanType-specific close hander
|
||||
* to ensure we don't run it twice (nor type->checkclose()). */
|
||||
int close_handler_done;
|
||||
|
||||
struct dropbear_progress_connection *conn_pending;
|
||||
int initconn; /* used for TCP forwarding, whether the channel has been
|
||||
fully initialised */
|
||||
@@ -84,7 +80,7 @@ struct Channel {
|
||||
int flushing;
|
||||
|
||||
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
|
||||
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
|
||||
void (*read_mangler)(const struct Channel*, const unsigned char* bytes, int *len);
|
||||
|
||||
const struct ChanType* type;
|
||||
|
||||
@@ -94,11 +90,18 @@ struct Channel {
|
||||
struct ChanType {
|
||||
|
||||
int sepfds; /* Whether this channel has separate pipes for in/out or not */
|
||||
char *name;
|
||||
const char *name;
|
||||
/* Sets up the channel */
|
||||
int (*inithandler)(struct Channel*);
|
||||
int (*check_close)(struct Channel*);
|
||||
/* Called to check whether a channel should close, separately from the FD being closed.
|
||||
Used for noticing process exiting */
|
||||
int (*check_close)(const struct Channel*);
|
||||
/* Handler for ssh_msg_channel_request */
|
||||
void (*reqhandler)(struct Channel*);
|
||||
void (*closehandler)(struct Channel*);
|
||||
/* Called prior to sending ssh_msg_channel_close, used for sending exit status */
|
||||
void (*closehandler)(const struct Channel*);
|
||||
/* Frees resources, called just prior to channel being removed */
|
||||
void (*cleanup)(const struct Channel*);
|
||||
};
|
||||
|
||||
/* Callback for connect_remote */
|
||||
@@ -107,7 +110,7 @@ void channel_connect_done(int result, int sock, void* user_data, const char* err
|
||||
void chaninitialise(const struct ChanType *chantypes[]);
|
||||
void chancleanup(void);
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
|
||||
void channelio(fd_set *readfd, fd_set *writefd);
|
||||
void channelio(const fd_set *readfd, const fd_set *writefd);
|
||||
struct Channel* getchannel(void);
|
||||
/* Returns an arbitrary channel that is in a ready state - not
|
||||
being initialised and no EOF in either direction. NULL if none. */
|
||||
@@ -115,8 +118,8 @@ struct Channel* get_any_ready_channel(void);
|
||||
|
||||
void recv_msg_channel_open(void);
|
||||
void recv_msg_channel_request(void);
|
||||
void send_msg_channel_failure(struct Channel *channel);
|
||||
void send_msg_channel_success(struct Channel *channel);
|
||||
void send_msg_channel_failure(const struct Channel *channel);
|
||||
void send_msg_channel_success(const struct Channel *channel);
|
||||
void recv_msg_channel_data(void);
|
||||
void recv_msg_channel_extended_data(void);
|
||||
void recv_msg_channel_window_adjust(void);
|
||||
@@ -126,16 +129,16 @@ void recv_msg_channel_eof(void);
|
||||
void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
circbuffer * buf);
|
||||
|
||||
#ifdef DROPBEAR_CLIENT
|
||||
#if DROPBEAR_CLIENT
|
||||
extern const struct ChanType clichansess;
|
||||
#endif
|
||||
|
||||
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
|
||||
#if DROPBEAR_LISTENERS || DROPBEAR_CLIENT
|
||||
int send_msg_channel_open_init(int fd, const struct ChanType *type);
|
||||
void recv_msg_channel_open_confirmation(void);
|
||||
void recv_msg_channel_open_failure(void);
|
||||
#endif
|
||||
void start_send_channel_request(struct Channel *channel, char *type);
|
||||
void start_send_channel_request(const struct Channel *channel, const char *type);
|
||||
|
||||
void send_msg_request_success(void);
|
||||
void send_msg_request_failure(void);
|
||||
|
||||
@@ -41,6 +41,9 @@ struct ChanSess {
|
||||
|
||||
char * cmd; /* command to exec */
|
||||
pid_t pid; /* child process pid */
|
||||
/* command that was sent by the client, if authorized_keys command= or
|
||||
dropbear -c was used */
|
||||
char *original_command;
|
||||
|
||||
/* pty details */
|
||||
int master; /* the master terminal fd*/
|
||||
@@ -58,7 +61,7 @@ struct ChanSess {
|
||||
/* Used to set $SSH_CLIENT in the child session. */
|
||||
char *client_string;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
#if DROPBEAR_X11FWD
|
||||
struct Listener * x11listener;
|
||||
int x11port;
|
||||
char * x11authprot;
|
||||
@@ -67,15 +70,11 @@ struct ChanSess {
|
||||
unsigned char x11singleconn;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
#if DROPBEAR_SVR_AGENTFWD
|
||||
struct Listener * agentlistener;
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
char *original_command;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ChildPid {
|
||||
@@ -89,11 +88,12 @@ void addnewvar(const char* param, const char* var);
|
||||
void cli_send_chansess_request(void);
|
||||
void cli_tty_cleanup(void);
|
||||
void cli_chansess_winchange(void);
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
void cli_send_netcat_request(void);
|
||||
#endif
|
||||
|
||||
void svr_chansessinitialise(void);
|
||||
void svr_chansess_checksignal(void);
|
||||
extern const struct ChanType svrchansess;
|
||||
|
||||
struct SigMap {
|
||||
|
||||
@@ -56,19 +56,19 @@ void cbuf_free(circbuffer * cbuf) {
|
||||
m_free(cbuf);
|
||||
}
|
||||
|
||||
unsigned int cbuf_getused(circbuffer * cbuf) {
|
||||
unsigned int cbuf_getused(const circbuffer * cbuf) {
|
||||
|
||||
return cbuf->used;
|
||||
|
||||
}
|
||||
|
||||
unsigned int cbuf_getavail(circbuffer * cbuf) {
|
||||
unsigned int cbuf_getavail(const circbuffer * cbuf) {
|
||||
|
||||
return cbuf->size - cbuf->used;
|
||||
|
||||
}
|
||||
|
||||
unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||
unsigned int cbuf_writelen(const circbuffer *cbuf) {
|
||||
|
||||
dropbear_assert(cbuf->used <= cbuf->size);
|
||||
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
|
||||
@@ -86,7 +86,7 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||
return cbuf->size - cbuf->writepos;
|
||||
}
|
||||
|
||||
void cbuf_readptrs(circbuffer *cbuf,
|
||||
void cbuf_readptrs(const circbuffer *cbuf,
|
||||
unsigned char **p1, unsigned int *len1,
|
||||
unsigned char **p2, unsigned int *len2) {
|
||||
*p1 = &cbuf->data[cbuf->readpos];
|
||||
|
||||
@@ -38,12 +38,12 @@ typedef struct circbuf circbuffer;
|
||||
circbuffer * cbuf_new(unsigned int size);
|
||||
void cbuf_free(circbuffer * cbuf);
|
||||
|
||||
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
|
||||
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
|
||||
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
|
||||
unsigned int cbuf_getused(const circbuffer * cbuf); /* how much data stored */
|
||||
unsigned int cbuf_getavail(const circbuffer * cbuf); /* how much we can write */
|
||||
unsigned int cbuf_writelen(const circbuffer *cbuf); /* max linear write len */
|
||||
|
||||
/* returns pointers to the two portions of the circular buffer that can be read */
|
||||
void cbuf_readptrs(circbuffer *cbuf,
|
||||
void cbuf_readptrs(const circbuffer *cbuf,
|
||||
unsigned char **p1, unsigned int *len1,
|
||||
unsigned char **p2, unsigned int *len2);
|
||||
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
|
||||
#include "agentfwd.h"
|
||||
#include "session.h"
|
||||
@@ -52,6 +52,7 @@ const struct ChanType cli_chan_agent = {
|
||||
new_agent_chan,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -108,7 +109,7 @@ static int new_agent_chan(struct Channel * channel) {
|
||||
data Any data, depending on packet type. Encoding as in the ssh packet
|
||||
protocol.
|
||||
*/
|
||||
static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
static buffer * agent_request(unsigned char type, const buffer *data) {
|
||||
|
||||
buffer * payload = NULL;
|
||||
buffer * inbuf = NULL;
|
||||
@@ -130,7 +131,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
}
|
||||
buf_setpos(payload, 0);
|
||||
|
||||
ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
|
||||
ret = atomicio(vwrite, fd, buf_getptr(payload, payload->len), payload->len);
|
||||
if ((size_t)ret != payload->len) {
|
||||
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
|
||||
goto out;
|
||||
@@ -230,7 +231,7 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
void cli_setup_agent(struct Channel *channel) {
|
||||
void cli_setup_agent(const struct Channel *channel) {
|
||||
if (!getenv("SSH_AUTH_SOCK")) {
|
||||
return;
|
||||
}
|
||||
@@ -254,11 +255,12 @@ void cli_load_agent_keys(m_list *ret_list) {
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
buffer *data_buf) {
|
||||
const buffer *data_buf, enum signature_type sigtype) {
|
||||
buffer *request_data = NULL;
|
||||
buffer *response = NULL;
|
||||
unsigned int siglen;
|
||||
int packet_type;
|
||||
int flags = 0;
|
||||
|
||||
/* Request format
|
||||
byte SSH2_AGENTC_SIGN_REQUEST
|
||||
@@ -270,7 +272,12 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
|
||||
buf_putbufstring(request_data, data_buf);
|
||||
buf_putint(request_data, 0);
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
|
||||
flags |= SSH_AGENT_RSA_SHA2_256;
|
||||
}
|
||||
#endif
|
||||
buf_putint(request_data, flags);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
|
||||
|
||||
66
cli-auth.c
66
cli-auth.c
@@ -51,7 +51,7 @@ void cli_auth_getmethods() {
|
||||
|
||||
encrypt_packet();
|
||||
|
||||
#ifdef DROPBEAR_CLI_IMMEDIATE_AUTH
|
||||
#if DROPBEAR_CLI_IMMEDIATE_AUTH
|
||||
/* We can't haven't two auth requests in-flight with delayed zlib mode
|
||||
since if the first one succeeds then the remote side will
|
||||
expect the second one to be compressed.
|
||||
@@ -60,9 +60,11 @@ void cli_auth_getmethods() {
|
||||
*/
|
||||
if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
|
||||
#if DROPBEAR_USE_PASSWORD_ENV
|
||||
if (getenv(DROPBEAR_PASSWORD_ENV)) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
|
||||
}
|
||||
#endif
|
||||
if (cli_auth_try() == DROPBEAR_SUCCESS) {
|
||||
TRACE(("skipped initial none auth query"))
|
||||
/* Note that there will be two auth responses in-flight */
|
||||
@@ -78,6 +80,7 @@ void recv_msg_userauth_banner() {
|
||||
char* banner = NULL;
|
||||
unsigned int bannerlen;
|
||||
unsigned int i, linecount;
|
||||
int truncated = 0;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_banner"))
|
||||
if (ses.authstate.authdone) {
|
||||
@@ -90,26 +93,29 @@ void recv_msg_userauth_banner() {
|
||||
|
||||
if (bannerlen > MAX_BANNER_SIZE) {
|
||||
TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen))
|
||||
goto out;
|
||||
}
|
||||
truncated = 1;
|
||||
} else {
|
||||
cleantext(banner);
|
||||
|
||||
cleantext(banner);
|
||||
|
||||
/* Limit to 25 lines */
|
||||
linecount = 1;
|
||||
for (i = 0; i < bannerlen; i++) {
|
||||
if (banner[i] == '\n') {
|
||||
if (linecount >= MAX_BANNER_LINES) {
|
||||
banner[i] = '\0';
|
||||
break;
|
||||
/* Limit to 24 lines */
|
||||
linecount = 1;
|
||||
for (i = 0; i < bannerlen; i++) {
|
||||
if (banner[i] == '\n') {
|
||||
if (linecount >= MAX_BANNER_LINES) {
|
||||
banner[i] = '\0';
|
||||
truncated = 1;
|
||||
break;
|
||||
}
|
||||
linecount++;
|
||||
}
|
||||
linecount++;
|
||||
}
|
||||
fprintf(stderr, "%s\n", banner);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\n", banner);
|
||||
if (truncated) {
|
||||
fprintf(stderr, "[Banner from the server is too long]\n");
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(banner);
|
||||
TRACE(("leave recv_msg_userauth_banner"))
|
||||
}
|
||||
@@ -121,21 +127,21 @@ out:
|
||||
* SSH_MSG_USERAUTH_INFO_REQUEST. */
|
||||
void recv_msg_userauth_specific_60() {
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
recv_msg_userauth_pk_ok();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) {
|
||||
recv_msg_userauth_info_request();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) {
|
||||
/* Eventually there could be proper password-changing
|
||||
* support. However currently few servers seem to
|
||||
@@ -179,7 +185,7 @@ void recv_msg_userauth_failure() {
|
||||
TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT"));
|
||||
return;
|
||||
} else {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
/* If it was a pubkey auth request, we should cross that key
|
||||
* off the list. */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
@@ -187,7 +193,7 @@ void recv_msg_userauth_failure() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
/* If we get a failure message for keyboard interactive without
|
||||
* receiving any request info packet, then we don't bother trying
|
||||
* keyboard interactive again */
|
||||
@@ -227,19 +233,19 @@ void recv_msg_userauth_failure() {
|
||||
for (i = 0; i <= methlen; i++) {
|
||||
if (methods[i] == '\0') {
|
||||
TRACE(("auth method '%s'", tok))
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
if (strncmp(AUTH_METHOD_PUBKEY, tok,
|
||||
AUTH_METHOD_PUBKEY_LEN) == 0) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
if (strncmp(AUTH_METHOD_INTERACT, tok,
|
||||
AUTH_METHOD_INTERACT_LEN) == 0) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
if (strncmp(AUTH_METHOD_PASSWORD, tok,
|
||||
AUTH_METHOD_PASSWORD_LEN) == 0) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
|
||||
@@ -267,7 +273,7 @@ void recv_msg_userauth_success() {
|
||||
cli_ses.state = USERAUTH_SUCCESS_RCVD;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
cli_auth_pubkey_cleanup();
|
||||
#endif
|
||||
}
|
||||
@@ -281,14 +287,14 @@ int cli_auth_try() {
|
||||
|
||||
/* Order to try is pubkey, interactive, password.
|
||||
* As soon as "finished" is set for one, we don't do any more. */
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
|
||||
finished = cli_auth_pubkey();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PUBKEY;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
|
||||
@@ -300,7 +306,7 @@ int cli_auth_try() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
|
||||
@@ -324,14 +330,14 @@ int cli_auth_try() {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_CLI_PASSWORD_AUTH) || defined(ENABLE_CLI_INTERACT_AUTH)
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH || DROPBEAR_CLI_INTERACT_AUTH
|
||||
/* A helper for getpass() that exits if the user cancels. The returned
|
||||
* password is statically allocated by getpass() */
|
||||
char* getpass_or_cancel(char* prompt)
|
||||
char* getpass_or_cancel(const char* prompt)
|
||||
{
|
||||
char* password = NULL;
|
||||
|
||||
#ifdef DROPBEAR_PASSWORD_ENV
|
||||
#if DROPBEAR_USE_PASSWORD_ENV
|
||||
/* Password provided in an environment var */
|
||||
password = getenv(DROPBEAR_PASSWORD_ENV);
|
||||
if (password)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
|
||||
static char* get_response(char* prompt)
|
||||
{
|
||||
@@ -172,4 +172,4 @@ void cli_auth_interactive() {
|
||||
TRACE(("leave cli_auth_interactive"))
|
||||
|
||||
}
|
||||
#endif /* ENABLE_CLI_INTERACT_AUTH */
|
||||
#endif /* DROPBEAR_CLI_INTERACT_AUTH */
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
|
||||
#ifdef ENABLE_CLI_ASKPASS_HELPER
|
||||
#if DROPBEAR_CLI_ASKPASS_HELPER
|
||||
/* Returns 1 if we want to use the askpass program, 0 otherwise */
|
||||
static int want_askpass()
|
||||
{
|
||||
@@ -113,7 +113,7 @@ static char *gui_getpass(const char *prompt) {
|
||||
TRACE(("leave gui_getpass"))
|
||||
return(buf);
|
||||
}
|
||||
#endif /* ENABLE_CLI_ASKPASS_HELPER */
|
||||
#endif /* DROPBEAR_CLI_ASKPASS_HELPER */
|
||||
|
||||
void cli_auth_password() {
|
||||
|
||||
@@ -125,7 +125,7 @@ void cli_auth_password() {
|
||||
|
||||
snprintf(prompt, sizeof(prompt), "%s@%s's password: ",
|
||||
cli_opts.username, cli_opts.remotehost);
|
||||
#ifdef ENABLE_CLI_ASKPASS_HELPER
|
||||
#if DROPBEAR_CLI_ASKPASS_HELPER
|
||||
if (want_askpass())
|
||||
{
|
||||
password = gui_getpass(prompt);
|
||||
@@ -158,4 +158,4 @@ void cli_auth_password() {
|
||||
|
||||
TRACE(("leave cli_auth_password"))
|
||||
}
|
||||
#endif /* ENABLE_CLI_PASSWORD_AUTH */
|
||||
#endif /* DROPBEAR_CLI_PASSWORD_AUTH */
|
||||
|
||||
112
cli-authpubkey.c
112
cli-authpubkey.c
@@ -32,8 +32,8 @@
|
||||
#include "auth.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign);
|
||||
|
||||
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
|
||||
* We use it to remove the key we tried from the list */
|
||||
@@ -59,13 +59,15 @@ void recv_msg_userauth_pk_ok() {
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
enum signkey_type keytype;
|
||||
enum signature_type sigtype;
|
||||
unsigned int remotelen;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_pk_ok"))
|
||||
|
||||
algotype = buf_getstring(ses.payload, &algolen);
|
||||
keytype = signkey_type_from_name(algotype, algolen);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
|
||||
sigtype = signature_type_from_name(algotype, algolen);
|
||||
keytype = signkey_type_from_signature(sigtype);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", sigtype))
|
||||
m_free(algotype);
|
||||
|
||||
keybuf = buf_new(MAX_PUBKEY_SIZE);
|
||||
@@ -112,7 +114,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("matching key"))
|
||||
/* XXX TODO: if it's an encrypted key, here we ask for their
|
||||
* password */
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, sigtype, 1);
|
||||
} else {
|
||||
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
|
||||
}
|
||||
@@ -120,31 +122,32 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("leave recv_msg_userauth_pk_ok"))
|
||||
}
|
||||
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
buffer *data_buf) {
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
|
||||
const buffer *data_buf) {
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
// TODO: rsa-sha256 agent
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
agent_buf_sign(sigblob, key, data_buf);
|
||||
agent_buf_sign(sigblob, key, data_buf, sigtype);
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
} else
|
||||
#endif /* ENABLE_CLI_AGENTFWD */
|
||||
#endif /* DROPBEAR_CLI_AGENTFWD */
|
||||
{
|
||||
buf_put_sign(buf, key, type, data_buf);
|
||||
buf_put_sign(buf, key, sigtype, data_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: make it take an agent reference to use as well */
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign) {
|
||||
|
||||
const char *algoname = NULL;
|
||||
unsigned int algolen;
|
||||
buffer* sigbuf = NULL;
|
||||
enum signkey_type keytype = signkey_type_from_signature(sigtype);
|
||||
|
||||
TRACE(("enter send_msg_userauth_pubkey"))
|
||||
TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype))
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
@@ -160,10 +163,9 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
buf_putbyte(ses.writepayload, realsign);
|
||||
|
||||
algoname = signkey_name_from_type(type, &algolen);
|
||||
|
||||
algoname = signature_name_from_type(sigtype, &algolen);
|
||||
buf_putstring(ses.writepayload, algoname, algolen);
|
||||
buf_put_pub_key(ses.writepayload, key, type);
|
||||
buf_put_pub_key(ses.writepayload, key, keytype);
|
||||
|
||||
if (realsign) {
|
||||
TRACE(("realsign"))
|
||||
@@ -172,7 +174,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
|
||||
buf_putbufstring(sigbuf, ses.session_id);
|
||||
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
|
||||
cli_buf_put_sign(ses.writepayload, key, sigtype, sigbuf);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
}
|
||||
|
||||
@@ -182,21 +184,87 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
/* Returns 1 if a key was tried */
|
||||
int cli_auth_pubkey() {
|
||||
|
||||
enum signature_type sigtype = DROPBEAR_SIGNATURE_NONE;
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
if (!cli_opts.agent_keys_loaded) {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
TRACE(("cli_auth_pubkey: agent keys loaded"))
|
||||
}
|
||||
#endif
|
||||
|
||||
/* iterate through privkeys to remove ones not allowed in server-sig-algs */
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
if (cli_ses.server_sig_algs) {
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
TRACE(("server-sig-algs allows rsa sha256"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNKEY_RSA)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("server-sig-algs allows rsa sha1"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
} else
|
||||
#endif /* DROPBEAR_RSA */
|
||||
{
|
||||
/* Not RSA */
|
||||
const char *name = NULL;
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
name = signature_name_from_type(sigtype, NULL);
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, name)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
TRACE(("server-sig-algs allows %s", name))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match, skip this key */
|
||||
TRACE(("server-sig-algs no match keytype %d, skipping", key->type))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
} else {
|
||||
/* Server didn't provide a server-sig-algs list, we'll
|
||||
assume all except rsa-sha256 are OK. */
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("no server-sig-algs, using rsa sha1"))
|
||||
break;
|
||||
#else
|
||||
/* only support rsa-sha256, skip this key */
|
||||
TRACE(("no server-sig-algs, skipping rsa sha256"))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
#endif
|
||||
} /* key->type == DROPBEAR_SIGNKEY_RSA */
|
||||
#endif /* DROPBEAR_RSA */
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
TRACE(("no server-sig-algs, using key"))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
/* Send a trial request */
|
||||
send_msg_userauth_pubkey(key, key->type, 0);
|
||||
send_msg_userauth_pubkey(key, sigtype, 0);
|
||||
cli_ses.lastprivkey = key;
|
||||
TRACE(("leave cli_auth_pubkey-success"))
|
||||
return 1;
|
||||
@@ -209,7 +277,7 @@ int cli_auth_pubkey() {
|
||||
|
||||
void cli_auth_pubkey_cleanup() {
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
m_close(cli_opts.agent_fd);
|
||||
cli_opts.agent_fd = -1;
|
||||
#endif
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
static void cli_closechansess(struct Channel *channel);
|
||||
static void cli_closechansess(const struct Channel *channel);
|
||||
static int cli_initchansess(struct Channel *channel);
|
||||
static void cli_chansessreq(struct Channel *channel);
|
||||
static void send_chansess_pty_req(struct Channel *channel);
|
||||
static void send_chansess_shell_req(struct Channel *channel);
|
||||
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
|
||||
static void send_chansess_pty_req(const struct Channel *channel);
|
||||
static void send_chansess_shell_req(const struct Channel *channel);
|
||||
static void cli_escape_handler(const struct Channel *channel, const unsigned char* buf, int *len);
|
||||
static int cli_init_netcat(struct Channel *channel);
|
||||
|
||||
static void cli_tty_setup(void);
|
||||
@@ -52,6 +52,7 @@ const struct ChanType clichansess = {
|
||||
NULL, /* checkclosehandler */
|
||||
cli_chansessreq, /* reqhandler */
|
||||
cli_closechansess, /* closehandler */
|
||||
NULL, /* cleanup */
|
||||
};
|
||||
|
||||
static void cli_chansessreq(struct Channel *channel) {
|
||||
@@ -83,7 +84,7 @@ out:
|
||||
|
||||
|
||||
/* If the main session goes, we close it up */
|
||||
static void cli_closechansess(struct Channel *UNUSED(channel)) {
|
||||
static void cli_closechansess(const struct Channel *UNUSED(channel)) {
|
||||
cli_tty_cleanup(); /* Restore tty modes etc */
|
||||
|
||||
/* This channel hasn't gone yet, so we have > 1 */
|
||||
@@ -270,7 +271,7 @@ void cli_chansess_winchange() {
|
||||
cli_ses.winchange = 0;
|
||||
}
|
||||
|
||||
static void send_chansess_pty_req(struct Channel *channel) {
|
||||
static void send_chansess_pty_req(const struct Channel *channel) {
|
||||
|
||||
char* term = NULL;
|
||||
|
||||
@@ -303,7 +304,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
TRACE(("leave send_chansess_pty_req"))
|
||||
}
|
||||
|
||||
static void send_chansess_shell_req(struct Channel *channel) {
|
||||
static void send_chansess_shell_req(const struct Channel *channel) {
|
||||
|
||||
char* reqtype = NULL;
|
||||
|
||||
@@ -355,7 +356,7 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
cli_init_stdpipe_sess(channel);
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
if (cli_opts.agent_fwd) {
|
||||
cli_setup_agent(channel);
|
||||
}
|
||||
@@ -379,7 +380,7 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
return 0; /* Success */
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
|
||||
static const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
@@ -387,7 +388,8 @@ static const struct ChanType cli_chan_netcat = {
|
||||
cli_init_netcat, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
cli_closechansess,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void cli_send_netcat_request() {
|
||||
@@ -452,7 +454,7 @@ do_escape(unsigned char c) {
|
||||
}
|
||||
|
||||
static
|
||||
void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) {
|
||||
void cli_escape_handler(const struct Channel* UNUSED(channel), const unsigned char* buf, int *len) {
|
||||
char c;
|
||||
int skip_char = 0;
|
||||
|
||||
|
||||
80
cli-kex.c
80
cli-kex.c
@@ -39,7 +39,7 @@
|
||||
#include "ecc.h"
|
||||
|
||||
|
||||
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
|
||||
static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen);
|
||||
#define MAX_KNOWNHOSTS_LINE 4500
|
||||
|
||||
void send_msg_kexdh_init() {
|
||||
@@ -48,6 +48,7 @@ void send_msg_kexdh_init() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.dh_param) {
|
||||
@@ -58,8 +59,9 @@ void send_msg_kexdh_init() {
|
||||
}
|
||||
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
#ifdef DROPBEAR_ECDH
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.ecdh_param) {
|
||||
if (cli_ses.ecdh_param) {
|
||||
@@ -68,9 +70,9 @@ void send_msg_kexdh_init() {
|
||||
cli_ses.ecdh_param = gen_kexecdh_param();
|
||||
}
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
|
||||
#endif
|
||||
break;
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
#endif
|
||||
#if DROPBEAR_CURVE25519
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.curve25519_param) {
|
||||
@@ -79,9 +81,9 @@ void send_msg_kexdh_init() {
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
#endif
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
|
||||
@@ -92,7 +94,7 @@ void send_msg_kexdh_init() {
|
||||
void recv_msg_kexdh_reply() {
|
||||
|
||||
sign_key *hostkey = NULL;
|
||||
unsigned int type, keybloblen;
|
||||
unsigned int keytype, keybloblen;
|
||||
unsigned char* keyblob = NULL;
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_reply"))
|
||||
@@ -100,8 +102,8 @@ void recv_msg_kexdh_reply() {
|
||||
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
|
||||
dropbear_exit("Received out-of-order kexdhreply");
|
||||
}
|
||||
type = ses.newkeys->algo_hostkey;
|
||||
TRACE(("type is %d", type))
|
||||
keytype = ses.newkeys->algo_hostkey;
|
||||
TRACE(("keytype is %d", keytype))
|
||||
|
||||
hostkey = new_sign_key();
|
||||
keybloblen = buf_getint(ses.payload);
|
||||
@@ -112,12 +114,13 @@ void recv_msg_kexdh_reply() {
|
||||
checkhostkey(keyblob, keybloblen);
|
||||
}
|
||||
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &keytype) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting pubkey"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
{
|
||||
DEF_MP_INT(dh_f);
|
||||
@@ -131,37 +134,40 @@ void recv_msg_kexdh_reply() {
|
||||
mp_clear(&dh_f);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
#ifdef DROPBEAR_ECDH
|
||||
{
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
#endif
|
||||
#if DROPBEAR_CURVE25519
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
{
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
cli_ses.dh_param = NULL;
|
||||
}
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
cli_ses.ecdh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
#if DROPBEAR_CURVE25519
|
||||
if (cli_ses.curve25519_param) {
|
||||
free_kexcurve25519_param(cli_ses.curve25519_param);
|
||||
cli_ses.curve25519_param = NULL;
|
||||
@@ -169,7 +175,8 @@ void recv_msg_kexdh_reply() {
|
||||
#endif
|
||||
|
||||
cli_ses.param_kex_algo = NULL;
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
|
||||
if (buf_verify(ses.payload, hostkey, ses.newkeys->algo_signature,
|
||||
ses.hash) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad hostkey signature");
|
||||
}
|
||||
|
||||
@@ -181,7 +188,7 @@ void recv_msg_kexdh_reply() {
|
||||
TRACE(("leave recv_msg_kexdh_init"))
|
||||
}
|
||||
|
||||
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen,
|
||||
static void ask_to_confirm(const unsigned char* keyblob, unsigned int keybloblen,
|
||||
const char* algoname) {
|
||||
|
||||
char* fp = NULL;
|
||||
@@ -278,7 +285,7 @@ out:
|
||||
return hostsfile;
|
||||
}
|
||||
|
||||
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
FILE *hostsfile = NULL;
|
||||
int readonly = 0;
|
||||
@@ -406,3 +413,38 @@ out:
|
||||
}
|
||||
m_free(fingerprint);
|
||||
}
|
||||
|
||||
void recv_msg_ext_info(void) {
|
||||
/* This message is not client-specific in the protocol but Dropbear only handles
|
||||
a server-sent message at present. */
|
||||
unsigned int num_ext;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("enter recv_msg_ext_info"))
|
||||
|
||||
/* Must be after the first SSH_MSG_NEWKEYS */
|
||||
TRACE(("last %d, donefirst %d, donescond %d", ses.lastpacket, ses.kexstate.donefirstkex, ses.kexstate.donesecondkex))
|
||||
if (!(ses.lastpacket == SSH_MSG_NEWKEYS && !ses.kexstate.donesecondkex)) {
|
||||
TRACE(("leave recv_msg_ext_info: ignoring packet received at the wrong time"))
|
||||
return;
|
||||
}
|
||||
|
||||
num_ext = buf_getint(ses.payload);
|
||||
TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext))
|
||||
|
||||
for (i = 0; i < num_ext; i++) {
|
||||
unsigned int name_len;
|
||||
char *ext_name = buf_getstring(ses.payload, &name_len);
|
||||
TRACE(("extension %d name '%s'", i, ext_name))
|
||||
if (cli_ses.server_sig_algs == NULL
|
||||
&& name_len == strlen(SSH_SERVER_SIG_ALGS)
|
||||
&& strcmp(ext_name, SSH_SERVER_SIG_ALGS) == 0) {
|
||||
cli_ses.server_sig_algs = buf_getbuf(ses.payload);
|
||||
} else {
|
||||
/* valid extension values could be >MAX_STRING_LEN */
|
||||
buf_eatstring(ses.payload);
|
||||
}
|
||||
m_free(ext_name);
|
||||
}
|
||||
TRACE(("leave recv_msg_ext_info"))
|
||||
}
|
||||
|
||||
68
cli-main.c
68
cli-main.c
@@ -35,13 +35,13 @@
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
static void cli_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
|
||||
static void kill_proxy_sighandler(int signo);
|
||||
#endif
|
||||
|
||||
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dbclient) || !DROPBEAR_MULTI
|
||||
#if defined(DBMULTI_dbclient) && DROPBEAR_MULTI
|
||||
int cli_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
@@ -66,15 +66,15 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
|
||||
cli_opts.remotehost, cli_opts.remoteport))
|
||||
TRACE(("user='%s' host='%s' port='%s' bind_address='%s' bind_port='%s'", cli_opts.username,
|
||||
cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address, cli_opts.bind_port))
|
||||
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
pid_t proxy_cmd_pid = 0;
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
cli_proxy_cmd(&sock_in, &sock_out, &proxy_cmd_pid);
|
||||
m_free(cli_opts.proxycmd);
|
||||
@@ -86,7 +86,8 @@ int main(int argc, char ** argv) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses);
|
||||
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
|
||||
cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port);
|
||||
sock_in = sock_out = -1;
|
||||
}
|
||||
|
||||
@@ -98,29 +99,31 @@ int main(int argc, char ** argv) {
|
||||
#endif /* DBMULTI stuff */
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
char exitmsg[150];
|
||||
char fullmsg[300];
|
||||
|
||||
char fmtbuf[300];
|
||||
char exitmsg[500];
|
||||
/* Note that exit message must be rendered before session cleanup */
|
||||
|
||||
if (!sessinitdone) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
|
||||
format);
|
||||
/* Render the formatted exit message */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), format, param);
|
||||
TRACE(("Exited, cleaning up: %s", exitmsg))
|
||||
|
||||
/* Add the prefix depending on session/auth state */
|
||||
if (!ses.init_done) {
|
||||
snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
|
||||
} else {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf),
|
||||
snprintf(fullmsg, sizeof(fullmsg),
|
||||
"Connection to %s@%s:%s exited: %s",
|
||||
cli_opts.username, cli_opts.remotehost,
|
||||
cli_opts.remoteport, format);
|
||||
cli_opts.remoteport, exitmsg);
|
||||
}
|
||||
|
||||
/* Arguments to the exit printout may be unsafe to use after session_cleanup() */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param);
|
||||
|
||||
/* Do the cleanup first, since then the terminal will be reset */
|
||||
session_cleanup();
|
||||
/* Avoid printing onwards from terminal cruft */
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
dropbear_log(LOG_INFO, "%s", exitmsg);;
|
||||
dropbear_log(LOG_INFO, "%s", fullmsg);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
@@ -128,6 +131,12 @@ static void cli_dropbear_log(int priority,
|
||||
const char* format, va_list param) {
|
||||
|
||||
char printbuf[1024];
|
||||
const char *name;
|
||||
|
||||
name = cli_opts.progname;
|
||||
if (!name) {
|
||||
name = "dbclient";
|
||||
}
|
||||
|
||||
vsnprintf(printbuf, sizeof(printbuf), format, param);
|
||||
|
||||
@@ -137,11 +146,11 @@ static void cli_dropbear_log(int priority,
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
|
||||
fprintf(stderr, "%s: %s\n", name, printbuf);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
static void exec_proxy_cmd(void *user_data_cmd) {
|
||||
static void exec_proxy_cmd(const void *user_data_cmd) {
|
||||
const char *cmd = user_data_cmd;
|
||||
char *usershell;
|
||||
|
||||
@@ -150,12 +159,27 @@ static void exec_proxy_cmd(void *user_data_cmd) {
|
||||
dropbear_exit("Failed to run '%s'\n", cmd);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out) {
|
||||
char * ex_cmd = NULL;
|
||||
size_t ex_cmdlen;
|
||||
int ret;
|
||||
|
||||
/* File descriptor "-j &3" */
|
||||
if (*cli_opts.proxycmd == '&') {
|
||||
char *p = cli_opts.proxycmd + 1;
|
||||
int sock = strtoul(p, &p, 10);
|
||||
/* must be a single number, and not stdin/stdout/stderr */
|
||||
if (sock > 2 && sock < 1024 && *p == '\0') {
|
||||
*sock_in = sock;
|
||||
*sock_out = sock;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Normal proxycommand */
|
||||
|
||||
/* So that spawn_command knows which shell to run */
|
||||
fill_passwd(cli_opts.own_user);
|
||||
|
||||
ex_cmdlen = strlen(cli_opts.proxycmd) + 6; /* "exec " + command + '\0' */
|
||||
@@ -175,4 +199,4 @@ static void kill_proxy_sighandler(int UNUSED(signo)) {
|
||||
kill_proxy_command();
|
||||
_exit(1);
|
||||
}
|
||||
#endif /* ENABLE_CLI_PROXYCMD */
|
||||
#endif /* DROPBEAR_CLI_PROXYCMD */
|
||||
|
||||
148
cli-runopts.c
148
cli-runopts.c
@@ -37,13 +37,13 @@ static void printhelp(void);
|
||||
static void parse_hostname(const char* orighostarg);
|
||||
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
|
||||
static void fill_own_user(void);
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename, int warnfail);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
#if DROPBEAR_CLI_ANYTCPFWD
|
||||
static void addforward(const char* str, m_list *fwdlist);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
static void add_netcat(const char *str);
|
||||
#endif
|
||||
static void add_extendedopt(const char *str);
|
||||
@@ -51,7 +51,7 @@ static void add_extendedopt(const char *str);
|
||||
static void printhelp() {
|
||||
|
||||
fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
#if DROPBEAR_CLI_MULTIHOP
|
||||
"Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
|
||||
#else
|
||||
"Usage: %s [options] [user@]host[/port] [command]\n"
|
||||
@@ -66,38 +66,39 @@ static void printhelp() {
|
||||
"-y -y Don't perform any remote host key checking (caution)\n"
|
||||
"-s Request a subsystem (use by external sftp)\n"
|
||||
"-o option Set option in OpenSSH-like format ('-o help' to list options)\n"
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
"-i <identityfile> (multiple allowed, default %s)\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
"-A Enable agent auth forwarding\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
"-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n"
|
||||
"-g Allow remote hosts to connect to forwarded ports\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
"-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
|
||||
#endif
|
||||
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
|
||||
"-K <keepalive> (0 is never, default %d)\n"
|
||||
"-I <idle_timeout> (0 is never, default %d)\n"
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
"-B <endhost:endport> Netcat-alike forwarding\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
"-J <proxy_program> Use program pipe rather than TCP connection\n"
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
|
||||
"-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
|
||||
#endif
|
||||
"-b [bind_address][:bind_port]\n"
|
||||
"-V Version\n"
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
"-v verbose (compiled with DEBUG_TRACE)\n"
|
||||
#endif
|
||||
,DROPBEAR_VERSION, cli_opts.progname,
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
DROPBEAR_DEFAULT_CLI_AUTHKEY,
|
||||
#endif
|
||||
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
|
||||
@@ -106,31 +107,31 @@ static void printhelp() {
|
||||
|
||||
void cli_getopts(int argc, char ** argv) {
|
||||
unsigned int i, j;
|
||||
char ** next = 0;
|
||||
char ** next = NULL;
|
||||
enum {
|
||||
OPT_EXTENDED_OPTIONS,
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
OPT_AUTHKEY,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
OPT_LOCALTCPFWD,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
OPT_REMOTETCPFWD,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
OPT_NETCAT,
|
||||
#endif
|
||||
/* a flag (no arg) if 'next' is NULL, a string-valued option otherwise */
|
||||
OPT_OTHER
|
||||
} opt;
|
||||
unsigned int cmdlen;
|
||||
char* dummy = NULL; /* Not used for anything real */
|
||||
|
||||
char* recv_window_arg = NULL;
|
||||
char* keepalive_arg = NULL;
|
||||
char* idle_timeout_arg = NULL;
|
||||
char *host_arg = NULL;
|
||||
char *bind_arg = NULL;
|
||||
char c;
|
||||
|
||||
/* see printhelp() for options */
|
||||
@@ -145,31 +146,33 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.always_accept_key = 0;
|
||||
cli_opts.no_hostkey_check = 0;
|
||||
cli_opts.is_subsystem = 0;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
cli_opts.privkeys = list_new();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
#if DROPBEAR_CLI_ANYTCPFWD
|
||||
cli_opts.exit_on_fwd_failure = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
cli_opts.localfwds = list_new();
|
||||
opts.listen_fwd_all = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
cli_opts.remotefwds = list_new();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
cli_opts.agent_fwd = 0;
|
||||
cli_opts.agent_fd = -1;
|
||||
cli_opts.agent_keys_loaded = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
cli_opts.proxycmd = NULL;
|
||||
#endif
|
||||
cli_opts.bind_address = NULL;
|
||||
cli_opts.bind_port = NULL;
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.compress_mode = DROPBEAR_COMPRESS_ON;
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
opts.cipher_list = NULL;
|
||||
opts.mac_list = NULL;
|
||||
#endif
|
||||
@@ -211,9 +214,9 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.always_accept_key = 1;
|
||||
break;
|
||||
case 'p': /* remoteport */
|
||||
next = &cli_opts.remoteport;
|
||||
next = (char**)&cli_opts.remoteport;
|
||||
break;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
case 'i': /* an identityfile */
|
||||
opt = OPT_AUTHKEY;
|
||||
break;
|
||||
@@ -236,7 +239,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
case 'o':
|
||||
opt = OPT_EXTENDED_OPTIONS;
|
||||
break;
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
case 'L':
|
||||
opt = OPT_LOCALTCPFWD;
|
||||
break;
|
||||
@@ -244,17 +247,17 @@ void cli_getopts(int argc, char ** argv) {
|
||||
opts.listen_fwd_all = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
case 'R':
|
||||
opt = OPT_REMOTETCPFWD;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
case 'B':
|
||||
opt = OPT_NETCAT;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
case 'J':
|
||||
next = &cli_opts.proxycmd;
|
||||
break;
|
||||
@@ -278,12 +281,12 @@ void cli_getopts(int argc, char ** argv) {
|
||||
case 'I':
|
||||
next = &idle_timeout_arg;
|
||||
break;
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
case 'A':
|
||||
cli_opts.agent_fwd = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
case 'c':
|
||||
next = &opts.cipher_list;
|
||||
break;
|
||||
@@ -291,22 +294,22 @@ void cli_getopts(int argc, char ** argv) {
|
||||
next = &opts.mac_list;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
case 'v':
|
||||
debug_trace = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'F':
|
||||
case 'e':
|
||||
#ifndef ENABLE_USER_ALGO_LIST
|
||||
#if !DROPBEAR_USER_ALGO_LIST
|
||||
case 'c':
|
||||
case 'm':
|
||||
#endif
|
||||
case 'D':
|
||||
#ifndef ENABLE_CLI_REMOTETCPFWD
|
||||
#if !DROPBEAR_CLI_REMOTETCPFWD
|
||||
case 'R':
|
||||
#endif
|
||||
#ifndef ENABLE_CLI_LOCALTCPFWD
|
||||
#if !DROPBEAR_CLI_LOCALTCPFWD
|
||||
case 'L':
|
||||
#endif
|
||||
case 'V':
|
||||
@@ -314,8 +317,8 @@ void cli_getopts(int argc, char ** argv) {
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'b':
|
||||
next = &dummy;
|
||||
/* FALLTHROUGH */
|
||||
next = &bind_arg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"WARNING: Ignoring unknown option -%c\n", c);
|
||||
@@ -338,28 +341,28 @@ void cli_getopts(int argc, char ** argv) {
|
||||
add_extendedopt(&argv[i][j]);
|
||||
}
|
||||
else
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
if (opt == OPT_AUTHKEY) {
|
||||
TRACE(("opt authkey"))
|
||||
loadidentityfile(&argv[i][j], 1);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
if (opt == OPT_REMOTETCPFWD) {
|
||||
TRACE(("opt remotetcpfwd"))
|
||||
addforward(&argv[i][j], cli_opts.remotefwds);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
if (opt == OPT_LOCALTCPFWD) {
|
||||
TRACE(("opt localtcpfwd"))
|
||||
addforward(&argv[i][j], cli_opts.localfwds);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
if (opt == OPT_NETCAT) {
|
||||
TRACE(("opt netcat"))
|
||||
add_netcat(&argv[i][j]);
|
||||
@@ -375,6 +378,11 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
/* -c help doesn't need a hostname */
|
||||
parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
/* Done with options/flags; now handle the hostname (which may not
|
||||
* start with a hyphen) and optional command */
|
||||
|
||||
@@ -405,11 +413,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* And now a few sanity checks and setup */
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
/* To match the common path of m_freeing it */
|
||||
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
|
||||
@@ -420,6 +424,18 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.remoteport = "22";
|
||||
}
|
||||
|
||||
if (bind_arg) {
|
||||
/* split [host][:port] */
|
||||
char *port = strrchr(bind_arg, ':');
|
||||
if (port) {
|
||||
cli_opts.bind_port = m_strdup(port+1);
|
||||
*port = '\0';
|
||||
}
|
||||
if (strlen(bind_arg) > 0) {
|
||||
cli_opts.bind_address = m_strdup(bind_arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* If not explicitly specified with -t or -T, we don't want a pty if
|
||||
* there's a command, but we do otherwise */
|
||||
if (cli_opts.wantpty == 9) {
|
||||
@@ -457,13 +473,13 @@ void cli_getopts(int argc, char ** argv) {
|
||||
opts.idle_timeout_secs = val;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
if (cli_opts.cmd && cli_opts.netcat_host) {
|
||||
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_DEFAULT_CLI_AUTHKEY) && defined(ENABLE_CLI_PUBKEY_AUTH)
|
||||
#if (DROPBEAR_CLI_PUBKEY_AUTH)
|
||||
{
|
||||
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
|
||||
loadidentityfile(expand_path, 0);
|
||||
@@ -474,14 +490,14 @@ void cli_getopts(int argc, char ** argv) {
|
||||
/* The hostname gets set up last, since
|
||||
* in multi-hop mode it will require knowledge
|
||||
* of other flags such as -i */
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
#if DROPBEAR_CLI_MULTIHOP
|
||||
parse_multihop_hostname(host_arg, argv[0]);
|
||||
#else
|
||||
parse_hostname(host_arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename, int warnfail) {
|
||||
sign_key *key;
|
||||
enum signkey_type keytype;
|
||||
@@ -504,7 +520,7 @@ static void loadidentityfile(const char* filename, int warnfail) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
#if DROPBEAR_CLI_MULTIHOP
|
||||
|
||||
static char*
|
||||
multihop_passthrough_args() {
|
||||
@@ -514,13 +530,13 @@ multihop_passthrough_args() {
|
||||
m_list_elem *iter;
|
||||
/* Fill out -i, -y, -W options that make sense for all
|
||||
* the intermediate processes */
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
len += 3 + strlen(key->filename);
|
||||
}
|
||||
#endif /* ENABLE_CLI_PUBKEY_AUTH */
|
||||
#endif /* DROPBEAR_CLI_PUBKEY_AUTH */
|
||||
|
||||
len += 30; /* space for -W <size>, terminator. */
|
||||
ret = m_malloc(len);
|
||||
@@ -543,7 +559,7 @@ multihop_passthrough_args() {
|
||||
total += written;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
@@ -552,7 +568,7 @@ multihop_passthrough_args() {
|
||||
dropbear_assert((unsigned int)written < size);
|
||||
total += written;
|
||||
}
|
||||
#endif /* ENABLE_CLI_PUBKEY_AUTH */
|
||||
#endif /* DROPBEAR_CLI_PUBKEY_AUTH */
|
||||
|
||||
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
|
||||
if (total > 0)
|
||||
@@ -636,7 +652,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
}
|
||||
m_free(hostbuf);
|
||||
}
|
||||
#endif /* !ENABLE_CLI_MULTIHOP */
|
||||
#endif /* !DROPBEAR_CLI_MULTIHOP */
|
||||
|
||||
/* Parses a [user@]hostname[/port] argument. */
|
||||
static void parse_hostname(const char* orighostarg) {
|
||||
@@ -675,7 +691,7 @@ static void parse_hostname(const char* orighostarg) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
static void add_netcat(const char* origstr) {
|
||||
char *portstr = NULL;
|
||||
|
||||
@@ -728,7 +744,7 @@ static void fill_own_user() {
|
||||
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
#if DROPBEAR_CLI_ANYTCPFWD
|
||||
/* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
|
||||
* set, and add it to the forwarding list */
|
||||
static void addforward(const char* origstr, m_list *fwdlist) {
|
||||
@@ -870,17 +886,18 @@ static void add_extendedopt(const char* origstr) {
|
||||
|
||||
if (strcmp(origstr, "help") == 0) {
|
||||
dropbear_log(LOG_INFO, "Available options:\n"
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
#if DROPBEAR_CLI_ANYTCPFWD
|
||||
"\tExitOnForwardFailure\n"
|
||||
#endif
|
||||
#ifndef DISABLE_SYSLOG
|
||||
"\tUseSyslog\n"
|
||||
#endif
|
||||
"\tPort\n"
|
||||
);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
#if DROPBEAR_CLI_ANYTCPFWD
|
||||
if (match_extendedopt(&optstr, "ExitOnForwardFailure") == DROPBEAR_SUCCESS) {
|
||||
cli_opts.exit_on_fwd_failure = parse_flag_value(optstr);
|
||||
return;
|
||||
@@ -894,5 +911,10 @@ static void add_extendedopt(const char* origstr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (match_extendedopt(&optstr, "Port") == DROPBEAR_SUCCESS) {
|
||||
cli_opts.remoteport = optstr;
|
||||
return;
|
||||
}
|
||||
|
||||
dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli},
|
||||
{SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_CHANNEL_FAILURE, ignore_recv_response},
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
|
||||
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
|
||||
#else
|
||||
@@ -81,14 +81,15 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
|
||||
#endif
|
||||
{0, 0} /* End */
|
||||
{SSH_MSG_EXT_INFO, recv_msg_ext_info},
|
||||
{0, NULL} /* End */
|
||||
};
|
||||
|
||||
static const struct ChanType *cli_chantypes[] = {
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
&cli_chan_tcpremote,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
&cli_chan_agent,
|
||||
#endif
|
||||
NULL /* Null termination */
|
||||
@@ -118,7 +119,7 @@ void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection
|
||||
cli_session_init(proxy_cmd_pid);
|
||||
|
||||
/* Ready to go */
|
||||
sessinitdone = 1;
|
||||
ses.init_done = 1;
|
||||
|
||||
/* Exchange identification */
|
||||
send_session_identification();
|
||||
@@ -133,7 +134,7 @@ void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_KEX_FIRST_FOLLOWS
|
||||
#if DROPBEAR_KEX_FIRST_FOLLOWS
|
||||
static void cli_send_kex_first_guess() {
|
||||
send_msg_kexdh_init();
|
||||
}
|
||||
@@ -165,13 +166,6 @@ static void cli_session_init(pid_t proxy_cmd_pid) {
|
||||
cli_ses.lastprivkey = NULL;
|
||||
cli_ses.lastauthtype = 0;
|
||||
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
cli_ses.cipher_none_after_auth = get_algo_usable(sshciphers, "none");
|
||||
set_algo_usable(sshciphers, "none", 0);
|
||||
#else
|
||||
cli_ses.cipher_none_after_auth = 0;
|
||||
#endif
|
||||
|
||||
/* For printing "remote host closed" for the user */
|
||||
ses.remoteclosed = cli_remoteclosed;
|
||||
|
||||
@@ -182,13 +176,13 @@ static void cli_session_init(pid_t proxy_cmd_pid) {
|
||||
|
||||
ses.isserver = 0;
|
||||
|
||||
#ifdef USE_KEX_FIRST_FOLLOWS
|
||||
#if DROPBEAR_KEX_FIRST_FOLLOWS
|
||||
ses.send_kex_first_guess = cli_send_kex_first_guess;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void send_msg_service_request(char* servicename) {
|
||||
static void send_msg_service_request(const char* servicename) {
|
||||
|
||||
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
|
||||
|
||||
@@ -275,19 +269,11 @@ static void cli_sessionloop() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
if (cli_ses.cipher_none_after_auth)
|
||||
{
|
||||
set_algo_usable(sshciphers, "none", 1);
|
||||
send_msg_kexinit();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.backgrounded) {
|
||||
int devnull;
|
||||
/* keeping stdin open steals input from the terminal and
|
||||
is confusing, though stdout/stderr could be useful. */
|
||||
devnull = open(_PATH_DEVNULL, O_RDONLY);
|
||||
devnull = open(DROPBEAR_PATH_DEVNULL, O_RDONLY);
|
||||
if (devnull < 0) {
|
||||
dropbear_exit("Opening /dev/null: %d %s",
|
||||
errno, strerror(errno));
|
||||
@@ -299,7 +285,7 @@ static void cli_sessionloop() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
if (cli_opts.netcat_host) {
|
||||
cli_send_netcat_request();
|
||||
} else
|
||||
@@ -308,10 +294,10 @@ static void cli_sessionloop() {
|
||||
cli_send_chansess_request();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
setup_localtcp();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
setup_remotetcp();
|
||||
#endif
|
||||
|
||||
@@ -353,7 +339,7 @@ void kill_proxy_command(void) {
|
||||
|
||||
static void cli_session_cleanup(void) {
|
||||
|
||||
if (!sessinitdone) {
|
||||
if (!ses.init_done) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -367,10 +353,13 @@ static void cli_session_cleanup(void) {
|
||||
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
|
||||
|
||||
cli_tty_cleanup();
|
||||
|
||||
if (cli_ses.server_sig_algs) {
|
||||
buf_free(cli_ses.server_sig_algs);
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_finished() {
|
||||
TRACE(("cli_finished()"))
|
||||
|
||||
session_cleanup();
|
||||
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
||||
|
||||
25
cli-tcpfwd.c
25
cli-tcpfwd.c
@@ -23,7 +23,6 @@
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
#include "dbutil.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "channel.h"
|
||||
@@ -32,7 +31,7 @@
|
||||
#include "ssh.h"
|
||||
#include "netio.h"
|
||||
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
static int newtcpforwarded(struct Channel * channel);
|
||||
|
||||
const struct ChanType cli_chan_tcpremote = {
|
||||
@@ -41,11 +40,12 @@ const struct ChanType cli_chan_tcpremote = {
|
||||
newtcpforwarded,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
static int cli_localtcp(const char* listenaddr,
|
||||
unsigned int listenport,
|
||||
const char* remoteaddr,
|
||||
@@ -56,11 +56,12 @@ static const struct ChanType cli_chan_tcplocal = {
|
||||
tcp_prio_inithandler,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
#if DROPBEAR_CLI_ANYTCPFWD
|
||||
static void fwd_failed(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
static void fwd_failed(const char* format, ...)
|
||||
{
|
||||
@@ -77,7 +78,7 @@ static void fwd_failed(const char* format, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
void setup_localtcp() {
|
||||
m_list_elem *iter;
|
||||
int ret;
|
||||
@@ -136,7 +137,7 @@ static int cli_localtcp(const char* listenaddr,
|
||||
tcpinfo->chantype = &cli_chan_tcplocal;
|
||||
tcpinfo->tcp_type = direct;
|
||||
|
||||
ret = listen_tcpfwd(tcpinfo);
|
||||
ret = listen_tcpfwd(tcpinfo, NULL);
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(tcpinfo);
|
||||
@@ -144,9 +145,9 @@ static int cli_localtcp(const char* listenaddr,
|
||||
TRACE(("leave cli_localtcp: %d", ret))
|
||||
return ret;
|
||||
}
|
||||
#endif /* ENABLE_CLI_LOCALTCPFWD */
|
||||
#endif /* DROPBEAR_CLI_LOCALTCPFWD */
|
||||
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
static void send_msg_global_request_remotetcp(const char *addr, int port) {
|
||||
|
||||
TRACE(("enter send_msg_global_request_remotetcp"))
|
||||
@@ -234,7 +235,7 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
char *origaddr = NULL;
|
||||
unsigned int origport;
|
||||
m_list_elem * iter = NULL;
|
||||
struct TCPFwdEntry *fwd;
|
||||
struct TCPFwdEntry *fwd = NULL;
|
||||
char portstring[NI_MAXSERV];
|
||||
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
@@ -265,7 +266,7 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
}
|
||||
|
||||
|
||||
if (iter == NULL) {
|
||||
if (iter == NULL || fwd == NULL) {
|
||||
/* We didn't request forwarding on that port */
|
||||
cleantext(origaddr);
|
||||
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
|
||||
@@ -274,7 +275,7 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
}
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%u", fwd->connectport);
|
||||
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel);
|
||||
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL, NULL);
|
||||
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
|
||||
@@ -285,4 +286,4 @@ out:
|
||||
TRACE(("leave newtcpdirect: err %d", err))
|
||||
return err;
|
||||
}
|
||||
#endif /* ENABLE_CLI_REMOTETCPFWD */
|
||||
#endif /* DROPBEAR_CLI_REMOTETCPFWD */
|
||||
|
||||
446
common-algo.c
446
common-algo.c
@@ -30,6 +30,9 @@
|
||||
#include "dh_groups.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
#include "gcm.h"
|
||||
#include "chachapoly.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* This file (algo.c) organises the ciphers which can be used, and is used to
|
||||
* decide which ciphers/hashes/compression/signing to use during key exchange*/
|
||||
@@ -53,27 +56,23 @@ static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
|
||||
/* Remember to add new ciphers/hashes to regciphers/reghashes too */
|
||||
|
||||
#ifdef DROPBEAR_AES256
|
||||
#if DROPBEAR_AES256
|
||||
static const struct dropbear_cipher dropbear_aes256 =
|
||||
{&aes_desc, 32, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES128
|
||||
#if DROPBEAR_AES128
|
||||
static const struct dropbear_cipher dropbear_aes128 =
|
||||
{&aes_desc, 16, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
static const struct dropbear_cipher dropbear_blowfish =
|
||||
{&blowfish_desc, 16, 8};
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH256
|
||||
#if DROPBEAR_TWOFISH256
|
||||
static const struct dropbear_cipher dropbear_twofish256 =
|
||||
{&twofish_desc, 32, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
#if DROPBEAR_TWOFISH128
|
||||
static const struct dropbear_cipher dropbear_twofish128 =
|
||||
{&twofish_desc, 16, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
#if DROPBEAR_3DES
|
||||
static const struct dropbear_cipher dropbear_3des =
|
||||
{&des3_desc, 24, 8};
|
||||
#endif
|
||||
@@ -84,15 +83,15 @@ const struct dropbear_cipher dropbear_nocipher =
|
||||
|
||||
/* A few void* s are required to silence warnings
|
||||
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
|
||||
#ifdef DROPBEAR_ENABLE_CBC_MODE
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
const struct dropbear_cipher_mode dropbear_mode_cbc =
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_none =
|
||||
{void_start, void_cipher, void_cipher};
|
||||
{void_start, void_cipher, void_cipher, NULL, NULL, NULL};
|
||||
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
/* a wrapper to make ctr_start and cbc_start look the same */
|
||||
static int dropbear_big_endian_ctr_start(int cipher,
|
||||
const unsigned char *IV,
|
||||
@@ -101,29 +100,29 @@ static int dropbear_big_endian_ctr_start(int cipher,
|
||||
return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
|
||||
}
|
||||
const struct dropbear_cipher_mode dropbear_mode_ctr =
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
{&hash_desc, keysize, hashsize} */
|
||||
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
#if DROPBEAR_SHA1_HMAC
|
||||
static const struct dropbear_hash dropbear_sha1 =
|
||||
{&sha1_desc, 20, 20};
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA1_96_HMAC
|
||||
#if DROPBEAR_SHA1_96_HMAC
|
||||
static const struct dropbear_hash dropbear_sha1_96 =
|
||||
{&sha1_desc, 20, 12};
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
#if DROPBEAR_SHA2_256_HMAC
|
||||
static const struct dropbear_hash dropbear_sha2_256 =
|
||||
{&sha256_desc, 32, 32};
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
#if DROPBEAR_SHA2_512_HMAC
|
||||
static const struct dropbear_hash dropbear_sha2_512 =
|
||||
{&sha512_desc, 64, 64};
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
#if DROPBEAR_MD5_HMAC
|
||||
static const struct dropbear_hash dropbear_md5 =
|
||||
{&md5_desc, 16, 16};
|
||||
#endif
|
||||
@@ -137,72 +136,82 @@ const struct dropbear_hash dropbear_nohash =
|
||||
* that is also supported by the server will get used. */
|
||||
|
||||
algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
#ifdef DROPBEAR_AES128
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
{"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-gcm@openssh.com", 0, &dropbear_aes128, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-gcm@openssh.com", 0, &dropbear_aes256, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH_CTR
|
||||
#if DROPBEAR_TWOFISH_CTR
|
||||
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
|
||||
#ifdef DROPBEAR_TWOFISH256
|
||||
#if DROPBEAR_TWOFISH256
|
||||
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
#if DROPBEAR_TWOFISH128
|
||||
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#endif /* DROPBEAR_TWOFISH_CTR */
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
#ifdef DROPBEAR_ENABLE_CBC_MODE
|
||||
#ifdef DROPBEAR_AES128
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH256
|
||||
#if DROPBEAR_TWOFISH256
|
||||
{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
|
||||
{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
#if DROPBEAR_TWOFISH128
|
||||
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
#if DROPBEAR_3DES
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_3DES */
|
||||
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshhashes[] = {
|
||||
#ifdef DROPBEAR_SHA1_96_HMAC
|
||||
#if DROPBEAR_SHA1_96_HMAC
|
||||
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
#if DROPBEAR_SHA1_HMAC
|
||||
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
#if DROPBEAR_SHA2_256_HMAC
|
||||
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
#if DROPBEAR_SHA2_512_HMAC
|
||||
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
#if DROPBEAR_MD5_HMAC
|
||||
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_NONE_INTEGRITY
|
||||
{"none", 0, (void*)&dropbear_nohash, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -227,23 +236,31 @@ algo_type ssh_nocompress[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshhostkey[] = {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
algo_type sigalgs[] = {
|
||||
#if DROPBEAR_ED25519
|
||||
{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
#if DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECC_256
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
#if DROPBEAR_ECC_384
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
|
||||
#if DROPBEAR_RSA
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
{"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
{"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_DSS
|
||||
{"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -251,54 +268,54 @@ algo_type sshhostkey[] = {
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
|
||||
#endif
|
||||
#if DROPBEAR_DH_GROUP14
|
||||
#if DROPBEAR_DH_GROUP14_SHA1
|
||||
static const struct dropbear_kex kex_dh_group14_sha1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
|
||||
#if DROPBEAR_DH_GROUP14_256
|
||||
static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha256_desc };
|
||||
#endif
|
||||
#if DROPBEAR_DH_GROUP14_SHA256
|
||||
static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha256_desc };
|
||||
#endif
|
||||
#if DROPBEAR_DH_GROUP16
|
||||
static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
|
||||
#endif
|
||||
|
||||
/* These can't be const since dropbear_ecc_fill_dp() fills out
|
||||
ecc_curve at runtime */
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#if DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECC_256
|
||||
static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
static const struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECC_521
|
||||
static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
|
||||
#endif
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
#if DROPBEAR_CURVE25519
|
||||
/* Referred to directly */
|
||||
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
|
||||
#endif
|
||||
|
||||
/* data == NULL for non-kex algorithm identifiers */
|
||||
algo_type sshkex[] = {
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
#if DROPBEAR_CURVE25519
|
||||
{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
|
||||
{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECC_521
|
||||
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#if DROPBEAR_ECC_256
|
||||
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_DH_GROUP14
|
||||
#if DROPBEAR_DH_GROUP14_256
|
||||
#if DROPBEAR_DH_GROUP14_SHA256
|
||||
{"diffie-hellman-group14-sha256", 0, &kex_dh_group14_sha256, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_DH_GROUP14_SHA1
|
||||
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14_sha1, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
@@ -307,49 +324,123 @@ algo_type sshkex[] = {
|
||||
#if DROPBEAR_DH_GROUP16
|
||||
{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
|
||||
#endif
|
||||
#ifdef USE_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_EXT_INFO
|
||||
#if DROPBEAR_CLIENT
|
||||
/* Set unusable by svr_algos_initialise() */
|
||||
{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
/* algolen specifies the length of algo, algos is our local list to match
|
||||
* against.
|
||||
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
|
||||
* otherwise */
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (strlen(algos[i].name) == algolen
|
||||
&& (strncmp(algos[i].name, algo, algolen) == 0)) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* Output a comma separated list of algorithms to a buffer */
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
|
||||
unsigned int i, len;
|
||||
unsigned int donefirst = 0;
|
||||
buffer *algolist = NULL;
|
||||
unsigned int startpos;
|
||||
|
||||
algolist = buf_new(300);
|
||||
startpos = buf->pos;
|
||||
/* Placeholder for length */
|
||||
buf_putint(buf, 0);
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
if (donefirst)
|
||||
buf_putbyte(algolist, ',');
|
||||
if (localalgos[i].usable || useall) {
|
||||
if (donefirst) {
|
||||
buf_putbyte(buf, ',');
|
||||
}
|
||||
donefirst = 1;
|
||||
len = strlen(localalgos[i].name);
|
||||
buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
|
||||
buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
|
||||
}
|
||||
}
|
||||
buf_putstring(buf, (const char*)algolist->data, algolist->len);
|
||||
buf_free(algolist);
|
||||
/* Fill out the length */
|
||||
len = buf->pos - startpos - 4;
|
||||
buf_setpos(buf, startpos);
|
||||
buf_putint(buf, len);
|
||||
TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
buf_put_algolist_all(buf, localalgos, 0);
|
||||
}
|
||||
|
||||
/* returns a list of pointers into algolist, of null-terminated names.
|
||||
ret_list should be passed in with space for *ret_count elements,
|
||||
on return *ret_count has the number of names filled.
|
||||
algolist is modified. */
|
||||
static void get_algolist(char* algolist, unsigned int algolist_len,
|
||||
const char* *ret_list, unsigned int *ret_count) {
|
||||
unsigned int max_count = *ret_count;
|
||||
unsigned int i;
|
||||
|
||||
if (*ret_count == 0) {
|
||||
return;
|
||||
}
|
||||
if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
*ret_count = 0;
|
||||
}
|
||||
|
||||
/* ret_list will contain a list of the strings parsed out.
|
||||
We will have at least one string (even if it's just "") */
|
||||
ret_list[0] = algolist;
|
||||
*ret_count = 1;
|
||||
for (i = 0; i < algolist_len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (algolist[i] == ',') {
|
||||
if (*ret_count >= max_count) {
|
||||
/* Too many */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
algolist[i] = '\0';
|
||||
ret_list[*ret_count] = &algolist[i+1];
|
||||
(*ret_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return DROPBEAR_SUCCESS if the namelist contains algo,
|
||||
DROPBEAR_FAILURE otherwise. buf position is not incremented. */
|
||||
int buf_has_algo(buffer *buf, const char *algo) {
|
||||
unsigned char* algolist = NULL;
|
||||
unsigned int orig_pos = buf->pos;
|
||||
unsigned int len, remotecount, i;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO];
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
algolist = buf_getstring(buf, &len);
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], algo) == 0) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (algolist) {
|
||||
m_free(algolist);
|
||||
}
|
||||
buf_setpos(buf, orig_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
algo_type * first_usable_algo(algo_type algos[]) {
|
||||
int i;
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (algos[i].usable) {
|
||||
return &algos[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
@@ -358,9 +449,7 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess)
|
||||
{
|
||||
|
||||
int kexguess2, int *goodguess) {
|
||||
char * algolist = NULL;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
@@ -375,40 +464,8 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* remotenames will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotenames[0] = algolist;
|
||||
remotecount = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotenames[remotecount] = &algolist[i+1];
|
||||
remotecount++;
|
||||
}
|
||||
if (remotecount >= MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
|
||||
*kexguess2 = KEXGUESS2_YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*kexguess2 == KEXGUESS2_LOOK) {
|
||||
*kexguess2 = KEXGUESS2_NO;
|
||||
}
|
||||
}
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
@@ -440,12 +497,11 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
}
|
||||
if (strcmp(servnames[j], clinames[i]) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (goodguess && kexguess2) {
|
||||
if (*kexguess2 == KEXGUESS2_YES) {
|
||||
if (goodguess != NULL) {
|
||||
if (kexguess2) {
|
||||
if (i == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
@@ -468,42 +524,10 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
|
||||
void
|
||||
set_algo_usable(algo_type algos[], const char * algo_name, int usable)
|
||||
{
|
||||
algo_type *a;
|
||||
for (a = algos; a->name != NULL; a++)
|
||||
{
|
||||
if (strcmp(a->name, algo_name) == 0)
|
||||
{
|
||||
a->usable = usable;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_algo_usable(algo_type algos[], const char * algo_name)
|
||||
{
|
||||
algo_type *a;
|
||||
for (a = algos; a->name != NULL; a++)
|
||||
{
|
||||
if (strcmp(a->name, algo_name) == 0)
|
||||
{
|
||||
return a->usable;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_NONE_CIPHER */
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
|
||||
char *
|
||||
algolist_string(algo_type algos[])
|
||||
algolist_string(const algo_type algos[])
|
||||
{
|
||||
char *ret_list;
|
||||
buffer *b = buf_new(200);
|
||||
@@ -531,21 +555,6 @@ check_algo(const char* algo_name, algo_type *algos)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
try_add_algo(const char *algo_name, algo_type *algos,
|
||||
const char *algo_desc, algo_type * new_algos, int *num_ret)
|
||||
{
|
||||
algo_type *match_algo = check_algo(algo_name, algos);
|
||||
if (!match_algo)
|
||||
{
|
||||
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
|
||||
return;
|
||||
}
|
||||
|
||||
new_algos[*num_ret] = *match_algo;
|
||||
(*num_ret)++;
|
||||
}
|
||||
|
||||
/* Checks a user provided comma-separated algorithm list for available
|
||||
* options. Any that are not acceptable are removed in-place. Returns the
|
||||
* number of valid algorithms. */
|
||||
@@ -553,30 +562,43 @@ int
|
||||
check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
const char *algo_desc)
|
||||
{
|
||||
algo_type new_algos[MAX_PROPOSED_ALGO];
|
||||
/* this has two passes. first we sweep through the given list of
|
||||
* algorithms and mark them as usable=2 in the algo_type[] array... */
|
||||
int num_ret = 0;
|
||||
algo_type new_algos[MAX_PROPOSED_ALGO+1];
|
||||
char *work_list = m_strdup(user_algo_list);
|
||||
char *last_name = work_list;
|
||||
char *start = work_list;
|
||||
char *c;
|
||||
for (c = work_list; *c; c++)
|
||||
int n;
|
||||
/* So we can iterate and look for null terminator */
|
||||
memset(new_algos, 0x0, sizeof(new_algos));
|
||||
for (c = work_list, n = 0; ; c++)
|
||||
{
|
||||
if (*c == ',')
|
||||
{
|
||||
char oc = *c;
|
||||
if (n >= MAX_PROPOSED_ALGO) {
|
||||
dropbear_exit("Too many algorithms '%s'", user_algo_list);
|
||||
}
|
||||
if (*c == ',' || *c == '\0') {
|
||||
algo_type *match_algo = NULL;
|
||||
*c = '\0';
|
||||
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
|
||||
match_algo = check_algo(start, algos);
|
||||
if (match_algo) {
|
||||
if (check_algo(start, new_algos)) {
|
||||
TRACE(("Skip repeated algorithm '%s'", start))
|
||||
} else {
|
||||
new_algos[n] = *match_algo;
|
||||
n++;
|
||||
}
|
||||
} else {
|
||||
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc);
|
||||
}
|
||||
c++;
|
||||
last_name = c;
|
||||
start = c;
|
||||
}
|
||||
if (oc == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
|
||||
m_free(work_list);
|
||||
|
||||
new_algos[num_ret].name = NULL;
|
||||
|
||||
/* Copy one more as a blank delimiter */
|
||||
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
|
||||
return num_ret;
|
||||
/* n+1 to include a null terminator */
|
||||
memcpy(algos, new_algos, sizeof(*new_algos) * (n+1));
|
||||
return n;
|
||||
}
|
||||
#endif /* ENABLE_USER_ALGO_LIST */
|
||||
#endif /* DROPBEAR_USER_ALGO_LIST */
|
||||
|
||||
@@ -32,25 +32,24 @@
|
||||
#include "circbuffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "channel.h"
|
||||
#include "ssh.h"
|
||||
#include "listener.h"
|
||||
#include "runopts.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
|
||||
const char *text, const char *lang);
|
||||
static void send_msg_channel_open_confirmation(struct Channel* channel,
|
||||
static void send_msg_channel_open_confirmation(const struct Channel* channel,
|
||||
unsigned int recvwindow,
|
||||
unsigned int recvmaxpacket);
|
||||
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *moredata, unsigned int *morelen);
|
||||
static void send_msg_channel_window_adjust(struct Channel *channel,
|
||||
static void send_msg_channel_window_adjust(const struct Channel *channel,
|
||||
unsigned int incr);
|
||||
static void send_msg_channel_data(struct Channel *channel, int isextended);
|
||||
static void send_msg_channel_eof(struct Channel *channel);
|
||||
static void send_msg_channel_close(struct Channel *channel);
|
||||
static void remove_channel(struct Channel *channel);
|
||||
static unsigned int write_pending(struct Channel * channel);
|
||||
static unsigned int write_pending(const struct Channel * channel);
|
||||
static void check_close(struct Channel *channel);
|
||||
static void close_chan_fd(struct Channel *channel, int fd, int how);
|
||||
|
||||
@@ -78,7 +77,7 @@ void chaninitialise(const struct ChanType *chantypes[]) {
|
||||
|
||||
ses.chantypes = chantypes;
|
||||
|
||||
#ifdef USING_LISTENERS
|
||||
#if DROPBEAR_LISTENERS
|
||||
listeners_initialise();
|
||||
#endif
|
||||
|
||||
@@ -145,7 +144,6 @@ static struct Channel* newchannel(unsigned int remotechan,
|
||||
newchan->index = i;
|
||||
newchan->sent_close = newchan->recv_close = 0;
|
||||
newchan->sent_eof = newchan->recv_eof = 0;
|
||||
newchan->close_handler_done = 0;
|
||||
|
||||
newchan->remotechan = remotechan;
|
||||
newchan->transwindow = transwindow;
|
||||
@@ -199,7 +197,7 @@ struct Channel* getchannel() {
|
||||
}
|
||||
|
||||
/* Iterate through the channels, performing IO if available */
|
||||
void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
void channelio(const fd_set *readfds, const fd_set *writefds) {
|
||||
|
||||
/* Listeners such as TCP, X11, agent-auth */
|
||||
struct Channel *channel;
|
||||
@@ -255,7 +253,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USING_LISTENERS
|
||||
#if DROPBEAR_LISTENERS
|
||||
handle_listeners(readfds);
|
||||
#endif
|
||||
}
|
||||
@@ -263,7 +261,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
|
||||
/* Returns true if there is data remaining to be written to stdin or
|
||||
* stderr of a channel's endpoint. */
|
||||
static unsigned int write_pending(struct Channel * channel) {
|
||||
static unsigned int write_pending(const struct Channel * channel) {
|
||||
|
||||
if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
|
||||
return 1;
|
||||
@@ -287,7 +285,7 @@ static void check_close(struct Channel *channel) {
|
||||
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
|
||||
|
||||
if (!channel->flushing
|
||||
&& !channel->close_handler_done
|
||||
&& !channel->sent_close
|
||||
&& channel->type->check_close
|
||||
&& channel->type->check_close(channel))
|
||||
{
|
||||
@@ -299,7 +297,7 @@ static void check_close(struct Channel *channel) {
|
||||
channel, to ensure that the shell has exited (and the exit status
|
||||
retrieved) before we close things up. */
|
||||
if (!channel->type->check_close
|
||||
|| channel->close_handler_done
|
||||
|| channel->sent_close
|
||||
|| channel->type->check_close(channel)) {
|
||||
close_allowed = 1;
|
||||
}
|
||||
@@ -386,10 +384,8 @@ void channel_connect_done(int result, int sock, void* user_data, const char* UNU
|
||||
static void send_msg_channel_close(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_close %p", (void*)channel))
|
||||
if (channel->type->closehandler
|
||||
&& !channel->close_handler_done) {
|
||||
if (channel->type->closehandler) {
|
||||
channel->type->closehandler(channel);
|
||||
channel->close_handler_done = 1;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -595,7 +591,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
|
||||
|
||||
} /* foreach channel */
|
||||
|
||||
#ifdef USING_LISTENERS
|
||||
#if DROPBEAR_LISTENERS
|
||||
set_listener_fds(readfds);
|
||||
#endif
|
||||
|
||||
@@ -662,10 +658,8 @@ static void remove_channel(struct Channel * channel) {
|
||||
m_close(channel->errfd);
|
||||
}
|
||||
|
||||
if (!channel->close_handler_done
|
||||
&& channel->type->closehandler) {
|
||||
channel->type->closehandler(channel);
|
||||
channel->close_handler_done = 1;
|
||||
if (channel->type->cleanup) {
|
||||
channel->type->cleanup(channel);
|
||||
}
|
||||
|
||||
if (channel->conn_pending) {
|
||||
@@ -691,13 +685,7 @@ void recv_msg_channel_request() {
|
||||
|
||||
TRACE(("enter recv_msg_channel_request %p", (void*)channel))
|
||||
|
||||
if (channel->sent_close) {
|
||||
TRACE(("leave recv_msg_channel_request: already closed channel"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->type->reqhandler
|
||||
&& !channel->close_handler_done) {
|
||||
if (channel->type->reqhandler) {
|
||||
channel->type->reqhandler(channel);
|
||||
} else {
|
||||
int wantreply;
|
||||
@@ -904,7 +892,7 @@ void recv_msg_channel_window_adjust() {
|
||||
|
||||
/* Increment the incoming data window for a channel, and let the remote
|
||||
* end know */
|
||||
static void send_msg_channel_window_adjust(struct Channel* channel,
|
||||
static void send_msg_channel_window_adjust(const struct Channel* channel,
|
||||
unsigned int incr) {
|
||||
|
||||
TRACE(("sending window adjust %d", incr))
|
||||
@@ -1009,9 +997,14 @@ cleanup:
|
||||
}
|
||||
|
||||
/* Send a failure message */
|
||||
void send_msg_channel_failure(struct Channel *channel) {
|
||||
void send_msg_channel_failure(const struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_failure"))
|
||||
|
||||
if (channel->sent_close) {
|
||||
TRACE(("Skipping sending msg_channel_failure for closed channel"))
|
||||
return;
|
||||
}
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
|
||||
@@ -1022,9 +1015,13 @@ void send_msg_channel_failure(struct Channel *channel) {
|
||||
}
|
||||
|
||||
/* Send a success message */
|
||||
void send_msg_channel_success(struct Channel *channel) {
|
||||
void send_msg_channel_success(const struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_success"))
|
||||
if (channel->sent_close) {
|
||||
TRACE(("Skipping sending msg_channel_success for closed channel"))
|
||||
return;
|
||||
}
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);
|
||||
@@ -1054,7 +1051,7 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
|
||||
|
||||
/* Confirm a channel open, and let the remote end know what number we've
|
||||
* allocated and the receive parameters */
|
||||
static void send_msg_channel_open_confirmation(struct Channel* channel,
|
||||
static void send_msg_channel_open_confirmation(const struct Channel* channel,
|
||||
unsigned int recvwindow,
|
||||
unsigned int recvmaxpacket) {
|
||||
|
||||
@@ -1114,7 +1111,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
}
|
||||
|
||||
|
||||
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
|
||||
#if (DROPBEAR_LISTENERS) || (DROPBEAR_CLIENT)
|
||||
/* Create a new channel, and start the open request. This is intended
|
||||
* for X11, agent, tcp forwarding, and should be filled with channel-specific
|
||||
* options, with the calling function calling encrypt_packet() after
|
||||
@@ -1210,7 +1207,7 @@ void recv_msg_channel_open_failure() {
|
||||
|
||||
remove_channel(channel);
|
||||
}
|
||||
#endif /* USING_LISTENERS */
|
||||
#endif /* DROPBEAR_LISTENERS */
|
||||
|
||||
void send_msg_request_success() {
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -1240,8 +1237,8 @@ struct Channel* get_any_ready_channel() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void start_send_channel_request(struct Channel *channel,
|
||||
char *type) {
|
||||
void start_send_channel_request(const struct Channel *channel,
|
||||
const char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
|
||||
166
common-kex.c
166
common-kex.c
@@ -36,6 +36,7 @@
|
||||
#include "dbrandom.h"
|
||||
#include "runopts.h"
|
||||
#include "ecc.h"
|
||||
#include "curve25519.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static void kexinitialise(void);
|
||||
@@ -48,7 +49,6 @@ static void read_kex_algos(void);
|
||||
/* helper function for gen_new_keys */
|
||||
static void hashkeys(unsigned char *out, unsigned int outlen,
|
||||
const hash_state * hs, const unsigned char X);
|
||||
static void finish_kexhashbuf(void);
|
||||
|
||||
|
||||
/* Send our list of algorithms we can use */
|
||||
@@ -65,7 +65,7 @@ void send_msg_kexinit() {
|
||||
buf_put_algolist(ses.writepayload, sshkex);
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
buf_put_algolist(ses.writepayload, sshhostkey);
|
||||
buf_put_algolist(ses.writepayload, sigalgs);
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshciphers);
|
||||
@@ -110,8 +110,9 @@ void send_msg_kexinit() {
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
|
||||
if (ses.send_kex_first_guess) {
|
||||
ses.newkeys->algo_kex = sshkex[0].data;
|
||||
ses.newkeys->algo_hostkey = sshhostkey[0].val;
|
||||
ses.newkeys->algo_kex = first_usable_algo(sshkex)->data;
|
||||
ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val;
|
||||
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
|
||||
ses.send_kex_first_guess();
|
||||
}
|
||||
|
||||
@@ -152,6 +153,7 @@ static void switch_keys() {
|
||||
TRACE(("switch_keys done"))
|
||||
ses.keys->algo_kex = ses.newkeys->algo_kex;
|
||||
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
|
||||
ses.keys->algo_signature = ses.newkeys->algo_signature;
|
||||
ses.keys->allow_compress = 0;
|
||||
m_free(ses.newkeys);
|
||||
ses.newkeys = NULL;
|
||||
@@ -173,6 +175,9 @@ void send_msg_newkeys() {
|
||||
|
||||
/* set up our state */
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
if (ses.kexstate.donefirstkex) {
|
||||
ses.kexstate.donesecondkex = 1;
|
||||
}
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
gen_new_keys();
|
||||
@@ -195,8 +200,6 @@ void recv_msg_newkeys() {
|
||||
|
||||
/* Set up the kex for the first time */
|
||||
void kexfirstinitialise() {
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifdef DISABLE_ZLIB
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
#else
|
||||
@@ -329,9 +332,13 @@ static void gen_new_keys() {
|
||||
hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
|
||||
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
|
||||
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
int recv_cipher = -1;
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) {
|
||||
recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv.algo_crypt->keysize, 0,
|
||||
@@ -341,9 +348,13 @@ static void gen_new_keys() {
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
|
||||
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
int trans_cipher = -1;
|
||||
if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) {
|
||||
trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans.algo_crypt->keysize, 0,
|
||||
@@ -391,6 +402,14 @@ int is_compress_recv() {
|
||||
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
}
|
||||
|
||||
static void* dropbear_zalloc(void* UNUSED(opaque), uInt items, uInt size) {
|
||||
return m_calloc(items, size);
|
||||
}
|
||||
|
||||
static void dropbear_zfree(void* UNUSED(opaque), void* ptr) {
|
||||
m_free(ptr);
|
||||
}
|
||||
|
||||
/* Set up new zlib compression streams, close the old ones. Only
|
||||
* called from gen_new_keys() */
|
||||
static void gen_new_zstream_recv() {
|
||||
@@ -399,8 +418,8 @@ static void gen_new_zstream_recv() {
|
||||
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->recv.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->recv.zstream->zfree = Z_NULL;
|
||||
ses.newkeys->recv.zstream->zalloc = dropbear_zalloc;
|
||||
ses.newkeys->recv.zstream->zfree = dropbear_zfree;
|
||||
|
||||
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
@@ -423,8 +442,8 @@ static void gen_new_zstream_trans() {
|
||||
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->trans.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->trans.zstream->zfree = Z_NULL;
|
||||
ses.newkeys->trans.zstream->zalloc = dropbear_zalloc;
|
||||
ses.newkeys->trans.zstream->zfree = dropbear_zfree;
|
||||
|
||||
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
|
||||
@@ -529,6 +548,7 @@ void recv_msg_kexinit() {
|
||||
TRACE(("leave recv_msg_kexinit"))
|
||||
}
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
static void load_dh_p(mp_int * dh_p)
|
||||
{
|
||||
bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes,
|
||||
@@ -553,9 +573,7 @@ struct kex_dh_param *gen_kexdh_param() {
|
||||
/* read the prime and generator*/
|
||||
load_dh_p(&dh_p);
|
||||
|
||||
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
mp_set_ul(&dh_g, DH_G_VAL);
|
||||
|
||||
/* calculate q = (p-1)/2 */
|
||||
/* dh_priv is just a temp var here */
|
||||
@@ -639,8 +657,9 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *gen_kexecdh_param() {
|
||||
struct kex_ecdh_param *param = m_malloc(sizeof(*param));
|
||||
if (ecc_make_key_ex(NULL, dropbear_ltc_prng,
|
||||
@@ -687,34 +706,32 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
ecc_free(Q_them);
|
||||
m_free(Q_them);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param () {
|
||||
#if DROPBEAR_CURVE25519
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param() {
|
||||
/* Per http://cr.yp.to/ecdh.html */
|
||||
struct kex_curve25519_param *param = m_malloc(sizeof(*param));
|
||||
const unsigned char basepoint[32] = {9};
|
||||
|
||||
genrandom(param->priv, CURVE25519_LEN);
|
||||
param->priv[0] &= 248;
|
||||
param->priv[31] &= 127;
|
||||
param->priv[31] |= 64;
|
||||
|
||||
curve25519_donna(param->pub, param->priv, basepoint);
|
||||
dropbear_curve25519_scalarmult(param->pub, param->priv, basepoint);
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param)
|
||||
{
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param) {
|
||||
m_burn(param->priv, CURVE25519_LEN);
|
||||
m_free(param);
|
||||
}
|
||||
|
||||
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_them,
|
||||
void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buffer *buf_pub_them,
|
||||
sign_key *hostkey) {
|
||||
unsigned char out[CURVE25519_LEN];
|
||||
const unsigned char* Q_C = NULL;
|
||||
@@ -726,7 +743,7 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
|
||||
dropbear_exit("Bad curve25519");
|
||||
}
|
||||
|
||||
curve25519_donna(out, param->priv, buf_pub_them->data);
|
||||
dropbear_curve25519_scalarmult(out, param->priv, buf_pub_them->data);
|
||||
|
||||
if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
|
||||
dropbear_exit("Bad curve25519");
|
||||
@@ -761,8 +778,7 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
|
||||
|
||||
static void finish_kexhashbuf(void) {
|
||||
void finish_kexhashbuf(void) {
|
||||
hash_state hs;
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
|
||||
@@ -774,7 +790,7 @@ static void finish_kexhashbuf(void) {
|
||||
hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize));
|
||||
buf_setlen(ses.hash, hash_desc->hashsize);
|
||||
|
||||
#if defined(DEBUG_KEXHASH) && defined(DEBUG_TRACE)
|
||||
#if defined(DEBUG_KEXHASH) && DEBUG_TRACE
|
||||
if (!debug_trace) {
|
||||
printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len);
|
||||
printhex("kexhash", ses.hash->data, ses.hash->len);
|
||||
@@ -813,21 +829,36 @@ static void read_kex_algos() {
|
||||
int goodguess = 0;
|
||||
int allgood = 1; /* we AND this with each goodguess and see if its still
|
||||
true after */
|
||||
|
||||
#ifdef USE_KEXGUESS2
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
|
||||
#else
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
|
||||
#endif
|
||||
int kexguess2 = 0;
|
||||
|
||||
buf_incrpos(ses.payload, 16); /* start after the cookie */
|
||||
|
||||
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
|
||||
|
||||
/* kex_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) {
|
||||
kexguess2 = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_EXT_INFO
|
||||
/* Determine if SSH_MSG_EXT_INFO messages should be sent.
|
||||
Should be done for the first key exchange. Only required on server side
|
||||
for server-sig-algs */
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
if (!ses.kexstate.donefirstkex) {
|
||||
if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) {
|
||||
ses.allow_ext_info = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
|
||||
if (algo == NULL || algo->data == NULL) {
|
||||
/* kexguess2, ext-info-c, ext-info-s should not match negotiation */
|
||||
erralgo = "kex";
|
||||
goto error;
|
||||
}
|
||||
@@ -836,17 +867,18 @@ static void read_kex_algos() {
|
||||
ses.newkeys->algo_kex = algo->data;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "hostkey";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hostkey algo %s", algo->name))
|
||||
ses.newkeys->algo_hostkey = algo->val;
|
||||
TRACE(("signature algo %s", algo->name))
|
||||
ses.newkeys->algo_signature = algo->val;
|
||||
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
|
||||
if (c2s_cipher_algo == NULL) {
|
||||
erralgo = "enc c->s";
|
||||
goto error;
|
||||
@@ -854,7 +886,7 @@ static void read_kex_algos() {
|
||||
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
|
||||
|
||||
/* encryption_algorithms_server_to_client */
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
|
||||
if (s2c_cipher_algo == NULL) {
|
||||
erralgo = "enc s->c";
|
||||
goto error;
|
||||
@@ -862,23 +894,33 @@ static void read_kex_algos() {
|
||||
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
|
||||
|
||||
/* mac_algorithms_client_to_server */
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) {
|
||||
c2s_hash_algo = NULL;
|
||||
} else
|
||||
#endif
|
||||
if (c2s_hash_algo == NULL) {
|
||||
erralgo = "mac c->s";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo->name))
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
|
||||
|
||||
/* mac_algorithms_server_to_client */
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) {
|
||||
s2c_hash_algo = NULL;
|
||||
} else
|
||||
#endif
|
||||
if (s2c_hash_algo == NULL) {
|
||||
erralgo = "mac s->c";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo->name))
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
|
||||
if (c2s_comp_algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
@@ -886,7 +928,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_comp_algo->name))
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
|
||||
if (s2c_comp_algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
@@ -920,8 +962,14 @@ static void read_kex_algos() {
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
|
||||
ses.newkeys->recv.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->trans.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
|
||||
@@ -936,13 +984,25 @@ static void read_kex_algos() {
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
|
||||
ses.newkeys->recv.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->trans.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
|
||||
}
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
fuzz_kex_fakealgos();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* reserved for future extensions */
|
||||
buf_getint(ses.payload);
|
||||
|
||||
|
||||
@@ -62,47 +62,38 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
void
|
||||
parse_ciphers_macs()
|
||||
{
|
||||
if (opts.cipher_list)
|
||||
{
|
||||
if (strcmp(opts.cipher_list, "help") == 0)
|
||||
{
|
||||
parse_ciphers_macs() {
|
||||
int printed_help = 0;
|
||||
if (opts.cipher_list) {
|
||||
if (strcmp(opts.cipher_list, "help") == 0) {
|
||||
char *ciphers = algolist_string(sshciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers: %s", ciphers);
|
||||
m_free(ciphers);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (strcmp(opts.cipher_list, "none") == 0)
|
||||
{
|
||||
/* Encryption is required during authentication */
|
||||
opts.cipher_list = "none,aes128-ctr";
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
|
||||
{
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0) {
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.mac_list)
|
||||
{
|
||||
if (strcmp(opts.mac_list, "help") == 0)
|
||||
{
|
||||
if (opts.mac_list) {
|
||||
if (strcmp(opts.mac_list, "help") == 0) {
|
||||
char *macs = algolist_string(sshhashes);
|
||||
dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
|
||||
dropbear_log(LOG_INFO, "Available MACs: %s", macs);
|
||||
m_free(macs);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
|
||||
{
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0) {
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (printed_help) {
|
||||
dropbear_exit(".");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -43,18 +43,11 @@ static void read_session_identification(void);
|
||||
|
||||
struct sshsession ses; /* GLOBAL */
|
||||
|
||||
/* need to know if the session struct has been initialised, this way isn't the
|
||||
* cleanest, but works OK */
|
||||
int sessinitdone = 0; /* GLOBAL */
|
||||
|
||||
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
|
||||
int exitflag = 0; /* GLOBAL */
|
||||
|
||||
/* called only at the start of a session, set up initial state */
|
||||
void common_session_init(int sock_in, int sock_out) {
|
||||
time_t now;
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
debug_start_net();
|
||||
#endif
|
||||
|
||||
@@ -75,6 +68,16 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
/* Sets it to lowdelay */
|
||||
update_channel_prio();
|
||||
|
||||
#if !DROPBEAR_SVR_MULTIUSER
|
||||
/* A sanity check to prevent an accidental configuration option
|
||||
leaving multiuser systems exposed */
|
||||
errno = 0;
|
||||
getuid();
|
||||
if (errno != ENOSYS) {
|
||||
dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
|
||||
}
|
||||
#endif
|
||||
|
||||
now = monotonic_now();
|
||||
ses.connect_time = now;
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
@@ -82,14 +85,18 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.last_packet_time_any_sent = 0;
|
||||
ses.last_packet_time_keepalive_sent = 0;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (!fuzz.fuzzing)
|
||||
#endif
|
||||
{
|
||||
if (pipe(ses.signal_pipe) < 0) {
|
||||
dropbear_exit("Signal pipe failed");
|
||||
}
|
||||
setnonblocking(ses.signal_pipe[0]);
|
||||
setnonblocking(ses.signal_pipe[1]);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
|
||||
}
|
||||
|
||||
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
|
||||
ses.transseq = 0;
|
||||
@@ -140,10 +147,14 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
ses.allowprivport = 0;
|
||||
|
||||
#if DROPBEAR_PLUGIN
|
||||
ses.plugin_session = NULL;
|
||||
#endif
|
||||
|
||||
TRACE(("leave session_init"))
|
||||
}
|
||||
|
||||
void session_loop(void(*loophandler)()) {
|
||||
void session_loop(void(*loophandler)(void)) {
|
||||
|
||||
fd_set readfd, writefd;
|
||||
struct timeval timeout;
|
||||
@@ -155,14 +166,19 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
timeout.tv_sec = select_timeout();
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&readfd);
|
||||
DROPBEAR_FD_ZERO(&writefd);
|
||||
DROPBEAR_FD_ZERO(&readfd);
|
||||
|
||||
dropbear_assert(ses.payload == NULL);
|
||||
|
||||
/* We get woken up when signal handlers write to this pipe.
|
||||
SIGCHLD in svr-chansession is the only one currently. */
|
||||
#if DROPBEAR_FUZZ
|
||||
if (!fuzz.fuzzing)
|
||||
#endif
|
||||
{
|
||||
FD_SET(ses.signal_pipe[0], &readfd);
|
||||
ses.channel_signal_pending = 0;
|
||||
}
|
||||
|
||||
/* set up for channels which can be read/written */
|
||||
setchannelfds(&readfd, &writefd, writequeue_has_space);
|
||||
@@ -190,7 +206,7 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
|
||||
|
||||
if (exitflag) {
|
||||
if (ses.exitflag) {
|
||||
dropbear_exit("Terminated by signal");
|
||||
}
|
||||
|
||||
@@ -203,13 +219,14 @@ void session_loop(void(*loophandler)()) {
|
||||
* want to iterate over channels etc for reading, to handle
|
||||
* server processes exiting etc.
|
||||
* We don't want to read/write FDs. */
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&readfd);
|
||||
DROPBEAR_FD_ZERO(&writefd);
|
||||
DROPBEAR_FD_ZERO(&readfd);
|
||||
}
|
||||
|
||||
/* We'll just empty out the pipe if required. We don't do
|
||||
any thing with the data, since the pipe's purpose is purely to
|
||||
wake up the select() above. */
|
||||
ses.channel_signal_pending = 0;
|
||||
if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
|
||||
char x;
|
||||
TRACE(("signal pipe set"))
|
||||
@@ -244,6 +261,10 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
handle_connect_fds(&writefd);
|
||||
|
||||
/* loop handler prior to channelio, in case the server loophandler closes
|
||||
channels on process exit */
|
||||
loophandler();
|
||||
|
||||
/* process pipes etc for the channels, ses.dataallowed == 0
|
||||
* during rekeying ) */
|
||||
channelio(&readfd, &writefd);
|
||||
@@ -255,11 +276,6 @@ void session_loop(void(*loophandler)()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (loophandler) {
|
||||
loophandler();
|
||||
}
|
||||
|
||||
} /* for(;;) */
|
||||
|
||||
/* Not reached */
|
||||
@@ -280,8 +296,8 @@ void session_cleanup() {
|
||||
TRACE(("enter session_cleanup"))
|
||||
|
||||
/* we can't cleanup if we don't know the session state */
|
||||
if (!sessinitdone) {
|
||||
TRACE(("leave session_cleanup: !sessinitdone"))
|
||||
if (!ses.init_done) {
|
||||
TRACE(("leave session_cleanup: !ses.init_done"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -295,7 +311,7 @@ void session_cleanup() {
|
||||
}
|
||||
|
||||
/* After these are freed most functions will fail */
|
||||
#ifdef DROPBEAR_CLEANUP
|
||||
#if DROPBEAR_CLEANUP
|
||||
/* listeners call cleanup functions, this should occur before
|
||||
other session state is freed. */
|
||||
remove_all_listeners();
|
||||
@@ -306,6 +322,16 @@ void session_cleanup() {
|
||||
buf_free(dequeue(&ses.writequeue));
|
||||
}
|
||||
|
||||
m_free(ses.newkeys);
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ses.remoteident);
|
||||
m_free(ses.authstate.pw_dir);
|
||||
m_free(ses.authstate.pw_name);
|
||||
@@ -335,7 +361,7 @@ void session_cleanup() {
|
||||
void send_session_identification() {
|
||||
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
|
||||
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
writebuf_enqueue(writebuf, 0);
|
||||
writebuf_enqueue(writebuf);
|
||||
}
|
||||
|
||||
static void read_session_identification() {
|
||||
@@ -344,8 +370,11 @@ static void read_session_identification() {
|
||||
int len = 0;
|
||||
char done = 0;
|
||||
int i;
|
||||
/* If they send more than 50 lines, something is wrong */
|
||||
for (i = 0; i < 50; i++) {
|
||||
|
||||
/* Servers may send other lines of data before sending the
|
||||
* version string, client must be able to process such lines.
|
||||
* If they send more than 50 lines, something is wrong */
|
||||
for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
|
||||
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
|
||||
|
||||
if (len < 0 && errno != EINTR) {
|
||||
@@ -361,7 +390,7 @@ static void read_session_identification() {
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
TRACE(("err: %s for '%s'\n", strerror(errno), linebuf))
|
||||
TRACE(("error reading remote ident: %s\n", strerror(errno)))
|
||||
ses.remoteclosed();
|
||||
} else {
|
||||
/* linebuf is already null terminated */
|
||||
@@ -395,7 +424,7 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
DROPBEAR_FD_ZERO(&fds);
|
||||
|
||||
/* select since it's a non-blocking fd */
|
||||
|
||||
@@ -550,10 +579,12 @@ static void update_timeout(long limit, long now, long last_event, long * timeout
|
||||
static long select_timeout() {
|
||||
/* determine the minimum timeout that might be required, so
|
||||
as to avoid waking when unneccessary */
|
||||
long timeout = LONG_MAX;
|
||||
long timeout = KEX_REKEY_TIMEOUT;
|
||||
long now = monotonic_now();
|
||||
|
||||
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
|
||||
if (!ses.kexstate.sentkexinit) {
|
||||
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
|
||||
}
|
||||
|
||||
if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
|
||||
/* AUTH_TIMEOUT is only relevant before authdone */
|
||||
|
||||
19
compat.c
19
compat.c
@@ -114,8 +114,8 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
|
||||
#endif /* HAVE_STRLCPY */
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
/* taken from openbsd-compat for OpenSSH 3.6.1p1 */
|
||||
/* "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"
|
||||
/* taken from openbsd-compat for OpenSSH 7.2p2 */
|
||||
/* "$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $"
|
||||
*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
@@ -123,15 +123,12 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
@@ -177,7 +174,7 @@ int daemon(int nochdir, int noclose) {
|
||||
if (!nochdir)
|
||||
(void)chdir("/");
|
||||
|
||||
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
|
||||
if (!noclose && (fd = open(DROPBEAR_PATH_DEVNULL, O_RDWR, 0)) != -1) {
|
||||
(void)dup2(fd, STDIN_FILENO);
|
||||
(void)dup2(fd, STDOUT_FILENO);
|
||||
(void)dup2(fd, STDERR_FILENO);
|
||||
|
||||
939
config.guess
vendored
939
config.guess
vendored
File diff suppressed because it is too large
Load Diff
2752
config.sub
vendored
2752
config.sub
vendored
File diff suppressed because it is too large
Load Diff
329
configure.ac
329
configure.ac
@@ -9,19 +9,119 @@ AC_PREREQ(2.59)
|
||||
AC_INIT
|
||||
AC_CONFIG_SRCDIR(buffer.c)
|
||||
|
||||
OLDCFLAGS=$CFLAGS
|
||||
# Record which revision is being built
|
||||
if test -s "`which hg`" && test -d "$srcdir/.hg"; then
|
||||
hgrev=`hg id -i -R "$srcdir"`
|
||||
AC_MSG_NOTICE([Source directory Mercurial base revision $hgrev])
|
||||
fi
|
||||
|
||||
ORIGCFLAGS="$CFLAGS"
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
if test -z "$LD" ; then
|
||||
LD=$CC
|
||||
fi
|
||||
AC_SUBST(LD)
|
||||
|
||||
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
|
||||
AC_DEFUN(DB_TRYADDCFLAGS,
|
||||
[{
|
||||
OLDFLAGS="$CFLAGS"
|
||||
TESTFLAGS="$1"
|
||||
CFLAGS="$CFLAGS $TESTFLAGS"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
|
||||
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDFLAGS" ]
|
||||
)
|
||||
}])
|
||||
|
||||
# set compile flags prior to other tests
|
||||
if test -z "$ORIGCFLAGS" && test "$GCC" = "yes"; then
|
||||
AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
|
||||
CFLAGS="-Os -W -Wall -Wno-pointer-sign"
|
||||
CFLAGS="-Os -W -Wall"
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE([Checking if compiler '$CC' supports -Wno-pointer-sign])
|
||||
DB_TRYADDCFLAGS([-Wno-pointer-sign])
|
||||
|
||||
AC_MSG_NOTICE([Checking if compiler '$CC' supports -fno-strict-overflow])
|
||||
DB_TRYADDCFLAGS([-fno-strict-overflow])
|
||||
|
||||
STATIC=0
|
||||
AC_ARG_ENABLE(static,
|
||||
[ --enable-static Build static binaries],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
STATIC=1
|
||||
AC_MSG_NOTICE(Static Build)
|
||||
fi
|
||||
], [])
|
||||
AC_SUBST(STATIC)
|
||||
|
||||
hardenbuild=1
|
||||
AC_ARG_ENABLE(harden,
|
||||
[ --disable-harden Don't set hardened build flags],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
hardenbuild=0
|
||||
AC_MSG_NOTICE(Disabling hardened build flags)
|
||||
fi
|
||||
], [])
|
||||
|
||||
if test "$hardenbuild" -eq 1; then
|
||||
AC_MSG_NOTICE(Checking for available hardened build flags:)
|
||||
# relocation flags don't make sense for static builds
|
||||
if test "$STATIC" -ne 1; then
|
||||
# pie
|
||||
DB_TRYADDCFLAGS([-fPIE])
|
||||
|
||||
OLDLDFLAGS="$LDFLAGS"
|
||||
TESTFLAGS="-Wl,-pie"
|
||||
LDFLAGS="$LDFLAGS $TESTFLAGS"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
|
||||
[
|
||||
LDFLAGS="$OLDLDFLAGS"
|
||||
TESTFLAGS="-pie"
|
||||
LDFLAGS="$LDFLAGS $TESTFLAGS"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
|
||||
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
|
||||
)
|
||||
]
|
||||
)
|
||||
# readonly elf relocation sections (relro)
|
||||
OLDLDFLAGS="$LDFLAGS"
|
||||
TESTFLAGS="-Wl,-z,now -Wl,-z,relro"
|
||||
LDFLAGS="$LDFLAGS $TESTFLAGS"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
|
||||
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
|
||||
)
|
||||
fi # non-static
|
||||
# stack protector. -strong is good but only in gcc 4.9 or later
|
||||
OLDCFLAGS="$CFLAGS"
|
||||
TESTFLAGS="-fstack-protector-strong"
|
||||
CFLAGS="$CFLAGS $TESTFLAGS"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
|
||||
[
|
||||
CFLAGS="$OLDCFLAGS"
|
||||
TESTFLAGS="-fstack-protector --param=ssp-buffer-size=4"
|
||||
CFLAGS="$CFLAGS $TESTFLAGS"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
|
||||
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDCFLAGS" ]
|
||||
)
|
||||
]
|
||||
)
|
||||
# FORTIFY_SOURCE
|
||||
DB_TRYADDCFLAGS([-D_FORTIFY_SOURCE=2])
|
||||
|
||||
# Spectre v2 mitigations
|
||||
DB_TRYADDCFLAGS([-mfunction-return=thunk])
|
||||
DB_TRYADDCFLAGS([-mindirect-branch=thunk])
|
||||
|
||||
fi
|
||||
|
||||
# large file support is useful for scp
|
||||
@@ -45,8 +145,8 @@ case "$host" in
|
||||
sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
|
||||
if test "$sol2ver" -ge 8; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(DISABLE_UTMP,,Disable utmp)
|
||||
AC_DEFINE(DISABLE_WTMP,,Disable wtmp)
|
||||
AC_DEFINE(DISABLE_UTMP,1,Disable utmp)
|
||||
AC_DEFINE(DISABLE_WTMP,1,Disable wtmp)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
@@ -55,18 +155,18 @@ case "$host" in
|
||||
;;
|
||||
|
||||
*-*-aix*)
|
||||
AC_DEFINE(AIX,,Using AIX)
|
||||
AC_DEFINE(AIX,1,Using AIX)
|
||||
# OpenSSH thinks it's broken. If it isn't, let me know.
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
|
||||
;;
|
||||
|
||||
*-*-hpux*)
|
||||
LIBS="$LIBS -lsec"
|
||||
# It's probably broken.
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
|
||||
;;
|
||||
*-dec-osf*)
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -80,7 +180,7 @@ AC_CHECK_DECL(__UCLIBC__,
|
||||
[
|
||||
no_loginfunc_check=1
|
||||
AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
|
||||
],,,)
|
||||
],,)
|
||||
|
||||
dnl We test for crypt() specially. On Linux (and others?) it resides in libcrypt
|
||||
dnl but we don't want link all binaries to -lcrypt, just dropbear server.
|
||||
@@ -118,7 +218,7 @@ AC_ARG_ENABLE(zlib,
|
||||
[ --disable-zlib Don't include zlib support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_ZLIB,, Use zlib)
|
||||
AC_DEFINE(DISABLE_ZLIB,1,Use zlib)
|
||||
AC_MSG_NOTICE(Disabling zlib)
|
||||
else
|
||||
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
|
||||
@@ -152,20 +252,20 @@ AC_ARG_WITH(pam,
|
||||
|
||||
|
||||
AC_ARG_ENABLE(pam,
|
||||
[ --enable-pam Try to include PAM support],
|
||||
[ --enable-pam Try to include PAM support],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
|
||||
AC_MSG_NOTICE(Enabling PAM)
|
||||
AC_CHECK_FUNCS(pam_fail_delay)
|
||||
else
|
||||
AC_DEFINE(DISABLE_PAM,, Use PAM)
|
||||
AC_DEFINE(DISABLE_PAM,1,Use PAM)
|
||||
AC_MSG_NOTICE(Disabling PAM)
|
||||
fi
|
||||
],
|
||||
[
|
||||
# disable it by default
|
||||
AC_DEFINE(DISABLE_PAM,, Use PAM)
|
||||
AC_DEFINE(DISABLE_PAM,1,Use PAM)
|
||||
AC_MSG_NOTICE(Disabling PAM)
|
||||
]
|
||||
)
|
||||
@@ -177,21 +277,26 @@ AC_ARG_ENABLE(openpty,
|
||||
AC_MSG_NOTICE(Not using openpty)
|
||||
else
|
||||
AC_MSG_NOTICE(Using openpty if available)
|
||||
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)])
|
||||
AC_SEARCH_LIBS(openpty, util, [dropbear_cv_func_have_openpty=yes])
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_NOTICE(Using openpty if available)
|
||||
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY)])
|
||||
AC_SEARCH_LIBS(openpty, util, [dropbear_cv_func_have_openpty=yes])
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
if test "x$dropbear_cv_func_have_openpty" = "xyes"; then
|
||||
AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)
|
||||
no_ptc_check=yes
|
||||
no_ptmx_check=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(syslog,
|
||||
[ --disable-syslog Don't include syslog support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_SYSLOG,, Using syslog)
|
||||
AC_DEFINE(DISABLE_SYSLOG,1,Using syslog)
|
||||
AC_MSG_NOTICE(Disabling syslog)
|
||||
else
|
||||
AC_MSG_NOTICE(Enabling syslog)
|
||||
@@ -217,12 +322,56 @@ AC_ARG_ENABLE(shadow,
|
||||
AC_MSG_NOTICE(Using shadow passwords if available)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(plugin,
|
||||
[ --enable-plugin Enable support for External Public Key Authentication plug-in],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 1, External Public Key Authentication)
|
||||
AC_MSG_NOTICE(Enabling support for External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=1
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 0, External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=0
|
||||
]
|
||||
|
||||
)
|
||||
AC_SUBST(DROPBEAR_PLUGIN)
|
||||
|
||||
AC_ARG_ENABLE(fuzz,
|
||||
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
|
||||
AC_MSG_NOTICE(Enabling fuzzing)
|
||||
DROPBEAR_FUZZ=1
|
||||
# libfuzzer needs linking with c++ libraries
|
||||
AC_PROG_CXX
|
||||
else
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
]
|
||||
|
||||
)
|
||||
AC_SUBST(DROPBEAR_FUZZ)
|
||||
AC_SUBST(CXX)
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h sys/uio.h])
|
||||
AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \
|
||||
crypt.h \
|
||||
pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \
|
||||
utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \
|
||||
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \
|
||||
sys/random.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@@ -295,7 +444,7 @@ AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,,Have struct sockaddr_in6)
|
||||
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,1,Have struct sockaddr_in6)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
|
||||
@@ -309,7 +458,7 @@ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_IN6_ADDR,,Have struct in6_addr)
|
||||
AC_DEFINE(HAVE_STRUCT_IN6_ADDR,1,Have struct in6_addr)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
|
||||
@@ -324,7 +473,7 @@ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_ADDRINFO,,Have struct addrinfo)
|
||||
AC_DEFINE(HAVE_STRUCT_ADDRINFO,1,Have struct addrinfo)
|
||||
fi
|
||||
|
||||
|
||||
@@ -371,38 +520,41 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
# POSIX monotonic time
|
||||
AC_CHECK_FUNCS(clock_gettime)
|
||||
|
||||
# OS X monotonic time
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
AC_CHECK_FUNCS(mach_absolute_time)
|
||||
|
||||
AC_CHECK_FUNCS(explicit_bzero memset_s)
|
||||
|
||||
AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
|
||||
|
||||
AC_ARG_ENABLE(bundled-libtom,
|
||||
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
|
||||
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
|
||||
Default is to use system if available, otherwise bundled.],
|
||||
Default is to use system if available, otherwise bundled.
|
||||
Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
BUNDLED_LIBTOM=1
|
||||
AC_MSG_NOTICE(Forcing bundled libtom*)
|
||||
else
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath",
|
||||
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt",
|
||||
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
fi
|
||||
],
|
||||
[
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
]
|
||||
)
|
||||
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom)
|
||||
AC_DEFINE(BUNDLED_LIBTOM,1,Use bundled libtom)
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBTOM_LIBS)
|
||||
@@ -413,36 +565,64 @@ dnl Added from OpenSSH 3.6.1p2's configure.ac
|
||||
dnl allow user to disable some login recording features
|
||||
AC_ARG_ENABLE(lastlog,
|
||||
[ --disable-lastlog Disable use of lastlog even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_LASTLOG,,Disable use of lastlog()) ]
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_LASTLOG,1,Disable use of lastlog())
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(utmp,
|
||||
[ --disable-utmp Disable use of utmp even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_UTMP,,Disable use of utmp) ]
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_UTMP,1,Disable use of utmp)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(utmpx,
|
||||
[ --disable-utmpx Disable use of utmpx even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_UTMPX,,Disable use of utmpx) ]
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_UTMPX,1,Disable use of utmpx)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmp,
|
||||
[ --disable-wtmp Disable use of wtmp even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_WTMP,,Disable use of wtmp) ]
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_WTMP,1,Disable use of wtmp)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmpx,
|
||||
[ --disable-wtmpx Disable use of wtmpx even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_WTMPX,,Disable use of wtmpx) ]
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_WTMPX,1,Disable use of wtmpx)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(loginfunc,
|
||||
[ --disable-loginfunc Disable use of login() etc. [no]],
|
||||
[ no_loginfunc_check=1
|
||||
AC_MSG_NOTICE(Not using login() etc) ]
|
||||
AC_MSG_NOTICE([Not using login() etc]) ]
|
||||
)
|
||||
AC_ARG_ENABLE(pututline,
|
||||
[ --disable-pututline Disable use of pututline() etc. ([uw]tmp) [no]],
|
||||
[ AC_DEFINE(DISABLE_PUTUTLINE,,Disable use of pututline()) ]
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_PUTUTLINE,1,Disable use of pututline())
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(pututxline,
|
||||
[ --disable-pututxline Disable use of pututxline() etc. ([uw]tmpx) [no]],
|
||||
[ AC_DEFINE(DISABLE_PUTUTXLINE,,Disable use of pututxline()) ]
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_PUTUTXLINE,1,Disable use of pututxline())
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_WITH(lastlog,
|
||||
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
|
||||
@@ -457,7 +637,7 @@ AC_ARG_WITH(lastlog,
|
||||
|
||||
if test -z "$no_loginfunc_check"; then
|
||||
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
|
||||
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,,Have login() function)])
|
||||
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,1,[Have login() function])])
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
fi
|
||||
|
||||
@@ -645,7 +825,9 @@ fi
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_CHECK_FUNCS([dup2 getpass getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
|
||||
AC_CHECK_FUNCS([getpass getspnam getusershell putenv])
|
||||
AC_CHECK_FUNCS([clearenv strlcpy strlcat daemon basename _getpty getaddrinfo ])
|
||||
AC_CHECK_FUNCS([freeaddrinfo getnameinfo fork writev getgrouplist])
|
||||
|
||||
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||
|
||||
@@ -653,7 +835,7 @@ AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||
if test -z "$no_ptmx_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
if test -e /dev/ptmx ; then
|
||||
AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx)
|
||||
AC_DEFINE(USE_DEV_PTMX,1,Use /dev/ptmx)
|
||||
fi
|
||||
else
|
||||
AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
|
||||
@@ -663,7 +845,7 @@ fi
|
||||
if test -z "$no_ptc_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
if test -e /dev/ptc ; then
|
||||
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts)
|
||||
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,1,Use /dev/ptc & /dev/pts)
|
||||
fi
|
||||
else
|
||||
AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
|
||||
@@ -672,60 +854,11 @@ fi
|
||||
|
||||
AC_EXEEXT
|
||||
|
||||
# XXX there must be a nicer way to do this
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
|
||||
AS_MKDIR_P(libtomcrypt/src/encauth/ccm)
|
||||
AS_MKDIR_P(libtomcrypt/src/encauth/eax)
|
||||
AS_MKDIR_P(libtomcrypt/src/encauth/gcm)
|
||||
AS_MKDIR_P(libtomcrypt/src/encauth/ocb)
|
||||
AS_MKDIR_P(libtomcrypt/src/hashes)
|
||||
AS_MKDIR_P(libtomcrypt/src/hashes/chc)
|
||||
AS_MKDIR_P(libtomcrypt/src/hashes/helper)
|
||||
AS_MKDIR_P(libtomcrypt/src/hashes/sha2)
|
||||
AS_MKDIR_P(libtomcrypt/src/hashes/whirl)
|
||||
AS_MKDIR_P(libtomcrypt/src/mac/hmac)
|
||||
AS_MKDIR_P(libtomcrypt/src/mac/omac)
|
||||
AS_MKDIR_P(libtomcrypt/src/mac/pelican)
|
||||
AS_MKDIR_P(libtomcrypt/src/mac/pmac)
|
||||
AS_MKDIR_P(libtomcrypt/src/mac/f9)
|
||||
AS_MKDIR_P(libtomcrypt/src/mac/xcbc)
|
||||
AS_MKDIR_P(libtomcrypt/src/math/fp)
|
||||
AS_MKDIR_P(libtomcrypt/src/misc/base64)
|
||||
AS_MKDIR_P(libtomcrypt/src/misc/crypt)
|
||||
AS_MKDIR_P(libtomcrypt/src/misc/mpi)
|
||||
AS_MKDIR_P(libtomcrypt/src/misc/pkcs5)
|
||||
AS_MKDIR_P(libtomcrypt/src/modes/cbc)
|
||||
AS_MKDIR_P(libtomcrypt/src/modes/cfb)
|
||||
AS_MKDIR_P(libtomcrypt/src/modes/ctr)
|
||||
AS_MKDIR_P(libtomcrypt/src/modes/ecb)
|
||||
AS_MKDIR_P(libtomcrypt/src/modes/ofb)
|
||||
AS_MKDIR_P(libtomcrypt/src/modes/f8)
|
||||
AS_MKDIR_P(libtomcrypt/src/modes/lrw)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/boolean)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/set)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utf8)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/dh)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/dsa)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/ecc)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/katja)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
|
||||
AS_MKDIR_P(libtomcrypt/src/prngs)
|
||||
(cd $srcdir; find libtomcrypt -type d) | xargs mkdir -pv
|
||||
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
|
||||
fi
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
|
||||
AC_OUTPUT
|
||||
@@ -749,4 +882,4 @@ AC_MSG_NOTICE([crypt() not available, dropbear server will not have password aut
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([Now edit options.h to choose features.])
|
||||
AC_MSG_NOTICE([Now edit localoptions.h to choose features.])
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
#if DROPBEAR_LTC_PRNG
|
||||
int dropbear_ltc_prng = -1;
|
||||
#endif
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
void crypto_init() {
|
||||
|
||||
const struct ltc_cipher_descriptor *regciphers[] = {
|
||||
#ifdef DROPBEAR_AES
|
||||
#if DROPBEAR_AES
|
||||
&aes_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
#if DROPBEAR_BLOWFISH
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH
|
||||
#if DROPBEAR_TWOFISH
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
#if DROPBEAR_3DES
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
@@ -32,16 +32,16 @@ void crypto_init() {
|
||||
const struct ltc_hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
#if DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA256
|
||||
#if DROPBEAR_SHA256
|
||||
&sha256_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA384
|
||||
#if DROPBEAR_SHA384
|
||||
&sha384_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA512
|
||||
#if DROPBEAR_SHA512
|
||||
&sha512_desc,
|
||||
#endif
|
||||
NULL
|
||||
@@ -60,14 +60,14 @@ void crypto_init() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
#if DROPBEAR_LTC_PRNG
|
||||
dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
|
||||
if (dropbear_ltc_prng == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
#if DROPBEAR_ECC
|
||||
ltc_mp = ltm_desc;
|
||||
dropbear_ecc_fill_dp();
|
||||
#endif
|
||||
|
||||
@@ -1,734 +0,0 @@
|
||||
/* Copyright 2008, Google Inc.
|
||||
* 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 Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* More information about curve25519 can be found here
|
||||
* http://cr.yp.to/ecdh.html
|
||||
*
|
||||
* djb's sample implementation of curve25519 is written in a special assembly
|
||||
* language called qhasm and uses the floating point registers.
|
||||
*
|
||||
* This is, almost, a clean room reimplementation from the curve25519 paper. It
|
||||
* uses many of the tricks described therein. Only the crecip function is taken
|
||||
* from the sample implementation.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t limb;
|
||||
|
||||
/* Field element representation:
|
||||
*
|
||||
* Field elements are written as an array of signed, 64-bit limbs, least
|
||||
* significant first. The value of the field element is:
|
||||
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
|
||||
*
|
||||
* i.e. the limbs are 26, 25, 26, 25, ... bits wide.
|
||||
*/
|
||||
|
||||
/* Sum two numbers: output += in */
|
||||
static void fsum(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
output[0+i] = (output[0+i] + in[0+i]);
|
||||
output[1+i] = (output[1+i] + in[1+i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the difference of two numbers: output = in - output
|
||||
* (note the order of the arguments!)
|
||||
*/
|
||||
static void fdifference(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = (in[i] - output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply a number by a scalar: output = in * scalar */
|
||||
static void fscalar_product(limb *output, const limb *in, const limb scalar) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = in[i] * scalar;
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply two numbers: output = in2 * in
|
||||
*
|
||||
* output must be distinct to both inputs. The inputs are reduced coefficient
|
||||
* form, the output is not.
|
||||
*/
|
||||
static void fproduct(limb *output, const limb *in2, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
|
||||
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[0]);
|
||||
output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[0]);
|
||||
output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[0]);
|
||||
output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
|
||||
2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[0]);
|
||||
output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[0]);
|
||||
output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[0]);
|
||||
output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[0]);
|
||||
output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[0]);
|
||||
output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[0]);
|
||||
output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[2]);
|
||||
output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[2]);
|
||||
output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[3])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[4]);
|
||||
output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[4]);
|
||||
output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[5])) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[6]);
|
||||
output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[6]);
|
||||
output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[7]));
|
||||
output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[8]);
|
||||
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */
|
||||
static void freduce_degree(limb *output) {
|
||||
/* Each of these shifts and adds ends up multiplying the value by 19. */
|
||||
output[8] += output[18] << 4;
|
||||
output[8] += output[18] << 1;
|
||||
output[8] += output[18];
|
||||
output[7] += output[17] << 4;
|
||||
output[7] += output[17] << 1;
|
||||
output[7] += output[17];
|
||||
output[6] += output[16] << 4;
|
||||
output[6] += output[16] << 1;
|
||||
output[6] += output[16];
|
||||
output[5] += output[15] << 4;
|
||||
output[5] += output[15] << 1;
|
||||
output[5] += output[15];
|
||||
output[4] += output[14] << 4;
|
||||
output[4] += output[14] << 1;
|
||||
output[4] += output[14];
|
||||
output[3] += output[13] << 4;
|
||||
output[3] += output[13] << 1;
|
||||
output[3] += output[13];
|
||||
output[2] += output[12] << 4;
|
||||
output[2] += output[12] << 1;
|
||||
output[2] += output[12];
|
||||
output[1] += output[11] << 4;
|
||||
output[1] += output[11] << 1;
|
||||
output[1] += output[11];
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
}
|
||||
|
||||
#if (-1 & 3) != 3
|
||||
#error "This code only works on a two's complement system"
|
||||
#endif
|
||||
|
||||
/* return v / 2^26, using only shifts and adds. */
|
||||
static inline limb
|
||||
div_by_2_26(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed*/
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x3ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 6;
|
||||
/* Should return v / (1<<26) */
|
||||
return (v + roundoff) >> 26;
|
||||
}
|
||||
|
||||
/* return v / (2^25), using only shifts and adds. */
|
||||
static inline limb
|
||||
div_by_2_25(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed*/
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x1ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 7;
|
||||
/* Should return v / (1<<25) */
|
||||
return (v + roundoff) >> 25;
|
||||
}
|
||||
|
||||
static inline s32
|
||||
div_s32_by_2_25(const s32 v)
|
||||
{
|
||||
const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;
|
||||
return (v + roundoff) >> 25;
|
||||
}
|
||||
|
||||
/* Reduce all coefficients of the short form input so that |x| < 2^26.
|
||||
*
|
||||
* On entry: |output[i]| < 2^62
|
||||
*/
|
||||
static void freduce_coefficients(limb *output) {
|
||||
unsigned i;
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
limb over = div_by_2_26(output[i]);
|
||||
output[i] -= over << 26;
|
||||
output[i+1] += over;
|
||||
|
||||
over = div_by_2_25(output[i+1]);
|
||||
output[i+1] -= over << 25;
|
||||
output[i+2] += over;
|
||||
}
|
||||
/* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38
|
||||
* So |over| will be no more than 77825 */
|
||||
{
|
||||
limb over = div_by_2_26(output[0]);
|
||||
output[0] -= over << 26;
|
||||
output[1] += over;
|
||||
}
|
||||
|
||||
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825
|
||||
* So |over| will be no more than 1. */
|
||||
{
|
||||
/* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */
|
||||
s32 over32 = div_s32_by_2_25((s32) output[1]);
|
||||
output[1] -= over32 << 25;
|
||||
output[2] += over32;
|
||||
}
|
||||
|
||||
/* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":
|
||||
* we have |output[2]| <= 2^26. This is good enough for all of our math,
|
||||
* but it will require an extra freduce_coefficients before fcontract. */
|
||||
}
|
||||
|
||||
/* A helpful wrapper around fproduct: output = in * in2.
|
||||
*
|
||||
* output must be distinct to both inputs. The output is reduced degree and
|
||||
* reduced coefficient.
|
||||
*/
|
||||
static void
|
||||
fmul(limb *output, const limb *in, const limb *in2) {
|
||||
limb t[19];
|
||||
fproduct(t, in, in2);
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
static void fsquare_inner(limb *output, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
|
||||
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
|
||||
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[2]));
|
||||
output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[3]));
|
||||
output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
|
||||
4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
|
||||
2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
|
||||
output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[5]));
|
||||
output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[6]) +
|
||||
2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
|
||||
output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[7]));
|
||||
output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[5])));
|
||||
output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[9]));
|
||||
output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[9])));
|
||||
output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[9]));
|
||||
output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[9])));
|
||||
output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[9]));
|
||||
output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[8]) +
|
||||
2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
|
||||
output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[9]));
|
||||
output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
|
||||
4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
|
||||
output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
|
||||
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
static void
|
||||
fsquare(limb *output, const limb *in) {
|
||||
limb t[19];
|
||||
fsquare_inner(t, in);
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
||||
static void
|
||||
fexpand(limb *output, const u8 *input) {
|
||||
#define F(n,start,shift,mask) \
|
||||
output[n] = ((((limb) input[start + 0]) | \
|
||||
((limb) input[start + 1]) << 8 | \
|
||||
((limb) input[start + 2]) << 16 | \
|
||||
((limb) input[start + 3]) << 24) >> shift) & mask;
|
||||
F(0, 0, 0, 0x3ffffff);
|
||||
F(1, 3, 2, 0x1ffffff);
|
||||
F(2, 6, 3, 0x3ffffff);
|
||||
F(3, 9, 5, 0x1ffffff);
|
||||
F(4, 12, 6, 0x3ffffff);
|
||||
F(5, 16, 0, 0x1ffffff);
|
||||
F(6, 19, 1, 0x3ffffff);
|
||||
F(7, 22, 3, 0x1ffffff);
|
||||
F(8, 25, 4, 0x3ffffff);
|
||||
F(9, 28, 6, 0x3ffffff);
|
||||
#undef F
|
||||
}
|
||||
|
||||
#if (-32 >> 1) != -16
|
||||
#error "This code only works when >> does sign-extension on negative numbers"
|
||||
#endif
|
||||
|
||||
/* Take a fully reduced polynomial form number and contract it into a
|
||||
* little-endian, 32-byte array
|
||||
*/
|
||||
static void
|
||||
fcontract(u8 *output, limb *input) {
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 2; ++j) {
|
||||
for (i = 0; i < 9; ++i) {
|
||||
if ((i & 1) == 1) {
|
||||
/* This calculation is a time-invariant way to make input[i] positive
|
||||
by borrowing from the next-larger limb.
|
||||
*/
|
||||
const s32 mask = (s32)(input[i]) >> 31;
|
||||
const s32 carry = -(((s32)(input[i]) & mask) >> 25);
|
||||
input[i] = (s32)(input[i]) + (carry << 25);
|
||||
input[i+1] = (s32)(input[i+1]) - carry;
|
||||
} else {
|
||||
const s32 mask = (s32)(input[i]) >> 31;
|
||||
const s32 carry = -(((s32)(input[i]) & mask) >> 26);
|
||||
input[i] = (s32)(input[i]) + (carry << 26);
|
||||
input[i+1] = (s32)(input[i+1]) - carry;
|
||||
}
|
||||
}
|
||||
{
|
||||
const s32 mask = (s32)(input[9]) >> 31;
|
||||
const s32 carry = -(((s32)(input[9]) & mask) >> 25);
|
||||
input[9] = (s32)(input[9]) + (carry << 25);
|
||||
input[0] = (s32)(input[0]) - (carry * 19);
|
||||
}
|
||||
}
|
||||
|
||||
/* The first borrow-propagation pass above ended with every limb
|
||||
except (possibly) input[0] non-negative.
|
||||
|
||||
Since each input limb except input[0] is decreased by at most 1
|
||||
by a borrow-propagation pass, the second borrow-propagation pass
|
||||
could only have wrapped around to decrease input[0] again if the
|
||||
first pass left input[0] negative *and* input[1] through input[9]
|
||||
were all zero. In that case, input[1] is now 2^25 - 1, and this
|
||||
last borrow-propagation step will leave input[1] non-negative.
|
||||
*/
|
||||
{
|
||||
const s32 mask = (s32)(input[0]) >> 31;
|
||||
const s32 carry = -(((s32)(input[0]) & mask) >> 26);
|
||||
input[0] = (s32)(input[0]) + (carry << 26);
|
||||
input[1] = (s32)(input[1]) - carry;
|
||||
}
|
||||
|
||||
/* Both passes through the above loop, plus the last 0-to-1 step, are
|
||||
necessary: if input[9] is -1 and input[0] through input[8] are 0,
|
||||
negative values will remain in the array until the end.
|
||||
*/
|
||||
|
||||
input[1] <<= 2;
|
||||
input[2] <<= 3;
|
||||
input[3] <<= 5;
|
||||
input[4] <<= 6;
|
||||
input[6] <<= 1;
|
||||
input[7] <<= 3;
|
||||
input[8] <<= 4;
|
||||
input[9] <<= 6;
|
||||
#define F(i, s) \
|
||||
output[s+0] |= input[i] & 0xff; \
|
||||
output[s+1] = (input[i] >> 8) & 0xff; \
|
||||
output[s+2] = (input[i] >> 16) & 0xff; \
|
||||
output[s+3] = (input[i] >> 24) & 0xff;
|
||||
output[0] = 0;
|
||||
output[16] = 0;
|
||||
F(0,0);
|
||||
F(1,3);
|
||||
F(2,6);
|
||||
F(3,9);
|
||||
F(4,12);
|
||||
F(5,16);
|
||||
F(6,19);
|
||||
F(7,22);
|
||||
F(8,25);
|
||||
F(9,28);
|
||||
#undef F
|
||||
}
|
||||
|
||||
/* Input: Q, Q', Q-Q'
|
||||
* Output: 2Q, Q+Q'
|
||||
*
|
||||
* x2 z3: long form
|
||||
* x3 z3: long form
|
||||
* x z: short form, destroyed
|
||||
* xprime zprime: short form, destroyed
|
||||
* qmqp: short form, preserved
|
||||
*/
|
||||
static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
limb *x3, limb *z3, /* output Q + Q' */
|
||||
limb *x, limb *z, /* input Q */
|
||||
limb *xprime, limb *zprime, /* input Q' */
|
||||
const limb *qmqp /* input Q - Q' */) {
|
||||
limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
|
||||
zzprime[19], zzzprime[19], xxxprime[19];
|
||||
|
||||
memcpy(origx, x, 10 * sizeof(limb));
|
||||
fsum(x, z);
|
||||
fdifference(z, origx); /* does x - z */
|
||||
|
||||
memcpy(origxprime, xprime, sizeof(limb) * 10);
|
||||
fsum(xprime, zprime);
|
||||
fdifference(zprime, origxprime);
|
||||
fproduct(xxprime, xprime, z);
|
||||
fproduct(zzprime, x, zprime);
|
||||
freduce_degree(xxprime);
|
||||
freduce_coefficients(xxprime);
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
memcpy(origxprime, xxprime, sizeof(limb) * 10);
|
||||
fsum(xxprime, zzprime);
|
||||
fdifference(zzprime, origxprime);
|
||||
fsquare(xxxprime, xxprime);
|
||||
fsquare(zzzprime, zzprime);
|
||||
fproduct(zzprime, zzzprime, qmqp);
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
memcpy(x3, xxxprime, sizeof(limb) * 10);
|
||||
memcpy(z3, zzprime, sizeof(limb) * 10);
|
||||
|
||||
fsquare(xx, x);
|
||||
fsquare(zz, z);
|
||||
fproduct(x2, xx, zz);
|
||||
freduce_degree(x2);
|
||||
freduce_coefficients(x2);
|
||||
fdifference(zz, xx); /* does zz = xx - zz */
|
||||
memset(zzz + 10, 0, sizeof(limb) * 9);
|
||||
fscalar_product(zzz, zz, 121665);
|
||||
/* No need to call freduce_degree here:
|
||||
fscalar_product doesn't increase the degree of its input. */
|
||||
freduce_coefficients(zzz);
|
||||
fsum(zzz, xx);
|
||||
fproduct(z2, zz, zzz);
|
||||
freduce_degree(z2);
|
||||
freduce_coefficients(z2);
|
||||
}
|
||||
|
||||
/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
|
||||
* them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
|
||||
* side-channel attacks.
|
||||
*
|
||||
* NOTE that this function requires that 'iswap' be 1 or 0; other values give
|
||||
* wrong results. Also, the two limb arrays must be in reduced-coefficient,
|
||||
* reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
|
||||
* and all all values in a[0..9],b[0..9] must have magnitude less than
|
||||
* INT32_MAX.
|
||||
*/
|
||||
static void
|
||||
swap_conditional(limb a[19], limb b[19], limb iswap) {
|
||||
unsigned i;
|
||||
const s32 swap = (s32) -iswap;
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
|
||||
a[i] = ((s32)a[i]) ^ x;
|
||||
b[i] = ((s32)b[i]) ^ x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates nQ where Q is the x-coordinate of a point on the curve
|
||||
*
|
||||
* resultx/resultz: the x coordinate of the resulting curve point (short form)
|
||||
* n: a little endian, 32-byte number
|
||||
* q: a point of the curve (short form)
|
||||
*/
|
||||
static void
|
||||
cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
|
||||
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
|
||||
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
|
||||
limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
|
||||
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
|
||||
|
||||
unsigned i, j;
|
||||
|
||||
memcpy(nqpqx, q, sizeof(limb) * 10);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
u8 byte = n[31 - i];
|
||||
for (j = 0; j < 8; ++j) {
|
||||
const limb bit = byte >> 7;
|
||||
|
||||
swap_conditional(nqx, nqpqx, bit);
|
||||
swap_conditional(nqz, nqpqz, bit);
|
||||
fmonty(nqx2, nqz2,
|
||||
nqpqx2, nqpqz2,
|
||||
nqx, nqz,
|
||||
nqpqx, nqpqz,
|
||||
q);
|
||||
swap_conditional(nqx2, nqpqx2, bit);
|
||||
swap_conditional(nqz2, nqpqz2, bit);
|
||||
|
||||
t = nqx;
|
||||
nqx = nqx2;
|
||||
nqx2 = t;
|
||||
t = nqz;
|
||||
nqz = nqz2;
|
||||
nqz2 = t;
|
||||
t = nqpqx;
|
||||
nqpqx = nqpqx2;
|
||||
nqpqx2 = t;
|
||||
t = nqpqz;
|
||||
nqpqz = nqpqz2;
|
||||
nqpqz2 = t;
|
||||
|
||||
byte <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(resultx, nqx, sizeof(limb) * 10);
|
||||
memcpy(resultz, nqz, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Shamelessly copied from djb's code
|
||||
* ----------------------------------------------------------------------------- */
|
||||
static void
|
||||
crecip(limb *out, const limb *z) {
|
||||
limb z2[10];
|
||||
limb z9[10];
|
||||
limb z11[10];
|
||||
limb z2_5_0[10];
|
||||
limb z2_10_0[10];
|
||||
limb z2_20_0[10];
|
||||
limb z2_50_0[10];
|
||||
limb z2_100_0[10];
|
||||
limb t0[10];
|
||||
limb t1[10];
|
||||
int i;
|
||||
|
||||
/* 2 */ fsquare(z2,z);
|
||||
/* 4 */ fsquare(t1,z2);
|
||||
/* 8 */ fsquare(t0,t1);
|
||||
/* 9 */ fmul(z9,t0,z);
|
||||
/* 11 */ fmul(z11,z9,z2);
|
||||
/* 22 */ fsquare(t0,z11);
|
||||
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
|
||||
|
||||
/* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
|
||||
/* 2^7 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^8 - 2^3 */ fsquare(t0,t1);
|
||||
/* 2^9 - 2^4 */ fsquare(t1,t0);
|
||||
/* 2^10 - 2^5 */ fsquare(t0,t1);
|
||||
/* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
|
||||
|
||||
/* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
|
||||
/* 2^12 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
|
||||
|
||||
/* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
|
||||
/* 2^22 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
|
||||
|
||||
/* 2^41 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^42 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
|
||||
|
||||
/* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
|
||||
/* 2^52 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
|
||||
|
||||
/* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
|
||||
/* 2^102 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
|
||||
|
||||
/* 2^201 - 2^1 */ fsquare(t0,t1);
|
||||
/* 2^202 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
|
||||
|
||||
/* 2^251 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^252 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^253 - 2^3 */ fsquare(t1,t0);
|
||||
/* 2^254 - 2^4 */ fsquare(t0,t1);
|
||||
/* 2^255 - 2^5 */ fsquare(t1,t0);
|
||||
/* 2^255 - 21 */ fmul(out,t1,z11);
|
||||
}
|
||||
|
||||
int curve25519_donna(u8 *, const u8 *, const u8 *);
|
||||
|
||||
int
|
||||
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
|
||||
limb bp[10], x[10], z[11], zmone[10];
|
||||
uint8_t e[32];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; ++i) e[i] = secret[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
|
||||
fexpand(bp, basepoint);
|
||||
cmult(x, z, e, bp);
|
||||
crecip(zmone, z);
|
||||
fmul(z, x, zmone);
|
||||
freduce_coefficients(z);
|
||||
fcontract(mypublic, z);
|
||||
return 0;
|
||||
}
|
||||
497
curve25519.c
Normal file
497
curve25519.c
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 "includes.h"
|
||||
#include "dbrandom.h"
|
||||
#include "curve25519.h"
|
||||
|
||||
#if DROPBEAR_CURVE25519 || DROPBEAR_ED25519
|
||||
|
||||
/* Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
* https://tweetnacl.cr.yp.to/ */
|
||||
|
||||
#define FOR(i,n) for (i = 0;i < n;++i)
|
||||
#define sv static void
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned long u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
typedef i64 gf[16];
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
static const gf
|
||||
_121665 = {0xDB41,1};
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
#if DROPBEAR_ED25519
|
||||
static const gf
|
||||
gf0,
|
||||
gf1 = {1},
|
||||
D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
|
||||
X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
|
||||
Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666};
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static const gf
|
||||
D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
|
||||
I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int vn(const u8 *x,const u8 *y,u32 n)
|
||||
{
|
||||
u32 i,d = 0;
|
||||
FOR(i,n) d |= x[i]^y[i];
|
||||
return (1 & ((d - 1) >> 8)) - 1;
|
||||
}
|
||||
|
||||
static int crypto_verify_32(const u8 *x,const u8 *y)
|
||||
{
|
||||
return vn(x,y,32);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
sv set25519(gf r, const gf a)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) r[i]=a[i];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv car25519(gf o)
|
||||
{
|
||||
int i;
|
||||
i64 c;
|
||||
FOR(i,16) {
|
||||
o[i]+=(1LL<<16);
|
||||
c=o[i]>>16;
|
||||
o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15);
|
||||
o[i]-=c<<16;
|
||||
}
|
||||
}
|
||||
|
||||
sv sel25519(gf p,gf q,int b)
|
||||
{
|
||||
i64 t,i,c=~(b-1);
|
||||
FOR(i,16) {
|
||||
t= c&(p[i]^q[i]);
|
||||
p[i]^=t;
|
||||
q[i]^=t;
|
||||
}
|
||||
}
|
||||
|
||||
sv pack25519(u8 *o,const gf n)
|
||||
{
|
||||
int i,j,b;
|
||||
gf m,t;
|
||||
FOR(i,16) t[i]=n[i];
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
FOR(j,2) {
|
||||
m[0]=t[0]-0xffed;
|
||||
for(i=1;i<15;i++) {
|
||||
m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
|
||||
m[i-1]&=0xffff;
|
||||
}
|
||||
m[15]=t[15]-0x7fff-((m[14]>>16)&1);
|
||||
b=(m[15]>>16)&1;
|
||||
m[14]&=0xffff;
|
||||
sel25519(t,m,1-b);
|
||||
}
|
||||
FOR(i,16) {
|
||||
o[2*i]=t[i]&0xff;
|
||||
o[2*i+1]=t[i]>>8;
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int neq25519(const gf a, const gf b)
|
||||
{
|
||||
u8 c[32],d[32];
|
||||
pack25519(c,a);
|
||||
pack25519(d,b);
|
||||
return crypto_verify_32(c,d);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
static u8 par25519(const gf a)
|
||||
{
|
||||
u8 d[32];
|
||||
pack25519(d,a);
|
||||
return d[0]&1;
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv unpack25519(gf o, const u8 *n)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8);
|
||||
o[15]&=0x7fff;
|
||||
}
|
||||
|
||||
sv A(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]+b[i];
|
||||
}
|
||||
|
||||
sv Z(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]-b[i];
|
||||
}
|
||||
|
||||
sv M(gf o,const gf a,const gf b)
|
||||
{
|
||||
i64 i,j,t[31];
|
||||
FOR(i,31) t[i]=0;
|
||||
FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j];
|
||||
FOR(i,15) t[i]+=38*t[i+16];
|
||||
FOR(i,16) o[i]=t[i];
|
||||
car25519(o);
|
||||
car25519(o);
|
||||
}
|
||||
|
||||
sv S(gf o,const gf a)
|
||||
{
|
||||
M(o,a,a);
|
||||
}
|
||||
|
||||
sv inv25519(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=253;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=2&&a!=4) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY
|
||||
sv pow2523(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=250;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=1) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
void dropbear_curve25519_scalarmult(u8 *q,const u8 *n,const u8 *p)
|
||||
{
|
||||
u8 z[32];
|
||||
i64 x[80],r,i;
|
||||
gf a,b,c,d,e,f;
|
||||
FOR(i,31) z[i]=n[i];
|
||||
z[31]=(n[31]&127)|64;
|
||||
z[0]&=248;
|
||||
unpack25519(x,p);
|
||||
FOR(i,16) {
|
||||
b[i]=x[i];
|
||||
d[i]=a[i]=c[i]=0;
|
||||
}
|
||||
a[0]=d[0]=1;
|
||||
for(i=254;i>=0;--i) {
|
||||
r=(z[i>>3]>>(i&7))&1;
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
A(c,b,d);
|
||||
Z(b,b,d);
|
||||
S(d,e);
|
||||
S(f,a);
|
||||
M(a,c,a);
|
||||
M(c,b,e);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
S(b,a);
|
||||
Z(c,d,f);
|
||||
M(a,c,_121665);
|
||||
A(a,a,d);
|
||||
M(c,c,a);
|
||||
M(a,d,f);
|
||||
M(d,b,x);
|
||||
S(b,e);
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
}
|
||||
FOR(i,16) {
|
||||
x[i+16]=a[i];
|
||||
x[i+32]=c[i];
|
||||
x[i+48]=b[i];
|
||||
x[i+64]=d[i];
|
||||
}
|
||||
inv25519(x+32,x+32);
|
||||
M(x+16,x+16,x+32);
|
||||
pack25519(q,x+16);
|
||||
}
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
static int crypto_hash(u8 *out,const u8 *m,u64 n)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, m, n);
|
||||
return sha512_done(&hs, out);
|
||||
}
|
||||
|
||||
sv add(gf p[4],gf q[4])
|
||||
{
|
||||
gf a,b,c,d,t,e,f,g,h;
|
||||
|
||||
Z(a, p[1], p[0]);
|
||||
Z(t, q[1], q[0]);
|
||||
M(a, a, t);
|
||||
A(b, p[0], p[1]);
|
||||
A(t, q[0], q[1]);
|
||||
M(b, b, t);
|
||||
M(c, p[3], q[3]);
|
||||
M(c, c, D2);
|
||||
M(d, p[2], q[2]);
|
||||
A(d, d, d);
|
||||
Z(e, b, a);
|
||||
Z(f, d, c);
|
||||
A(g, d, c);
|
||||
A(h, b, a);
|
||||
|
||||
M(p[0], e, f);
|
||||
M(p[1], h, g);
|
||||
M(p[2], g, f);
|
||||
M(p[3], e, h);
|
||||
}
|
||||
|
||||
sv cswap(gf p[4],gf q[4],u8 b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,4)
|
||||
sel25519(p[i],q[i],b);
|
||||
}
|
||||
|
||||
sv pack(u8 *r,gf p[4])
|
||||
{
|
||||
gf tx, ty, zi;
|
||||
inv25519(zi, p[2]);
|
||||
M(tx, p[0], zi);
|
||||
M(ty, p[1], zi);
|
||||
pack25519(r, ty);
|
||||
r[31] ^= par25519(tx) << 7;
|
||||
}
|
||||
|
||||
sv scalarmult(gf p[4],gf q[4],const u8 *s)
|
||||
{
|
||||
int i;
|
||||
set25519(p[0],gf0);
|
||||
set25519(p[1],gf1);
|
||||
set25519(p[2],gf1);
|
||||
set25519(p[3],gf0);
|
||||
for (i = 255;i >= 0;--i) {
|
||||
u8 b = (s[i/8]>>(i&7))&1;
|
||||
cswap(p,q,b);
|
||||
add(q,p);
|
||||
add(p,p);
|
||||
cswap(p,q,b);
|
||||
}
|
||||
}
|
||||
|
||||
sv scalarbase(gf p[4],const u8 *s)
|
||||
{
|
||||
gf q[4];
|
||||
set25519(q[0],X);
|
||||
set25519(q[1],Y);
|
||||
set25519(q[2],gf1);
|
||||
M(q[3],X,Y);
|
||||
scalarmult(p,q,s);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_make_key(u8 *pk,u8 *sk)
|
||||
{
|
||||
u8 d[64];
|
||||
gf p[4];
|
||||
|
||||
genrandom(sk, 32);
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
scalarbase(p,d);
|
||||
pack(pk,p);
|
||||
}
|
||||
|
||||
static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
|
||||
|
||||
sv modL(u8 *r,i64 x[64])
|
||||
{
|
||||
i64 carry,i,j;
|
||||
for (i = 63;i >= 32;--i) {
|
||||
carry = 0;
|
||||
for (j = i - 32;j < i - 12;++j) {
|
||||
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
|
||||
carry = (x[j] + 128) >> 8;
|
||||
x[j] -= carry << 8;
|
||||
}
|
||||
x[j] += carry;
|
||||
x[i] = 0;
|
||||
}
|
||||
carry = 0;
|
||||
FOR(j,32) {
|
||||
x[j] += carry - (x[31] >> 4) * L[j];
|
||||
carry = x[j] >> 8;
|
||||
x[j] &= 255;
|
||||
}
|
||||
FOR(j,32) x[j] -= carry * L[j];
|
||||
FOR(i,32) {
|
||||
x[i+1] += x[i] >> 8;
|
||||
r[i] = x[i] & 255;
|
||||
}
|
||||
}
|
||||
|
||||
sv reduce(u8 *r)
|
||||
{
|
||||
i64 x[64],i;
|
||||
FOR(i,64) x[i] = (u64) r[i];
|
||||
FOR(i,64) r[i] = 0;
|
||||
modL(r,x);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_sign(const u8 *m,u32 mlen,u8 *s,u32 *slen,const u8 *sk, const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 d[64],h[64],r[64];
|
||||
i64 x[64];
|
||||
gf p[4];
|
||||
u32 i,j;
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
*slen = 64;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,d + 32,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,r);
|
||||
reduce(r);
|
||||
scalarbase(p,r);
|
||||
pack(s,p);
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
reduce(h);
|
||||
|
||||
FOR(i,64) x[i] = 0;
|
||||
FOR(i,32) x[i] = (u64) r[i];
|
||||
FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j];
|
||||
modL(s + 32,x);
|
||||
}
|
||||
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int unpackneg(gf r[4],const u8 p[32])
|
||||
{
|
||||
gf t, chk, num, den, den2, den4, den6;
|
||||
set25519(r[2],gf1);
|
||||
unpack25519(r[1],p);
|
||||
S(num,r[1]);
|
||||
M(den,num,D);
|
||||
Z(num,num,r[2]);
|
||||
A(den,r[2],den);
|
||||
|
||||
S(den2,den);
|
||||
S(den4,den2);
|
||||
M(den6,den4,den2);
|
||||
M(t,den6,num);
|
||||
M(t,t,den);
|
||||
|
||||
pow2523(t,t);
|
||||
M(t,t,num);
|
||||
M(t,t,den);
|
||||
M(t,t,den);
|
||||
M(r[0],t,den);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) M(r[0],r[0],I);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) return -1;
|
||||
|
||||
if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]);
|
||||
|
||||
M(r[3],r[0],r[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dropbear_ed25519_verify(const u8 *m,u32 mlen,const u8 *s,u32 slen,const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 t[32],h[64];
|
||||
gf p[4],q[4];
|
||||
|
||||
if (slen < 64) return -1;
|
||||
|
||||
if (unpackneg(q,pk)) return -1;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
|
||||
reduce(h);
|
||||
scalarmult(p,q,h);
|
||||
|
||||
scalarbase(q,s + 32);
|
||||
add(p,q);
|
||||
pack(t,p);
|
||||
|
||||
if (crypto_verify_32(s, t))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519 || DROPBEAR_ED25519 */
|
||||
37
curve25519.h
Normal file
37
curve25519.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. */
|
||||
|
||||
#ifndef DROPBEAR_CURVE25519_H
|
||||
#define DROPBEAR_CURVE25519_H
|
||||
|
||||
void dropbear_curve25519_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
|
||||
void dropbear_ed25519_make_key(unsigned char *pk, unsigned char *sk);
|
||||
void dropbear_ed25519_sign(const unsigned char *m, unsigned long mlen,
|
||||
unsigned char *s, unsigned long *slen,
|
||||
const unsigned char *sk, const unsigned char *pk);
|
||||
int dropbear_ed25519_verify(const unsigned char *m, unsigned long mlen,
|
||||
const unsigned char *s, unsigned long slen,
|
||||
const unsigned char *pk);
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519_H */
|
||||
17
dbclient.1
17
dbclient.1
@@ -111,11 +111,22 @@ if 0 disables keepalives. If no response is received for 3 consecutive keepalive
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
.TP
|
||||
|
||||
.\" TODO: how to avoid a line break between these two -J arguments?
|
||||
.B \-J \fIproxy_command
|
||||
.TP
|
||||
.B \-J \fI&fd
|
||||
.br
|
||||
Use the standard input/output of the program \fIproxy_command\fR rather than using
|
||||
a normal TCP connection. A hostname should be still be provided, as this is used for
|
||||
comparing saved hostkeys. This command will be executed as "exec proxy_command ..." with the
|
||||
default shell.
|
||||
|
||||
The second form &fd will make dbclient use the numeric file descriptor as a socket. This
|
||||
can be used for more complex tunnelling scenarios. Example usage with socat is
|
||||
|
||||
socat EXEC:'dbclient -J &38 ev',fdin=38,fdout=38 TCP4:host.example.com:22
|
||||
|
||||
.TP
|
||||
.B \-B \fIendhost:endport
|
||||
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
|
||||
@@ -133,8 +144,8 @@ Can be used to give options in the format used by OpenSSH config file. This is
|
||||
useful for specifying options for which there is no separate command-line flag.
|
||||
For full details of the options listed below, and their possible values, see
|
||||
ssh_config(5).
|
||||
The following options have currently been implemented:
|
||||
|
||||
For now following options have been implemented:
|
||||
.RS
|
||||
.TP
|
||||
.B ExitOnForwardFailure
|
||||
@@ -147,6 +158,10 @@ Send dbclient log messages to syslog in addition to stderr.
|
||||
.B \-s
|
||||
The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR
|
||||
.TP
|
||||
.B \-b \fI[address][:port]
|
||||
Bind to a specific local address when connecting to the remote host. This can be used to choose from
|
||||
multiple outgoing interfaces. Either address or port (or both) can be given.
|
||||
.TP
|
||||
.B \-V
|
||||
Print the version
|
||||
|
||||
|
||||
13
dbhelpers.c
13
dbhelpers.c
@@ -9,16 +9,9 @@ void m_burn(void *data, unsigned int len) {
|
||||
#elif defined(HAVE_EXPLICIT_BZERO)
|
||||
explicit_bzero(data, len);
|
||||
#else
|
||||
/* Based on the method in David Wheeler's
|
||||
* "Secure Programming for Linux and Unix HOWTO". May not be safe
|
||||
* against link-time optimisation. */
|
||||
volatile char *p = data;
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
while (len--) {
|
||||
*p++ = 0x0;
|
||||
}
|
||||
/* This must be volatile to avoid compiler optimisation */
|
||||
volatile void *p = data;
|
||||
memset((void*)p, 0x0, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
/* This header defines some things that are also used by libtomcrypt/math.
|
||||
We avoid including normal include.h since that can result in conflicting
|
||||
definitinos - only include config.h */
|
||||
definitions - only include config.h */
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
192
dbmalloc.c
Normal file
192
dbmalloc.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "dbmalloc.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
|
||||
void * m_calloc(size_t nmemb, size_t size) {
|
||||
if (SIZE_T_MAX / nmemb < size) {
|
||||
dropbear_exit("m_calloc failed");
|
||||
}
|
||||
return m_malloc(nmemb*size);
|
||||
}
|
||||
|
||||
void * m_strdup(const char * str) {
|
||||
char* ret;
|
||||
unsigned int len;
|
||||
len = strlen(str);
|
||||
|
||||
ret = m_malloc(len+1);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_strdup failed");
|
||||
}
|
||||
memcpy(ret, str, len+1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !DROPBEAR_TRACKING_MALLOC
|
||||
|
||||
/* Simple wrappers around malloc etc */
|
||||
void * m_malloc(size_t size) {
|
||||
|
||||
void* ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
ret = calloc(1, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
ret = realloc(ptr, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
/* For fuzzing */
|
||||
|
||||
struct dbmalloc_header {
|
||||
unsigned int epoch;
|
||||
struct dbmalloc_header *prev;
|
||||
struct dbmalloc_header *next;
|
||||
};
|
||||
|
||||
static void put_alloc(struct dbmalloc_header *header);
|
||||
static void remove_alloc(struct dbmalloc_header *header);
|
||||
|
||||
/* end of the linked list */
|
||||
static struct dbmalloc_header* staple;
|
||||
|
||||
unsigned int current_epoch = 0;
|
||||
|
||||
void m_malloc_set_epoch(unsigned int epoch) {
|
||||
current_epoch = epoch;
|
||||
}
|
||||
|
||||
void m_malloc_free_epoch(unsigned int epoch, int dofree) {
|
||||
struct dbmalloc_header* header;
|
||||
struct dbmalloc_header* nextheader = NULL;
|
||||
struct dbmalloc_header* oldstaple = staple;
|
||||
staple = NULL;
|
||||
/* free allocations from this epoch, create a new staple-anchored list from
|
||||
the remainder */
|
||||
for (header = oldstaple; header; header = nextheader)
|
||||
{
|
||||
nextheader = header->next;
|
||||
if (header->epoch == epoch) {
|
||||
if (dofree) {
|
||||
free(header);
|
||||
}
|
||||
} else {
|
||||
header->prev = NULL;
|
||||
header->next = NULL;
|
||||
put_alloc(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void put_alloc(struct dbmalloc_header *header) {
|
||||
assert(header->next == NULL);
|
||||
assert(header->prev == NULL);
|
||||
if (staple) {
|
||||
staple->prev = header;
|
||||
}
|
||||
header->next = staple;
|
||||
staple = header;
|
||||
}
|
||||
|
||||
static void remove_alloc(struct dbmalloc_header *header) {
|
||||
if (header->prev) {
|
||||
header->prev->next = header->next;
|
||||
}
|
||||
if (header->next) {
|
||||
header->next->prev = header->prev;
|
||||
}
|
||||
if (staple == header) {
|
||||
staple = header->next;
|
||||
}
|
||||
header->prev = NULL;
|
||||
header->next = NULL;
|
||||
}
|
||||
|
||||
static struct dbmalloc_header* get_header(void* ptr) {
|
||||
char* bptr = ptr;
|
||||
return (struct dbmalloc_header*)&bptr[-sizeof(struct dbmalloc_header)];
|
||||
}
|
||||
|
||||
void * m_malloc(size_t size) {
|
||||
char* mem = NULL;
|
||||
struct dbmalloc_header* header = NULL;
|
||||
|
||||
if (size == 0 || size > 1e9) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
|
||||
size = size + sizeof(struct dbmalloc_header);
|
||||
|
||||
mem = calloc(1, size);
|
||||
if (mem == NULL) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
header = (struct dbmalloc_header*)mem;
|
||||
put_alloc(header);
|
||||
header->epoch = current_epoch;
|
||||
return &mem[sizeof(struct dbmalloc_header)];
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
char* mem = NULL;
|
||||
struct dbmalloc_header* header = NULL;
|
||||
if (size == 0 || size > 1e9) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
|
||||
header = get_header(ptr);
|
||||
remove_alloc(header);
|
||||
|
||||
size = size + sizeof(struct dbmalloc_header);
|
||||
mem = realloc(header, size);
|
||||
if (mem == NULL) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
|
||||
header = (struct dbmalloc_header*)mem;
|
||||
put_alloc(header);
|
||||
return &mem[sizeof(struct dbmalloc_header)];
|
||||
}
|
||||
|
||||
void m_free_direct(void* ptr) {
|
||||
struct dbmalloc_header* header = NULL;
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
header = get_header(ptr);
|
||||
remove_alloc(header);
|
||||
free(header);
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_TRACKING_MALLOC */
|
||||
|
||||
void * m_realloc_ltm(void* ptr, size_t oldsize, size_t newsize) {
|
||||
(void)oldsize;
|
||||
return m_realloc(ptr, newsize);
|
||||
}
|
||||
|
||||
void m_free_ltm(void *mem, size_t size) {
|
||||
(void)size;
|
||||
m_free_direct(mem);
|
||||
}
|
||||
27
dbmalloc.h
Normal file
27
dbmalloc.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef DBMALLOC_H_
|
||||
#define DBMALLOC_H_
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdlib.h"
|
||||
#include "options.h"
|
||||
|
||||
void * m_malloc(size_t size);
|
||||
void * m_calloc(size_t nmemb, size_t size);
|
||||
void * m_strdup(const char * str);
|
||||
void * m_realloc(void* ptr, size_t size);
|
||||
|
||||
#if DROPBEAR_TRACKING_MALLOC
|
||||
void m_free_direct(void* ptr);
|
||||
void m_malloc_set_epoch(unsigned int epoch);
|
||||
void m_malloc_free_epoch(unsigned int epoch, int dofree);
|
||||
|
||||
#else
|
||||
/* plain wrapper */
|
||||
#define m_free_direct free
|
||||
|
||||
#endif
|
||||
|
||||
#define m_free(X) do {m_free_direct(X); (X) = NULL;} while (0)
|
||||
|
||||
|
||||
#endif /* DBMALLOC_H_ */
|
||||
188
dbrandom.c
188
dbrandom.c
@@ -27,7 +27,7 @@
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
#include "runopts.h"
|
||||
|
||||
/* this is used to generate unique output from the same hashpool */
|
||||
static uint32_t counter = 0;
|
||||
@@ -49,24 +49,19 @@ static int donerandinit = 0;
|
||||
*
|
||||
*/
|
||||
|
||||
/* Pass len=0 to hash an entire file */
|
||||
/* Pass wantlen=0 to hash an entire file */
|
||||
static int
|
||||
process_file(hash_state *hs, const char *filename,
|
||||
unsigned int len, int prngd)
|
||||
{
|
||||
static int already_blocked = 0;
|
||||
int readfd;
|
||||
unsigned int wantlen, int prngd) {
|
||||
int readfd = -1;
|
||||
unsigned int readcount;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
if (prngd)
|
||||
{
|
||||
if (prngd) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
readfd = connect_unix(filename);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
readfd = open(filename, O_RDONLY);
|
||||
}
|
||||
|
||||
@@ -75,58 +70,31 @@ process_file(hash_state *hs, const char *filename,
|
||||
}
|
||||
|
||||
readcount = 0;
|
||||
while (len == 0 || readcount < len)
|
||||
{
|
||||
while (wantlen == 0 || readcount < wantlen) {
|
||||
int readlen, wantread;
|
||||
unsigned char readbuf[4096];
|
||||
if (!already_blocked && !prngd)
|
||||
{
|
||||
int res;
|
||||
struct timeval timeout;
|
||||
fd_set read_fds;
|
||||
|
||||
timeout.tv_sec = 2;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(readfd, &read_fds);
|
||||
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (res == 0)
|
||||
{
|
||||
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
|
||||
already_blocked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
if (wantlen == 0) {
|
||||
wantread = sizeof(readbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
wantread = MIN(sizeof(readbuf), len-readcount);
|
||||
} else {
|
||||
wantread = MIN(sizeof(readbuf), wantlen-readcount);
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
if (prngd)
|
||||
{
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (prngd) {
|
||||
char egdcmd[2];
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)wantread;
|
||||
if (write(readfd, egdcmd, 2) < 0)
|
||||
{
|
||||
if (write(readfd, egdcmd, 2) < 0) {
|
||||
dropbear_exit("Can't send command to egd");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
readlen = read(readfd, readbuf, wantread);
|
||||
if (readlen <= 0) {
|
||||
if (readlen < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (readlen == 0 && len == 0)
|
||||
{
|
||||
if (readlen == 0 && wantlen == 0) {
|
||||
/* whole file was read as requested */
|
||||
break;
|
||||
}
|
||||
@@ -141,10 +109,16 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void addrandom(unsigned char * buf, unsigned int len)
|
||||
void addrandom(const unsigned char * buf, unsigned int len)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
/* existing state (zeroes on startup) */
|
||||
@@ -157,7 +131,12 @@ void addrandom(unsigned char * buf, unsigned int len)
|
||||
|
||||
static void write_urandom()
|
||||
{
|
||||
#ifndef DROPBEAR_PRNGD_SOCKET
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if !DROPBEAR_USE_PRNGD
|
||||
/* This is opportunistic, don't worry about failure */
|
||||
unsigned char buf[INIT_SEED_SIZE];
|
||||
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
|
||||
@@ -170,6 +149,75 @@ static void write_urandom()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
void fuzz_seed(void) {
|
||||
hash_state hs;
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
|
||||
sha1_done(&hs, hashpool);
|
||||
|
||||
counter = 0;
|
||||
donerandinit = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_GETRANDOM
|
||||
/* Reads entropy seed with getrandom().
|
||||
* May block if the kernel isn't ready.
|
||||
* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int process_getrandom(hash_state *hs) {
|
||||
char buf[INIT_SEED_SIZE];
|
||||
ssize_t ret;
|
||||
|
||||
/* First try non-blocking so that we can warn about waiting */
|
||||
ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
/* Old kernel */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
/* Other errors fall through to blocking getrandom() */
|
||||
TRACE(("first getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
if (errno == EAGAIN) {
|
||||
dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised...");
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait blocking if needed. Loop in case we get EINTR */
|
||||
while (ret != sizeof(buf)) {
|
||||
ret = getrandom(buf, sizeof(buf), 0);
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success */
|
||||
break;
|
||||
}
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
/* Try again. */
|
||||
continue;
|
||||
}
|
||||
if (ret >= 0) {
|
||||
TRACE(("Short read %zd from getrandom() shouldn't happen", ret))
|
||||
/* Try again? */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Unexpected problem, fall back to /dev/urandom */
|
||||
TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success, stir in the entropy */
|
||||
sha1_process(hs, (void*)buf, sizeof(buf));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
}
|
||||
#endif /* HAVE_GETRANDOM */
|
||||
|
||||
/* Initialise the prng from /dev/urandom or prngd. This function can
|
||||
* be called multiple times */
|
||||
void seedrandom() {
|
||||
@@ -179,27 +227,45 @@ void seedrandom() {
|
||||
pid_t pid;
|
||||
struct timeval tv;
|
||||
clock_t clockval;
|
||||
int urandom_seeded = 0;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
|
||||
/* existing state */
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
#ifdef HAVE_GETRANDOM
|
||||
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!urandom_seeded) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
} /* urandom_seeded */
|
||||
|
||||
/* A few other sources to fall back on.
|
||||
* Add more here for other platforms */
|
||||
#ifdef __linux__
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
void seedrandom(void);
|
||||
void genrandom(unsigned char* buf, unsigned int len);
|
||||
void addrandom(unsigned char * buf, unsigned int len);
|
||||
void addrandom(const unsigned char * buf, unsigned int len);
|
||||
void gen_random_mpint(mp_int *max, mp_int *rand);
|
||||
|
||||
#endif /* DROPBEAR_RANDOM_H_ */
|
||||
|
||||
168
dbutil.c
168
dbutil.c
@@ -79,7 +79,7 @@ void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_N
|
||||
void (*_dropbear_log)(int priority, const char* format, va_list param)
|
||||
= generic_dropbear_log;
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
int debug_trace = 0;
|
||||
#endif
|
||||
|
||||
@@ -120,6 +120,13 @@ static void generic_dropbear_exit(int exitcode, const char* format,
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
/* longjmp before cleaning up svr_opts */
|
||||
if (fuzz.do_jmp) {
|
||||
longjmp(fuzz.jmp, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
@@ -149,7 +156,7 @@ void dropbear_log(int priority, const char* format, ...) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
|
||||
static double debug_start_time = -1;
|
||||
|
||||
@@ -214,7 +221,7 @@ void dropbear_trace2(const char* format, ...) {
|
||||
#endif /* DEBUG_TRACE */
|
||||
|
||||
/* Connect to a given unix socket. The socket is blocking */
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
#if ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* path) {
|
||||
struct sockaddr_un addr;
|
||||
int fd = -1;
|
||||
@@ -241,7 +248,7 @@ int connect_unix(const char* path) {
|
||||
* it will be run after the child has fork()ed, and is passed exec_data.
|
||||
* If ret_errfd == NULL then stderr will not be captured.
|
||||
* ret_pid can be passed as NULL to discard the pid. */
|
||||
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
|
||||
int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
|
||||
int infds[2];
|
||||
int outfds[2];
|
||||
@@ -262,7 +269,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef USE_VFORK
|
||||
#if DROPBEAR_VFORK
|
||||
pid = vfork();
|
||||
#else
|
||||
pid = fork();
|
||||
@@ -371,7 +378,7 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
|
||||
execv(usershell, argv);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
void printhex(const char * label, const unsigned char * buf, int len) {
|
||||
|
||||
int i;
|
||||
@@ -392,6 +399,7 @@ void printhex(const char * label, const unsigned char * buf, int len) {
|
||||
void printmpint(const char *label, mp_int *mp) {
|
||||
buffer *buf = buf_new(1000);
|
||||
buf_putmpint(buf, mp);
|
||||
fprintf(stderr, "%d bits ", mp_count_bits(mp));
|
||||
printhex(label, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
|
||||
@@ -465,7 +473,7 @@ out:
|
||||
* authkeys file.
|
||||
* Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
|
||||
/* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */
|
||||
#if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH)
|
||||
#if DROPBEAR_CLIENT || DROPBEAR_SVR_PUBKEY_AUTH
|
||||
int buf_getline(buffer * line, FILE * authfile) {
|
||||
|
||||
int c = EOF;
|
||||
@@ -506,7 +514,7 @@ out:
|
||||
void m_close(int fd) {
|
||||
int val;
|
||||
|
||||
if (fd == -1) {
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -520,57 +528,26 @@ void m_close(int fd) {
|
||||
}
|
||||
}
|
||||
|
||||
void * m_malloc(size_t size) {
|
||||
|
||||
void* ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
ret = calloc(1, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void * m_strdup(const char * str) {
|
||||
char* ret;
|
||||
|
||||
ret = strdup(str);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_strdup failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
ret = realloc(ptr, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setnonblocking(int fd) {
|
||||
|
||||
TRACE(("setnonblocking: %d", fd))
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
if (errno == ENODEV) {
|
||||
/* Some devices (like /dev/null redirected in)
|
||||
* can't be set to non-blocking */
|
||||
TRACE(("ignoring ENODEV for setnonblocking"))
|
||||
} else {
|
||||
{
|
||||
dropbear_exit("Couldn't set nonblocking");
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE(("leave setnonblocking"))
|
||||
}
|
||||
@@ -628,57 +605,84 @@ int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
return c;
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||
/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
|
||||
reach userspace include headers */
|
||||
#ifndef CLOCK_MONOTONIC_COARSE
|
||||
#define CLOCK_MONOTONIC_COARSE 6
|
||||
/* higher-resolution monotonic timestamp, falls back to gettimeofday */
|
||||
void gettime_wrapper(struct timespec *now) {
|
||||
struct timeval tv;
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
/* time stands still when fuzzing */
|
||||
now->tv_sec = 5;
|
||||
now->tv_nsec = 0;
|
||||
}
|
||||
#endif
|
||||
static clockid_t get_linux_clock_source() {
|
||||
struct timespec ts;
|
||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
|
||||
return CLOCK_MONOTONIC_COARSE;
|
||||
}
|
||||
|
||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
|
||||
return CLOCK_MONOTONIC;
|
||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
/* POSIX monotonic clock. Newer Linux, BSD, MacOSX >10.12 */
|
||||
if (clock_gettime(CLOCK_MONOTONIC, now) == 0) {
|
||||
return;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
time_t monotonic_now() {
|
||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||
static clockid_t clock_source = -2;
|
||||
|
||||
if (clock_source == -2) {
|
||||
/* First run, find out which one works.
|
||||
-1 will fall back to time() */
|
||||
clock_source = get_linux_clock_source();
|
||||
}
|
||||
|
||||
if (clock_source >= 0) {
|
||||
struct timespec ts;
|
||||
if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
|
||||
/* Intermittent clock failures should not happen */
|
||||
dropbear_exit("Clock broke");
|
||||
{
|
||||
/* Old linux toolchain - kernel might support it but not the build headers */
|
||||
/* Also glibc <2.17 requires -lrt which we neglect to add */
|
||||
static int linux_monotonic_failed = 0;
|
||||
if (!linux_monotonic_failed) {
|
||||
/* CLOCK_MONOTONIC isn't in some headers */
|
||||
int clock_source_monotonic = 1;
|
||||
if (syscall(SYS_clock_gettime, clock_source_monotonic, now) == 0) {
|
||||
return;
|
||||
} else {
|
||||
/* Don't try again */
|
||||
linux_monotonic_failed = 1;
|
||||
}
|
||||
return ts.tv_sec;
|
||||
}
|
||||
#endif /* linux clock_gettime */
|
||||
}
|
||||
#endif /* linux fallback clock_gettime */
|
||||
|
||||
#if defined(HAVE_MACH_ABSOLUTE_TIME)
|
||||
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||
{
|
||||
/* OS X pre 10.12, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||
static mach_timebase_info_data_t timebase_info;
|
||||
uint64_t scaled_time;
|
||||
if (timebase_info.denom == 0) {
|
||||
mach_timebase_info(&timebase_info);
|
||||
}
|
||||
return mach_absolute_time() * timebase_info.numer / timebase_info.denom
|
||||
/ 1e9;
|
||||
scaled_time = mach_absolute_time() * timebase_info.numer / timebase_info.denom;
|
||||
now->tv_sec = scaled_time / 1000000000;
|
||||
now->tv_nsec = scaled_time % 1000000000;
|
||||
}
|
||||
#endif /* osx mach_absolute_time */
|
||||
|
||||
/* Fallback for everything else - this will sometimes go backwards */
|
||||
return time(NULL);
|
||||
gettimeofday(&tv, NULL);
|
||||
now->tv_sec = tv.tv_sec;
|
||||
now->tv_nsec = 1000*tv.tv_usec;
|
||||
}
|
||||
|
||||
/* second-resolution monotonic timestamp */
|
||||
time_t monotonic_now() {
|
||||
struct timespec ts;
|
||||
gettime_wrapper(&ts);
|
||||
return ts.tv_sec;
|
||||
}
|
||||
|
||||
void fsync_parent_dir(const char* fn) {
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
char *fn_dir = m_strdup(fn);
|
||||
char *dir = dirname(fn_dir);
|
||||
int dirfd = open(dir, O_RDONLY);
|
||||
|
||||
if (dirfd != -1) {
|
||||
if (fsync(dirfd) != 0) {
|
||||
TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
|
||||
}
|
||||
m_close(dirfd);
|
||||
} else {
|
||||
TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
|
||||
}
|
||||
|
||||
m_free(fn_dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
22
dbutil.h
22
dbutil.h
@@ -30,6 +30,7 @@
|
||||
#include "buffer.h"
|
||||
#include "queue.h"
|
||||
#include "dbhelpers.h"
|
||||
#include "dbmalloc.h"
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog(const char *ident);
|
||||
@@ -45,7 +46,7 @@ void dropbear_log(int priority, const char* format, ...) ATTRIB_PRINTF(2,3) ;
|
||||
|
||||
void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void printhex(const char * label, const unsigned char * buf, int len);
|
||||
@@ -56,20 +57,16 @@ extern int debug_trace;
|
||||
|
||||
char * stripcontrol(const char * text);
|
||||
|
||||
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
|
||||
int *writefd, int *readfd, int *errfd, pid_t *pid);
|
||||
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
#if ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* addr);
|
||||
#endif
|
||||
int buf_readfile(buffer* buf, const char* filename);
|
||||
int buf_getline(buffer * line, FILE * authfile);
|
||||
|
||||
void m_close(int fd);
|
||||
void * m_malloc(size_t size);
|
||||
void * m_strdup(const char * str);
|
||||
void * m_realloc(void* ptr, size_t size);
|
||||
#define m_free(X) do {free(X); (X) = NULL;} while (0)
|
||||
void setnonblocking(int fd);
|
||||
void disallow_core(void);
|
||||
int m_str_to_uint(const char* str, unsigned int *val);
|
||||
@@ -86,7 +83,18 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
|
||||
/* Returns a time in seconds that doesn't go backwards - does not correspond to
|
||||
a real-world clock */
|
||||
time_t monotonic_now(void);
|
||||
/* Higher resolution clock_gettime(CLOCK_MONOTONIC) wrapper */
|
||||
void gettime_wrapper(struct timespec *now);
|
||||
|
||||
char * expand_homedir_path(const char *inpath);
|
||||
|
||||
void fsync_parent_dir(const char* fn);
|
||||
|
||||
#if DROPBEAR_MSAN
|
||||
/* FD_ZERO seems to leave some memory uninitialized. clear it to avoid false positives */
|
||||
#define DROPBEAR_FD_ZERO(fds) do { memset((fds), 0x0, sizeof(fd_set)); FD_ZERO(fds); } while(0)
|
||||
#else
|
||||
#define DROPBEAR_FD_ZERO(fds) FD_ZERO(fds)
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_DBUTIL_H_ */
|
||||
|
||||
36
debian/changelog
vendored
36
debian/changelog
vendored
@@ -1,3 +1,39 @@
|
||||
dropbear (2020.79-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Jun 2020 22:51:57 +0800
|
||||
|
||||
dropbear (2019.78-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 27 Mar 2019 22:51:57 +0800
|
||||
|
||||
dropbear (2019.77-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sat, 23 Mar 2019 22:51:57 +0800
|
||||
|
||||
dropbear (2018.76-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tue, 27 Feb 2018 22:51:57 +0800
|
||||
|
||||
dropbear (2017.75-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 May 2017 22:51:57 +0800
|
||||
|
||||
dropbear (2016.74-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 21 Jul 2016 22:51:57 +0800
|
||||
|
||||
dropbear (2016.73-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
1
debian/dropbear.docs
vendored
1
debian/dropbear.docs
vendored
@@ -1,4 +1,3 @@
|
||||
README
|
||||
TODO
|
||||
debian/README.runit
|
||||
debian/README.Debian.diet
|
||||
|
||||
23
debug.h
23
debug.h
@@ -33,27 +33,15 @@
|
||||
* etc. Don't use this normally, it might cause problems */
|
||||
/* #define DEBUG_VALGRIND */
|
||||
|
||||
/* Define this to compile in trace debugging printf()s.
|
||||
* You'll need to run programs with "-v" to turn this on.
|
||||
*
|
||||
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
|
||||
* since the printing may not sanitise strings etc. This will add a reasonable
|
||||
* amount to your executable size. */
|
||||
/*#define DEBUG_TRACE*/
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
* attempting to track down a problem */
|
||||
/*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
|
||||
ses.writepayload->pos == 0)*/
|
||||
|
||||
#ifndef CHECKCLEARTOWRITE
|
||||
#define CHECKCLEARTOWRITE()
|
||||
|
||||
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
|
||||
* output when Dropbear forks. This will allow it gprof to be used.
|
||||
* It's useful to run dropbear -F, so you don't fork as much */
|
||||
/* (This is Linux specific) */
|
||||
/*#define DEBUG_FORKGPROF*/
|
||||
#endif
|
||||
|
||||
/* A couple of flags, not usually useful, and mightn't do anything */
|
||||
|
||||
@@ -61,7 +49,8 @@
|
||||
/*#define DEBUG_RSA*/
|
||||
|
||||
/* you don't need to touch this block */
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
extern int debug_trace;
|
||||
#define TRACE(X) dropbear_trace X;
|
||||
#define TRACE2(X) dropbear_trace2 X;
|
||||
#else /*DEBUG_TRACE*/
|
||||
@@ -71,7 +60,9 @@
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
You will need to pass "-F" as well. */
|
||||
/* #define DEBUG_NOFORK */
|
||||
#ifndef DEBUG_NOFORK
|
||||
#define DEBUG_NOFORK 0
|
||||
#endif
|
||||
|
||||
|
||||
/* For testing as non-root on shadowed systems, include the crypt of a password
|
||||
|
||||
314
default_options.h
Normal file
314
default_options.h
Normal file
@@ -0,0 +1,314 @@
|
||||
#ifndef DROPBEAR_DEFAULT_OPTIONS_H_
|
||||
#define DROPBEAR_DEFAULT_OPTIONS_H_
|
||||
/*
|
||||
> > > Read This < < <
|
||||
|
||||
default_options.h documents compile-time options, and provides default values.
|
||||
|
||||
Local customisation should be added to localoptions.h which is
|
||||
used if it exists in the build directory. Options defined there will override
|
||||
any options in this file.
|
||||
|
||||
Options can also be defined with -DDROPBEAR_XXX=[0,1] in Makefile CFLAGS
|
||||
|
||||
IMPORTANT: Some options will require "make clean" after changes */
|
||||
|
||||
#define DROPBEAR_DEFPORT "22"
|
||||
|
||||
/* Listen on all interfaces */
|
||||
#define DROPBEAR_DEFADDRESS ""
|
||||
|
||||
/* Default hostkey paths - these can be specified on the command line */
|
||||
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
|
||||
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
|
||||
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
|
||||
#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key"
|
||||
|
||||
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
|
||||
* on chosen ports and keeps accepting connections. This is the default.
|
||||
*
|
||||
* Set INETD_MODE if you want to be able to run Dropbear with inetd (or
|
||||
* similar), where it will use stdin/stdout for connections, and each process
|
||||
* lasts for a single connection. Dropbear should be invoked with the -i flag
|
||||
* for inetd, and can only accept IPv4 connections.
|
||||
*
|
||||
* Both of these flags can be defined at once, don't compile without at least
|
||||
* one of them. */
|
||||
#define NON_INETD_MODE 1
|
||||
#define INETD_MODE 1
|
||||
|
||||
/* Include verbose debug output, enabled with -v at runtime.
|
||||
* This will add a reasonable amount to your executable size. */
|
||||
#define DEBUG_TRACE 0
|
||||
|
||||
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
|
||||
* several kB in binary size however will make the symmetrical ciphers and hashes
|
||||
* slower, perhaps by 50%. Recommended for small systems that aren't doing
|
||||
* much traffic. */
|
||||
#define DROPBEAR_SMALL_CODE 1
|
||||
|
||||
/* Enable X11 Forwarding - server only */
|
||||
#define DROPBEAR_X11FWD 0
|
||||
|
||||
/* Enable TCP Fowarding */
|
||||
/* 'Local' is "-L" style (client listening port forwarded via server)
|
||||
* 'Remote' is "-R" style (server listening port forwarded via client) */
|
||||
#define DROPBEAR_CLI_LOCALTCPFWD 1
|
||||
#define DROPBEAR_CLI_REMOTETCPFWD 1
|
||||
|
||||
#define DROPBEAR_SVR_LOCALTCPFWD 1
|
||||
#define DROPBEAR_SVR_REMOTETCPFWD 1
|
||||
|
||||
/* Enable Authentication Agent Forwarding */
|
||||
#define DROPBEAR_SVR_AGENTFWD 1
|
||||
#define DROPBEAR_CLI_AGENTFWD 1
|
||||
|
||||
/* Note: Both DROPBEAR_CLI_PROXYCMD and DROPBEAR_CLI_NETCAT must be set to
|
||||
* allow multihop dbclient connections */
|
||||
|
||||
/* Allow using -J <proxycommand> to run the connection through a
|
||||
pipe to a program, rather the normal TCP connection */
|
||||
#define DROPBEAR_CLI_PROXYCMD 1
|
||||
|
||||
/* Enable "Netcat mode" option. This will forward standard input/output
|
||||
* to a remote TCP-forwarded connection */
|
||||
#define DROPBEAR_CLI_NETCAT 1
|
||||
|
||||
/* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
|
||||
#define DROPBEAR_USER_ALGO_LIST 1
|
||||
|
||||
/* Encryption - at least one required.
|
||||
* AES128 should be enabled, some very old implementations might only
|
||||
* support 3DES.
|
||||
* Including both AES keysize variants (128 and 256) will result in
|
||||
* a minimal size increase */
|
||||
#define DROPBEAR_AES128 1
|
||||
#define DROPBEAR_AES256 1
|
||||
#define DROPBEAR_3DES 0
|
||||
#define DROPBEAR_TWOFISH256 0
|
||||
#define DROPBEAR_TWOFISH128 0
|
||||
|
||||
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
|
||||
* generally faster than AES256 on CPU w/o dedicated AES instructions,
|
||||
* having the same key size. Recommended.
|
||||
* Compiling in will add ~5,5kB to binary size on x86-64 */
|
||||
#define DROPBEAR_CHACHA20POLY1305 1
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. Recommended. */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE 1
|
||||
|
||||
/* Enable CBC mode for ciphers. This has security issues though
|
||||
may be required for compatibility with old implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE 0
|
||||
|
||||
/* Enable "Galois/Counter Mode" for ciphers. This authenticated
|
||||
* encryption mode is combination of CTR mode and GHASH. Recommended
|
||||
* for security and forwards compatibility, but slower than CTR on
|
||||
* CPU w/o dedicated AES/GHASH instructions.
|
||||
* Compiling in will add ~6kB to binary size on x86-64 */
|
||||
#define DROPBEAR_ENABLE_GCM_MODE 0
|
||||
|
||||
/* Message integrity. sha2-256 is recommended as a default,
|
||||
sha1 for compatibility */
|
||||
#define DROPBEAR_SHA1_HMAC 1
|
||||
#define DROPBEAR_SHA2_256_HMAC 1
|
||||
#define DROPBEAR_SHA1_96_HMAC 0
|
||||
|
||||
/* Hostkey/public key algorithms - at least one required, these are used
|
||||
* for hostkey as well as for verifying signatures with pubkey auth.
|
||||
* Removing either of these won't save very much space.
|
||||
* RSA is recommended
|
||||
* DSS may be necessary to connect to some systems though
|
||||
is not recommended for new keys */
|
||||
#define DROPBEAR_RSA 1
|
||||
#define DROPBEAR_DSS 1
|
||||
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
|
||||
* code (either ECDSA or ECDH) increases binary size - around 30kB
|
||||
* on x86-64 */
|
||||
#define DROPBEAR_ECDSA 1
|
||||
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
|
||||
binary size - around 7,5kB on x86-64 */
|
||||
#define DROPBEAR_ED25519 1
|
||||
|
||||
/* RSA must be >=1024 */
|
||||
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
|
||||
/* DSS is always 1024 */
|
||||
/* ECDSA defaults to largest size configured, usually 521 */
|
||||
/* Ed25519 is always 256 */
|
||||
|
||||
/* Add runtime flag "-R" to generate hostkeys as-needed when the first
|
||||
connection using that key type occurs.
|
||||
This avoids the need to otherwise run "dropbearkey" and avoids some problems
|
||||
with badly seeded /dev/urandom when systems first boot. */
|
||||
#define DROPBEAR_DELAY_HOSTKEY 1
|
||||
|
||||
|
||||
/* Key exchange algorithm.
|
||||
|
||||
* group14_sha1 - 2048 bit, sha1
|
||||
* group14_sha256 - 2048 bit, sha2-256
|
||||
* group16 - 4096 bit, sha2-512
|
||||
* group1 - 1024 bit, sha1
|
||||
* curve25519 - elliptic curve DH
|
||||
* ecdh - NIST elliptic curve DH (256, 384, 521)
|
||||
*
|
||||
* group1 is too small for security though is necessary if you need
|
||||
compatibility with some implementations such as Dropbear versions < 0.53
|
||||
* group14 is supported by most implementations.
|
||||
* group16 provides a greater strength level but is slower and increases binary size
|
||||
* curve25519 and ecdh algorithms are faster than non-elliptic curve methods
|
||||
* curve25519 increases binary size by ~2,5kB on x86-64
|
||||
* including either ECDH or ECDSA increases binary size by ~30kB on x86-64
|
||||
|
||||
* Small systems should generally include either curve25519 or ecdh for performance.
|
||||
* curve25519 is less widely supported but is faster
|
||||
*/
|
||||
#define DROPBEAR_DH_GROUP14_SHA1 1
|
||||
#define DROPBEAR_DH_GROUP14_SHA256 1
|
||||
#define DROPBEAR_DH_GROUP16 0
|
||||
#define DROPBEAR_CURVE25519 1
|
||||
#define DROPBEAR_ECDH 1
|
||||
#define DROPBEAR_DH_GROUP1 1
|
||||
|
||||
/* When group1 is enabled it will only be allowed by Dropbear client
|
||||
not as a server, due to concerns over its strength. Set to 0 to allow
|
||||
group1 in Dropbear server too */
|
||||
#define DROPBEAR_DH_GROUP1_CLIENTONLY 1
|
||||
|
||||
/* Control the memory/performance/compression tradeoff for zlib.
|
||||
* Set windowBits=8 for least memory usage, see your system's
|
||||
* zlib.h for full details.
|
||||
* Default settings (windowBits=15) will use 256kB for compression
|
||||
* windowBits=8 will use 129kB for compression.
|
||||
* Both modes will use ~35kB for decompression (using windowBits=15 for
|
||||
* interoperability) */
|
||||
#define DROPBEAR_ZLIB_WINDOW_BITS 15
|
||||
|
||||
/* Whether to do reverse DNS lookups. */
|
||||
#define DO_HOST_LOOKUP 0
|
||||
|
||||
/* Whether to print the message of the day (MOTD). */
|
||||
#define DO_MOTD 1
|
||||
#define MOTD_FILENAME "/etc/motd"
|
||||
|
||||
/* Authentication Types - at least one required.
|
||||
RFC Draft requires pubkey auth, and recommends password */
|
||||
#define DROPBEAR_SVR_PASSWORD_AUTH 1
|
||||
|
||||
/* Note: PAM auth is quite simple and only works for PAM modules which just do
|
||||
* a simple "Login: " "Password: " (you can edit the strings in svr-authpam.c).
|
||||
* It's useful for systems like OS X where standard password crypts don't work
|
||||
* but there's an interface via a PAM module. It won't work for more complex
|
||||
* PAM challenge/response.
|
||||
* You can't enable both PASSWORD and PAM. */
|
||||
#define DROPBEAR_SVR_PAM_AUTH 0
|
||||
|
||||
/* ~/.ssh/authorized_keys authentication */
|
||||
#define DROPBEAR_SVR_PUBKEY_AUTH 1
|
||||
|
||||
/* Whether to take public key options in
|
||||
* authorized_keys file into account */
|
||||
#define DROPBEAR_SVR_PUBKEY_OPTIONS 1
|
||||
|
||||
/* Set this to 0 if your system does not have multiple user support.
|
||||
(Linux kernel CONFIG_MULTIUSER option)
|
||||
The resulting binary will not run on a normal system. */
|
||||
#define DROPBEAR_SVR_MULTIUSER 1
|
||||
|
||||
/* Client authentication options */
|
||||
#define DROPBEAR_CLI_PASSWORD_AUTH 1
|
||||
#define DROPBEAR_CLI_PUBKEY_AUTH 1
|
||||
|
||||
/* A default argument for dbclient -i <privatekey>.
|
||||
Homedir is prepended unless path begins with / */
|
||||
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
|
||||
|
||||
/* Allow specifying the password for dbclient via the DROPBEAR_PASSWORD
|
||||
* environment variable. */
|
||||
#define DROPBEAR_USE_PASSWORD_ENV 1
|
||||
|
||||
/* Define this (as well as DROPBEAR_CLI_PASSWORD_AUTH) to allow the use of
|
||||
* a helper program for the ssh client. The helper program should be
|
||||
* specified in the SSH_ASKPASS environment variable, and dbclient
|
||||
* should be run with DISPLAY set and no tty. The program should
|
||||
* return the password on standard output */
|
||||
#define DROPBEAR_CLI_ASKPASS_HELPER 0
|
||||
|
||||
/* Save a network roundtrip by sendng a real auth request immediately after
|
||||
* sending a query for the available methods. This is not yet enabled by default
|
||||
since it could cause problems with non-compliant servers */
|
||||
#define DROPBEAR_CLI_IMMEDIATE_AUTH 0
|
||||
|
||||
/* Set this to use PRNGD or EGD instead of /dev/urandom */
|
||||
#define DROPBEAR_USE_PRNGD 0
|
||||
#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng"
|
||||
|
||||
/* Specify the number of clients we will allow to be connected but
|
||||
* not yet authenticated. After this limit, connections are rejected */
|
||||
/* The first setting is per-IP, to avoid denial of service */
|
||||
#define MAX_UNAUTH_PER_IP 5
|
||||
|
||||
/* And then a global limit to avoid chewing memory if connections
|
||||
* come from many IPs */
|
||||
#define MAX_UNAUTH_CLIENTS 30
|
||||
|
||||
/* Default maximum number of failed authentication tries (server option) */
|
||||
/* -T server option overrides */
|
||||
#define MAX_AUTH_TRIES 10
|
||||
|
||||
/* The default file to store the daemon's process ID, for shutdown
|
||||
scripts etc. This can be overridden with the -P flag */
|
||||
#define DROPBEAR_PIDFILE "/var/run/dropbear.pid"
|
||||
|
||||
/* The command to invoke for xauth when using X11 forwarding.
|
||||
* "-q" for quiet */
|
||||
#define XAUTH_COMMAND "/usr/bin/xauth -q"
|
||||
|
||||
|
||||
/* if you want to enable running an sftp server (such as the one included with
|
||||
* OpenSSH), set the path below and set DROPBEAR_SFTPSERVER.
|
||||
* The sftp-server program is not provided by Dropbear itself */
|
||||
#define DROPBEAR_SFTPSERVER 1
|
||||
#define SFTPSERVER_PATH "/usr/libexec/sftp-server"
|
||||
|
||||
/* This is used by the scp binary when used as a client binary. If you're
|
||||
* not using the Dropbear client, you'll need to change it */
|
||||
#define DROPBEAR_PATH_SSH_PROGRAM "/usr/bin/dbclient"
|
||||
|
||||
/* Whether to log commands executed by a client. This only logs the
|
||||
* (single) command sent to the server, not what a user did in a
|
||||
* shell/sftp session etc. */
|
||||
#define LOG_COMMANDS 0
|
||||
|
||||
/* Window size limits. These tend to be a trade-off between memory
|
||||
usage and network performance: */
|
||||
/* Size of the network receive window. This amount of memory is allocated
|
||||
as a per-channel receive buffer. Increasing this value can make a
|
||||
significant difference to network performance. 24kB was empirically
|
||||
chosen for a 100mbit ethernet network. The value can be altered at
|
||||
runtime with the -W argument. */
|
||||
#define DEFAULT_RECV_WINDOW 24576
|
||||
/* Maximum size of a received SSH data packet - this _MUST_ be >= 32768
|
||||
in order to interoperate with other implementations */
|
||||
#define RECV_MAX_PAYLOAD_LEN 32768
|
||||
/* Maximum size of a transmitted data packet - this can be any value,
|
||||
though increasing it may not make a significant difference. */
|
||||
#define TRANS_MAX_PAYLOAD_LEN 16384
|
||||
|
||||
/* Ensure that data is transmitted every KEEPALIVE seconds. This can
|
||||
be overridden at runtime with -K. 0 disables keepalives */
|
||||
#define DEFAULT_KEEPALIVE 0
|
||||
|
||||
/* If this many KEEPALIVES are sent with no packets received from the
|
||||
other side, exit. Not run-time configurable - if you have a need
|
||||
for runtime configuration please mail the Dropbear list */
|
||||
#define DEFAULT_KEEPALIVE_LIMIT 3
|
||||
|
||||
/* Ensure that data is received within IDLE_TIMEOUT seconds. This can
|
||||
be overridden at runtime with -I. 0 disables idle timeouts */
|
||||
#define DEFAULT_IDLE_TIMEOUT 0
|
||||
|
||||
/* The default path. This will often get replaced by the shell */
|
||||
#define DEFAULT_PATH "/usr/bin:/bin"
|
||||
|
||||
#endif /* DROPBEAR_DEFAULT_OPTIONS_H_ */
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "options.h"
|
||||
#include "dh_groups.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
@@ -92,3 +94,4 @@ const unsigned char dh_p_16[DH_P_16_LEN] = {
|
||||
/* Same for all groups */
|
||||
const int DH_G_VAL = 2;
|
||||
|
||||
#endif /* DROPBEAR_NORMAL_DH */
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define DROPBEAR_DH_GROUPS_H
|
||||
#include "options.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
#define DH_P_1_LEN 128
|
||||
extern const unsigned char dh_p_1[DH_P_1_LEN];
|
||||
@@ -17,8 +19,8 @@ extern const unsigned char dh_p_14[DH_P_14_LEN];
|
||||
extern const unsigned char dh_p_16[DH_P_16_LEN];
|
||||
#endif
|
||||
|
||||
|
||||
extern const int DH_G_VAL;
|
||||
|
||||
#endif /* DROPBEAR_NORMAL_DH */
|
||||
|
||||
#endif
|
||||
|
||||
20
dropbear.8
20
dropbear.8
@@ -91,6 +91,13 @@ if 0 disables keepalives. If no response is received for 3 consecutive keepalive
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
.TP
|
||||
.B \-T \fImax_authentication_attempts
|
||||
Set the number of authentication attempts allowed per connection. If unspecified the default is 10 (MAX_AUTH_TRIES)
|
||||
.TP
|
||||
.B \-c \fIforced_command
|
||||
Disregard the command provided by the user and always run \fIforced_command\fR. This also
|
||||
overrides any authorized_keys command= option.
|
||||
.TP
|
||||
.B \-V
|
||||
Print the version
|
||||
|
||||
@@ -100,7 +107,7 @@ Print the version
|
||||
Authorized Keys
|
||||
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
|
||||
ECDSA, or DSS
|
||||
ECDSA, Ed25519 or DSS
|
||||
key. Each line is of the form
|
||||
.TP
|
||||
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
|
||||
@@ -129,6 +136,7 @@ same functionality with other means even if no-pty is set.
|
||||
.TP
|
||||
.B command=\fR"\fIforced_command\fR"
|
||||
Disregard the command provided by the user and always run \fIforced_command\fR.
|
||||
The -c command line option overrides this.
|
||||
|
||||
The authorized_keys file and its containing ~/.ssh directory must only be
|
||||
writable by the user, otherwise Dropbear will not allow a login using public
|
||||
@@ -138,10 +146,12 @@ key authentication.
|
||||
Host Key Files
|
||||
|
||||
Host key files are read at startup from a standard location, by default
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
|
||||
/etc/dropbear/dropbear_ecdsa_host_key
|
||||
or specified on the commandline with -r. These are of the form generated
|
||||
by dropbearkey. The -R option can be used to automatically generate keys
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key,
|
||||
/etc/dropbear/dropbear_ecdsa_host_key and /etc/dropbear/dropbear_ed25519_host_key
|
||||
|
||||
If the -r command line option is specified the default files are not loaded.
|
||||
Host key files are of the form generated by dropbearkey.
|
||||
The -R option can be used to automatically generate keys
|
||||
in the default location - keys will be generated after startup when the first
|
||||
connection is established. This had the benefit that the system /dev/urandom
|
||||
random number source has a better chance of being securely seeded.
|
||||
|
||||
8
dropbear_lint.sh
Executable file
8
dropbear_lint.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
EXITCODE=0
|
||||
|
||||
# #ifdef instead of #if
|
||||
grep '#ifdef DROPBEAR' -I *.c *.h && EXITCODE=1
|
||||
|
||||
exit $EXITCODE
|
||||
@@ -53,8 +53,8 @@ static void printhelp(char * progname) {
|
||||
progname);
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_dropbearconvert) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearconvert) && defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearconvert) || !DROPBEAR_MULTI
|
||||
#if defined(DBMULTI_dropbearconvert) && DROPBEAR_MULTI
|
||||
int dropbearconvert_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
@@ -67,7 +67,7 @@ int main(int argc, char ** argv) {
|
||||
crypto_init();
|
||||
seedrandom();
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
/* It's hard for it to get in the way _too_ much */
|
||||
debug_trace = 1;
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
|
||||
.SH DESCRIPTION
|
||||
.B dropbearkey
|
||||
generates a
|
||||
\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
|
||||
\fIRSA\fR, \fIDSS\fR, \fIECDSA\fR, or \fIEd25519\fR
|
||||
format SSH private key, and saves it to a file for the use with the
|
||||
Dropbear client or server.
|
||||
Note that
|
||||
@@ -26,6 +26,7 @@ Type of key to generate.
|
||||
Must be one of
|
||||
.I rsa
|
||||
.I ecdsa
|
||||
.I ed25519
|
||||
or
|
||||
.IR dss .
|
||||
.TP
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
* mp_int y
|
||||
* mp_int x
|
||||
*
|
||||
* Ed25519:
|
||||
* string "ssh-ed25519"
|
||||
* string k (32 bytes) + A (32 bytes)
|
||||
*
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -51,6 +55,7 @@
|
||||
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "gened25519.h"
|
||||
#include "ecdsa.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "dbrandom.h"
|
||||
@@ -67,36 +72,42 @@ static void printhelp(char * progname) {
|
||||
|
||||
fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
|
||||
"-t type Type of key to generate. One of:\n"
|
||||
#ifdef DROPBEAR_RSA
|
||||
#if DROPBEAR_RSA
|
||||
" rsa\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
" dss\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECDSA
|
||||
" ecdsa\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" ed25519\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key.\n"
|
||||
" ~/.ssh/id_dropbear is recommended for client keys.\n"
|
||||
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
" DSS has a fixed size of 1024 bits\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECDSA
|
||||
" ECDSA has sizes "
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#if DROPBEAR_ECC_256
|
||||
"256 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
"384 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECC_521
|
||||
"521 "
|
||||
#endif
|
||||
"\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" Ed25519 has a fixed size of 256 bits\n"
|
||||
#endif
|
||||
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
"-v verbose\n"
|
||||
#endif
|
||||
,progname);
|
||||
@@ -106,7 +117,15 @@ static void printhelp(char * progname) {
|
||||
static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
if (bits != 256) {
|
||||
dropbear_exit("Ed25519 keys have a fixed size of 256 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
@@ -114,7 +133,7 @@ static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPEAR_DSS
|
||||
#if DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
|
||||
@@ -126,20 +145,20 @@ static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearkey) || !DROPBEAR_MULTI
|
||||
#if defined(DBMULTI_dropbearkey) && DROPBEAR_MULTI
|
||||
int dropbearkey_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
#endif
|
||||
|
||||
int i;
|
||||
char ** next = 0;
|
||||
char ** next = NULL;
|
||||
char * filename = NULL;
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
|
||||
char * typetext = NULL;
|
||||
char * sizetext = NULL;
|
||||
unsigned int bits = 0;
|
||||
unsigned int bits = 0, genbits;
|
||||
int printpub = 0;
|
||||
|
||||
crypto_init();
|
||||
@@ -174,7 +193,7 @@ int main(int argc, char ** argv) {
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
#ifdef DEBUG_TRACE
|
||||
#if DEBUG_TRACE
|
||||
case 'v':
|
||||
debug_trace = 1;
|
||||
break;
|
||||
@@ -206,24 +225,30 @@ int main(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
#if DROPBEAR_RSA
|
||||
if (strcmp(typetext, "rsa") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
if (strcmp(typetext, "dss") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECDSA
|
||||
if (strcmp(typetext, "ecdsa") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
if (strcmp(typetext, "ed25519") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_ED25519;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_NONE) {
|
||||
fprintf(stderr, "Unknown key type '%s'\n", typetext);
|
||||
@@ -240,8 +265,9 @@ int main(int argc, char ** argv) {
|
||||
check_signkey_bits(keytype, bits);;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Generating key, this may take a while...\n");
|
||||
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
|
||||
genbits = signkey_generate_get_bits(keytype, bits);
|
||||
fprintf(stderr, "Generating %u bit %s key, this may take a while...\n", genbits, typetext);
|
||||
if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)
|
||||
{
|
||||
dropbear_exit("Failed to generate key.\n");
|
||||
}
|
||||
|
||||
106
dss.c
106
dss.c
@@ -37,13 +37,14 @@
|
||||
* See FIPS186 or the Handbook of Applied Cryptography for details of the
|
||||
* algorithm */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
/* Load a dss key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_dss_key.
|
||||
* These should be freed with dss_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter buf_get_dss_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
@@ -56,17 +57,41 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|| buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
|
||||
|| buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
|
||||
return DROPBEAR_FAILURE;
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
|
||||
dropbear_log(LOG_WARNING, "DSS key too short");
|
||||
TRACE(("leave buf_get_dss_pub_key: short key"))
|
||||
return DROPBEAR_FAILURE;
|
||||
if (mp_count_bits(key->p) != DSS_P_BITS) {
|
||||
dropbear_log(LOG_WARNING, "Bad DSS p");
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mp_count_bits(key->q) != DSS_Q_BITS) {
|
||||
dropbear_log(LOG_WARNING, "Bad DSS q");
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* test 1 < g < p */
|
||||
if (mp_cmp_d(key->g, 1) != MP_GT) {
|
||||
dropbear_log(LOG_WARNING, "Bad DSS g");
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp(key->g, key->p) != MP_LT) {
|
||||
dropbear_log(LOG_WARNING, "Bad DSS g");
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
TRACE(("leave buf_get_dss_pub_key: success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
out:
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
|
||||
@@ -86,7 +111,7 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
m_mp_alloc_init_multi(&key->x, NULL);
|
||||
ret = buf_getmpint(buf, key->x);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->x);
|
||||
m_mp_free_multi(&key->x, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -101,26 +126,7 @@ void dss_key_free(dropbear_dss_key *key) {
|
||||
TRACE2(("enter dsa_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
if (key->p) {
|
||||
mp_clear(key->p);
|
||||
m_free(key->p);
|
||||
}
|
||||
if (key->q) {
|
||||
mp_clear(key->q);
|
||||
m_free(key->q);
|
||||
}
|
||||
if (key->g) {
|
||||
mp_clear(key->g);
|
||||
m_free(key->g);
|
||||
}
|
||||
if (key->y) {
|
||||
mp_clear(key->y);
|
||||
m_free(key->y);
|
||||
}
|
||||
if (key->x) {
|
||||
mp_clear(key->x);
|
||||
m_free(key->x);
|
||||
}
|
||||
m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
|
||||
m_free(key);
|
||||
TRACE2(("leave dsa_key_free"))
|
||||
}
|
||||
@@ -133,7 +139,7 @@ void dss_key_free(dropbear_dss_key *key) {
|
||||
* mpint g
|
||||
* mpint y
|
||||
*/
|
||||
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key) {
|
||||
|
||||
dropbear_assert(key != NULL);
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
@@ -145,7 +151,7 @@ void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
}
|
||||
|
||||
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
|
||||
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
void buf_put_dss_priv_key(buffer* buf, const dropbear_dss_key *key) {
|
||||
|
||||
dropbear_assert(key != NULL);
|
||||
buf_put_dss_pub_key(buf, key);
|
||||
@@ -153,10 +159,10 @@ void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a DSS signature (in buf) made on data by the key given.
|
||||
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
hash_state hs;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
@@ -178,6 +184,13 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if DEBUG_DSS_VERIFY
|
||||
printmpint("dss verify p", key->p);
|
||||
printmpint("dss verify q", key->q);
|
||||
printmpint("dss verify g", key->g);
|
||||
printmpint("dss verify y", key->y);
|
||||
#endif
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
@@ -187,11 +200,18 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
/* w = (s')-1 mod q */
|
||||
/* let val1 = s' */
|
||||
bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
|
||||
#if DEBUG_DSS_VERIFY
|
||||
printmpint("dss verify s'", &val1);
|
||||
#endif
|
||||
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, s' >= q"))
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp_d(&val1, 0) != MP_GT) {
|
||||
TRACE(("verify failed, s' <= 0"))
|
||||
goto out;
|
||||
}
|
||||
/* let val2 = w = (s')^-1 mod q*/
|
||||
if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
|
||||
goto out;
|
||||
@@ -200,6 +220,9 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
/* u1 = ((SHA(M')w) mod q */
|
||||
/* let val1 = SHA(M') = msghash */
|
||||
bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
|
||||
#if DEBUG_DSS_VERIFY
|
||||
printmpint("dss verify r'", &val1);
|
||||
#endif
|
||||
|
||||
/* let val3 = u1 = ((SHA(M')w) mod q */
|
||||
if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
|
||||
@@ -213,6 +236,10 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
TRACE(("verify failed, r' >= q"))
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp_d(&val1, 0) != MP_GT) {
|
||||
TRACE(("verify failed, r' <= 0"))
|
||||
goto out;
|
||||
}
|
||||
/* let val4 = u2 = ((r')w) mod q */
|
||||
if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
|
||||
goto out;
|
||||
@@ -253,10 +280,11 @@ out:
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
size_t written;
|
||||
DEF_MP_INT(dss_k);
|
||||
DEF_MP_INT(dss_m);
|
||||
DEF_MP_INT(dss_temp1);
|
||||
@@ -313,31 +341,31 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
buf_putint(buf, 2*SHA1_HASH_SIZE);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_r);
|
||||
writelen = mp_ubin_size(&dss_r);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_r);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_s);
|
||||
writelen = mp_ubin_size(&dss_s);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_s);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
|
||||
17
dss.h
17
dss.h
@@ -28,9 +28,9 @@
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
typedef struct {
|
||||
typedef struct dropbear_DSS_Key {
|
||||
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
@@ -41,14 +41,17 @@ typedef struct {
|
||||
|
||||
} dropbear_dss_key;
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
|
||||
#define DSS_P_BITS 1024
|
||||
#define DSS_Q_BITS 160
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf);
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf);
|
||||
#endif
|
||||
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
|
||||
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);
|
||||
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key);
|
||||
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key);
|
||||
void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key);
|
||||
void buf_put_dss_priv_key(buffer* buf, const dropbear_dss_key *key);
|
||||
void dss_key_free(dropbear_dss_key *key);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
60
ecc.c
60
ecc.c
@@ -1,13 +1,12 @@
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
#include "ecc.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
#if DROPBEAR_ECC
|
||||
|
||||
/* .dp members are filled out by dropbear_ecc_fill_dp() at startup */
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#if DROPBEAR_ECC_256
|
||||
struct dropbear_ecc_curve ecc_curve_nistp256 = {
|
||||
32, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
@@ -15,7 +14,7 @@ struct dropbear_ecc_curve ecc_curve_nistp256 = {
|
||||
"nistp256" /* .name */
|
||||
};
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
struct dropbear_ecc_curve ecc_curve_nistp384 = {
|
||||
48, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
@@ -23,7 +22,7 @@ struct dropbear_ecc_curve ecc_curve_nistp384 = {
|
||||
"nistp384" /* .name */
|
||||
};
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECC_521
|
||||
struct dropbear_ecc_curve ecc_curve_nistp521 = {
|
||||
66, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
@@ -33,13 +32,13 @@ struct dropbear_ecc_curve ecc_curve_nistp521 = {
|
||||
#endif
|
||||
|
||||
struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#if DROPBEAR_ECC_256
|
||||
&ecc_curve_nistp256,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
&ecc_curve_nistp384,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECC_521
|
||||
&ecc_curve_nistp521,
|
||||
#endif
|
||||
NULL
|
||||
@@ -82,7 +81,7 @@ ecc_key * new_ecc_key(void) {
|
||||
|
||||
/* Copied from libtomcrypt ecc_import.c (version there is static), modified
|
||||
for different mp_int pointer without LTC_SOURCE */
|
||||
static int ecc_is_point(ecc_key *key)
|
||||
static int ecc_is_point(const ecc_key *key)
|
||||
{
|
||||
mp_int *prime, *b, *t1, *t2;
|
||||
int err;
|
||||
@@ -167,13 +166,13 @@ ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *c
|
||||
key = new_ecc_key();
|
||||
key->dp = curve->dp;
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
if (mp_from_ubin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read x"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
if (mp_from_ubin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read y"))
|
||||
goto out;
|
||||
}
|
||||
@@ -213,7 +212,7 @@ ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *c
|
||||
|
||||
/* a modified version of libtomcrypt's "ecc_shared_secret" to output
|
||||
a mp_int instead. */
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key)
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, const ecc_key *private_key)
|
||||
{
|
||||
ecc_point *result = NULL;
|
||||
mp_int *prime = NULL, *shared_secret = NULL;
|
||||
@@ -221,46 +220,41 @@ mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key)
|
||||
|
||||
/* type valid? */
|
||||
if (private_key->type != PK_PRIVATE) {
|
||||
goto done;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (private_key->dp != public_key->dp) {
|
||||
goto done;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* make new point */
|
||||
result = ltc_ecc_new_point();
|
||||
if (result == NULL) {
|
||||
goto done;
|
||||
goto out;
|
||||
}
|
||||
|
||||
prime = m_malloc(sizeof(*prime));
|
||||
m_mp_init(prime);
|
||||
|
||||
if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) {
|
||||
goto done;
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) {
|
||||
goto done;
|
||||
goto out;
|
||||
}
|
||||
|
||||
shared_secret = m_malloc(sizeof(*shared_secret));
|
||||
m_mp_init(shared_secret);
|
||||
if (mp_copy(result->x, shared_secret) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
mp_clear(prime);
|
||||
m_free(prime);
|
||||
ltc_ecc_del_point(result);
|
||||
|
||||
err = DROPBEAR_SUCCESS;
|
||||
done:
|
||||
if (err == DROPBEAR_SUCCESS) {
|
||||
shared_secret = m_malloc(sizeof(*shared_secret));
|
||||
m_mp_init(shared_secret);
|
||||
mp_copy(result->x, shared_secret);
|
||||
}
|
||||
|
||||
if (prime) {
|
||||
mp_clear(prime);
|
||||
m_free(prime);
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
ltc_ecc_del_point(result);
|
||||
}
|
||||
|
||||
out:
|
||||
if (err == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
5
ecc.h
5
ecc.h
@@ -2,11 +2,10 @@
|
||||
#define DROPBEAR_DROPBEAR_ECC_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
#if DROPBEAR_ECC
|
||||
|
||||
struct dropbear_ecc_curve {
|
||||
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
|
||||
@@ -29,7 +28,7 @@ void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key);
|
||||
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve);
|
||||
int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key);
|
||||
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, const ecc_key *priv_key);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
27
ecdsa.c
27
ecdsa.c
@@ -1,4 +1,3 @@
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "crypto_desc.h"
|
||||
@@ -6,7 +5,7 @@
|
||||
#include "ecdsa.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECDSA
|
||||
|
||||
int signkey_is_ecdsa(enum signkey_type type)
|
||||
{
|
||||
@@ -15,18 +14,18 @@ int signkey_is_ecdsa(enum signkey_type type)
|
||||
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
}
|
||||
|
||||
enum signkey_type ecdsa_signkey_type(ecc_key * key) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
enum signkey_type ecdsa_signkey_type(const ecc_key * key) {
|
||||
#if DROPBEAR_ECC_256
|
||||
if (key->dp == ecc_curve_nistp256.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
if (key->dp == ecc_curve_nistp384.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECC_521
|
||||
if (key->dp == ecc_curve_nistp521.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
}
|
||||
@@ -38,17 +37,17 @@ ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
|
||||
const ltc_ecc_set_type *dp = NULL; /* curve domain parameters */
|
||||
ecc_key *new_key = NULL;
|
||||
switch (bit_size) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#if DROPBEAR_ECC_256
|
||||
case 256:
|
||||
dp = ecc_curve_nistp256.dp;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
case 384:
|
||||
dp = ecc_curve_nistp384.dp;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECC_521
|
||||
case 521:
|
||||
dp = ecc_curve_nistp521.dp;
|
||||
break;
|
||||
@@ -56,13 +55,13 @@ ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
|
||||
}
|
||||
if (!dp) {
|
||||
dropbear_exit("Key size %d isn't valid. Try "
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#if DROPBEAR_ECC_256
|
||||
"256 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#if DROPBEAR_ECC_384
|
||||
"384 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#if DROPBEAR_ECC_521
|
||||
"521 "
|
||||
#endif
|
||||
, bit_size);
|
||||
@@ -154,7 +153,7 @@ void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
|
||||
buf_putmpint(buf, key->k);
|
||||
}
|
||||
|
||||
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
void buf_put_ecdsa_sign(buffer *buf, const ecc_key *key, const buffer *data_buf) {
|
||||
/* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
|
||||
int err = DROPBEAR_FAILURE;
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
@@ -272,7 +271,7 @@ out:
|
||||
}
|
||||
|
||||
|
||||
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
int buf_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf) {
|
||||
/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
hash_state hs;
|
||||
|
||||
23
ecdsa.h
23
ecdsa.h
@@ -5,17 +5,18 @@
|
||||
#include "buffer.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECDSA
|
||||
|
||||
/* Prefer the larger size - it's fast anyway */
|
||||
#if defined(DROPBEAR_ECC_521)
|
||||
#define ECDSA_DEFAULT_SIZE 521
|
||||
#elif defined(DROPBEAR_ECC_384)
|
||||
#define ECDSA_DEFAULT_SIZE 384
|
||||
#elif defined(DROPBEAR_ECC_256)
|
||||
/* prefer 256 or 384 since those are SHOULD for
|
||||
draft-ietf-curdle-ssh-kex-sha2.txt */
|
||||
#if DROPBEAR_ECC_256
|
||||
#define ECDSA_DEFAULT_SIZE 256
|
||||
#elif DROPBEAR_ECC_384
|
||||
#define ECDSA_DEFAULT_SIZE 384
|
||||
#elif DROPBEAR_ECC_521
|
||||
#define ECDSA_DEFAULT_SIZE 521
|
||||
#else
|
||||
#define ECDSA_DEFAULT_SIZE 0
|
||||
#error ECDSA cannot be enabled without enabling at least one size (256, 384, 521)
|
||||
#endif
|
||||
|
||||
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
|
||||
@@ -23,10 +24,10 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf);
|
||||
ecc_key *buf_get_ecdsa_priv_key(buffer *buf);
|
||||
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key);
|
||||
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key);
|
||||
enum signkey_type ecdsa_signkey_type(ecc_key * key);
|
||||
enum signkey_type ecdsa_signkey_type(const ecc_key * key);
|
||||
|
||||
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf);
|
||||
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf);
|
||||
void buf_put_ecdsa_sign(buffer *buf, const ecc_key *key, const buffer *data_buf);
|
||||
int buf_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf);
|
||||
/* Returns 1 on success */
|
||||
int signkey_is_ecdsa(enum signkey_type type);
|
||||
|
||||
|
||||
182
ed25519.c
Normal file
182
ed25519.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. */
|
||||
|
||||
/* Perform Ed25519 operations on data, including reading keys, signing and
|
||||
* verification. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "curve25519.h"
|
||||
#include "ed25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
/* Load a public ed25519 key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_ed25519_key.
|
||||
* These should be freed with ed25519_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) {
|
||||
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter buf_get_ed25519_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
|
||||
|
||||
len = buf_getint(buf);
|
||||
if (len != CURVE25519_LEN || buf->len - buf->pos < len) {
|
||||
TRACE(("leave buf_get_ed25519_pub_key: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
m_burn(key->priv, CURVE25519_LEN);
|
||||
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_get_ed25519_pub_key: success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Same as buf_get_ed25519_pub_key, but reads private key at the end.
|
||||
* Loads a public and private ed25519 key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_ed25519_priv_key(buffer *buf, dropbear_ed25519_key *key) {
|
||||
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter buf_get_ed25519_priv_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
|
||||
|
||||
len = buf_getint(buf);
|
||||
if (len != CURVE25519_LEN*2 || buf->len - buf->pos < len) {
|
||||
TRACE(("leave buf_get_ed25519_priv_key: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_get_ed25519_priv_key: success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void ed25519_key_free(dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE2(("enter ed25519_key_free"))
|
||||
|
||||
if (key == NULL) {
|
||||
TRACE2(("leave ed25519_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
m_burn(key->priv, CURVE25519_LEN);
|
||||
m_free(key);
|
||||
|
||||
TRACE2(("leave ed25519_key_free"))
|
||||
}
|
||||
|
||||
/* Put the public ed25519 key into the buffer in the required format */
|
||||
void buf_put_ed25519_pub_key(buffer *buf, const dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_ed25519_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putstring(buf, key->pub, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_pub_key"))
|
||||
}
|
||||
|
||||
/* Put the public and private ed25519 key into the buffer in the required format */
|
||||
void buf_put_ed25519_priv_key(buffer *buf, const dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_ed25519_priv_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putint(buf, CURVE25519_LEN*2);
|
||||
buf_putbytes(buf, key->priv, CURVE25519_LEN);
|
||||
buf_putbytes(buf, key->pub, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_priv_key"))
|
||||
}
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
|
||||
|
||||
unsigned char s[64];
|
||||
unsigned long slen = sizeof(s);
|
||||
|
||||
TRACE(("enter buf_put_ed25519_sign"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
dropbear_ed25519_sign(data_buf->data, data_buf->len, s, &slen, key->priv, key->pub);
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putstring(buf, s, slen);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_sign"))
|
||||
}
|
||||
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a signature in buf, made on data by the key given.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned char *s;
|
||||
unsigned long slen;
|
||||
|
||||
TRACE(("enter buf_ed25519_verify"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
slen = buf_getint(buf);
|
||||
if (slen != 64 || buf->len - buf->pos < slen) {
|
||||
TRACE(("leave buf_ed25519_verify: bad size"))
|
||||
goto out;
|
||||
}
|
||||
s = buf_getptr(buf, slen);
|
||||
|
||||
if (dropbear_ed25519_verify(data_buf->data, data_buf->len,
|
||||
s, slen, key->pub) == 0) {
|
||||
/* signature is valid */
|
||||
TRACE(("leave buf_ed25519_verify: success!"))
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE(("leave buf_ed25519_verify: ret %d", ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
54
ed25519.h
Normal file
54
ed25519.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. */
|
||||
|
||||
#ifndef DROPBEAR_ED25519_H_
|
||||
#define DROPBEAR_ED25519_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
#define CURVE25519_LEN 32
|
||||
|
||||
typedef struct dropbear_ED25519_Key {
|
||||
|
||||
unsigned char priv[CURVE25519_LEN];
|
||||
unsigned char pub[CURVE25519_LEN];
|
||||
|
||||
} dropbear_ed25519_key;
|
||||
|
||||
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf);
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
|
||||
#endif
|
||||
int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key);
|
||||
int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key);
|
||||
void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key);
|
||||
void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key);
|
||||
void ed25519_key_free(dropbear_ed25519_key *key);
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_ED25519_H_ */
|
||||
@@ -99,6 +99,10 @@ rsa.c RSA asymmetric crypto routines
|
||||
|
||||
dss.c DSS asymmetric crypto routines
|
||||
|
||||
ed25519.c Ed25519 asymmetric crypto routines
|
||||
|
||||
gened25519.c Ed25519 key generation
|
||||
|
||||
gendss.c DSS key generation
|
||||
|
||||
genrsa.c RSA key generation
|
||||
|
||||
209
fuzz-common.c
Normal file
209
fuzz-common.c
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "includes.h"
|
||||
|
||||
#include "includes.h"
|
||||
#include "fuzz.h"
|
||||
#include "dbutil.h"
|
||||
#include "runopts.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "session.h"
|
||||
#include "dbrandom.h"
|
||||
#include "bignum.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
|
||||
struct dropbear_fuzz_options fuzz;
|
||||
|
||||
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
|
||||
static void load_fixed_hostkeys(void);
|
||||
|
||||
void fuzz_common_setup(void) {
|
||||
fuzz.fuzzing = 1;
|
||||
fuzz.wrapfds = 1;
|
||||
fuzz.do_jmp = 1;
|
||||
fuzz.input = m_malloc(sizeof(buffer));
|
||||
_dropbear_log = fuzz_dropbear_log;
|
||||
crypto_init();
|
||||
fuzz_seed();
|
||||
/* let any messages get flushed */
|
||||
setlinebuf(stdout);
|
||||
}
|
||||
|
||||
int fuzz_set_input(const uint8_t *Data, size_t Size) {
|
||||
|
||||
fuzz.input->data = (unsigned char*)Data;
|
||||
fuzz.input->size = Size;
|
||||
fuzz.input->len = Size;
|
||||
fuzz.input->pos = 0;
|
||||
|
||||
memset(&ses, 0x0, sizeof(ses));
|
||||
memset(&svr_ses, 0x0, sizeof(svr_ses));
|
||||
wrapfd_setup();
|
||||
|
||||
fuzz_seed();
|
||||
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
#if DEBUG_TRACE
|
||||
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
|
||||
if (debug_trace) {
|
||||
char printbuf[1024];
|
||||
vsnprintf(printbuf, sizeof(printbuf), format, param);
|
||||
fprintf(stderr, "%s\n", printbuf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
|
||||
/* No print */
|
||||
}
|
||||
#endif /* DEBUG_TRACE */
|
||||
|
||||
void fuzz_svr_setup(void) {
|
||||
fuzz_common_setup();
|
||||
|
||||
_dropbear_exit = svr_dropbear_exit;
|
||||
|
||||
char *argv[] = {
|
||||
"-E",
|
||||
};
|
||||
|
||||
int argc = sizeof(argv) / sizeof(*argv);
|
||||
svr_getopts(argc, argv);
|
||||
|
||||
/* user lookups might be slow, cache it */
|
||||
fuzz.pw_name = m_strdup("person");
|
||||
fuzz.pw_dir = m_strdup("/tmp");
|
||||
fuzz.pw_shell = m_strdup("/bin/zsh");
|
||||
fuzz.pw_passwd = m_strdup("!!zzznope");
|
||||
|
||||
load_fixed_hostkeys();
|
||||
}
|
||||
|
||||
static void load_fixed_hostkeys(void) {
|
||||
#include "fuzz-hostkeys.c"
|
||||
|
||||
buffer *b = buf_new(3000);
|
||||
enum signkey_type type;
|
||||
|
||||
TRACE(("load fixed hostkeys"))
|
||||
|
||||
svr_opts.hostkey = new_sign_key();
|
||||
|
||||
buf_setlen(b, 0);
|
||||
buf_putbytes(b, keyr, keyr_len);
|
||||
buf_setpos(b, 0);
|
||||
type = DROPBEAR_SIGNKEY_RSA;
|
||||
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("failed fixed rsa hostkey");
|
||||
}
|
||||
|
||||
buf_setlen(b, 0);
|
||||
buf_putbytes(b, keyd, keyd_len);
|
||||
buf_setpos(b, 0);
|
||||
type = DROPBEAR_SIGNKEY_DSS;
|
||||
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("failed fixed dss hostkey");
|
||||
}
|
||||
|
||||
buf_setlen(b, 0);
|
||||
buf_putbytes(b, keye, keye_len);
|
||||
buf_setpos(b, 0);
|
||||
type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("failed fixed ecdsa hostkey");
|
||||
}
|
||||
|
||||
buf_setlen(b, 0);
|
||||
buf_putbytes(b, keyed25519, keyed25519_len);
|
||||
buf_setpos(b, 0);
|
||||
type = DROPBEAR_SIGNKEY_ED25519;
|
||||
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("failed fixed ed25519 hostkey");
|
||||
}
|
||||
|
||||
buf_free(b);
|
||||
}
|
||||
|
||||
void fuzz_kex_fakealgos(void) {
|
||||
ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
|
||||
}
|
||||
|
||||
void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
|
||||
if (local_host) {
|
||||
*local_host = m_strdup("fuzzlocalhost");
|
||||
}
|
||||
if (local_port) {
|
||||
*local_port = m_strdup("1234");
|
||||
}
|
||||
if (remote_host) {
|
||||
*remote_host = m_strdup("fuzzremotehost");
|
||||
}
|
||||
if (remote_port) {
|
||||
*remote_port = m_strdup("9876");
|
||||
}
|
||||
}
|
||||
|
||||
/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
|
||||
void fuzz_fake_send_kexdh_reply(void) {
|
||||
assert(!ses.dh_K);
|
||||
m_mp_alloc_init_multi(&ses.dh_K, NULL);
|
||||
mp_set_ul(ses.dh_K, 12345678uL);
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
|
||||
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
|
||||
static int once = 0;
|
||||
if (!once) {
|
||||
fuzz_svr_setup();
|
||||
fuzz.skip_kexmaths = skip_kexmaths;
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
get prefix. input format is
|
||||
string prefix
|
||||
uint32 wrapfd seed
|
||||
... to be extended later
|
||||
[bytes] ssh input stream
|
||||
*/
|
||||
|
||||
/* be careful to avoid triggering buffer.c assertions */
|
||||
if (fuzz.input->len < 8) {
|
||||
return 0;
|
||||
}
|
||||
size_t prefix_size = buf_getint(fuzz.input);
|
||||
if (prefix_size != 4) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t wrapseed = buf_getint(fuzz.input);
|
||||
wrapfd_setseed(wrapseed);
|
||||
|
||||
int fakesock = 20;
|
||||
wrapfd_add(fakesock, fuzz.input, PLAIN);
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
svr_session(fakesock, fakesock);
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const void* fuzz_get_algo(const algo_type *algos, const char* name) {
|
||||
const algo_type *t;
|
||||
for (t = algos; t->name; t++) {
|
||||
if (strcmp(t->name, name) == 0) {
|
||||
return t->data;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
48
fuzz-harness.c
Normal file
48
fuzz-harness.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int i;
|
||||
buffer *input = buf_new(100000);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
printf("arg %s\n", argv[i]);
|
||||
#if DEBUG_TRACE
|
||||
if (strcmp(argv[i], "-v") == 0) {
|
||||
debug_trace = 1;
|
||||
TRACE(("debug printing on"))
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int old_fuzz_wrapfds = 0;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
/* ignore arguments */
|
||||
continue;
|
||||
}
|
||||
|
||||
char* fn = argv[i];
|
||||
buf_setlen(input, 0);
|
||||
buf_readfile(input, fn);
|
||||
buf_setpos(input, 0);
|
||||
|
||||
fuzz.wrapfds = old_fuzz_wrapfds;
|
||||
printf("Running %s once \n", fn);
|
||||
LLVMFuzzerTestOneInput(input->data, input->len);
|
||||
printf("Running %s twice \n", fn);
|
||||
LLVMFuzzerTestOneInput(input->data, input->len);
|
||||
printf("Done %s\n", fn);
|
||||
|
||||
/* Disable wrapfd so it won't interfere with buf_readfile() above */
|
||||
old_fuzz_wrapfds = fuzz.wrapfds;
|
||||
fuzz.wrapfds = 0;
|
||||
}
|
||||
|
||||
printf("Finished\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
139
fuzz-hostkeys.c
Normal file
139
fuzz-hostkeys.c
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
unsigned char keyr[] = {
|
||||
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00,
|
||||
0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xb1,
|
||||
0x06, 0x95, 0xc9, 0xa8, 0x38, 0xb9, 0x99, 0x91, 0xb5, 0x17, 0x39, 0xb9,
|
||||
0xfa, 0xa4, 0x49, 0xf8, 0x2a, 0x4c, 0x14, 0xbd, 0xb6, 0x85, 0xdb, 0x38,
|
||||
0x99, 0x44, 0xfa, 0xd6, 0xaa, 0x67, 0xef, 0x00, 0x75, 0x2b, 0x6a, 0x5c,
|
||||
0x1b, 0x50, 0xa8, 0x52, 0xf9, 0xa7, 0xee, 0xe2, 0xb3, 0x80, 0x38, 0x92,
|
||||
0x20, 0x86, 0x7c, 0xe5, 0x89, 0xb3, 0x06, 0xe4, 0x3b, 0xd1, 0xe2, 0x45,
|
||||
0xea, 0xc1, 0xd5, 0x8e, 0x05, 0xfb, 0x90, 0x29, 0xd9, 0x41, 0xb3, 0x05,
|
||||
0x31, 0x1e, 0xcc, 0xeb, 0x89, 0xdc, 0xd2, 0x6a, 0x99, 0x23, 0xbd, 0x7a,
|
||||
0xbe, 0x8c, 0xe3, 0x3f, 0xa1, 0xe8, 0xf5, 0xb4, 0x51, 0x40, 0xb4, 0xb1,
|
||||
0xc1, 0x16, 0x9f, 0x07, 0xbb, 0x99, 0xaa, 0x4b, 0x8f, 0x11, 0x19, 0x3c,
|
||||
0x18, 0xbd, 0x6e, 0xce, 0x14, 0x54, 0x2c, 0x16, 0x4a, 0x5f, 0x89, 0xe4,
|
||||
0x6b, 0x9f, 0x55, 0x68, 0xcc, 0x09, 0x8e, 0x4b, 0x92, 0xc8, 0x87, 0xfe,
|
||||
0x09, 0xed, 0x53, 0x6e, 0xff, 0x5f, 0x15, 0x0d, 0x19, 0x9d, 0xa6, 0x54,
|
||||
0xd2, 0xea, 0x59, 0x4f, 0xa1, 0x7c, 0xf6, 0xf5, 0x7f, 0x32, 0x23, 0xed,
|
||||
0x72, 0xa8, 0x96, 0x17, 0x87, 0x06, 0xf2, 0xc7, 0xcd, 0xda, 0x4a, 0x10,
|
||||
0xd1, 0xfd, 0xb8, 0xf1, 0xaf, 0x25, 0x55, 0x32, 0x45, 0x39, 0x95, 0xec,
|
||||
0x0c, 0xa9, 0xf0, 0x47, 0x8b, 0x66, 0xe0, 0xb7, 0xa2, 0xf6, 0x35, 0x50,
|
||||
0x27, 0xe7, 0x2f, 0x90, 0x35, 0x5b, 0xd5, 0x62, 0x19, 0xb4, 0x41, 0xd4,
|
||||
0x52, 0xe7, 0x7f, 0x97, 0xfc, 0x5b, 0x4a, 0x5b, 0x19, 0x06, 0x65, 0x2d,
|
||||
0x23, 0x29, 0x15, 0x8b, 0x05, 0xaf, 0xbe, 0xd3, 0x4a, 0x27, 0x5b, 0xc9,
|
||||
0xc0, 0xd0, 0xd2, 0xba, 0x8b, 0x00, 0x7a, 0x2f, 0x39, 0xa0, 0x13, 0xb9,
|
||||
0xe6, 0xf5, 0x4b, 0x21, 0x54, 0x57, 0xb3, 0xf9, 0x6c, 0x6f, 0xd0, 0x17,
|
||||
0xf4, 0x50, 0x9d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xf2, 0xda, 0x5f, 0xfb,
|
||||
0xe2, 0xda, 0xfc, 0xe0, 0xdf, 0x3a, 0x0e, 0x14, 0x18, 0xc1, 0xd9, 0x1f,
|
||||
0x43, 0xe3, 0x65, 0x3e, 0x07, 0xe7, 0x8d, 0xdc, 0x1d, 0x11, 0xc1, 0xd6,
|
||||
0xc0, 0xd8, 0xda, 0x53, 0xf5, 0x04, 0x73, 0x51, 0x1b, 0x26, 0xef, 0x4e,
|
||||
0xf5, 0xce, 0x3d, 0x77, 0x21, 0x94, 0xd0, 0xc7, 0xc1, 0xda, 0x19, 0x7d,
|
||||
0xf8, 0xc5, 0x4c, 0xc8, 0xee, 0x7d, 0xd1, 0xbb, 0x02, 0x90, 0x2b, 0xff,
|
||||
0x4e, 0x4d, 0xd7, 0x9d, 0x72, 0x0c, 0x60, 0x0f, 0x4b, 0x83, 0xf5, 0xc2,
|
||||
0x26, 0xd6, 0x22, 0xb8, 0x60, 0x3a, 0xf9, 0x2f, 0x92, 0x2a, 0x2e, 0x14,
|
||||
0xa7, 0x56, 0x1c, 0x56, 0x05, 0x41, 0x92, 0xac, 0xb1, 0x4e, 0x44, 0x1e,
|
||||
0x70, 0x42, 0xda, 0xc7, 0xc8, 0x9c, 0xae, 0x29, 0x2d, 0x0c, 0x3a, 0xff,
|
||||
0x9b, 0xb6, 0xad, 0xb4, 0xfb, 0x49, 0x28, 0x96, 0x74, 0xf5, 0x94, 0x74,
|
||||
0xb7, 0x40, 0x93, 0x2b, 0x34, 0x29, 0xd2, 0x8a, 0xf3, 0x99, 0xf9, 0xe9,
|
||||
0xd8, 0xcc, 0x48, 0x1d, 0x3e, 0xc1, 0x82, 0x35, 0x4f, 0xef, 0xb1, 0x81,
|
||||
0x3c, 0xe1, 0xa1, 0x03, 0x65, 0xac, 0x21, 0x21, 0x40, 0x61, 0xfb, 0xd3,
|
||||
0x54, 0xac, 0xa1, 0xf2, 0xf0, 0x61, 0xd9, 0x01, 0x4e, 0xc2, 0x28, 0xb1,
|
||||
0x7c, 0x27, 0x6e, 0x56, 0x68, 0x69, 0x8f, 0xc5, 0xfd, 0xca, 0x39, 0x6e,
|
||||
0x22, 0x09, 0xf1, 0xb4, 0xd5, 0xac, 0xb8, 0xe0, 0x1b, 0x21, 0x86, 0xf4,
|
||||
0xc8, 0x15, 0xc6, 0x1f, 0x21, 0xae, 0xcb, 0xab, 0x5a, 0x09, 0x30, 0x9e,
|
||||
0xdd, 0x6c, 0x38, 0x59, 0xec, 0x59, 0x3a, 0x08, 0xee, 0x46, 0x7b, 0x78,
|
||||
0x23, 0xbc, 0xfc, 0xe2, 0xda, 0xe8, 0x1a, 0x65, 0xe6, 0xe0, 0x78, 0xd3,
|
||||
0xb0, 0x03, 0x2e, 0xf1, 0xb8, 0xca, 0x8e, 0x90, 0x75, 0xaf, 0xf7, 0xa8,
|
||||
0x48, 0xed, 0x82, 0xc9, 0xcf, 0x44, 0x56, 0xfc, 0x05, 0xfd, 0x6b, 0x00,
|
||||
0x00, 0x00, 0x81, 0x00, 0xfc, 0x94, 0xdf, 0x42, 0xc7, 0x9a, 0xa2, 0xff,
|
||||
0x32, 0xdf, 0x06, 0xb6, 0x4d, 0x90, 0x31, 0x28, 0x28, 0xdb, 0x03, 0xf9,
|
||||
0xa6, 0xb3, 0xa2, 0x91, 0x4c, 0xdf, 0x6e, 0xf6, 0xb9, 0x44, 0x3b, 0xdd,
|
||||
0x17, 0xc1, 0xc8, 0x1d, 0xd1, 0xc0, 0xc0, 0x30, 0x22, 0xbe, 0x24, 0x2e,
|
||||
0x0e, 0xdf, 0xe0, 0x18, 0x37, 0x3e, 0xb8, 0x7f, 0xb2, 0x50, 0x34, 0xc4,
|
||||
0x08, 0x5e, 0x69, 0x1f, 0xd5, 0xc9, 0xce, 0x47, 0x7d, 0x75, 0x5e, 0x3b,
|
||||
0x87, 0xdd, 0x46, 0x35, 0x01, 0x0f, 0x17, 0x8a, 0xf1, 0xf1, 0xc4, 0xa9,
|
||||
0x94, 0xa7, 0x6e, 0xce, 0x80, 0xe3, 0x17, 0x2e, 0xb0, 0xef, 0x63, 0xa7,
|
||||
0x11, 0x86, 0x96, 0x4a, 0x63, 0x2d, 0x9e, 0x92, 0x62, 0x43, 0x43, 0x72,
|
||||
0xa5, 0xdc, 0xa0, 0xcd, 0x19, 0x93, 0xd7, 0xe0, 0x80, 0x41, 0x27, 0xea,
|
||||
0xe4, 0xe8, 0xc1, 0x91, 0x9e, 0x13, 0xb3, 0x9c, 0xd1, 0xed, 0xcb, 0xbf,
|
||||
0x00, 0x00, 0x00, 0x81, 0x00, 0xb3, 0x6b, 0xee, 0xa4, 0x70, 0x4e, 0xfb,
|
||||
0xf9, 0x7e, 0x2e, 0x74, 0x5d, 0x3e, 0x8b, 0x3f, 0xff, 0x8c, 0xde, 0x68,
|
||||
0x38, 0xda, 0xce, 0xc0, 0x66, 0x4b, 0xca, 0x35, 0xc3, 0x97, 0xa8, 0xf0,
|
||||
0x00, 0x8e, 0xb3, 0x46, 0x60, 0xd0, 0x4d, 0x7e, 0x7b, 0xdf, 0x17, 0x7b,
|
||||
0x2f, 0xc4, 0x16, 0xee, 0x45, 0xdb, 0xa5, 0x5d, 0xc0, 0x72, 0xe9, 0xc6,
|
||||
0x91, 0x0f, 0xd9, 0x30, 0x74, 0x6c, 0xde, 0x93, 0xb5, 0xb6, 0xaf, 0x52,
|
||||
0x53, 0x3c, 0x08, 0x55, 0xea, 0xb8, 0x66, 0x07, 0xbe, 0xce, 0xf9, 0x80,
|
||||
0x8d, 0xe0, 0xca, 0xdc, 0x63, 0xe8, 0x58, 0x94, 0x22, 0x4f, 0x08, 0x66,
|
||||
0x13, 0x9e, 0x63, 0x2e, 0x92, 0x7a, 0xb6, 0x66, 0x94, 0x9b, 0x71, 0x66,
|
||||
0xd3, 0x08, 0xc9, 0x89, 0xea, 0x78, 0x35, 0x0d, 0xf2, 0x25, 0x55, 0xd4,
|
||||
0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
|
||||
0xa3
|
||||
};
|
||||
unsigned int keyr_len = 805;
|
||||
unsigned char keye[] = {
|
||||
0x00, 0x00, 0x00, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68,
|
||||
0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
|
||||
0x00, 0x00, 0x08, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
|
||||
0x00, 0x00, 0x41, 0x04, 0x0a, 0x00, 0x6c, 0x7c, 0x1c, 0xc4, 0x03, 0x44,
|
||||
0x46, 0x70, 0xba, 0x00, 0x7c, 0x79, 0x89, 0x7b, 0xc3, 0xd6, 0x32, 0x98,
|
||||
0x34, 0xe7, 0x1c, 0x60, 0x04, 0x73, 0xd9, 0xb5, 0x7e, 0x94, 0x04, 0x04,
|
||||
0xea, 0xc8, 0xb8, 0xfb, 0xd4, 0x70, 0x9f, 0x29, 0xa7, 0x8d, 0x9a, 0x64,
|
||||
0x3a, 0x8c, 0x45, 0x23, 0x37, 0x5a, 0x2b, 0x4f, 0x54, 0x91, 0x80, 0xf1,
|
||||
0xac, 0x3a, 0xf5, 0x6d, 0xfa, 0xe8, 0x76, 0x20, 0x00, 0x00, 0x00, 0x21,
|
||||
0x00, 0xc2, 0xaf, 0xbe, 0xdc, 0x06, 0xff, 0x3d, 0x08, 0x9b, 0x73, 0xe0,
|
||||
0x3c, 0x58, 0x28, 0x70, 0x9b, 0x23, 0x39, 0x51, 0xd7, 0xbc, 0xa7, 0x1a,
|
||||
0xf5, 0xb4, 0x23, 0xd3, 0xf6, 0x17, 0xa6, 0x9c, 0x02
|
||||
};
|
||||
unsigned int keye_len = 141;
|
||||
unsigned char keyd[] = {
|
||||
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x64, 0x73, 0x73, 0x00,
|
||||
0x00, 0x00, 0x81, 0x00, 0xb0, 0x02, 0x19, 0x8b, 0xf3, 0x46, 0xf9, 0xc5,
|
||||
0x47, 0x78, 0x3d, 0x7f, 0x04, 0x10, 0x0a, 0x43, 0x8e, 0x00, 0x9e, 0xa4,
|
||||
0x30, 0xfd, 0x47, 0xb9, 0x05, 0x9e, 0x95, 0xaa, 0x37, 0x9a, 0x91, 0xbf,
|
||||
0xf8, 0xb9, 0xe0, 0x8d, 0x97, 0x49, 0x87, 0xe2, 0xe6, 0x90, 0xc1, 0xe4,
|
||||
0x61, 0x57, 0x77, 0xfd, 0x91, 0x1d, 0xe1, 0x4b, 0xa0, 0xb2, 0xbc, 0xa1,
|
||||
0x6a, 0x6a, 0xdd, 0x31, 0xda, 0xe7, 0x54, 0x03, 0xfd, 0x48, 0x62, 0x8a,
|
||||
0x1d, 0x1d, 0xe2, 0x26, 0x76, 0x29, 0x08, 0xab, 0x65, 0x88, 0x74, 0x02,
|
||||
0x1e, 0xa9, 0x29, 0x1b, 0x69, 0x3b, 0xb4, 0x5f, 0x62, 0x80, 0xa3, 0xa6,
|
||||
0x4b, 0xc3, 0x0e, 0x89, 0x24, 0xe4, 0x8a, 0x31, 0xae, 0x89, 0x7a, 0x7a,
|
||||
0x58, 0x44, 0x46, 0x77, 0x62, 0x33, 0xa2, 0x5d, 0x17, 0x0e, 0x0b, 0x64,
|
||||
0xee, 0x1a, 0x02, 0xbd, 0xf8, 0x27, 0x86, 0xe1, 0x87, 0x92, 0x84, 0xc7,
|
||||
0x00, 0x00, 0x00, 0x15, 0x00, 0xb3, 0x8b, 0x81, 0x39, 0x9c, 0xba, 0xe1,
|
||||
0x1d, 0x9a, 0x8b, 0x89, 0xb3, 0x08, 0x9b, 0x12, 0xa8, 0x7b, 0xea, 0x25,
|
||||
0x8d, 0x00, 0x00, 0x00, 0x80, 0x76, 0x3f, 0x72, 0xb2, 0xef, 0xc3, 0x16,
|
||||
0xd8, 0x09, 0x36, 0x23, 0x03, 0xf9, 0x5c, 0xac, 0x8b, 0x51, 0x35, 0x2e,
|
||||
0x36, 0xba, 0x39, 0xd0, 0x57, 0x19, 0x4f, 0x14, 0x8b, 0xea, 0x32, 0xfc,
|
||||
0x86, 0x41, 0xea, 0x85, 0x71, 0x4d, 0x52, 0x0c, 0xff, 0xc1, 0xd3, 0xd5,
|
||||
0xcd, 0x2e, 0x37, 0xcc, 0xe1, 0xcc, 0x22, 0x38, 0xa8, 0x47, 0x16, 0x34,
|
||||
0x3b, 0x32, 0x9c, 0x2f, 0x0f, 0xcd, 0x5f, 0x7f, 0x06, 0x64, 0x89, 0xc5,
|
||||
0x02, 0x4f, 0x9a, 0x70, 0x11, 0xf0, 0xaa, 0xe1, 0x7a, 0x75, 0x49, 0x8d,
|
||||
0x0f, 0x8d, 0x5b, 0x54, 0xe2, 0xe7, 0x10, 0x6e, 0xe5, 0xbd, 0xb7, 0x62,
|
||||
0xf7, 0x40, 0x59, 0x39, 0x31, 0xd9, 0x13, 0x7b, 0xa3, 0xdf, 0x0d, 0x31,
|
||||
0x52, 0x43, 0xe0, 0xaf, 0x19, 0x12, 0x15, 0x12, 0x34, 0x01, 0x6f, 0xcf,
|
||||
0x62, 0x21, 0xe4, 0xc8, 0x34, 0x69, 0xc9, 0x85, 0xe3, 0xde, 0xd7, 0x0c,
|
||||
0xac, 0x00, 0x00, 0x00, 0x80, 0x41, 0xa3, 0xc5, 0xa4, 0x89, 0x86, 0xc8,
|
||||
0x17, 0xf3, 0x8e, 0x68, 0x72, 0xbe, 0x13, 0x8b, 0x63, 0xe3, 0x07, 0xe3,
|
||||
0xd5, 0xa4, 0xa2, 0xd3, 0x2c, 0x2f, 0xbe, 0x16, 0x71, 0xc9, 0x79, 0x64,
|
||||
0x5a, 0x1e, 0x19, 0x82, 0x07, 0xe2, 0x93, 0xda, 0x22, 0xcf, 0x6d, 0xdd,
|
||||
0x38, 0xcb, 0x6e, 0x6b, 0x0f, 0x95, 0x8d, 0xfa, 0x3f, 0xbb, 0xb8, 0x6a,
|
||||
0x7d, 0xc3, 0x22, 0x1e, 0x49, 0xcf, 0x98, 0x73, 0x05, 0x5d, 0x97, 0xfa,
|
||||
0x4c, 0xf2, 0x82, 0x3d, 0x98, 0x61, 0x4e, 0x96, 0x80, 0x26, 0x79, 0xda,
|
||||
0x24, 0xf8, 0xa1, 0x9c, 0x71, 0x82, 0xe6, 0xc7, 0xdc, 0xc2, 0xa5, 0xd0,
|
||||
0xf4, 0x36, 0xba, 0xaa, 0xee, 0xd3, 0x43, 0x46, 0x1d, 0xaa, 0x53, 0xea,
|
||||
0x85, 0x2c, 0x1b, 0xc8, 0x7c, 0x3c, 0xe7, 0x06, 0x44, 0xab, 0x16, 0xad,
|
||||
0xc6, 0x54, 0x91, 0x9a, 0xb9, 0xc0, 0xeb, 0x93, 0x8c, 0xca, 0x39, 0xcf,
|
||||
0x6f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x90, 0x26, 0x0a, 0xfc, 0x15, 0x99,
|
||||
0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
|
||||
0xf9, 0x39
|
||||
};
|
||||
unsigned int keyd_len = 458;
|
||||
unsigned char keyed25519[] = {
|
||||
0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
|
||||
0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
|
||||
0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
|
||||
0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
|
||||
0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
|
||||
0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
|
||||
0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
|
||||
};
|
||||
unsigned int keyed25519_len = 83;
|
||||
246
fuzz-wrapfd.c
Normal file
246
fuzz-wrapfd.c
Normal file
@@ -0,0 +1,246 @@
|
||||
#define FUZZ_SKIP_WRAP 1
|
||||
#include "includes.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
|
||||
#include "dbutil.h"
|
||||
|
||||
#include "fuzz.h"
|
||||
|
||||
#define IOWRAP_MAXFD (FD_SETSIZE-1)
|
||||
static const int MAX_RANDOM_IN = 50000;
|
||||
static const double CHANCE_CLOSE = 1.0 / 600;
|
||||
static const double CHANCE_INTR = 1.0 / 900;
|
||||
static const double CHANCE_READ1 = 0.96;
|
||||
static const double CHANCE_READ2 = 0.5;
|
||||
static const double CHANCE_WRITE1 = 0.96;
|
||||
static const double CHANCE_WRITE2 = 0.5;
|
||||
|
||||
struct fdwrap {
|
||||
enum wrapfd_mode mode;
|
||||
buffer *buf;
|
||||
int closein;
|
||||
int closeout;
|
||||
};
|
||||
|
||||
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
|
||||
/* for quick selection of in-use descriptors */
|
||||
static int wrap_used[IOWRAP_MAXFD+1];
|
||||
static unsigned int nused;
|
||||
static unsigned short rand_state[3];
|
||||
|
||||
void wrapfd_setup(void) {
|
||||
TRACE(("wrapfd_setup"))
|
||||
nused = 0;
|
||||
memset(wrap_fds, 0x0, sizeof(wrap_fds));
|
||||
memset(wrap_used, 0x0, sizeof(wrap_used));
|
||||
|
||||
memset(rand_state, 0x0, sizeof(rand_state));
|
||||
wrapfd_setseed(50);
|
||||
}
|
||||
|
||||
void wrapfd_setseed(uint32_t seed) {
|
||||
memcpy(rand_state, &seed, sizeof(seed));
|
||||
nrand48(rand_state);
|
||||
}
|
||||
|
||||
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
|
||||
TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode))
|
||||
assert(fd >= 0);
|
||||
assert(fd <= IOWRAP_MAXFD);
|
||||
assert(wrap_fds[fd].mode == UNUSED);
|
||||
assert(buf || mode == RANDOMIN);
|
||||
|
||||
wrap_fds[fd].mode = mode;
|
||||
wrap_fds[fd].buf = buf;
|
||||
wrap_fds[fd].closein = 0;
|
||||
wrap_fds[fd].closeout = 0;
|
||||
wrap_used[nused] = fd;
|
||||
|
||||
nused++;
|
||||
}
|
||||
|
||||
void wrapfd_remove(int fd) {
|
||||
unsigned int i, j;
|
||||
TRACE(("wrapfd_remove %d", fd))
|
||||
assert(fd >= 0);
|
||||
assert(fd <= IOWRAP_MAXFD);
|
||||
assert(wrap_fds[fd].mode != UNUSED);
|
||||
wrap_fds[fd].mode = UNUSED;
|
||||
|
||||
|
||||
/* remove from used list */
|
||||
for (i = 0, j = 0; i < nused; i++) {
|
||||
if (wrap_used[i] != fd) {
|
||||
wrap_used[j] = wrap_used[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
nused--;
|
||||
}
|
||||
|
||||
int wrapfd_close(int fd) {
|
||||
if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
|
||||
wrapfd_remove(fd);
|
||||
return 0;
|
||||
} else {
|
||||
return close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int wrapfd_read(int fd, void *out, size_t count) {
|
||||
size_t maxread;
|
||||
buffer *buf;
|
||||
|
||||
if (!fuzz.wrapfds) {
|
||||
return read(fd, out, count);
|
||||
}
|
||||
|
||||
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
|
||||
/* XXX - assertion failure? */
|
||||
TRACE(("Bad read descriptor %d\n", fd))
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(count != 0);
|
||||
|
||||
if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
|
||||
wrap_fds[fd].closein = 1;
|
||||
errno = ECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (erand48(rand_state) < CHANCE_INTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = wrap_fds[fd].buf;
|
||||
if (buf) {
|
||||
maxread = MIN(buf->len - buf->pos, count);
|
||||
/* returns 0 if buf is EOF, as intended */
|
||||
if (maxread > 0) {
|
||||
maxread = nrand48(rand_state) % maxread + 1;
|
||||
}
|
||||
memcpy(out, buf_getptr(buf, maxread), maxread);
|
||||
buf_incrpos(buf, maxread);
|
||||
return maxread;
|
||||
}
|
||||
|
||||
maxread = MIN(MAX_RANDOM_IN, count);
|
||||
maxread = nrand48(rand_state) % maxread + 1;
|
||||
memset(out, 0xef, maxread);
|
||||
return maxread;
|
||||
}
|
||||
|
||||
int wrapfd_write(int fd, const void* in, size_t count) {
|
||||
unsigned const volatile char* volin = in;
|
||||
unsigned int i;
|
||||
|
||||
if (!fuzz.wrapfds) {
|
||||
return write(fd, in, count);
|
||||
}
|
||||
|
||||
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
|
||||
/* XXX - assertion failure? */
|
||||
TRACE(("Bad read descriptor %d\n", fd))
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(count != 0);
|
||||
|
||||
/* force read to exercise sanitisers */
|
||||
for (i = 0; i < count; i++) {
|
||||
(void)volin[i];
|
||||
}
|
||||
|
||||
if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
|
||||
wrap_fds[fd].closeout = 1;
|
||||
errno = ECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (erand48(rand_state) < CHANCE_INTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nrand48(rand_state) % (count+1);
|
||||
}
|
||||
|
||||
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds, struct timeval *timeout) {
|
||||
int i, nset, sel;
|
||||
int ret = 0;
|
||||
int fdlist[IOWRAP_MAXFD+1];
|
||||
|
||||
memset(fdlist, 0x0, sizeof(fdlist));
|
||||
|
||||
if (!fuzz.wrapfds) {
|
||||
return select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
|
||||
assert(nfds <= IOWRAP_MAXFD+1);
|
||||
|
||||
if (erand48(rand_state) < CHANCE_INTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read */
|
||||
if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
|
||||
for (i = 0, nset = 0; i < nfds; i++) {
|
||||
if (FD_ISSET(i, readfds)) {
|
||||
assert(wrap_fds[i].mode != UNUSED);
|
||||
fdlist[nset] = i;
|
||||
nset++;
|
||||
}
|
||||
}
|
||||
DROPBEAR_FD_ZERO(readfds);
|
||||
|
||||
if (nset > 0) {
|
||||
/* set one */
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
FD_SET(sel, readfds);
|
||||
ret++;
|
||||
|
||||
if (erand48(rand_state) < CHANCE_READ2) {
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
if (!FD_ISSET(sel, readfds)) {
|
||||
FD_SET(sel, readfds);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* write */
|
||||
if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
|
||||
for (i = 0, nset = 0; i < nfds; i++) {
|
||||
if (FD_ISSET(i, writefds)) {
|
||||
assert(wrap_fds[i].mode != UNUSED);
|
||||
fdlist[nset] = i;
|
||||
nset++;
|
||||
}
|
||||
}
|
||||
DROPBEAR_FD_ZERO(writefds);
|
||||
|
||||
/* set one */
|
||||
if (nset > 0) {
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
FD_SET(sel, writefds);
|
||||
ret++;
|
||||
|
||||
if (erand48(rand_state) < CHANCE_WRITE2) {
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
if (!FD_ISSET(sel, writefds)) {
|
||||
FD_SET(sel, writefds);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
25
fuzz-wrapfd.h
Normal file
25
fuzz-wrapfd.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef FUZZ_WRAPFD_H
|
||||
#define FUZZ_WRAPFD_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
enum wrapfd_mode {
|
||||
UNUSED = 0,
|
||||
PLAIN,
|
||||
INPROGRESS,
|
||||
RANDOMIN
|
||||
};
|
||||
|
||||
void wrapfd_setup(void);
|
||||
void wrapfd_setseed(uint32_t seed);
|
||||
// doesn't take ownership of buf. buf is optional.
|
||||
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
|
||||
|
||||
// called via #defines for read/write/select
|
||||
int wrapfd_read(int fd, void *out, size_t count);
|
||||
int wrapfd_write(int fd, const void* in, size_t count);
|
||||
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds, struct timeval *timeout);
|
||||
int wrapfd_close(int fd);
|
||||
|
||||
#endif // FUZZ_WRAPFD_H
|
||||
72
fuzz.h
Normal file
72
fuzz.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef DROPBEAR_FUZZ_H
|
||||
#define DROPBEAR_FUZZ_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "algo.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
|
||||
// once per process
|
||||
void fuzz_common_setup(void);
|
||||
void fuzz_svr_setup(void);
|
||||
|
||||
// must be called once per fuzz iteration.
|
||||
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
|
||||
int fuzz_set_input(const uint8_t *Data, size_t Size);
|
||||
|
||||
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths);
|
||||
const void* fuzz_get_algo(const algo_type *algos, const char* name);
|
||||
|
||||
// fuzzer functions that intrude into general code
|
||||
void fuzz_kex_fakealgos(void);
|
||||
int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
|
||||
const char* algo, unsigned int algolen,
|
||||
const unsigned char* keyblob, unsigned int keybloblen);
|
||||
extern const char * const * fuzz_signkey_names;
|
||||
void fuzz_seed(void);
|
||||
void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
void fuzz_fake_send_kexdh_reply(void);
|
||||
|
||||
// fake IO wrappers
|
||||
#ifndef FUZZ_SKIP_WRAP
|
||||
#define select(nfds, readfds, writefds, exceptfds, timeout) \
|
||||
wrapfd_select(nfds, readfds, writefds, exceptfds, timeout)
|
||||
#define write(fd, buf, count) wrapfd_write(fd, buf, count)
|
||||
#define read(fd, buf, count) wrapfd_read(fd, buf, count)
|
||||
#define close(fd) wrapfd_close(fd)
|
||||
#endif // FUZZ_SKIP_WRAP
|
||||
|
||||
struct dropbear_fuzz_options {
|
||||
int fuzzing;
|
||||
|
||||
// fuzzing input
|
||||
buffer *input;
|
||||
struct dropbear_cipher recv_cipher;
|
||||
struct dropbear_hash recv_mac;
|
||||
int wrapfds;
|
||||
|
||||
// whether to skip slow bignum maths
|
||||
int skip_kexmaths;
|
||||
|
||||
// dropbear_exit() jumps back
|
||||
int do_jmp;
|
||||
sigjmp_buf jmp;
|
||||
|
||||
uid_t pw_uid;
|
||||
gid_t pw_gid;
|
||||
char* pw_name;
|
||||
char* pw_dir;
|
||||
char* pw_shell;
|
||||
char* pw_passwd;
|
||||
};
|
||||
|
||||
extern struct dropbear_fuzz_options fuzz;
|
||||
|
||||
#endif // DROPBEAR_FUZZ
|
||||
|
||||
#endif /* DROPBEAR_FUZZ_H */
|
||||
72
fuzzer-kexcurve25519.c
Normal file
72
fuzzer-kexcurve25519.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "runopts.h"
|
||||
#include "algo.h"
|
||||
#include "bignum.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
static struct key_context* keep_newkeys = NULL;
|
||||
/* number of generated parameters is limited by the timeout for the first run.
|
||||
TODO move this to the libfuzzer initialiser function instead if the timeout
|
||||
doesn't apply there */
|
||||
#define NUM_PARAMS 20
|
||||
static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
|
||||
|
||||
if (!once) {
|
||||
fuzz_common_setup();
|
||||
fuzz_svr_setup();
|
||||
|
||||
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
|
||||
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Pre-generate parameters */
|
||||
int i;
|
||||
for (i = 0; i < NUM_PARAMS; i++) {
|
||||
curve25519_params[i] = gen_kexcurve25519_param();
|
||||
}
|
||||
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
|
||||
with DROPBEAR_KEX_CURVE25519 */
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Choose from the collection of curve25519 params */
|
||||
unsigned int e = buf_getint(fuzz.input);
|
||||
struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];
|
||||
|
||||
buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
|
||||
|
||||
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
|
||||
kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
|
||||
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
buf_free(ecdh_qs);
|
||||
|
||||
buf_free(ses.hash);
|
||||
buf_free(ses.session_id);
|
||||
/* kexhashbuf is freed in kexdh_comb_key */
|
||||
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
76
fuzzer-kexdh.c
Normal file
76
fuzzer-kexdh.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "runopts.h"
|
||||
#include "algo.h"
|
||||
#include "bignum.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
static struct key_context* keep_newkeys = NULL;
|
||||
/* number of generated parameters is limited by the timeout for the first run.
|
||||
TODO move this to the libfuzzer initialiser function instead if the timeout
|
||||
doesn't apply there */
|
||||
#define NUM_PARAMS 20
|
||||
static struct kex_dh_param *dh_params[NUM_PARAMS];
|
||||
|
||||
if (!once) {
|
||||
fuzz_common_setup();
|
||||
fuzz_svr_setup();
|
||||
|
||||
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
|
||||
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Pre-generate parameters */
|
||||
int i;
|
||||
for (i = 0; i < NUM_PARAMS; i++) {
|
||||
dh_params[i] = gen_kexdh_param();
|
||||
}
|
||||
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
|
||||
with DROPBEAR_KEX_NORMAL_DH */
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Choose from the collection of ecdh params */
|
||||
unsigned int e = buf_getint(fuzz.input);
|
||||
struct kex_dh_param * dh_param = dh_params[e % NUM_PARAMS];
|
||||
|
||||
DEF_MP_INT(dh_e);
|
||||
m_mp_init(&dh_e);
|
||||
if (buf_getmpint(fuzz.input, &dh_e) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad kex value");
|
||||
}
|
||||
|
||||
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
|
||||
kexdh_comb_key(dh_param, &dh_e, svr_opts.hostkey);
|
||||
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
mp_clear(&dh_e);
|
||||
|
||||
buf_free(ses.hash);
|
||||
buf_free(ses.session_id);
|
||||
/* kexhashbuf is freed in kexdh_comb_key */
|
||||
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
82
fuzzer-kexecdh.c
Normal file
82
fuzzer-kexecdh.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "runopts.h"
|
||||
#include "algo.h"
|
||||
#include "bignum.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
|
||||
static struct key_context* keep_newkeys = NULL;
|
||||
/* number of generated parameters is limited by the timeout for the first run */
|
||||
#define NUM_PARAMS 80
|
||||
static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
|
||||
|
||||
if (!once) {
|
||||
fuzz_common_setup();
|
||||
fuzz_svr_setup();
|
||||
|
||||
/* ses gets zeroed by fuzz_set_input */
|
||||
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
|
||||
ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
|
||||
ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
|
||||
assert(ecdh[0]);
|
||||
assert(ecdh[1]);
|
||||
assert(ecdh[2]);
|
||||
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Pre-generate parameters */
|
||||
int i;
|
||||
for (i = 0; i < NUM_PARAMS; i++) {
|
||||
ses.newkeys->algo_kex = ecdh[i % 3];
|
||||
ecdh_params[i] = gen_kexecdh_param();
|
||||
}
|
||||
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
|
||||
with DROPBEAR_KEX_ECDH */
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* random choice of ecdh 256, 384, 521 */
|
||||
unsigned char b = buf_getbyte(fuzz.input);
|
||||
ses.newkeys->algo_kex = ecdh[b % 3];
|
||||
|
||||
/* Choose from the collection of ecdh params */
|
||||
unsigned int e = buf_getint(fuzz.input);
|
||||
struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];
|
||||
|
||||
buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
|
||||
|
||||
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
|
||||
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
|
||||
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
buf_free(ecdh_qs);
|
||||
|
||||
buf_free(ses.hash);
|
||||
buf_free(ses.session_id);
|
||||
/* kexhashbuf is freed in kexdh_comb_key */
|
||||
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
fuzzer-preauth.c
Normal file
6
fuzzer-preauth.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "fuzz.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return fuzz_run_preauth(Data, Size, 0);
|
||||
}
|
||||
|
||||
6
fuzzer-preauth_nomaths.c
Normal file
6
fuzzer-preauth_nomaths.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "fuzz.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return fuzz_run_preauth(Data, Size, 1);
|
||||
}
|
||||
|
||||
54
fuzzer-pubkey.c
Normal file
54
fuzzer-pubkey.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void setup_fuzzer(void) {
|
||||
fuzz_common_setup();
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
if (!once) {
|
||||
setup_fuzzer();
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
buffer *line = buf_getstringbuf(fuzz.input);
|
||||
buffer *keyblob = buf_getstringbuf(fuzz.input);
|
||||
|
||||
unsigned int algolen;
|
||||
char* algoname = buf_getstring(keyblob, &algolen);
|
||||
|
||||
if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNKEY_NONE) {
|
||||
dropbear_exit("fuzzer imagined a bogus algorithm");
|
||||
}
|
||||
|
||||
int ret = fuzz_checkpubkey_line(line, 5, "/home/me/authorized_keys",
|
||||
algoname, algolen,
|
||||
keyblob->data, keyblob->len);
|
||||
|
||||
if (ret == DROPBEAR_SUCCESS) {
|
||||
/* fuzz_checkpubkey_line() should have cleaned up for failure */
|
||||
svr_pubkey_options_cleanup();
|
||||
}
|
||||
|
||||
buf_free(line);
|
||||
buf_free(keyblob);
|
||||
m_free(algoname);
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
79
fuzzer-verify.c
Normal file
79
fuzzer-verify.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "dss.h"
|
||||
|
||||
static void setup_fuzzer(void) {
|
||||
fuzz_common_setup();
|
||||
}
|
||||
|
||||
static buffer *verifydata;
|
||||
|
||||
/* Tests reading a public key and verifying a signature */
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
if (!once) {
|
||||
setup_fuzzer();
|
||||
verifydata = buf_new(30);
|
||||
buf_putstring(verifydata, "x", 1);
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
sign_key *key = new_sign_key();
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
|
||||
enum signature_type sigtype;
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
/* Flip a coin to decide rsa signature type */
|
||||
int flag = buf_getbyte(fuzz.input);
|
||||
if (flag & 0x01) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
} else {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
}
|
||||
} else {
|
||||
sigtype = signature_type_from_signkey(keytype);
|
||||
}
|
||||
if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) {
|
||||
/* The fuzzer is capable of generating keys with a signature to match.
|
||||
We don't want false positives if the key is bogus, since a client/server
|
||||
wouldn't be trusting a bogus key anyway */
|
||||
int boguskey = 0;
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
/* So far have seen dss keys with bad p/q/g domain parameters */
|
||||
int pprime, qprime, trials;
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
|
||||
assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
|
||||
assert(mp_prime_is_prime(key->dsskey->q, trials, &qprime) == MP_OKAY);
|
||||
boguskey = !(pprime && qprime);
|
||||
/* Could also check g**q mod p == 1 */
|
||||
}
|
||||
|
||||
if (!boguskey) {
|
||||
printf("Random key/signature managed to verify!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
sign_key_free(key);
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
12
fuzzers_test.sh
Executable file
12
fuzzers_test.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
# runs fuzz corpus with standalone fuzzers
|
||||
|
||||
result=0
|
||||
|
||||
test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
|
||||
for f in `make list-fuzz-targets`; do
|
||||
./$f fuzzcorpus/$f/* || result=1
|
||||
done
|
||||
|
||||
exit $result
|
||||
120
gcm.c
Normal file
120
gcm.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 "includes.h"
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
#include "gcm.h"
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
|
||||
#define GHASH_LEN 16
|
||||
|
||||
static const struct dropbear_hash dropbear_ghash =
|
||||
{NULL, 0, GHASH_LEN};
|
||||
|
||||
static int dropbear_gcm_start(int cipher, const unsigned char *IV,
|
||||
const unsigned char *key, int keylen,
|
||||
int UNUSED(num_rounds), dropbear_gcm_state *state) {
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_gcm_start"))
|
||||
|
||||
if ((err = gcm_init(&state->gcm, cipher, key, keylen)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
memcpy(state->iv, IV, GCM_NONCE_LEN);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_start"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_gcm_crypt(unsigned int UNUSED(seq),
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
dropbear_gcm_state *state, int direction) {
|
||||
unsigned char *iv, tag[GHASH_LEN];
|
||||
int i, err;
|
||||
|
||||
TRACE2(("enter dropbear_gcm_crypt"))
|
||||
|
||||
if (len < 4 || taglen != GHASH_LEN) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
gcm_reset(&state->gcm);
|
||||
|
||||
if ((err = gcm_add_iv(&state->gcm,
|
||||
state->iv, GCM_NONCE_LEN)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = gcm_add_aad(&state->gcm, in, 4)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = gcm_process(&state->gcm, (unsigned char *) in + 4,
|
||||
len - 4, out + 4, direction)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direction == LTC_ENCRYPT) {
|
||||
gcm_done(&state->gcm, out + len, &taglen);
|
||||
} else {
|
||||
gcm_done(&state->gcm, tag, &taglen);
|
||||
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment invocation counter */
|
||||
iv = state->iv + GCM_IVFIX_LEN;
|
||||
for (i = GCM_IVCTR_LEN - 1; i >= 0 && ++iv[i] == 0; i--);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_crypt"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_gcm_getlength(unsigned int UNUSED(seq),
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, dropbear_gcm_state* UNUSED(state)) {
|
||||
TRACE2(("enter dropbear_gcm_getlength"))
|
||||
|
||||
if (len < 4) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
LOAD32H(*outlen, in);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_getlength"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_gcm =
|
||||
{(void *)dropbear_gcm_start, NULL, NULL,
|
||||
(void *)dropbear_gcm_crypt,
|
||||
(void *)dropbear_gcm_getlength, &dropbear_ghash};
|
||||
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
47
gcm.h
Normal file
47
gcm.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. */
|
||||
|
||||
#ifndef DROPBEAR_DROPBEAR_GCM_H_
|
||||
#define DROPBEAR_DROPBEAR_GCM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
|
||||
#define GCM_IVFIX_LEN 4
|
||||
#define GCM_IVCTR_LEN 8
|
||||
#define GCM_NONCE_LEN (GCM_IVFIX_LEN + GCM_IVCTR_LEN)
|
||||
|
||||
typedef struct {
|
||||
gcm_state gcm;
|
||||
unsigned char iv[GCM_NONCE_LEN];
|
||||
} dropbear_gcm_state;
|
||||
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_gcm;
|
||||
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_GCM_H_ */
|
||||
35
gendss.c
35
gendss.c
@@ -35,13 +35,13 @@
|
||||
|
||||
/* This is just a test */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
static void getq(dropbear_dss_key *key);
|
||||
static void getp(dropbear_dss_key *key, unsigned int size);
|
||||
static void getg(dropbear_dss_key *key);
|
||||
static void getx(dropbear_dss_key *key);
|
||||
static void gety(dropbear_dss_key *key);
|
||||
static void getq(const dropbear_dss_key *key);
|
||||
static void getp(const dropbear_dss_key *key, unsigned int size);
|
||||
static void getg(const dropbear_dss_key *key);
|
||||
static void getx(const dropbear_dss_key *key);
|
||||
static void gety(const dropbear_dss_key *key);
|
||||
|
||||
dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
@@ -65,9 +65,10 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
}
|
||||
|
||||
static void getq(dropbear_dss_key *key) {
|
||||
static void getq(const dropbear_dss_key *key) {
|
||||
|
||||
unsigned char buf[QSIZE];
|
||||
int trials;
|
||||
|
||||
/* 160 bit prime */
|
||||
genrandom(buf, QSIZE);
|
||||
@@ -76,20 +77,21 @@ static void getq(dropbear_dss_key *key) {
|
||||
|
||||
bytes_to_mp(key->q, buf, QSIZE);
|
||||
|
||||
/* 18 rounds are required according to HAC */
|
||||
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
|
||||
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->q));
|
||||
if (mp_prime_next_prime(key->q, trials, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void getp(dropbear_dss_key *key, unsigned int size) {
|
||||
static void getp(const dropbear_dss_key *key, unsigned int size) {
|
||||
|
||||
DEF_MP_INT(tempX);
|
||||
DEF_MP_INT(tempC);
|
||||
DEF_MP_INT(tempP);
|
||||
DEF_MP_INT(temp2q);
|
||||
int result;
|
||||
int result, trials;
|
||||
unsigned char *buf;
|
||||
|
||||
m_mp_init_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
|
||||
@@ -129,9 +131,10 @@ static void getp(dropbear_dss_key *key, unsigned int size) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* now check for prime, 5 rounds is enough according to HAC */
|
||||
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->p));
|
||||
/* result == 1 => p is prime */
|
||||
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
|
||||
if (mp_prime_is_prime(key->p, trials, &result) != MP_OKAY) {
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -142,7 +145,7 @@ static void getp(dropbear_dss_key *key, unsigned int size) {
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
static void getg(dropbear_dss_key * key) {
|
||||
static void getg(const dropbear_dss_key * key) {
|
||||
|
||||
DEF_MP_INT(div);
|
||||
DEF_MP_INT(h);
|
||||
@@ -179,12 +182,12 @@ static void getg(dropbear_dss_key * key) {
|
||||
mp_clear_multi(&div, &h, &val, NULL);
|
||||
}
|
||||
|
||||
static void getx(dropbear_dss_key *key) {
|
||||
static void getx(const dropbear_dss_key *key) {
|
||||
|
||||
gen_random_mpint(key->q, key->x);
|
||||
}
|
||||
|
||||
static void gety(dropbear_dss_key *key) {
|
||||
static void gety(const dropbear_dss_key *key) {
|
||||
|
||||
if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) {
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
|
||||
2
gendss.h
2
gendss.h
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
dropbear_dss_key * gen_dss_priv_key(unsigned int size);
|
||||
|
||||
|
||||
47
gened25519.c
Normal file
47
gened25519.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "dbrandom.h"
|
||||
#include "curve25519.h"
|
||||
#include "gened25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size) {
|
||||
|
||||
dropbear_ed25519_key *key;
|
||||
|
||||
if (size != 256) {
|
||||
dropbear_exit("Ed25519 keys have a fixed size of 256 bits");
|
||||
}
|
||||
|
||||
key = m_malloc(sizeof(*key));
|
||||
dropbear_ed25519_make_key(key->pub, key->priv);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user