mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
266 Commits
DROPBEAR_2
...
DROPBEAR_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd0352d93b | ||
|
|
30ec18d938 | ||
|
|
9d495ab2b5 | ||
|
|
9174de47a9 | ||
|
|
d857faf18e | ||
|
|
d5c8ba1690 | ||
|
|
9bb9b4829d | ||
|
|
e25c297c3c | ||
|
|
b9073961f7 | ||
|
|
a7a79d569a | ||
|
|
6165f53fcd | ||
|
|
4122cac66b | ||
|
|
a1dcebe4f4 | ||
|
|
6cbb23a819 | ||
|
|
5c57a31184 | ||
|
|
7b2c42aa75 | ||
|
|
1ed8d3938e | ||
|
|
b24984deb3 | ||
|
|
eabd9f5e60 | ||
|
|
d4609682af | ||
|
|
634415f79e | ||
|
|
4ba830fc31 | ||
|
|
3022a46039 | ||
|
|
d9a868ff60 | ||
|
|
c890a0c133 | ||
|
|
9ec934a94a | ||
|
|
5e606a964b | ||
|
|
d88034434c | ||
|
|
776d908703 | ||
|
|
444b15889f | ||
|
|
957450582f | ||
|
|
6d2d3669f3 | ||
|
|
1387654cc8 | ||
|
|
10eb218fb0 | ||
|
|
bfb2b30de6 | ||
|
|
426d4d72c6 | ||
|
|
cce29ba38c | ||
|
|
ed2e276b3a | ||
|
|
12a020aa62 | ||
|
|
b969101b33 | ||
|
|
86a742f635 | ||
|
|
9468f7f6d6 | ||
|
|
628a3f5cca | ||
|
|
e815e97440 | ||
|
|
0e7409c7ff | ||
|
|
393ca2a290 | ||
|
|
ad1d48e07b | ||
|
|
ac98aae160 | ||
|
|
c1267398a2 | ||
|
|
8c3a2bb63e | ||
|
|
923fc9087c | ||
|
|
83511fecc0 | ||
|
|
ed0552f214 | ||
|
|
5cf83a7212 | ||
|
|
7808eff0a9 | ||
|
|
da57dd13c5 | ||
|
|
f1826ea389 | ||
|
|
c884e5000e | ||
|
|
1ccac01cee | ||
|
|
50a5d3756f | ||
|
|
ca86726f9f | ||
|
|
6b5317e7cc | ||
|
|
2a1d28ea3a | ||
|
|
0e0ff51582 | ||
|
|
cd700aaf6e | ||
|
|
188ec1e258 | ||
|
|
d01fb265d6 | ||
|
|
db688e3ec1 | ||
|
|
e767bbb41f | ||
|
|
2b599df57a | ||
|
|
5baa10a6b6 | ||
|
|
3e1a389629 | ||
|
|
37e6207396 | ||
|
|
927a2dc849 | ||
|
|
ce9f9594da | ||
|
|
f0bf37b6cb | ||
|
|
2f0b35a105 | ||
|
|
7a9ed81f5f | ||
|
|
12e7d570a2 | ||
|
|
bb7934bf04 | ||
|
|
fb3c718963 | ||
|
|
231fc607f9 | ||
|
|
9594a3aa45 | ||
|
|
162fcab347 | ||
|
|
0c8bdfd7cd | ||
|
|
5e4dc71907 | ||
|
|
3e4433f715 | ||
|
|
29062e629f | ||
|
|
47f7272ba1 | ||
|
|
bf6f3f613d | ||
|
|
0c9a643216 | ||
|
|
fa2d843403 | ||
|
|
1dc5312f00 | ||
|
|
73444f2957 | ||
|
|
a18a6b8db8 | ||
|
|
bf56591fb8 | ||
|
|
5ea428a30d | ||
|
|
af524c4d65 | ||
|
|
2bc9f35052 | ||
|
|
55a0c5068f | ||
|
|
8128b15e41 | ||
|
|
8081b0e033 | ||
|
|
61cecbb337 | ||
|
|
aee1309c91 | ||
|
|
710c1df413 | ||
|
|
0f165a95a8 | ||
|
|
581f04c80b | ||
|
|
511be4acc6 | ||
|
|
d77b29f1d7 | ||
|
|
092a4d9a7e | ||
|
|
b3cab3ce31 | ||
|
|
e5279b0e2e | ||
|
|
9ff337aa3b | ||
|
|
441facc6e0 | ||
|
|
998d6cdfc4 | ||
|
|
ddc10b2d0c | ||
|
|
4f6f651b7d | ||
|
|
68c7667a20 | ||
|
|
0b62d71e70 | ||
|
|
be5780ef90 | ||
|
|
e5c52796c3 | ||
|
|
c5e36f8e3c | ||
|
|
5a85c4b91b | ||
|
|
0201072c1b | ||
|
|
aa029ed991 | ||
|
|
0777e896f1 | ||
|
|
7f90231b8f | ||
|
|
cbe63bbabe | ||
|
|
de1deaf0bd | ||
|
|
e00a97944a | ||
|
|
a65f84db38 | ||
|
|
8c8ecec3e9 | ||
|
|
b77864931b | ||
|
|
e60a84d0ed | ||
|
|
f025277147 | ||
|
|
1e00d0b926 | ||
|
|
29b1455f36 | ||
|
|
0162c116da | ||
|
|
58fe1c2d2a | ||
|
|
4363b8b32d | ||
|
|
cfac8435a7 | ||
|
|
35f26ff855 | ||
|
|
f66fc01620 | ||
|
|
082a2dde35 | ||
|
|
814ab77538 | ||
|
|
8eefb092c8 | ||
|
|
55e7f0486a | ||
|
|
88ac2da7c2 | ||
|
|
27510a6e9e | ||
|
|
7fda6418e1 | ||
|
|
45bd0edae5 | ||
|
|
3d733a16e9 | ||
|
|
fe623afaad | ||
|
|
b840a980e3 | ||
|
|
2ec98eb048 | ||
|
|
253cd3b66b | ||
|
|
920120d05a | ||
|
|
4ba058986e | ||
|
|
03b7255ddd | ||
|
|
2de7f8b224 | ||
|
|
bbf2f1d571 | ||
|
|
9cdd5e99a4 | ||
|
|
897ed7125b | ||
|
|
459d259185 | ||
|
|
aac6336e49 | ||
|
|
fc1155f974 | ||
|
|
6a09fa23d0 | ||
|
|
142a0f8a83 | ||
|
|
d1dec41f76 | ||
|
|
69a165db86 | ||
|
|
dffb33cecf | ||
|
|
e7917c16c9 | ||
|
|
e05b7f0b76 | ||
|
|
aeea70f95f | ||
|
|
ded40babb5 | ||
|
|
e355f69401 | ||
|
|
c2b1327deb | ||
|
|
f7ba7444e8 | ||
|
|
aafeebd0c8 | ||
|
|
6b0d47b364 | ||
|
|
d9e790e7dc | ||
|
|
51b5cdd430 | ||
|
|
aced7b5b00 | ||
|
|
0475594cb2 | ||
|
|
04518e9e80 | ||
|
|
a57947c513 | ||
|
|
372e81a842 | ||
|
|
41f531ceaf | ||
|
|
b46d46667f | ||
|
|
226671b550 | ||
|
|
916cfa6b83 | ||
|
|
49263b5314 | ||
|
|
95a21c8fd7 | ||
|
|
57166b400c | ||
|
|
79660f2eb1 | ||
|
|
3ea9068e18 | ||
|
|
e4c672bdbb | ||
|
|
791a78ad1f | ||
|
|
6da90b34fe | ||
|
|
43769b5bb3 | ||
|
|
f98eb5808b | ||
|
|
3525cabf48 | ||
|
|
54a76342f5 | ||
|
|
154a65fc31 | ||
|
|
bd7a46f514 | ||
|
|
79a307bca2 | ||
|
|
38f42a0fa2 | ||
|
|
b4cdfcb506 | ||
|
|
d3cef72f26 | ||
|
|
ef151888fb | ||
|
|
ba15bbfe33 | ||
|
|
3bdfae61a2 | ||
|
|
4404126501 | ||
|
|
5c87c6a435 | ||
|
|
adeb372a66 | ||
|
|
c0d7c6693f | ||
|
|
3ec4670478 | ||
|
|
f842712551 | ||
|
|
9f01625e23 | ||
|
|
7f091e7019 | ||
|
|
4f07805d0a | ||
|
|
a7d1a9cfcb | ||
|
|
48c83aa9d0 | ||
|
|
c797c1750c | ||
|
|
c6bdc810ab | ||
|
|
a8135dec1e | ||
|
|
2fdb5fd6ce | ||
|
|
7f42096d0f | ||
|
|
e2c813df4d | ||
|
|
a2f70a3751 | ||
|
|
286fa93a8d | ||
|
|
557d86aa79 | ||
|
|
8e68d5e2d5 | ||
|
|
1a16da38d5 | ||
|
|
cbd3d5e3a5 | ||
|
|
78fbed8c3e | ||
|
|
f267ca1f3a | ||
|
|
a6eb824950 | ||
|
|
dcd1527a11 | ||
|
|
f8a92d1eed | ||
|
|
e55e468754 | ||
|
|
ff2aa20565 | ||
|
|
90b5691183 | ||
|
|
5af0d33164 | ||
|
|
e5072c6b12 | ||
|
|
90cf7f012c | ||
|
|
484516da51 | ||
|
|
5abe22d1a5 | ||
|
|
f6b304250b | ||
|
|
36526700a9 | ||
|
|
32294978a3 | ||
|
|
a0e931005b | ||
|
|
9c7485331a | ||
|
|
99d9cf500b | ||
|
|
4f62da0f0d | ||
|
|
b4bcc60657 | ||
|
|
5139bd42f6 | ||
|
|
cf7a271f90 | ||
|
|
74cad1612f | ||
|
|
73e22c115c | ||
|
|
9be0d6b53d | ||
|
|
bbf6d5f2f5 | ||
|
|
c4861340e9 | ||
|
|
5996c3824c | ||
|
|
c172fb3b32 | ||
|
|
03a0d11c4d |
12
.hgsigs
12
.hgsigs
@@ -1,3 +1,15 @@
|
||||
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjDoF+wd1ipDx1wkzdeBQNqgCgykUrSbXv76FBbxKntVbk9oS3GjI=
|
||||
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho=
|
||||
85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc=
|
||||
9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB
|
||||
095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC
|
||||
f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6QCePVovn/avKXUyNwNBYCcov6JLYqkAnRCPQdkXgv20N3t10r6PRMBBo1/S
|
||||
deb211f75ca194e2fcf0d2e5f71c60474e42ec95 0 iEYEABECAAYFAlJO01cACgkQjPn4sExkf7yDqACaA/P+Yl/K2Cv3OC5G0b7ck2Kb75EAoIeW7qpCyclzJLWwk95koED+4lxD
|
||||
025237c9f0a1a60a616f984d82fb2a9270d3b0ea 0 iEYEABECAAYFAlJeqDYACgkQjPn4sExkf7y5nQCfW6t+TJySBTTo+gCfDUBPRVxvNe8AoIn/15aWfqH/A2G9uikfoVtWK3pd
|
||||
a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVqACg6IP0fU29+Feh/TDeemDA+2XAzrIAoIdZfMDvVYlDoWotZD8ACFnf5H1P
|
||||
9ec083a21adfcb099f21eb03704b66d14a4ba800 0 iEYEABECAAYFAlKE4JoACgkQjPn4sExkf7wLDgCghkVGwMjI138bEv+ORVzN7zIH7cEAoLckaxZc1k1aXlmlSCRlP8cuKH3o
|
||||
3d1d7d151c0ce3a79da62e86463f5632fa2b144a 0 iEYEABECAAYFAlKd5AEACgkQjPn4sExkf7wzWgCfdvPEEIdlMPqcbOQMJ7b+eAyy164An2ip1lPh1eS5g26/gSfruvWBVym4
|
||||
277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
|
||||
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
|
||||
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq
|
||||
2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu
|
||||
|
||||
11
.hgtags
11
.hgtags
@@ -35,3 +35,14 @@ d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55
|
||||
0000000000000000000000000000000000000000 t:ltc-0.95-orig
|
||||
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
|
||||
0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1
|
||||
1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56
|
||||
96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57
|
||||
e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58
|
||||
7b68e581985fd4ea50869f8608ab95cda5d17876 DROPBEAR_2013.59
|
||||
a50a1dc743317fad9b3737bc68fbca640659bb6d DROPBEAR_2013.60
|
||||
e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
|
||||
3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62
|
||||
2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
|
||||
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
|
||||
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65
|
||||
735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66
|
||||
|
||||
20
.travis.yml
Normal file
20
.travis.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
script:
|
||||
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install
|
||||
- ~/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
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev
|
||||
|
||||
env:
|
||||
- BUNDLEDLIBTOM=--disable-bundled-libtom
|
||||
- BUNDLEDLIBTOM=--enable-bundled-libtom
|
||||
- MULTI=1
|
||||
272
CHANGES
272
CHANGES
@@ -1,3 +1,259 @@
|
||||
2015.67 - Wednesday 28 January 2015
|
||||
|
||||
- Call fsync() after generating private keys to ensure they aren't lost if a
|
||||
reboot occurs. Thanks to Peter Korsgaard
|
||||
|
||||
- Disable non-delayed zlib compression by default on the server. Can be
|
||||
enabled if required for old clients with DROPBEAR_SERVER_DELAY_ZLIB
|
||||
|
||||
- Default client key path ~/.ssh/id_dropbear
|
||||
|
||||
- Prefer stronger algorithms by default, from Fedor Brunner.
|
||||
AES256 over 3DES
|
||||
Diffie-hellman group14 over group1
|
||||
|
||||
- Add option to disable CBC ciphers.
|
||||
|
||||
- Disable twofish in default options.h
|
||||
|
||||
- Enable sha2 HMAC algorithms by default, the code was already required
|
||||
for ECC key exchange. sha1 is the first preference still for performance.
|
||||
|
||||
- Fix installing dropbear.8 in a separate build directory, from Like Ma
|
||||
|
||||
- Allow configure to succeed if libtomcrypt/libtommath are missing, from Elan Ruusamäe
|
||||
|
||||
- Don't crash if ssh-agent provides an unknown type of key. From Catalin Patulea
|
||||
|
||||
- Minor bug fixes, a few issues found by Coverity scan
|
||||
|
||||
2014.66 - Thursday 23 October 2014
|
||||
|
||||
- Use the same keepalive handling behaviour as OpenSSH. This will work better
|
||||
with some SSH implementations that have different behaviour with unknown
|
||||
message types.
|
||||
|
||||
- Don't reply with SSH_MSG_UNIMPLEMENTED when we receive a reply to our own
|
||||
keepalive message
|
||||
|
||||
- Set $SSH_CLIENT to keep bash happy, patch from Ryan Cleere
|
||||
|
||||
- Fix wtmp which broke since 2013.62, patch from Whoopie
|
||||
|
||||
2014.65 - Friday 8 August 2014
|
||||
|
||||
- Fix 2014.64 regression, server session hang on exit with scp (and probably
|
||||
others), thanks to NiLuJe for tracking it down
|
||||
|
||||
- Fix 2014.64 regression, clock_gettime() error handling which broke on older
|
||||
Linux kernels, reported by NiLuJe
|
||||
|
||||
- Fix 2014.64 regression, writev() could occassionally fail with EAGAIN which
|
||||
wasn't caught
|
||||
|
||||
- Avoid error message when trying to set QoS on proxycommand or multihop pipes
|
||||
|
||||
- Use /usr/bin/xauth, thanks to Mike Frysinger
|
||||
|
||||
- Don't exit the client if the local user entry can't be found, thanks to iquaba
|
||||
|
||||
2014.64 - Sunday 27 July 2014
|
||||
|
||||
- Fix compiling with ECDSA and DSS disabled
|
||||
|
||||
- Don't exit abruptly if too many outgoing packets are queued for writev(). Patch
|
||||
thanks to Ronny Meeus
|
||||
|
||||
- The -K keepalive option now behaves more like OpenSSH's "ServerAliveInterval".
|
||||
If no response is received after 3 keepalives then the session is terminated. This
|
||||
will close connections faster than waiting for a TCP timeout.
|
||||
|
||||
- Rework TCP priority setting. New settings are
|
||||
if (connecting || ptys || x11) tos = LOWDELAY
|
||||
else if (tcp_forwards) tos = 0
|
||||
else tos = BULK
|
||||
Thanks to Catalin Patulea for the suggestion.
|
||||
|
||||
- Improve handling of many concurrent new TCP forwarded connections, should now
|
||||
be able to handle as many as MAX_CHANNELS. Thanks to Eduardo Silva for reporting
|
||||
and investigating it.
|
||||
|
||||
- Make sure that exit messages from the client are printed, regression in 2013.57
|
||||
|
||||
- Use monotonic clock where available, timeouts won't be affected by system time
|
||||
changes
|
||||
|
||||
- Add -V for version
|
||||
|
||||
2014.63 - Wednesday 19 February 2014
|
||||
|
||||
- Fix ~. to terminate a client interactive session after waking a laptop
|
||||
from sleep.
|
||||
|
||||
- Changed port separator syntax again, now using host^port. This is because
|
||||
IPv6 link-local addresses use %. Reported by Gui Iribarren
|
||||
|
||||
- Avoid constantly relinking dropbearmulti target, fix "make install"
|
||||
for multi target, thanks to Mike Frysinger
|
||||
|
||||
- Avoid getting stuck in a loop writing huge key files, reported by Bruno
|
||||
Thomsen
|
||||
|
||||
- Don't link dropbearkey or dropbearconvert to libz or libutil,
|
||||
thanks to Nicolas Boos
|
||||
|
||||
- Fix linking -lcrypt on systems without /usr/lib, thanks to Nicolas Boos
|
||||
|
||||
- Avoid crash on exit due to cleaned up keys before last packets are sent,
|
||||
debugged by Ronald Wahl
|
||||
|
||||
- Fix a race condition in rekeying where Dropbear would exit if it received a
|
||||
still-in-flight packet after initiating rekeying. Reported by Oliver Metz.
|
||||
This is a longstanding bug but is triggered more easily since 2013.57
|
||||
|
||||
- Fix README for ecdsa keys, from Catalin Patulea
|
||||
|
||||
- Ensure that generated RSA keys are always exactly the length
|
||||
requested. Previously Dropbear always generated N+16 or N+15 bit keys.
|
||||
Thanks to Unit 193
|
||||
|
||||
- Fix DROPBEAR_CLI_IMMEDIATE_AUTH mode which saves a network round trip if the
|
||||
first public key succeeds. Still not enabled by default, needs more
|
||||
compatibility testing with other implementations.
|
||||
|
||||
- Fix for port 0 forwarding in the client and port forwarding with Apache MINA SSHD. Thanks to
|
||||
|
||||
- Fix for bad system linux/pkt-sched.h header file with older Linux
|
||||
kernels, from Steve Dover
|
||||
|
||||
- Fix signal handlers so that errno is saved, thanks to Erik Ahlén for a patch
|
||||
and Mark Wickham for independently spotting the same problem.
|
||||
|
||||
2013.62 - Tuesday 3 December 2013
|
||||
|
||||
- Disable "interactive" QoS connection options when a connection doesn't
|
||||
have a PTY (eg scp, rsync). Thanks to Catalin Patulea for the patch.
|
||||
|
||||
- Log when a hostkey is generated with -R, fix some bugs in handling server
|
||||
hostkey commandline options
|
||||
|
||||
- Fix crash in Dropbearconvert and 521 bit key, reported by NiLuJe
|
||||
|
||||
- Update config.guess and config.sub again
|
||||
|
||||
2013.61test - Thursday 14 November 2013
|
||||
|
||||
- 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.
|
||||
|
||||
- curve25519-sha256@libssh.org support for setting up encryption keys. This is
|
||||
another elliptic curve mode with less potential of NSA interference in
|
||||
algorithm parameters. curve25519-donna code thanks to Adam Langley
|
||||
|
||||
- -R option to automatically generate hostkeys. This is recommended for
|
||||
embedded platforms since it allows the system random number device
|
||||
/dev/urandom a longer startup time to generate a secure seed before the
|
||||
hostkey is required.
|
||||
|
||||
- Compile fixes for old vendor compilers like Tru64 from Daniel Richard G.
|
||||
|
||||
- Make authorized_keys handling more robust, don't exit encountering
|
||||
malformed lines. Thanks to Lorin Hochstein and Mark Stillwell
|
||||
|
||||
2013.60 - Wednesday 16 October 2013
|
||||
|
||||
- Fix "make install" so that it doesn't always install to /bin and /sbin
|
||||
|
||||
- Fix "make install MULTI=1", installing manpages failed
|
||||
|
||||
- Fix "make install" when scp is included since it has no manpage
|
||||
|
||||
- Make --disable-bundled-libtom work
|
||||
|
||||
2013.59 - Friday 4 October 2013
|
||||
|
||||
- Fix crash from -J command
|
||||
Thanks to Lluís Batlle i Rossell and Arnaud Mouiche for patches
|
||||
|
||||
- Avoid reading too much from /proc/net/rt_cache since that causes
|
||||
system slowness.
|
||||
|
||||
- Improve EOF handling for half-closed connections
|
||||
Thanks to Catalin Patulea
|
||||
|
||||
- Send a banner message to report PAM error messages intended for the user
|
||||
Patch from Martin Donnelly
|
||||
|
||||
- Limit the size of decompressed payloads, avoids memory exhaustion denial
|
||||
of service
|
||||
Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
|
||||
|
||||
- Avoid disclosing existence of valid users through inconsistent delays
|
||||
Thanks to Logan Lamb for reporting. CVE-2013-4434
|
||||
|
||||
- Update config.guess and config.sub for newer architectures
|
||||
|
||||
- Avoid segfault in server for locked accounts
|
||||
|
||||
- "make install" now installs manpages
|
||||
dropbearkey.8 has been renamed to dropbearkey.1
|
||||
manpage added for dropbearconvert
|
||||
|
||||
- Get rid of one second delay when running non-interactive commands
|
||||
|
||||
|
||||
2013.58 - Thursday 18 April 2013
|
||||
|
||||
- Fix building with Zlib disabled, thanks to Hans Harder and cuma@freetz
|
||||
|
||||
- Use % as a separator for ports, fixes scp in multihop mode, from Hans Harder
|
||||
|
||||
- Reject logins for other users when running as non-root, from Hans Harder
|
||||
|
||||
- Disable client immediate authentication request by default, it prevents
|
||||
passwordless logins from working
|
||||
|
||||
2013.57 - Monday 15 April 2013
|
||||
|
||||
- Decreased connection setup time particularly with high latency connections,
|
||||
the number of round trips has been reduced for both client and server.
|
||||
CPU time hasn't been changed.
|
||||
|
||||
- Client will send an initial key exchange guess to save a round trip.
|
||||
Dropbear implements an extension kexguess2@matt.ucc.asn.au to allow the first
|
||||
packet guess to succeed in wider circumstances than the standard behaviour.
|
||||
When communicating with other implementations the standard behaviour is used.
|
||||
|
||||
- Client side: when public key or password authentication with
|
||||
$DROPBEAR_PASSWORD is used an initial authentication request will
|
||||
be sent immediately rather than querying the list of available methods.
|
||||
This behaviour is enabled by CLI_IMMEDIATE_AUTH option (on by default),
|
||||
please let the Dropbear author know if it causes any interoperability
|
||||
problems.
|
||||
|
||||
- Implement client escape characters ~. (terminate session) and
|
||||
~^Z (background session)
|
||||
|
||||
- Server will more reliably clean up utmp when connection is closed, reported by
|
||||
Mattias Walström
|
||||
|
||||
- Don't crash if /dev/urandom isn't writable (RHEL5), thanks to Scott Case
|
||||
|
||||
- Add "-y -y" client option to skip host key checking, thanks to Hans Harder
|
||||
|
||||
- scp didn't work properly on systems using vfork(), thanks to Frank Van Uffelen
|
||||
|
||||
- Added IUTF8 terminal mode support (Linux and Mac OS). Not standardised yet
|
||||
though probably will be soon
|
||||
|
||||
- Some verbose DROPBEAR_TRACE output is now hidden unless $DROPBEAR_TRACE2
|
||||
enviroment variable is set
|
||||
|
||||
- Fix using asymmetric MAC algorithms (broke in )
|
||||
|
||||
- Renamed configure.in to configure.ac to quieten autoconf, from Mike Frysinger
|
||||
|
||||
2013.56 - Thursday 21 March 2013
|
||||
|
||||
- Allow specifying cipher (-c) and MAC (-m) lists for dbclient
|
||||
@@ -20,10 +276,10 @@
|
||||
|
||||
- Allow using IPv6 bracket notation for addresses in server "-p" option, from Ben Jencks
|
||||
|
||||
- A few improvements for Android from Reimar Döffinger
|
||||
- A few improvements for Android from Reimar Döffinger
|
||||
|
||||
- Fix memory leak for TCP forwarded connections to hosts that timed out,
|
||||
reported by Norbert Benczúr. Appears to be a very long-standing bug.
|
||||
reported by Norbert Benczúr. Appears to be a very long-standing bug.
|
||||
|
||||
- Fix "make clean" for out of tree builds
|
||||
|
||||
@@ -235,7 +491,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
|
||||
- Security: dbclient previously would prompt to confirm a
|
||||
mismatching hostkey but wouldn't warn loudly. It will now
|
||||
exit upon a mismatch.
|
||||
exit upon a mismatch. CVE-2007-1099
|
||||
|
||||
- Compile fixes, make sure that all variable definitions are at the start
|
||||
of a scope.
|
||||
@@ -297,7 +553,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
(thanks to Tomas Vanek for helping track it down)
|
||||
|
||||
- Implement per-IP pre-authentication connection limits
|
||||
(after some poking from Pablo Fernandez)
|
||||
(after some poking from Pablo Fernandez) CVE-2006-1206
|
||||
|
||||
- Exit gracefully if trying to connect to as SSH v1 server
|
||||
(reported by Rushi Lala)
|
||||
@@ -318,7 +574,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
- SECURITY: fix for buffer allocation error in server code, could potentially
|
||||
allow authenticated users to gain elevated privileges. All multi-user systems
|
||||
running the server should upgrade (or apply the patch available on the
|
||||
Dropbear webpage).
|
||||
Dropbear webpage). CVE-2005-4178
|
||||
|
||||
- Fix channel handling code so that redirecting to /dev/null doesn't use
|
||||
100% CPU.
|
||||
@@ -525,7 +781,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
- SECURITY: Don't try to free() uninitialised variables in DSS verification
|
||||
code. Thanks to Arne Bernin for pointing out this bug. This is possibly
|
||||
exploitable, all users with DSS and pubkey-auth compiled in are advised to
|
||||
upgrade.
|
||||
upgrade. CVE-2004-2486
|
||||
|
||||
- Clean up agent forwarding socket files correctly, patch from Gerrit Pape.
|
||||
|
||||
@@ -649,7 +905,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
Lobenstock and Mihnea Stoenescu
|
||||
|
||||
- Use daemon() function if available (or our own copy) rather than separate
|
||||
code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard
|
||||
code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard
|
||||
Blackham for his suggestion on what to look at)
|
||||
|
||||
- Fixed up support for first_kex_packet_follows, required to talk to ssh.com
|
||||
@@ -768,7 +1024,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
- Various signedness fixes
|
||||
- Can listen on multiple ports
|
||||
- added option to disable openpty with configure script,
|
||||
(from K.-P. Kirchdörfer <kapeka at epost.de>)
|
||||
(from K.-P. Kirchdörfer <kapeka at epost.de>)
|
||||
- Various cleanups to bignum code
|
||||
(thanks to Tom St Denis <tomstdenis at iahu.ca>)
|
||||
- Fix compile error when disabling RSA
|
||||
|
||||
54
LICENSE
54
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-2008 Matt Johnston
|
||||
Copyright (c) 2002-2014 Matt Johnston
|
||||
Portions copyright (c) 2004 Mihnea Stoenescu
|
||||
All rights reserved.
|
||||
|
||||
@@ -87,3 +87,55 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
|
||||
|
||||
=====
|
||||
|
||||
curve25519-donna:
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
4
MULTI
4
MULTI
@@ -20,7 +20,3 @@ etc
|
||||
then execute as normal:
|
||||
|
||||
./dropbear <options here>
|
||||
|
||||
"make install" doesn't currently work for multi-binary configuration, though
|
||||
in most situations where it is being used, the target and build systems will
|
||||
differ.
|
||||
|
||||
102
Makefile.in
102
Makefile.in
@@ -13,50 +13,54 @@ ifndef PROGRAMS
|
||||
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
|
||||
endif
|
||||
|
||||
LTC=libtomcrypt/libtomcrypt.a
|
||||
LTM=libtommath/libtommath.a
|
||||
STATIC_LTC=libtomcrypt/libtomcrypt.a
|
||||
STATIC_LTM=libtommath/libtommath.a
|
||||
|
||||
LIBTOM_LIBS=@LIBTOM_LIBS@
|
||||
|
||||
ifeq (@BUNDLED_LIBTOM@, 1)
|
||||
LIBTOM_DEPS=$(LTC) $(LTM)
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBS+=$(LTC) $(LTM)
|
||||
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
endif
|
||||
|
||||
COMMONOBJS=dbutil.o buffer.o \
|
||||
dss.o bignum.o \
|
||||
signkey.o rsa.o random.o \
|
||||
signkey.o rsa.o dbrandom.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o
|
||||
atomicio.o compat.o fake-rfc2553.o \
|
||||
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
|
||||
gensignkey.o gendss.o genrsa.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.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 \
|
||||
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
|
||||
svr-tcpfwd.o svr-authpam.o
|
||||
|
||||
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
|
||||
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-runopts.o cli-chansession.o \
|
||||
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
|
||||
cli-agentfwd.o list.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 \
|
||||
common-runopts.o circbuffer.o
|
||||
common-runopts.o circbuffer.o curve25519-donna.o
|
||||
|
||||
KEYOBJS=dropbearkey.o gendss.o genrsa.o
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
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 random.h service.h auth.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
|
||||
listener.h fake-rfc2553.h ecc.h ecdsa.h
|
||||
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
@@ -66,9 +70,11 @@ VPATH=@srcdir@
|
||||
srcdir=@srcdir@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
bindir=${exec_prefix}/bin
|
||||
sbindir=${exec_prefix}/sbin
|
||||
exec_prefix=@exec_prefix@
|
||||
datarootdir = @datarootdir@
|
||||
bindir=@bindir@
|
||||
sbindir=@sbindir@
|
||||
mandir=@mandir@
|
||||
|
||||
CC=@CC@
|
||||
AR=@AR@
|
||||
@@ -120,36 +126,34 @@ strip: $(TARGETS)
|
||||
|
||||
install: $(addprefix inst_, $(TARGETS))
|
||||
|
||||
installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS))
|
||||
|
||||
insdbmulti: dropbearmulti
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
-chown root $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
|
||||
|
||||
insmultidropbear: dropbearmulti
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
|
||||
$(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
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(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
|
||||
|
||||
# dropbear should go in sbin, so it needs a seperate rule
|
||||
inst_dropbear: dropbear
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 755 dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
-chown root $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
inst_%: $*
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
-chown root $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
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
|
||||
|
||||
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
|
||||
|
||||
|
||||
# for some reason the rule further down doesn't like $($@objs) as a prereq.
|
||||
@@ -158,8 +162,14 @@ dbclient: $(dbclientobjs)
|
||||
dropbearkey: $(dropbearkeyobjs)
|
||||
dropbearconvert: $(dropbearconvertobjs)
|
||||
|
||||
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
|
||||
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
|
||||
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)
|
||||
|
||||
# scp doesn't use the libs so is special.
|
||||
scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
@@ -169,14 +179,14 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
# multi-binary compilation.
|
||||
MULTIOBJS=
|
||||
ifeq ($(MULTI),1)
|
||||
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@
|
||||
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
|
||||
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
|
||||
endif
|
||||
|
||||
dropbearmulti: multilink
|
||||
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
|
||||
multibinary: $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
|
||||
multibinary: dropbearmulti$(EXEEXT)
|
||||
|
||||
multilink: multibinary $(addprefix link, $(PROGRAMS))
|
||||
|
||||
@@ -184,10 +194,10 @@ link%:
|
||||
-rm -f $*$(EXEEXT)
|
||||
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
|
||||
|
||||
$(LTC): options.h
|
||||
cd libtomcrypt && $(MAKE) clean && $(MAKE)
|
||||
$(STATIC_LTC): options.h
|
||||
cd libtomcrypt && $(MAKE)
|
||||
|
||||
$(LTM): options.h
|
||||
$(STATIC_LTM): options.h
|
||||
cd libtommath && $(MAKE)
|
||||
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
|
||||
|
||||
12
README
12
README
@@ -1,4 +1,4 @@
|
||||
This is Dropbear, a smallish SSH 2 server and client.
|
||||
This is Dropbear, a smallish SSH server and client.
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
INSTALL has compilation instructions.
|
||||
@@ -42,8 +42,7 @@ If you have an OpenSSH-style private key ~/.ssh/id_rsa, you need to do:
|
||||
dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_rsa.db
|
||||
dbclient -i ~/.ssh/id_rsa.db <hostname>
|
||||
|
||||
Currently encrypted keys aren't supported, neither is agent forwarding. At some
|
||||
stage both hopefully will be.
|
||||
Dropbear does not support encrypted hostkeys though can connect to ssh-agent.
|
||||
|
||||
============================================================================
|
||||
|
||||
@@ -52,13 +51,18 @@ dropbearkey's '-y' option.
|
||||
|
||||
============================================================================
|
||||
|
||||
To run the server, you need to generate server keys, this is one-off:
|
||||
To run the server, you need to 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
|
||||
|
||||
or alternatively convert OpenSSH keys to Dropbear:
|
||||
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
|
||||
|
||||
You can also get Dropbear to create keys when the first connection is made -
|
||||
this is preferable to generating keys when the system boots. Make sure
|
||||
/etc/dropbear/ exists and then pass '-R' to the dropbear server.
|
||||
|
||||
============================================================================
|
||||
|
||||
If the server is run as non-root, you most likely won't be able to allocate a
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len);
|
||||
buffer *data_buf);
|
||||
void cli_setup_agent(struct Channel *channel);
|
||||
|
||||
#ifdef __hpux
|
||||
|
||||
61
algo.h
61
algo.h
@@ -35,7 +35,7 @@
|
||||
|
||||
struct Algo_Type {
|
||||
|
||||
unsigned char *name; /* identifying name */
|
||||
const unsigned char *name; /* identifying name */
|
||||
char val; /* a value for this cipher, or -1 for invalid */
|
||||
const void *data; /* algorithm specific data */
|
||||
char usable; /* whether we can use this algorithm */
|
||||
@@ -51,6 +51,7 @@ extern algo_type sshhostkey[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type ssh_compress[];
|
||||
extern algo_type ssh_delaycompress[];
|
||||
extern algo_type ssh_nocompress[];
|
||||
|
||||
extern const struct dropbear_cipher dropbear_nocipher;
|
||||
@@ -59,8 +60,8 @@ extern const struct dropbear_hash dropbear_nohash;
|
||||
|
||||
struct dropbear_cipher {
|
||||
const struct ltc_cipher_descriptor *cipherdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char blocksize;
|
||||
const unsigned long keysize;
|
||||
const unsigned char blocksize;
|
||||
};
|
||||
|
||||
struct dropbear_cipher_mode {
|
||||
@@ -74,19 +75,52 @@ struct dropbear_cipher_mode {
|
||||
};
|
||||
|
||||
struct dropbear_hash {
|
||||
const struct ltc_hash_descriptor *hashdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char hashsize;
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const unsigned long keysize;
|
||||
/* hashsize may be truncated from the size returned by hash_desc,
|
||||
eg sha1-96 */
|
||||
const unsigned char hashsize;
|
||||
};
|
||||
|
||||
enum dropbear_kex_mode {
|
||||
DROPBEAR_KEX_NORMAL_DH,
|
||||
DROPBEAR_KEX_ECDH,
|
||||
DROPBEAR_KEX_CURVE25519,
|
||||
};
|
||||
|
||||
struct dropbear_kex {
|
||||
enum dropbear_kex_mode mode;
|
||||
|
||||
/* "normal" DH KEX */
|
||||
const unsigned char *dh_p_bytes;
|
||||
const int dh_p_len;
|
||||
|
||||
/* elliptic curve DH KEX */
|
||||
#ifdef DROPBEAR_ECDH
|
||||
const struct dropbear_ecc_curve *ecc_curve;
|
||||
#else
|
||||
const void* dummy;
|
||||
#endif
|
||||
|
||||
/* both */
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
};
|
||||
|
||||
void crypto_init();
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]);
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
|
||||
|
||||
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
enum kexguess2_used {
|
||||
KEXGUESS2_LOOK,
|
||||
KEXGUESS2_NO,
|
||||
KEXGUESS2_YES,
|
||||
};
|
||||
|
||||
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
|
||||
#define KEXGUESS2_ALGO_ID 99
|
||||
|
||||
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess);
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
@@ -94,5 +128,10 @@ int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
char * algolist_string(algo_type algos[]);
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DROPBEAR_COMP_NONE,
|
||||
DROPBEAR_COMP_ZLIB,
|
||||
DROPBEAR_COMP_ZLIB_DELAY,
|
||||
};
|
||||
|
||||
#endif /* _ALGO_H_ */
|
||||
|
||||
5
auth.h
5
auth.h
@@ -36,6 +36,7 @@ void cli_authinitialise();
|
||||
void recv_msg_userauth_request();
|
||||
void send_msg_userauth_failure(int partial, int incrfail);
|
||||
void send_msg_userauth_success();
|
||||
void send_msg_userauth_banner(buffer *msg);
|
||||
void svr_auth_password();
|
||||
void svr_auth_pubkey();
|
||||
void svr_auth_pam();
|
||||
@@ -67,7 +68,7 @@ void recv_msg_userauth_pk_ok();
|
||||
void recv_msg_userauth_info_request();
|
||||
void cli_get_user();
|
||||
void cli_auth_getmethods();
|
||||
void cli_auth_try();
|
||||
int cli_auth_try();
|
||||
void recv_msg_userauth_banner();
|
||||
void cli_pubkeyfail();
|
||||
void cli_auth_password();
|
||||
@@ -105,7 +106,7 @@ struct AuthState {
|
||||
valid */
|
||||
unsigned int failcount; /* Number of (failed) authentication attempts.*/
|
||||
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||
client and server (though has differing [obvious]
|
||||
client and server (though has differing
|
||||
meanings). */
|
||||
unsigned perm_warn : 1; /* Server only, set if bad permissions on
|
||||
~/.ssh/authorized_keys have already been
|
||||
|
||||
25
bignum.c
25
bignum.c
@@ -52,6 +52,22 @@ void m_mp_init_multi(mp_int *mp, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void m_mp_alloc_init_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) {
|
||||
*cur_arg = m_malloc(sizeof(mp_int));
|
||||
if (mp_init(*cur_arg) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
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) {
|
||||
@@ -60,16 +76,13 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
}
|
||||
|
||||
/* hash the ssh representation of the mp_int mp */
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp) {
|
||||
|
||||
int i;
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp) {
|
||||
buffer * buf;
|
||||
|
||||
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
|
||||
plus header + some leeway*/
|
||||
buf_putmpint(buf, mp);
|
||||
i = buf->pos;
|
||||
buf_setpos(buf, 0);
|
||||
sha1_process(hs, buf_getptr(buf, i), i);
|
||||
hash_desc->process(hs, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
7
bignum.h
7
bignum.h
@@ -26,10 +26,13 @@
|
||||
#define _BIGNUM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
void m_mp_init(mp_int *mp);
|
||||
void m_mp_init_multi(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 bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp);
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp);
|
||||
|
||||
#endif /* _BIGNUM_H_ */
|
||||
|
||||
9
buffer.c
9
buffer.c
@@ -269,6 +269,11 @@ void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
|
||||
|
||||
}
|
||||
|
||||
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
|
||||
buf_putstring(buf, buf_str->data, buf_str->len);
|
||||
}
|
||||
|
||||
/* put the set of len bytes into the buffer, incrementing the pos, increasing
|
||||
* len if required */
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
@@ -282,7 +287,7 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
|
||||
unsigned int len, pad = 0;
|
||||
TRACE(("enter buf_putmpint"))
|
||||
TRACE2(("enter buf_putmpint"))
|
||||
|
||||
dropbear_assert(mp != NULL);
|
||||
|
||||
@@ -318,7 +323,7 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
buf_incrwritepos(buf, len-pad);
|
||||
}
|
||||
|
||||
TRACE(("leave buf_putmpint"))
|
||||
TRACE2(("leave buf_putmpint"))
|
||||
}
|
||||
|
||||
/* Retrieve an mp_int from the buffer.
|
||||
|
||||
1
buffer.h
1
buffer.h
@@ -59,6 +59,7 @@ buffer * buf_getstringbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str);
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
|
||||
void buf_putmpint(buffer* buf, mp_int * mp);
|
||||
int buf_getmpint(buffer* buf, mp_int* mp);
|
||||
|
||||
28
channel.h
28
channel.h
@@ -29,14 +29,6 @@
|
||||
#include "buffer.h"
|
||||
#include "circbuffer.h"
|
||||
|
||||
/* channel->type values */
|
||||
#define CHANNEL_ID_NONE 0
|
||||
#define CHANNEL_ID_SESSION 1
|
||||
#define CHANNEL_ID_X11 2
|
||||
#define CHANNEL_ID_AGENT 3
|
||||
#define CHANNEL_ID_TCPDIRECT 4
|
||||
#define CHANNEL_ID_TCPFORWARDED 5
|
||||
|
||||
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH_OPEN_CONNECT_FAILED 2
|
||||
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
|
||||
@@ -49,6 +41,13 @@
|
||||
|
||||
struct ChanType;
|
||||
|
||||
enum dropbear_channel_prio {
|
||||
DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */
|
||||
DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */
|
||||
DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */
|
||||
DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
|
||||
unsigned int index; /* the local channel index */
|
||||
@@ -83,8 +82,12 @@ struct Channel {
|
||||
|
||||
int flushing;
|
||||
|
||||
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
|
||||
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
|
||||
|
||||
const struct ChanType* type;
|
||||
|
||||
enum dropbear_channel_prio prio;
|
||||
};
|
||||
|
||||
struct ChanType {
|
||||
@@ -95,7 +98,6 @@ struct ChanType {
|
||||
int (*check_close)(struct Channel*);
|
||||
void (*reqhandler)(struct Channel*);
|
||||
void (*closehandler)(struct Channel*);
|
||||
|
||||
};
|
||||
|
||||
void chaninitialise(const struct ChanType *chantypes[]);
|
||||
@@ -103,6 +105,9 @@ void chancleanup();
|
||||
void setchannelfds(fd_set *readfd, fd_set *writefd);
|
||||
void channelio(fd_set *readfd, fd_set *writefd);
|
||||
struct Channel* getchannel();
|
||||
/* Returns an arbitrary channel that is in a ready state - not
|
||||
being initialised and no EOF in either direction. NULL if none. */
|
||||
struct Channel* get_any_ready_channel();
|
||||
|
||||
void recv_msg_channel_open();
|
||||
void recv_msg_channel_request();
|
||||
@@ -126,5 +131,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type);
|
||||
void recv_msg_channel_open_confirmation();
|
||||
void recv_msg_channel_open_failure();
|
||||
#endif
|
||||
void start_send_channel_request(struct Channel *channel, unsigned char *type);
|
||||
|
||||
void send_msg_request_success();
|
||||
void send_msg_request_failure();
|
||||
|
||||
|
||||
#endif /* _CHANNEL_H_ */
|
||||
|
||||
@@ -51,9 +51,12 @@ struct ChanSess {
|
||||
/* exit details */
|
||||
struct exitinfo exit;
|
||||
|
||||
/* Used to set $SSH_CONNECTION in the child session.
|
||||
Is only set temporarily before forking */
|
||||
|
||||
/* These are only set temporarily before forking */
|
||||
/* Used to set $SSH_CONNECTION in the child session. */
|
||||
char *connection_string;
|
||||
/* Used to set $SSH_CLIENT in the child session. */
|
||||
char *client_string;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
struct Listener * x11listener;
|
||||
@@ -89,7 +92,6 @@ void cli_chansess_winchange();
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
void cli_send_netcat_request();
|
||||
#endif
|
||||
void cli_start_send_channel_request(struct Channel *channel, unsigned char *type);
|
||||
|
||||
void svr_chansessinitialise();
|
||||
extern const struct ChanType svrchansess;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "channel.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "listener.h"
|
||||
#include "runopts.h"
|
||||
#include "atomicio.h"
|
||||
@@ -73,8 +73,8 @@ static int connect_agent() {
|
||||
return fd;
|
||||
}
|
||||
|
||||
// handle a request for a connection to the locally running ssh-agent
|
||||
// or forward.
|
||||
/* handle a request for a connection to the locally running ssh-agent
|
||||
or forward. */
|
||||
static int new_agent_chan(struct Channel * channel) {
|
||||
|
||||
int fd = -1;
|
||||
@@ -94,7 +94,6 @@ static int new_agent_chan(struct Channel * channel) {
|
||||
channel->readfd = fd;
|
||||
channel->writefd = fd;
|
||||
|
||||
// success
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -156,8 +155,6 @@ static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE(("agent_request readlen is %d", readlen))
|
||||
|
||||
buf_resize(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
|
||||
@@ -167,7 +164,6 @@ static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
}
|
||||
buf_incrwritepos(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
TRACE(("agent_request success, length %d", readlen))
|
||||
|
||||
out:
|
||||
if (payload)
|
||||
@@ -205,7 +201,7 @@ static void agent_get_key_list(m_list * ret_list)
|
||||
num = buf_getint(inbuf);
|
||||
for (i = 0; i < num; i++) {
|
||||
sign_key * pubkey = NULL;
|
||||
int key_type = DROPBEAR_SIGNKEY_ANY;
|
||||
enum signkey_type key_type = DROPBEAR_SIGNKEY_ANY;
|
||||
buffer * key_buf;
|
||||
|
||||
/* each public key is encoded as a string */
|
||||
@@ -214,13 +210,14 @@ static void agent_get_key_list(m_list * ret_list)
|
||||
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
|
||||
buf_free(key_buf);
|
||||
if (ret != DROPBEAR_SUCCESS) {
|
||||
/* This is slack, properly would cleanup vars etc */
|
||||
dropbear_exit("Bad pubkey received from agent");
|
||||
}
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
TRACE(("Skipping bad/unknown type pubkey from agent"));
|
||||
sign_key_free(pubkey);
|
||||
} else {
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
|
||||
list_append(ret_list, pubkey);
|
||||
list_append(ret_list, pubkey);
|
||||
}
|
||||
|
||||
/* We'll ignore the comment for now. might want it later.*/
|
||||
buf_eatstring(inbuf);
|
||||
@@ -238,7 +235,7 @@ void cli_setup_agent(struct Channel *channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
|
||||
start_send_channel_request(channel, "auth-agent-req@openssh.com");
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
encrypt_packet();
|
||||
@@ -257,7 +254,7 @@ void cli_load_agent_keys(m_list *ret_list) {
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
buffer *data_buf) {
|
||||
buffer *request_data = NULL;
|
||||
buffer *response = NULL;
|
||||
unsigned int siglen;
|
||||
@@ -269,10 +266,10 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
string data
|
||||
uint32 flags
|
||||
*/
|
||||
request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
|
||||
request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
|
||||
buf_putstring(request_data, data, len);
|
||||
buf_putbufstring(request_data, data_buf);
|
||||
buf_putint(request_data, 0);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
|
||||
99
cli-algo.c
99
cli-algo.c
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
* SSH client implementation
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* 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 "algo.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
|
||||
/*
|
||||
* The chosen [encryption | MAC | compression] algorithm to each
|
||||
* direction MUST be the first algorithm on the client's list
|
||||
* that is also on the server's list.
|
||||
*/
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess) {
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int count, i, j;
|
||||
algo_type * ret = NULL;
|
||||
|
||||
*goodguess = 0;
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("cli_buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out; /* just a sanity check, no other use */
|
||||
}
|
||||
|
||||
/* remotealgos will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotealgos[0] = algolist;
|
||||
count = 1;
|
||||
/* Iterate through, replacing ','s with NULs, to split it into
|
||||
* words. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotealgos[count] = &algolist[i+1];
|
||||
count++;
|
||||
}
|
||||
if (count >= MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
|
||||
for (j = 0; localalgos[j].name != NULL; j++) {
|
||||
if (localalgos[j].usable) {
|
||||
len = strlen(localalgos[j].name);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (len == strlen(remotealgos[i])
|
||||
&& strncmp(localalgos[j].name,
|
||||
remotealgos[i], len) == 0) {
|
||||
if (i == 0 && j == 0) {
|
||||
/* was a good guess */
|
||||
*goodguess = 1;
|
||||
}
|
||||
ret = &localalgos[j];
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
117
cli-auth.c
117
cli-auth.c
@@ -40,11 +40,8 @@ void cli_authinitialise() {
|
||||
|
||||
/* Send a "none" auth request to get available methods */
|
||||
void cli_auth_getmethods() {
|
||||
|
||||
TRACE(("enter cli_auth_getmethods"))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
@@ -53,8 +50,27 @@ void cli_auth_getmethods() {
|
||||
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave cli_auth_getmethods"))
|
||||
|
||||
#ifdef 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.
|
||||
Race described at
|
||||
http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/zlib-openssh.html
|
||||
*/
|
||||
if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
|
||||
if (getenv(DROPBEAR_PASSWORD_ENV)) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
|
||||
}
|
||||
if (cli_auth_try() == DROPBEAR_SUCCESS) {
|
||||
TRACE(("skipped initial none auth query"))
|
||||
/* Note that there will be two auth responses in-flight */
|
||||
cli_ses.ignore_next_auth_response = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
TRACE(("leave cli_auth_getmethods"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_banner() {
|
||||
@@ -144,31 +160,46 @@ void recv_msg_userauth_failure() {
|
||||
TRACE(("<- MSG_USERAUTH_FAILURE"))
|
||||
TRACE(("enter recv_msg_userauth_failure"))
|
||||
|
||||
if (ses.authstate.authdone) {
|
||||
TRACE(("leave recv_msg_userauth_failure, already authdone."))
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli_ses.state != USERAUTH_REQ_SENT) {
|
||||
/* Perhaps we should be more fatal? */
|
||||
dropbear_exit("Unexpected userauth failure");
|
||||
}
|
||||
|
||||
/* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for
|
||||
the "none" auth request, and then a response to the immediate auth request.
|
||||
We need to be careful handling them. */
|
||||
if (cli_ses.ignore_next_auth_response) {
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
cli_ses.ignore_next_auth_response = 0;
|
||||
TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT"));
|
||||
return;
|
||||
} else {
|
||||
#ifdef ENABLE_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) {
|
||||
cli_pubkeyfail();
|
||||
}
|
||||
/* If it was a pubkey auth request, we should cross that key
|
||||
* off the list. */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
cli_pubkeyfail();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_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 */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
|
||||
&& !cli_ses.interact_request_received) {
|
||||
TRACE(("setting auth_interact_failed = 1"))
|
||||
cli_ses.auth_interact_failed = 1;
|
||||
}
|
||||
/* If we get a failure message for keyboard interactive without
|
||||
* receiving any request info packet, then we don't bother trying
|
||||
* keyboard interactive again */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
|
||||
&& !cli_ses.interact_request_received) {
|
||||
TRACE(("setting auth_interact_failed = 1"))
|
||||
cli_ses.auth_interact_failed = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
cli_ses.state = USERAUTH_FAIL_RCVD;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
}
|
||||
|
||||
methods = buf_getstring(ses.payload, &methlen);
|
||||
|
||||
@@ -221,13 +252,14 @@ void recv_msg_userauth_failure() {
|
||||
}
|
||||
|
||||
m_free(methods);
|
||||
|
||||
cli_ses.state = USERAUTH_FAIL_RCVD;
|
||||
|
||||
TRACE(("leave recv_msg_userauth_failure"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_success() {
|
||||
/* This function can validly get called multiple times
|
||||
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
|
||||
|
||||
TRACE(("received msg_userauth_success"))
|
||||
/* Note: in delayed-zlib mode, setting authdone here
|
||||
* will enable compression in the transport layer */
|
||||
@@ -240,7 +272,7 @@ void recv_msg_userauth_success() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void cli_auth_try() {
|
||||
int cli_auth_try() {
|
||||
|
||||
int finished = 0;
|
||||
TRACE(("enter cli_auth_try"))
|
||||
@@ -256,37 +288,40 @@ void cli_auth_try() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
|
||||
} else if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
|
||||
if (cli_ses.auth_interact_failed) {
|
||||
finished = 0;
|
||||
#ifdef ENABLE_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");
|
||||
} else {
|
||||
cli_auth_interactive();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
|
||||
cli_auth_password();
|
||||
finished = 1;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
|
||||
} else if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
cli_auth_password();
|
||||
finished = 1;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
||||
#ifdef ENABLE_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");
|
||||
} else {
|
||||
if (!cli_ses.auth_interact_failed) {
|
||||
cli_auth_interactive();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
|
||||
finished = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
|
||||
|
||||
if (!finished) {
|
||||
dropbear_exit("No auth methods could be used.");
|
||||
if (finished) {
|
||||
TRACE(("leave cli_auth_try success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
TRACE(("leave cli_auth_try"))
|
||||
TRACE(("leave cli_auth_try failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* A helper for getpass() that exits if the user cancels. The returned
|
||||
|
||||
@@ -121,23 +121,19 @@ void recv_msg_userauth_pk_ok() {
|
||||
}
|
||||
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len)
|
||||
{
|
||||
buffer *data_buf) {
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
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, len);
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
||||
agent_buf_sign(sigblob, key, data_buf);
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
} else
|
||||
#endif /* ENABLE_CLI_AGENTFWD */
|
||||
{
|
||||
buf_put_sign(buf, key, type, data, len);
|
||||
buf_put_sign(buf, key, type, data_buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,10 +169,10 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
TRACE(("realsign"))
|
||||
/* We put the signature as well - this contains string(session id), then
|
||||
* the contents of the write payload to this point */
|
||||
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
|
||||
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
|
||||
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->data, sigbuf->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,10 @@
|
||||
static void cli_closechansess(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 int cli_init_netcat(struct Channel *channel);
|
||||
|
||||
static void cli_tty_setup();
|
||||
|
||||
@@ -70,7 +71,9 @@ static void cli_chansessreq(struct Channel *channel) {
|
||||
TRACE(("got exit-signal, ignoring it"))
|
||||
} else {
|
||||
TRACE(("unknown request '%s'", type))
|
||||
send_msg_channel_failure(channel);
|
||||
if (wantreply) {
|
||||
send_msg_channel_failure(channel);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -81,25 +84,12 @@ out:
|
||||
|
||||
/* If the main session goes, we close it up */
|
||||
static void cli_closechansess(struct Channel *UNUSED(channel)) {
|
||||
cli_tty_cleanup(); /* Restore tty modes etc */
|
||||
|
||||
/* This channel hasn't gone yet, so we have > 1 */
|
||||
if (ses.chancount > 1) {
|
||||
dropbear_log(LOG_INFO, "Waiting for other channels to close...");
|
||||
}
|
||||
|
||||
cli_tty_cleanup(); /* Restore tty modes etc */
|
||||
|
||||
}
|
||||
|
||||
void cli_start_send_channel_request(struct Channel *channel,
|
||||
unsigned char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
buf_putint(ses.writepayload, channel->remotechan);
|
||||
|
||||
buf_putstring(ses.writepayload, type, strlen(type));
|
||||
|
||||
}
|
||||
|
||||
/* Taken from OpenSSH's sshtty.c:
|
||||
@@ -286,7 +276,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_chansess_pty_req"))
|
||||
|
||||
cli_start_send_channel_request(channel, "pty-req");
|
||||
start_send_channel_request(channel, "pty-req");
|
||||
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
@@ -329,7 +319,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
|
||||
reqtype = "shell";
|
||||
}
|
||||
|
||||
cli_start_send_channel_request(channel, reqtype);
|
||||
start_send_channel_request(channel, reqtype);
|
||||
|
||||
/* XXX TODO */
|
||||
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
|
||||
@@ -356,6 +346,11 @@ static int cli_init_stdpipe_sess(struct Channel *channel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cli_init_netcat(struct Channel *channel) {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
return cli_init_stdpipe_sess(channel);
|
||||
}
|
||||
|
||||
static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
cli_init_stdpipe_sess(channel);
|
||||
@@ -368,13 +363,18 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
send_chansess_pty_req(channel);
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
|
||||
} else {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
|
||||
}
|
||||
|
||||
send_chansess_shell_req(channel);
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
cli_tty_setup();
|
||||
}
|
||||
channel->read_mangler = cli_escape_handler;
|
||||
cli_ses.last_char = '\r';
|
||||
}
|
||||
|
||||
return 0; /* Success */
|
||||
}
|
||||
@@ -384,7 +384,7 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
static const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
"direct-tcpip",
|
||||
cli_init_stdpipe_sess, /* inithandler */
|
||||
cli_init_netcat, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
@@ -395,6 +395,7 @@ void cli_send_netcat_request() {
|
||||
const unsigned char* source_host = "127.0.0.1";
|
||||
const int source_port = 22;
|
||||
|
||||
TRACE(("enter cli_send_netcat_request"))
|
||||
cli_opts.wantpty = 0;
|
||||
|
||||
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
|
||||
@@ -411,7 +412,7 @@ void cli_send_netcat_request() {
|
||||
buf_putint(ses.writepayload, source_port);
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave cli_send_chansess_request"))
|
||||
TRACE(("leave cli_send_netcat_request"))
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -429,3 +430,59 @@ void cli_send_chansess_request() {
|
||||
TRACE(("leave cli_send_chansess_request"))
|
||||
|
||||
}
|
||||
|
||||
/* returns 1 if the character should be consumed, 0 to pass through */
|
||||
static int
|
||||
do_escape(unsigned char c) {
|
||||
switch (c) {
|
||||
case '.':
|
||||
dropbear_exit("Terminated");
|
||||
return 1;
|
||||
break;
|
||||
case 0x1a:
|
||||
/* ctrl-z */
|
||||
cli_tty_cleanup();
|
||||
kill(getpid(), SIGTSTP);
|
||||
/* after continuation */
|
||||
cli_tty_setup();
|
||||
cli_ses.winchange = 1;
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) {
|
||||
char c;
|
||||
int skip_char = 0;
|
||||
|
||||
/* only handle escape characters if they are read one at a time. simplifies
|
||||
the code and avoids nasty people putting ~. at the start of a line to paste */
|
||||
if (*len != 1) {
|
||||
cli_ses.last_char = 0x0;
|
||||
return;
|
||||
}
|
||||
|
||||
c = buf[0];
|
||||
|
||||
if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) {
|
||||
skip_char = do_escape(c);
|
||||
cli_ses.last_char = 0x0;
|
||||
} else {
|
||||
if (c == DROPBEAR_ESCAPE_CHAR) {
|
||||
if (cli_ses.last_char == '\r') {
|
||||
cli_ses.last_char = DROPBEAR_ESCAPE_CHAR;
|
||||
skip_char = 1;
|
||||
} else {
|
||||
cli_ses.last_char = 0x0;
|
||||
}
|
||||
} else {
|
||||
cli_ses.last_char = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_char) {
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
139
cli-kex.c
139
cli-kex.c
@@ -33,44 +33,73 @@
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "runopts.h"
|
||||
#include "signkey.h"
|
||||
#include "ecc.h"
|
||||
|
||||
|
||||
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
|
||||
#define MAX_KNOWNHOSTS_LINE 4500
|
||||
|
||||
void send_msg_kexdh_init() {
|
||||
|
||||
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
|
||||
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
|
||||
TRACE(("send_msg_kexdh_init()"))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
|
||||
buf_putmpint(ses.writepayload, cli_ses.dh_e);
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.dh_param) {
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
}
|
||||
cli_ses.dh_param = gen_kexdh_param();
|
||||
}
|
||||
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
|
||||
break;
|
||||
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) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
}
|
||||
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
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.curve25519_param) {
|
||||
if (cli_ses.curve25519_param) {
|
||||
free_kexcurve25519_param(cli_ses.curve25519_param);
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
|
||||
encrypt_packet();
|
||||
ses.requirenext = SSH_MSG_KEXDH_REPLY;
|
||||
}
|
||||
|
||||
/* Handle a diffie-hellman key exchange reply. */
|
||||
void recv_msg_kexdh_reply() {
|
||||
|
||||
DEF_MP_INT(dh_f);
|
||||
sign_key *hostkey = NULL;
|
||||
unsigned int type, keybloblen;
|
||||
unsigned char* keyblob = NULL;
|
||||
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_reply"))
|
||||
|
||||
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
|
||||
dropbear_exit("Received out-of-order kexdhreply");
|
||||
}
|
||||
m_mp_init(&dh_f);
|
||||
type = ses.newkeys->algo_hostkey;
|
||||
TRACE(("type is %d", type))
|
||||
|
||||
@@ -88,19 +117,59 @@ void recv_msg_kexdh_reply() {
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
{
|
||||
DEF_MP_INT(dh_f);
|
||||
m_mp_init(&dh_f);
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
}
|
||||
break;
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
m_free(cli_ses.dh_e);
|
||||
m_free(cli_ses.dh_x);
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
cli_ses.dh_param = NULL;
|
||||
}
|
||||
#ifdef DROPBEAR_ECDH
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
cli_ses.ecdh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
if (cli_ses.curve25519_param) {
|
||||
free_kexcurve25519_param(cli_ses.curve25519_param);
|
||||
cli_ses.curve25519_param = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
cli_ses.param_kex_algo = NULL;
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad hostkey signature");
|
||||
}
|
||||
|
||||
@@ -112,7 +181,8 @@ 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(unsigned char* keyblob, unsigned int keybloblen,
|
||||
const char* algoname) {
|
||||
|
||||
char* fp = NULL;
|
||||
FILE *tty = NULL;
|
||||
@@ -120,14 +190,16 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
fp = sign_key_fingerprint(keyblob, keybloblen);
|
||||
if (cli_opts.always_accept_key) {
|
||||
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(fingerprint %s)\n",
|
||||
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
|
||||
cli_opts.remotehost,
|
||||
algoname,
|
||||
fp);
|
||||
m_free(fp);
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n) ",
|
||||
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ",
|
||||
cli_opts.remotehost,
|
||||
algoname,
|
||||
fp);
|
||||
m_free(fp);
|
||||
|
||||
@@ -217,16 +289,22 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
buffer * line = NULL;
|
||||
int ret;
|
||||
|
||||
if (cli_opts.no_hostkey_check) {
|
||||
fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
|
||||
return;
|
||||
}
|
||||
|
||||
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
|
||||
|
||||
hostsfile = open_known_hosts_file(&readonly);
|
||||
if (!hostsfile) {
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
ask_to_confirm(keyblob, keybloblen, algoname);
|
||||
/* ask_to_confirm will exit upon failure */
|
||||
return;
|
||||
}
|
||||
|
||||
line = buf_new(MAX_KNOWNHOSTS_LINE);
|
||||
hostlen = strlen(cli_opts.remotehost);
|
||||
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
|
||||
|
||||
do {
|
||||
if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
|
||||
@@ -246,7 +324,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
/* Compare hostnames */
|
||||
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
|
||||
hostlen) != 0) {
|
||||
TRACE(("hosts don't match"))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -280,17 +357,18 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
/* The keys didn't match. eep. Note that we're "leaking"
|
||||
the fingerprint strings here, but we're exiting anyway */
|
||||
dropbear_exit("\n\nHost key mismatch for %s !\n"
|
||||
dropbear_exit("\n\n%s host key mismatch for %s !\n"
|
||||
"Fingerprint is %s\n"
|
||||
"Expected %s\n"
|
||||
"If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts",
|
||||
algoname,
|
||||
cli_opts.remotehost,
|
||||
sign_key_fingerprint(keyblob, keybloblen),
|
||||
fingerprint ? fingerprint : "UNKNOWN");
|
||||
} while (1); /* keep going 'til something happens */
|
||||
|
||||
/* Key doesn't exist yet */
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
ask_to_confirm(keyblob, keybloblen, algoname);
|
||||
|
||||
/* If we get here, they said yes */
|
||||
|
||||
@@ -309,7 +387,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
buf_putbytes(line, algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
len = line->size - line->pos;
|
||||
TRACE(("keybloblen %d, len %d", keybloblen, len))
|
||||
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
|
||||
* will die horribly in the case anyway */
|
||||
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
|
||||
|
||||
15
cli-main.c
15
cli-main.c
@@ -28,6 +28,8 @@
|
||||
#include "dbutil.h"
|
||||
#include "runopts.h"
|
||||
#include "session.h"
|
||||
#include "dbrandom.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
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);
|
||||
@@ -51,6 +53,9 @@ int main(int argc, char ** argv) {
|
||||
|
||||
disallow_core();
|
||||
|
||||
seedrandom();
|
||||
crypto_init();
|
||||
|
||||
cli_getopts(argc, argv);
|
||||
|
||||
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
|
||||
@@ -98,11 +103,11 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
}
|
||||
|
||||
/* Do the cleanup first, since then the terminal will be reset */
|
||||
cli_session_cleanup();
|
||||
common_session_cleanup();
|
||||
session_cleanup();
|
||||
/* Avoid printing onwards from terminal cruft */
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
@@ -114,7 +119,7 @@ static void cli_dropbear_log(int UNUSED(priority),
|
||||
vsnprintf(printbuf, sizeof(printbuf), format, param);
|
||||
|
||||
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
|
||||
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
static void exec_proxy_cmd(void *user_data_cmd) {
|
||||
@@ -139,4 +144,4 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
|
||||
*sock_in = *sock_out = -1;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_CLI_PROXYCMD
|
||||
#endif /* ENABLE_CLI_PROXYCMD */
|
||||
|
||||
@@ -38,7 +38,7 @@ static void parse_hostname(const char* orighostarg);
|
||||
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
|
||||
static void fill_own_user();
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename);
|
||||
static void loadidentityfile(const char* filename, int warnfail);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
static void addforward(const char* str, m_list *fwdlist);
|
||||
@@ -62,9 +62,10 @@ static void printhelp() {
|
||||
"-N Don't run a remote command\n"
|
||||
"-f Run in background after auth\n"
|
||||
"-y Always accept remote host key if unknown\n"
|
||||
"-y -y Don't perform any remote host key checking (caution)\n"
|
||||
"-s Request a subsystem (use by external sftp)\n"
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
"-i <identityfile> (multiple allowed)\n"
|
||||
"-i <identityfile> (multiple allowed, default %s)\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
"-A Enable agent auth forwarding\n"
|
||||
@@ -89,10 +90,14 @@ static void printhelp() {
|
||||
"-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
|
||||
"-V Version\n"
|
||||
#ifdef DEBUG_TRACE
|
||||
"-v verbose (compiled with DEBUG_TRACE)\n"
|
||||
#endif
|
||||
,DROPBEAR_VERSION, cli_opts.progname,
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
DROPBEAR_DEFAULT_CLI_AUTHKEY,
|
||||
#endif
|
||||
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
|
||||
|
||||
}
|
||||
@@ -130,6 +135,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.backgrounded = 0;
|
||||
cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
|
||||
cli_opts.always_accept_key = 0;
|
||||
cli_opts.no_hostkey_check = 0;
|
||||
cli_opts.is_subsystem = 0;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
cli_opts.privkeys = list_new();
|
||||
@@ -150,7 +156,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.proxycmd = NULL;
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
opts.compress_mode = DROPBEAR_COMPRESS_ON;
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
opts.cipher_list = NULL;
|
||||
@@ -161,6 +167,8 @@ void cli_getopts(int argc, char ** argv) {
|
||||
opts.ipv6 = 1;
|
||||
*/
|
||||
opts.recv_window = DEFAULT_RECV_WINDOW;
|
||||
opts.keepalive_secs = DEFAULT_KEEPALIVE;
|
||||
opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
|
||||
|
||||
fill_own_user();
|
||||
|
||||
@@ -169,7 +177,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
if (nextiskey) {
|
||||
/* Load a hostkey since the previous argument was "-i" */
|
||||
loadidentityfile(argv[i]);
|
||||
loadidentityfile(argv[i], 1);
|
||||
nextiskey = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -213,6 +221,10 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
switch (argv[i][1]) {
|
||||
case 'y': /* always accept the remote hostkey */
|
||||
if (cli_opts.always_accept_key) {
|
||||
/* twice means no checking at all */
|
||||
cli_opts.no_hostkey_check = 1;
|
||||
}
|
||||
cli_opts.always_accept_key = 1;
|
||||
break;
|
||||
case 'p': /* remoteport */
|
||||
@@ -222,7 +234,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
case 'i': /* an identityfile */
|
||||
/* Keep scp happy when it changes "-i file" to "-ifile" */
|
||||
if (strlen(argv[i]) > 2) {
|
||||
loadidentityfile(&argv[i][2]);
|
||||
loadidentityfile(&argv[i][2], 1);
|
||||
} else {
|
||||
nextiskey = 1;
|
||||
}
|
||||
@@ -316,6 +328,10 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifndef ENABLE_CLI_LOCALTCPFWD
|
||||
case 'L':
|
||||
#endif
|
||||
case 'V':
|
||||
print_version();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'o':
|
||||
case 'b':
|
||||
next = &dummy;
|
||||
@@ -377,6 +393,13 @@ void cli_getopts(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
/* To match the common path of m_freeing it */
|
||||
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.remoteport == NULL) {
|
||||
cli_opts.remoteport = "22";
|
||||
}
|
||||
@@ -424,6 +447,14 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_DEFAULT_CLI_AUTHKEY
|
||||
{
|
||||
char *expand_path = expand_tilde(DROPBEAR_DEFAULT_CLI_AUTHKEY);
|
||||
loadidentityfile(expand_path, 0);
|
||||
m_free(expand_path);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The hostname gets set up last, since
|
||||
* in multi-hop mode it will require knowledge
|
||||
* of other flags such as -i */
|
||||
@@ -435,14 +466,18 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename) {
|
||||
static void loadidentityfile(const char* filename, int warnfail) {
|
||||
sign_key *key;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
|
||||
TRACE(("loadidentityfile %s", filename))
|
||||
|
||||
key = new_sign_key();
|
||||
keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
if (warnfail) {
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
}
|
||||
sign_key_free(key);
|
||||
} else {
|
||||
key->type = keytype;
|
||||
@@ -461,20 +496,31 @@ multihop_passthrough_args() {
|
||||
int total;
|
||||
unsigned int len = 0;
|
||||
m_list_elem *iter;
|
||||
/* Fill out -i and -W options that make sense for all
|
||||
/* Fill out -i, -y, -W options that make sense for all
|
||||
* the intermediate processes */
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
len += 3 + strlen(key->filename);
|
||||
}
|
||||
len += 20; // space for -W <size>, terminator.
|
||||
len += 30; /* space for -W <size>, terminator. */
|
||||
ret = m_malloc(len);
|
||||
total = 0;
|
||||
|
||||
if (cli_opts.no_hostkey_check)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-y -y ");
|
||||
total += written;
|
||||
}
|
||||
else if (cli_opts.always_accept_key)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-y ");
|
||||
total += written;
|
||||
}
|
||||
|
||||
if (opts.recv_window != DEFAULT_RECV_WINDOW)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
|
||||
int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
|
||||
total += written;
|
||||
}
|
||||
|
||||
@@ -482,11 +528,17 @@ multihop_passthrough_args() {
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
const size_t size = len - total;
|
||||
int written = snprintf(ret+total, size, "-i %s", key->filename);
|
||||
int written = snprintf(ret+total, size, "-i %s ", key->filename);
|
||||
dropbear_assert((unsigned int)written < size);
|
||||
total += written;
|
||||
}
|
||||
|
||||
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
|
||||
if (total > 0)
|
||||
{
|
||||
total--;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -557,7 +609,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
passthrough_args, remainder);
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* The stream will be incompressible since it's encrypted. */
|
||||
opts.enable_compress = 0;
|
||||
opts.compress_mode = DROPBEAR_COMPRESS_OFF;
|
||||
#endif
|
||||
m_free(passthrough_args);
|
||||
}
|
||||
@@ -587,7 +639,11 @@ static void parse_hostname(const char* orighostarg) {
|
||||
cli_opts.username = m_strdup(cli_opts.own_user);
|
||||
}
|
||||
|
||||
port = strchr(cli_opts.remotehost, '/');
|
||||
port = strchr(cli_opts.remotehost, '^');
|
||||
if (!port) {
|
||||
/* legacy separator */
|
||||
port = strchr(cli_opts.remotehost, '/');
|
||||
}
|
||||
if (port) {
|
||||
*port = '\0';
|
||||
cli_opts.remoteport = port+1;
|
||||
@@ -642,11 +698,13 @@ static void fill_own_user() {
|
||||
uid = getuid();
|
||||
|
||||
pw = getpwuid(uid);
|
||||
if (pw == NULL || pw->pw_name == NULL) {
|
||||
dropbear_exit("Unknown own user");
|
||||
if (pw && pw->pw_name != NULL) {
|
||||
cli_opts.own_user = m_strdup(pw->pw_name);
|
||||
} else {
|
||||
dropbear_log(LOG_INFO, "Warning: failed to identify current user. Trying anyway.");
|
||||
cli_opts.own_user = m_strdup("unknown");
|
||||
}
|
||||
|
||||
cli_opts.own_user = m_strdup(pw->pw_name);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* 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 "service.h"
|
||||
#include "dbutil.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
|
||||
void send_msg_service_request(char* servicename) {
|
||||
|
||||
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
|
||||
buf_putstring(ses.writepayload, servicename, strlen(servicename));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_service_request"))
|
||||
}
|
||||
|
||||
/* This just sets up the state variables right for the main client session loop
|
||||
* to deal with */
|
||||
void recv_msg_service_accept() {
|
||||
|
||||
unsigned char* servicename;
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter recv_msg_service_accept"))
|
||||
|
||||
servicename = buf_getstring(ses.payload, &len);
|
||||
|
||||
/* ssh-userauth */
|
||||
if (cli_ses.state == SERVICE_AUTH_REQ_SENT
|
||||
&& len == SSH_SERVICE_USERAUTH_LEN
|
||||
&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
|
||||
|
||||
cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
|
||||
m_free(servicename);
|
||||
TRACE(("leave recv_msg_service_accept: done ssh-userauth"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* ssh-connection */
|
||||
if (cli_ses.state == SERVICE_CONN_REQ_SENT
|
||||
&& len == SSH_SERVICE_CONNECTION_LEN
|
||||
&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
|
||||
|
||||
if (ses.authstate.authdone != 1) {
|
||||
dropbear_exit("Request for connection before auth");
|
||||
}
|
||||
|
||||
cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
|
||||
m_free(servicename);
|
||||
TRACE(("leave recv_msg_service_accept: done ssh-connection"))
|
||||
return;
|
||||
}
|
||||
|
||||
dropbear_exit("Unrecognised service accept");
|
||||
}
|
||||
117
cli-session.c
117
cli-session.c
@@ -31,16 +31,20 @@
|
||||
#include "packet.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "channel.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "service.h"
|
||||
#include "runopts.h"
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static void cli_remoteclosed();
|
||||
static void cli_sessionloop();
|
||||
static void cli_session_init();
|
||||
static void cli_finished();
|
||||
static void recv_msg_service_accept(void);
|
||||
static void cli_session_cleanup(void);
|
||||
static void recv_msg_global_request_cli(void);
|
||||
|
||||
struct clientsession cli_ses; /* GLOBAL */
|
||||
|
||||
@@ -65,9 +69,16 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
|
||||
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
|
||||
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
|
||||
{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
|
||||
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
|
||||
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
|
||||
#else
|
||||
/* For keepalive */
|
||||
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
|
||||
#endif
|
||||
{0, 0} /* End */
|
||||
};
|
||||
@@ -84,10 +95,6 @@ static const struct ChanType *cli_chantypes[] = {
|
||||
|
||||
void cli_session(int sock_in, int sock_out) {
|
||||
|
||||
seedrandom();
|
||||
|
||||
crypto_init();
|
||||
|
||||
common_session_init(sock_in, sock_out);
|
||||
|
||||
chaninitialise(cli_chantypes);
|
||||
@@ -99,7 +106,7 @@ void cli_session(int sock_in, int sock_out) {
|
||||
sessinitdone = 1;
|
||||
|
||||
/* Exchange identification */
|
||||
session_identification();
|
||||
send_session_identification();
|
||||
|
||||
send_msg_kexinit();
|
||||
|
||||
@@ -109,6 +116,12 @@ void cli_session(int sock_in, int sock_out) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_KEX_FIRST_FOLLOWS
|
||||
static void cli_send_kex_first_guess() {
|
||||
send_msg_kexdh_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cli_session_init() {
|
||||
|
||||
cli_ses.state = STATE_NOTHING;
|
||||
@@ -142,37 +155,61 @@ static void cli_session_init() {
|
||||
|
||||
/* For printing "remote host closed" for the user */
|
||||
ses.remoteclosed = cli_remoteclosed;
|
||||
ses.buf_match_algo = cli_buf_match_algo;
|
||||
|
||||
ses.extra_session_cleanup = cli_session_cleanup;
|
||||
|
||||
/* packet handlers */
|
||||
ses.packettypes = cli_packettypes;
|
||||
|
||||
ses.isserver = 0;
|
||||
|
||||
#ifdef USE_KEX_FIRST_FOLLOWS
|
||||
ses.send_kex_first_guess = cli_send_kex_first_guess;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void send_msg_service_request(char* servicename) {
|
||||
|
||||
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
|
||||
buf_putstring(ses.writepayload, servicename, strlen(servicename));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_service_request"))
|
||||
}
|
||||
|
||||
static void recv_msg_service_accept(void) {
|
||||
/* do nothing, if it failed then the server MUST have disconnected */
|
||||
}
|
||||
|
||||
/* This function drives the progress of the session - it initiates KEX,
|
||||
* service, userauth and channel requests */
|
||||
static void cli_sessionloop() {
|
||||
|
||||
TRACE(("enter cli_sessionloop"))
|
||||
TRACE2(("enter cli_sessionloop"))
|
||||
|
||||
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
|
||||
cli_ses.kex_state = KEXINIT_RCVD;
|
||||
if (ses.lastpacket == 0) {
|
||||
TRACE2(("exit cli_sessionloop: no real packets yet"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli_ses.kex_state == KEXINIT_RCVD) {
|
||||
|
||||
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
|
||||
/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
|
||||
* negotiation would have failed. */
|
||||
send_msg_kexdh_init();
|
||||
cli_ses.kex_state = KEXDH_INIT_SENT;
|
||||
if (!ses.kexstate.our_first_follows_matches) {
|
||||
send_msg_kexdh_init();
|
||||
}
|
||||
cli_ses.kex_state = KEXDH_INIT_SENT;
|
||||
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* A KEX has finished, so we should go back to our KEX_NOTHING state */
|
||||
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
|
||||
&& ses.kexstate.sentkexinit == 0) {
|
||||
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) {
|
||||
cli_ses.kex_state = KEX_NOTHING;
|
||||
}
|
||||
|
||||
@@ -182,10 +219,10 @@ static void cli_sessionloop() {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We should exit if we haven't donefirstkex: we shouldn't reach here
|
||||
* in normal operation */
|
||||
if (ses.kexstate.donefirstkex == 0) {
|
||||
TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"))
|
||||
/* We might reach here if we have partial packet reads or have
|
||||
* received SSG_MSG_IGNORE etc. Just skip it */
|
||||
TRACE2(("donefirstkex false\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,19 +232,19 @@ static void cli_sessionloop() {
|
||||
/* We've got the transport layer sorted, we now need to request
|
||||
* userauth */
|
||||
send_msg_service_request(SSH_SERVICE_USERAUTH);
|
||||
cli_ses.state = SERVICE_AUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent userauth service req"))
|
||||
return;
|
||||
|
||||
/* userauth code */
|
||||
case SERVICE_AUTH_ACCEPT_RCVD:
|
||||
cli_auth_getmethods();
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent userauth methods req"))
|
||||
return;
|
||||
|
||||
case USERAUTH_REQ_SENT:
|
||||
TRACE(("leave cli_sessionloop: waiting, req_sent"))
|
||||
return;
|
||||
|
||||
case USERAUTH_FAIL_RCVD:
|
||||
cli_auth_try();
|
||||
if (cli_auth_try() == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("No auth methods could be used.");
|
||||
}
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: cli_auth_try"))
|
||||
return;
|
||||
@@ -238,13 +275,6 @@ static void cli_sessionloop() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
setup_localtcp();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
setup_remotetcp();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
if (cli_opts.netcat_host) {
|
||||
cli_send_netcat_request();
|
||||
@@ -253,6 +283,14 @@ static void cli_sessionloop() {
|
||||
if (!cli_opts.no_cmd) {
|
||||
cli_send_chansess_request();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
setup_localtcp();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
setup_remotetcp();
|
||||
#endif
|
||||
|
||||
TRACE(("leave cli_sessionloop: running"))
|
||||
cli_ses.state = SESSION_RUNNING;
|
||||
return;
|
||||
@@ -274,11 +312,11 @@ static void cli_sessionloop() {
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE(("leave cli_sessionloop: fell out"))
|
||||
TRACE2(("leave cli_sessionloop: fell out"))
|
||||
|
||||
}
|
||||
|
||||
void cli_session_cleanup() {
|
||||
static void cli_session_cleanup(void) {
|
||||
|
||||
if (!sessinitdone) {
|
||||
return;
|
||||
@@ -296,8 +334,7 @@ void cli_session_cleanup() {
|
||||
|
||||
static void cli_finished() {
|
||||
|
||||
cli_session_cleanup();
|
||||
common_session_cleanup();
|
||||
session_cleanup();
|
||||
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
||||
cli_opts.remotehost, cli_opts.remoteport);
|
||||
exit(cli_ses.retval);
|
||||
@@ -337,3 +374,9 @@ void cleantext(unsigned char* dirtytext) {
|
||||
/* Null terminate */
|
||||
dirtytext[j] = '\0';
|
||||
}
|
||||
|
||||
static void recv_msg_global_request_cli(void) {
|
||||
TRACE(("recv_msg_global_request_cli"))
|
||||
/* Send a proper rejection */
|
||||
send_msg_request_failure();
|
||||
}
|
||||
|
||||
32
cli-tcpfwd.c
32
cli-tcpfwd.c
@@ -52,7 +52,7 @@ static int cli_localtcp(const char* listenaddr,
|
||||
static const struct ChanType cli_chan_tcplocal = {
|
||||
1, /* sepfds */
|
||||
"direct-tcpip",
|
||||
NULL,
|
||||
tcp_prio_inithandler,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
@@ -161,9 +161,10 @@ void cli_recv_msg_request_success() {
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
if (fwd->listenport == 0) {
|
||||
/* The server should let us know which port was allocated if we requestd port 0 */
|
||||
/* The server should let us know which port was allocated if we requested port 0 */
|
||||
int allocport = buf_getint(ses.payload);
|
||||
if (allocport > 0) {
|
||||
fwd->listenport = allocport;
|
||||
dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d",
|
||||
allocport, fwd->connectaddr, fwd->connectport);
|
||||
}
|
||||
@@ -193,8 +194,8 @@ void setup_remotetcp() {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->listenaddr)
|
||||
{
|
||||
// we store the addresses so that we can compare them
|
||||
// when the server sends them back
|
||||
/* we store the addresses so that we can compare them
|
||||
when the server sends them back */
|
||||
if (opts.listen_fwd_all) {
|
||||
fwd->listenaddr = m_strdup("");
|
||||
} else {
|
||||
@@ -220,18 +221,33 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
origaddr = buf_getstring(ses.payload, NULL);
|
||||
origport = buf_getint(ses.payload);
|
||||
|
||||
/* Find which port corresponds */
|
||||
/* Find which port corresponds. First try and match address as well as port,
|
||||
in case they want to forward different ports separately ... */
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport
|
||||
&& (strcmp(origaddr, fwd->listenaddr) == 0)) {
|
||||
&& strcmp(origaddr, fwd->listenaddr) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iter)
|
||||
{
|
||||
/* ... otherwise try to generically match the only forwarded port
|
||||
without address (also handles ::1 vs 127.0.0.1 vs localhost case).
|
||||
rfc4254 is vague about the definition of "address that was connected" */
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (iter == NULL) {
|
||||
/* We didn't request forwarding on that port */
|
||||
cleantext(origaddr);
|
||||
cleantext(origaddr);
|
||||
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
|
||||
origaddr, origport);
|
||||
goto out;
|
||||
@@ -251,6 +267,8 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
* progress succeeds */
|
||||
channel->writefd = sock;
|
||||
channel->initconn = 1;
|
||||
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
|
||||
err = SSH_OPEN_IN_PROGRESS;
|
||||
|
||||
|
||||
266
common-algo.c
266
common-algo.c
@@ -23,23 +23,28 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "kex.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.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*/
|
||||
|
||||
static int void_cipher(const unsigned char* in, unsigned char* out,
|
||||
unsigned long len, void *cipher_state) {
|
||||
unsigned long len, void* UNUSED(cipher_state)) {
|
||||
if (in != out) {
|
||||
memmove(out, in, len);
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int void_start(int cipher, const unsigned char *IV,
|
||||
const unsigned char *key,
|
||||
int keylen, int num_rounds, void *cipher_state) {
|
||||
static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
const unsigned char* UNUSED(key),
|
||||
int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@@ -79,10 +84,14 @@ 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
|
||||
const struct dropbear_cipher_mode dropbear_mode_cbc =
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
|
||||
#endif // DROPBEAR_ENABLE_CBC_MODE
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_none =
|
||||
{void_start, void_cipher, void_cipher};
|
||||
|
||||
#ifdef 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,
|
||||
@@ -93,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
|
||||
}
|
||||
const struct dropbear_cipher_mode dropbear_mode_ctr =
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
|
||||
#endif
|
||||
#endif // DROPBEAR_ENABLE_CTR_MODE
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
{&hash_desc, keysize, hashsize} */
|
||||
@@ -132,21 +141,15 @@ algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_AES128
|
||||
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* CBC modes are always enabled */
|
||||
#ifdef DROPBEAR_ENABLE_CBC_MODE
|
||||
#ifdef DROPBEAR_AES128
|
||||
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
@@ -157,9 +160,16 @@ algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"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_ENABLE_CBC_MODE */
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
|
||||
#endif
|
||||
@@ -190,7 +200,13 @@ algo_type sshhashes[] = {
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
algo_type ssh_compress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type ssh_delaycompress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
@@ -203,6 +219,17 @@ algo_type ssh_nocompress[] = {
|
||||
};
|
||||
|
||||
algo_type sshhostkey[] = {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
|
||||
#endif
|
||||
@@ -212,62 +239,51 @@ algo_type sshhostkey[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
|
||||
static const struct dropbear_kex kex_dh_group14 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
|
||||
|
||||
/* These can't be const since dropbear_ecc_fill_dp() fills out
|
||||
ecc_curve at runtime */
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
static struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
static struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
static struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
|
||||
#endif
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
/* Referred to directly */
|
||||
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
|
||||
#endif
|
||||
|
||||
algo_type sshkex[] = {
|
||||
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
|
||||
{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
|
||||
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
|
||||
#ifdef USE_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
void crypto_init() {
|
||||
|
||||
const struct ltc_cipher_descriptor *regciphers[] = {
|
||||
#ifdef DROPBEAR_AES
|
||||
&aes_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct ltc_hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
&sha256_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
&sha512_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -293,7 +309,7 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
unsigned int donefirst = 0;
|
||||
buffer *algolist = NULL;
|
||||
|
||||
algolist = buf_new(160);
|
||||
algolist = buf_new(200);
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
if (donefirst)
|
||||
@@ -307,6 +323,122 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
buf_free(algolist);
|
||||
}
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
* also in localalgos[], or return NULL on failure.
|
||||
* (*goodguess) is set to 1 if the preferred client/server algos match,
|
||||
* 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)
|
||||
{
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int remotecount, localcount, clicount, servcount, i, j;
|
||||
algo_type * ret = NULL;
|
||||
const unsigned char **clinames, **servnames;
|
||||
|
||||
if (goodguess) {
|
||||
*goodguess = 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
localnames[i] = localalgos[i].name;
|
||||
} else {
|
||||
localnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
localcount = i;
|
||||
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
clinames = remotenames;
|
||||
clicount = remotecount;
|
||||
servnames = localnames;
|
||||
servcount = localcount;
|
||||
} else {
|
||||
clinames = localnames;
|
||||
clicount = localcount;
|
||||
servnames = remotenames;
|
||||
servcount = remotecount;
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
for (i = 0; i < clicount; i++) {
|
||||
for (j = 0; j < servcount; j++) {
|
||||
if (!(servnames[j] && clinames[i])) {
|
||||
/* unusable algos are NULL */
|
||||
continue;
|
||||
}
|
||||
if (strcmp(servnames[j], clinames[i]) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (goodguess && kexguess2) {
|
||||
if (*kexguess2 == KEXGUESS2_YES) {
|
||||
if (i == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* set the algo to return */
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
ret = &localalgos[j];
|
||||
} else {
|
||||
ret = &localalgos[i];
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
|
||||
void
|
||||
@@ -337,7 +469,7 @@ get_algo_usable(algo_type algos[], const char * algo_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // DROPBEAR_NONE_CIPHER
|
||||
#endif /* DROPBEAR_NONE_CIPHER */
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
|
||||
@@ -418,4 +550,4 @@ check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
|
||||
return num_ret;
|
||||
}
|
||||
#endif // ENABLE_USER_ALGO_LIST
|
||||
#endif /* ENABLE_USER_ALGO_LIST */
|
||||
|
||||
150
common-channel.c
150
common-channel.c
@@ -59,6 +59,13 @@ static void close_chan_fd(struct Channel *channel, int fd, int how);
|
||||
#define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL)
|
||||
#define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel))
|
||||
|
||||
/* allow space for:
|
||||
* 1 byte byte SSH_MSG_CHANNEL_DATA
|
||||
* 4 bytes uint32 recipient channel
|
||||
* 4 bytes string data
|
||||
*/
|
||||
#define RECV_MAX_CHANNEL_DATA_LEN (RECV_MAX_PAYLOAD_LEN-(1+4+4))
|
||||
|
||||
/* Initialise all the channels */
|
||||
void chaninitialise(const struct ChanType *chantypes[]) {
|
||||
|
||||
@@ -165,7 +172,9 @@ static struct Channel* newchannel(unsigned int remotechan,
|
||||
|
||||
newchan->extrabuf = NULL; /* The user code can set it up */
|
||||
newchan->recvdonelen = 0;
|
||||
newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN;
|
||||
newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
|
||||
|
||||
newchan->prio = DROPBEAR_CHANNEL_PRIO_EARLY; /* inithandler sets it */
|
||||
|
||||
ses.channels[i] = newchan;
|
||||
ses.chancount++;
|
||||
@@ -201,11 +210,14 @@ struct Channel* getchannel() {
|
||||
/* Iterate through the channels, performing IO if available */
|
||||
void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
|
||||
/* Listeners such as TCP, X11, agent-auth */
|
||||
struct Channel *channel;
|
||||
unsigned int i;
|
||||
|
||||
/* foreach channel */
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
/* Close checking only needs to occur for channels that had IO events */
|
||||
int do_check_close = 0;
|
||||
|
||||
channel = ses.channels[i];
|
||||
if (channel == NULL) {
|
||||
@@ -217,6 +229,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
|
||||
TRACE(("send normal readfd"))
|
||||
send_msg_channel_data(channel, 0);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* read stderr data and send it over the wire */
|
||||
@@ -224,6 +237,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
&& FD_ISSET(channel->errfd, readfds)) {
|
||||
TRACE(("send normal errfd"))
|
||||
send_msg_channel_data(channel, 1);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* write to program/pipe stdin */
|
||||
@@ -235,20 +249,28 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
check_in_progress(), as it may be NULL */
|
||||
}
|
||||
writechannel(channel, channel->writefd, channel->writebuf);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* stderr for client mode */
|
||||
if (ERRFD_IS_WRITE(channel)
|
||||
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
|
||||
writechannel(channel, channel->errfd, channel->extrabuf);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
if (ses.channel_signal_pending) {
|
||||
/* SIGCHLD can change channel state for server sessions */
|
||||
do_check_close = 1;
|
||||
ses.channel_signal_pending = 0;
|
||||
}
|
||||
|
||||
/* handle any channel closing etc */
|
||||
check_close(channel);
|
||||
|
||||
if (do_check_close) {
|
||||
check_close(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/* Listeners such as TCP, X11, agent-auth */
|
||||
#ifdef USING_LISTENERS
|
||||
handle_listeners(readfds);
|
||||
#endif
|
||||
@@ -273,10 +295,10 @@ static unsigned int write_pending(struct Channel * channel) {
|
||||
static void check_close(struct Channel *channel) {
|
||||
int close_allowed = 0;
|
||||
|
||||
TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
|
||||
TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
|
||||
channel->writefd, channel->readfd,
|
||||
channel->errfd, channel->sent_close, channel->recv_close))
|
||||
TRACE(("writebuf size %d extrabuf size %d",
|
||||
TRACE2(("writebuf size %d extrabuf size %d",
|
||||
channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
|
||||
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
|
||||
|
||||
@@ -307,7 +329,9 @@ static void check_close(struct Channel *channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->recv_eof && !write_pending(channel)) {
|
||||
if ((channel->recv_eof && !write_pending(channel))
|
||||
/* have a server "session" and child has exited */
|
||||
|| (channel->type->check_close && close_allowed)) {
|
||||
close_chan_fd(channel, channel->writefd, SHUT_WR);
|
||||
}
|
||||
|
||||
@@ -336,6 +360,7 @@ static void check_close(struct Channel *channel) {
|
||||
|
||||
/* And if we can't receive any more data from them either, close up */
|
||||
if (channel->readfd == FD_CLOSED
|
||||
&& channel->writefd == FD_CLOSED
|
||||
&& (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)
|
||||
&& !channel->sent_close
|
||||
&& close_allowed
|
||||
@@ -471,8 +496,13 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Stuff to put over the wire */
|
||||
if (channel->transwindow > 0) {
|
||||
/* Stuff to put over the wire.
|
||||
Avoid queueing data to send if we're in the middle of a
|
||||
key re-exchange (!dataallowed), but still read from the
|
||||
FD if there's the possibility of "~."" to kill an
|
||||
interactive session (the read_mangler) */
|
||||
if (channel->transwindow > 0
|
||||
&& (ses.dataallowed || channel->read_mangler)) {
|
||||
|
||||
if (channel->readfd >= 0) {
|
||||
FD_SET(channel->readfd, readfds);
|
||||
@@ -552,21 +582,29 @@ static void remove_channel(struct Channel * channel) {
|
||||
}
|
||||
|
||||
|
||||
/* close the FDs in case they haven't been done
|
||||
* yet (they might have been shutdown etc) */
|
||||
TRACE(("CLOSE writefd %d", channel->writefd))
|
||||
close(channel->writefd);
|
||||
TRACE(("CLOSE readfd %d", channel->readfd))
|
||||
close(channel->readfd);
|
||||
TRACE(("CLOSE errfd %d", channel->errfd))
|
||||
close(channel->errfd);
|
||||
if (IS_DROPBEAR_SERVER || (channel->writefd != STDOUT_FILENO)) {
|
||||
/* close the FDs in case they haven't been done
|
||||
* yet (they might have been shutdown etc) */
|
||||
TRACE(("CLOSE writefd %d", channel->writefd))
|
||||
close(channel->writefd);
|
||||
TRACE(("CLOSE readfd %d", channel->readfd))
|
||||
close(channel->readfd);
|
||||
TRACE(("CLOSE errfd %d", channel->errfd))
|
||||
close(channel->errfd);
|
||||
}
|
||||
|
||||
channel->typedata = NULL;
|
||||
if (!channel->close_handler_done
|
||||
&& channel->type->closehandler) {
|
||||
channel->type->closehandler(channel);
|
||||
channel->close_handler_done = 1;
|
||||
}
|
||||
|
||||
ses.channels[channel->index] = NULL;
|
||||
m_free(channel);
|
||||
ses.chancount--;
|
||||
|
||||
update_channel_prio();
|
||||
|
||||
TRACE(("leave remove_channel"))
|
||||
}
|
||||
|
||||
@@ -589,7 +627,12 @@ void recv_msg_channel_request() {
|
||||
&& !channel->close_handler_done) {
|
||||
channel->type->reqhandler(channel);
|
||||
} else {
|
||||
send_msg_channel_failure(channel);
|
||||
int wantreply;
|
||||
buf_eatstring(ses.payload);
|
||||
wantreply = buf_getbool(ses.payload);
|
||||
if (wantreply) {
|
||||
send_msg_channel_failure(channel);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("leave recv_msg_channel_request"))
|
||||
@@ -625,7 +668,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
|
||||
* exttype if is extended */
|
||||
maxlen = MIN(maxlen,
|
||||
ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
|
||||
TRACE(("maxlen %d", maxlen))
|
||||
TRACE(("maxlen %zd", maxlen))
|
||||
if (maxlen == 0) {
|
||||
TRACE(("leave send_msg_channel_data: no window"))
|
||||
return;
|
||||
@@ -643,6 +686,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
|
||||
|
||||
/* read the data */
|
||||
len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen);
|
||||
|
||||
if (len <= 0) {
|
||||
if (len == 0 || errno != EINTR) {
|
||||
/* This will also get hit in the case of EAGAIN. The only
|
||||
@@ -650,12 +694,22 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
|
||||
in which case it can be treated the same as EOF */
|
||||
close_chan_fd(channel, fd, SHUT_RD);
|
||||
}
|
||||
ses.writepayload->len = ses.writepayload->pos = 0;
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
buf_setlen(ses.writepayload, 0);
|
||||
TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d",
|
||||
len, errno, fd))
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->read_mangler) {
|
||||
channel->read_mangler(channel, buf_getwriteptr(ses.writepayload, len), &len);
|
||||
if (len == 0) {
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
buf_setlen(ses.writepayload, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("send_msg_channel_data: len %d fd %d", len, fd))
|
||||
buf_incrwritepos(ses.writepayload, len);
|
||||
/* ... real size here */
|
||||
@@ -846,6 +900,10 @@ void recv_msg_channel_open() {
|
||||
}
|
||||
}
|
||||
|
||||
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
|
||||
}
|
||||
|
||||
chan_initwritebuf(channel);
|
||||
|
||||
/* success */
|
||||
@@ -859,6 +917,8 @@ failure:
|
||||
|
||||
cleanup:
|
||||
m_free(type);
|
||||
|
||||
update_channel_prio();
|
||||
|
||||
TRACE(("leave recv_msg_channel_open"))
|
||||
}
|
||||
@@ -974,7 +1034,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
* for X11, agent, tcp forwarding, and should be filled with channel-specific
|
||||
* options, with the calling function calling encrypt_packet() after
|
||||
* completion. It is mandatory for the caller to encrypt_packet() if
|
||||
* DROPBEAR_SUCCESS is returned */
|
||||
* a channel is returned. NULL is returned on failure. */
|
||||
int send_msg_channel_open_init(int fd, const struct ChanType *type) {
|
||||
|
||||
struct Channel* chan;
|
||||
@@ -1005,7 +1065,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
|
||||
buf_putstring(ses.writepayload, type->name, strlen(type->name));
|
||||
buf_putint(ses.writepayload, chan->index);
|
||||
buf_putint(ses.writepayload, opts.recv_window);
|
||||
buf_putint(ses.writepayload, RECV_MAX_PAYLOAD_LEN);
|
||||
buf_putint(ses.writepayload, RECV_MAX_CHANNEL_DATA_LEN);
|
||||
|
||||
TRACE(("leave send_msg_channel_open_init()"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
@@ -1040,9 +1100,14 @@ void recv_msg_channel_open_confirmation() {
|
||||
if (ret > 0) {
|
||||
remove_channel(channel);
|
||||
TRACE(("inithandler returned failure %d", ret))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
|
||||
}
|
||||
update_channel_prio();
|
||||
|
||||
TRACE(("leave recv_msg_channel_open_confirmation"))
|
||||
}
|
||||
@@ -1062,3 +1127,42 @@ void recv_msg_channel_open_failure() {
|
||||
remove_channel(channel);
|
||||
}
|
||||
#endif /* USING_LISTENERS */
|
||||
|
||||
void send_msg_request_success() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
void send_msg_request_failure() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
struct Channel* get_any_ready_channel() {
|
||||
if (ses.chancount == 0) {
|
||||
return NULL;
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
struct Channel *chan = ses.channels[i];
|
||||
if (chan
|
||||
&& !(chan->sent_eof || chan->recv_eof)
|
||||
&& !(chan->await_open || chan->initconn)) {
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void start_send_channel_request(struct Channel *channel,
|
||||
unsigned char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
buf_putint(ses.writepayload, channel->remotechan);
|
||||
|
||||
buf_putstring(ses.writepayload, type, strlen(type));
|
||||
|
||||
}
|
||||
|
||||
467
common-kex.c
467
common-kex.c
@@ -32,12 +32,13 @@
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "runopts.h"
|
||||
#include "ecc.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
#define DH_P_1_LEN 128
|
||||
static const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
@@ -51,8 +52,7 @@ static const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
/* diffie-hellman-group14-sha1 value for p */
|
||||
#define DH_P_14_LEN 256
|
||||
static const unsigned char dh_p_14[DH_P_14_LEN] = {
|
||||
const unsigned char dh_p_14[DH_P_14_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
@@ -80,14 +80,16 @@ static const unsigned char dh_p_14[DH_P_14_LEN] = {
|
||||
static const int DH_G_VAL = 2;
|
||||
|
||||
static void kexinitialise();
|
||||
void gen_new_keys();
|
||||
static void gen_new_keys();
|
||||
#ifndef DISABLE_ZLIB
|
||||
static void gen_new_zstreams();
|
||||
static void gen_new_zstream_recv();
|
||||
static void gen_new_zstream_trans();
|
||||
#endif
|
||||
static void read_kex_algos();
|
||||
/* helper function for gen_new_keys */
|
||||
static void hashkeys(unsigned char *out, int outlen,
|
||||
const hash_state * hs, unsigned const char X);
|
||||
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 */
|
||||
@@ -131,8 +133,8 @@ void send_msg_kexinit() {
|
||||
/* languages_server_to_client */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
|
||||
/* first_kex_packet_follows - unimplemented for now */
|
||||
buf_putbyte(ses.writepayload, 0x00);
|
||||
/* first_kex_packet_follows */
|
||||
buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL));
|
||||
|
||||
/* reserved unit32 */
|
||||
buf_putint(ses.writepayload, 0);
|
||||
@@ -144,16 +146,60 @@ void send_msg_kexinit() {
|
||||
encrypt_packet();
|
||||
ses.dataallowed = 0; /* don't send other packets during kex */
|
||||
|
||||
ses.kexstate.sentkexinit = 1;
|
||||
|
||||
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.send_kex_first_guess();
|
||||
}
|
||||
|
||||
TRACE(("DATAALLOWED=0"))
|
||||
TRACE(("-> KEXINIT"))
|
||||
ses.kexstate.sentkexinit = 1;
|
||||
|
||||
}
|
||||
|
||||
/* *** NOTE regarding (send|recv)_msg_newkeys ***
|
||||
* Changed by mihnea from the original kex.c to set dataallowed after a
|
||||
* completed key exchange, no matter the order in which it was performed.
|
||||
* This enables client mode without affecting server functionality.
|
||||
*/
|
||||
static void switch_keys() {
|
||||
TRACE2(("enter switch_keys"))
|
||||
if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) {
|
||||
dropbear_exit("Unexpected newkeys message");
|
||||
}
|
||||
|
||||
if (!ses.keys) {
|
||||
ses.keys = m_malloc(sizeof(*ses.newkeys));
|
||||
}
|
||||
if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) {
|
||||
TRACE(("switch_keys recv"))
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstream_recv();
|
||||
#endif
|
||||
ses.keys->recv = ses.newkeys->recv;
|
||||
m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv));
|
||||
ses.newkeys->recv.valid = 0;
|
||||
}
|
||||
if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) {
|
||||
TRACE(("switch_keys trans"))
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstream_trans();
|
||||
#endif
|
||||
ses.keys->trans = ses.newkeys->trans;
|
||||
m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans));
|
||||
ses.newkeys->trans.valid = 0;
|
||||
}
|
||||
if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys)
|
||||
{
|
||||
TRACE(("switch_keys done"))
|
||||
ses.keys->algo_kex = ses.newkeys->algo_kex;
|
||||
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
|
||||
ses.keys->allow_compress = 0;
|
||||
m_free(ses.newkeys);
|
||||
ses.newkeys = NULL;
|
||||
kexinitialise();
|
||||
}
|
||||
TRACE2(("leave switch_keys"))
|
||||
}
|
||||
|
||||
/* Bring new keys into use after a key exchange, and let the client know*/
|
||||
void send_msg_newkeys() {
|
||||
@@ -164,44 +210,25 @@ void send_msg_newkeys() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
|
||||
encrypt_packet();
|
||||
|
||||
|
||||
|
||||
/* set up our state */
|
||||
if (ses.kexstate.recvnewkeys) {
|
||||
TRACE(("while RECVNEWKEYS=1"))
|
||||
gen_new_keys();
|
||||
kexinitialise(); /* we've finished with this kex */
|
||||
TRACE((" -> DATAALLOWED=1"))
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
} else {
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
TRACE(("SENTNEWKEYS=1"))
|
||||
}
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
gen_new_keys();
|
||||
switch_keys();
|
||||
|
||||
TRACE(("-> MSG_NEWKEYS"))
|
||||
TRACE(("leave send_msg_newkeys"))
|
||||
}
|
||||
|
||||
/* Bring the new keys into use after a key exchange */
|
||||
void recv_msg_newkeys() {
|
||||
|
||||
TRACE(("<- MSG_NEWKEYS"))
|
||||
TRACE(("enter recv_msg_newkeys"))
|
||||
|
||||
/* simply check if we've sent SSH_MSG_NEWKEYS, and if so,
|
||||
* switch to the new keys */
|
||||
if (ses.kexstate.sentnewkeys) {
|
||||
TRACE(("while SENTNEWKEYS=1"))
|
||||
gen_new_keys();
|
||||
kexinitialise(); /* we've finished with this kex */
|
||||
TRACE((" -> DATAALLOWED=1"))
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
} else {
|
||||
TRACE(("RECVNEWKEYS=1"))
|
||||
ses.kexstate.recvnewkeys = 1;
|
||||
}
|
||||
ses.kexstate.recvnewkeys = 1;
|
||||
switch_keys();
|
||||
|
||||
TRACE(("leave recv_msg_newkeys"))
|
||||
}
|
||||
@@ -211,14 +238,24 @@ void recv_msg_newkeys() {
|
||||
void kexfirstinitialise() {
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (opts.enable_compress) {
|
||||
ses.compress_algos = ssh_compress;
|
||||
} else
|
||||
#endif
|
||||
#ifdef DISABLE_ZLIB
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
#else
|
||||
switch (opts.compress_mode)
|
||||
{
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
case DROPBEAR_COMPRESS_DELAYED:
|
||||
ses.compress_algos = ssh_delaycompress;
|
||||
break;
|
||||
|
||||
case DROPBEAR_COMPRESS_ON:
|
||||
ses.compress_algos = ssh_compress;
|
||||
break;
|
||||
|
||||
case DROPBEAR_COMPRESS_OFF:
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
kexinitialise();
|
||||
}
|
||||
|
||||
@@ -236,12 +273,14 @@ static void kexinitialise() {
|
||||
ses.kexstate.sentnewkeys = 0;
|
||||
|
||||
/* first_packet_follows */
|
||||
ses.kexstate.firstfollows = 0;
|
||||
ses.kexstate.them_firstfollows = 0;
|
||||
|
||||
ses.kexstate.datatrans = 0;
|
||||
ses.kexstate.datarecv = 0;
|
||||
|
||||
ses.kexstate.lastkextime = time(NULL);
|
||||
ses.kexstate.our_first_follows_matches = 0;
|
||||
|
||||
ses.kexstate.lastkextime = monotonic_now();
|
||||
|
||||
}
|
||||
|
||||
@@ -251,27 +290,30 @@ static void kexinitialise() {
|
||||
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
|
||||
*
|
||||
* See Section 7.2 of rfc4253 (ssh transport) for details */
|
||||
static void hashkeys(unsigned char *out, int outlen,
|
||||
static void hashkeys(unsigned char *out, unsigned int outlen,
|
||||
const hash_state * hs, const unsigned char X) {
|
||||
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
hash_state hs2;
|
||||
int offset;
|
||||
unsigned int offset;
|
||||
unsigned char tmpout[MAX_HASH_SIZE];
|
||||
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, &X, 1);
|
||||
sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
|
||||
sha1_done(&hs2, out);
|
||||
for (offset = SHA1_HASH_SIZE;
|
||||
hash_desc->process(&hs2, &X, 1);
|
||||
hash_desc->process(&hs2, ses.session_id->data, ses.session_id->len);
|
||||
hash_desc->done(&hs2, tmpout);
|
||||
memcpy(out, tmpout, MIN(hash_desc->hashsize, outlen));
|
||||
for (offset = hash_desc->hashsize;
|
||||
offset < outlen;
|
||||
offset += SHA1_HASH_SIZE)
|
||||
offset += hash_desc->hashsize)
|
||||
{
|
||||
/* need to extend */
|
||||
unsigned char k2[SHA1_HASH_SIZE];
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, out, offset);
|
||||
sha1_done(&hs2, k2);
|
||||
memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE));
|
||||
hash_desc->process(&hs2, out, offset);
|
||||
hash_desc->done(&hs2, tmpout);
|
||||
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
|
||||
}
|
||||
m_burn(&hs2, sizeof(hash_state));
|
||||
}
|
||||
|
||||
/* Generate the actual encryption/integrity keys, using the results of the
|
||||
@@ -281,8 +323,7 @@ static void hashkeys(unsigned char *out, int outlen,
|
||||
* ses.newkeys is the new set of keys which are generated, these are only
|
||||
* taken into use after both sides have sent a newkeys message */
|
||||
|
||||
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
|
||||
void gen_new_keys() {
|
||||
static void gen_new_keys() {
|
||||
|
||||
unsigned char C2S_IV[MAX_IV_LEN];
|
||||
unsigned char C2S_key[MAX_KEY_LEN];
|
||||
@@ -292,26 +333,26 @@ void gen_new_keys() {
|
||||
unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;
|
||||
|
||||
hash_state hs;
|
||||
unsigned int C2S_keysize, S2C_keysize;
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
char mactransletter, macrecvletter; /* Client or server specific */
|
||||
|
||||
TRACE(("enter gen_new_keys"))
|
||||
/* the dh_K and hash are the start of all hashes, we make use of that */
|
||||
|
||||
sha1_init(&hs);
|
||||
sha1_process_mp(&hs, ses.dh_K);
|
||||
hash_desc->init(&hs);
|
||||
hash_process_mp(hash_desc, &hs, ses.dh_K);
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
sha1_process(&hs, ses.hash, SHA1_HASH_SIZE);
|
||||
m_burn(ses.hash, SHA1_HASH_SIZE);
|
||||
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
|
||||
buf_burn(ses.hash);
|
||||
buf_free(ses.hash);
|
||||
ses.hash = NULL;
|
||||
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
trans_IV = C2S_IV;
|
||||
recv_IV = S2C_IV;
|
||||
trans_key = C2S_key;
|
||||
recv_key = S2C_key;
|
||||
C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
mactransletter = 'E';
|
||||
macrecvletter = 'F';
|
||||
} else {
|
||||
@@ -319,16 +360,14 @@ void gen_new_keys() {
|
||||
recv_IV = C2S_IV;
|
||||
trans_key = S2C_key;
|
||||
recv_key = C2S_key;
|
||||
C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
mactransletter = 'F';
|
||||
macrecvletter = 'E';
|
||||
}
|
||||
|
||||
hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A');
|
||||
hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B');
|
||||
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
|
||||
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
|
||||
hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A');
|
||||
hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B');
|
||||
hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C');
|
||||
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);
|
||||
@@ -354,32 +393,27 @@ void gen_new_keys() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans.algo_mac->hashdesc != NULL) {
|
||||
if (ses.newkeys->trans.algo_mac->hash_desc != NULL) {
|
||||
hashkeys(ses.newkeys->trans.mackey,
|
||||
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hash_desc->name);
|
||||
}
|
||||
|
||||
if (ses.newkeys->recv.algo_mac->hashdesc != NULL) {
|
||||
if (ses.newkeys->recv.algo_mac->hash_desc != NULL) {
|
||||
hashkeys(ses.newkeys->recv.mackey,
|
||||
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hash_desc->name);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstreams();
|
||||
#endif
|
||||
|
||||
/* Switch over to the new keys */
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
ses.keys = ses.newkeys;
|
||||
ses.newkeys = NULL;
|
||||
/* Ready to switch over */
|
||||
ses.newkeys->trans.valid = 1;
|
||||
ses.newkeys->recv.valid = 1;
|
||||
|
||||
m_burn(C2S_IV, sizeof(C2S_IV));
|
||||
m_burn(C2S_key, sizeof(C2S_key));
|
||||
m_burn(S2C_IV, sizeof(S2C_IV));
|
||||
m_burn(S2C_key, sizeof(S2C_key));
|
||||
m_burn(&hs, sizeof(hash_state));
|
||||
|
||||
TRACE(("leave gen_new_keys"))
|
||||
}
|
||||
@@ -400,7 +434,7 @@ int is_compress_recv() {
|
||||
|
||||
/* Set up new zlib compression streams, close the old ones. Only
|
||||
* called from gen_new_keys() */
|
||||
static void gen_new_zstreams() {
|
||||
static void gen_new_zstream_recv() {
|
||||
|
||||
/* create new zstreams */
|
||||
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
@@ -415,6 +449,17 @@ static void gen_new_zstreams() {
|
||||
} else {
|
||||
ses.newkeys->recv.zstream = NULL;
|
||||
}
|
||||
/* clean up old keys */
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_new_zstream_trans() {
|
||||
|
||||
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
@@ -432,14 +477,6 @@ static void gen_new_zstreams() {
|
||||
ses.newkeys->trans.zstream = NULL;
|
||||
}
|
||||
|
||||
/* clean up old keys */
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
if (ses.keys->trans.zstream != NULL) {
|
||||
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
@@ -457,9 +494,6 @@ static void gen_new_zstreams() {
|
||||
* and we calculate the first portion of the key-exchange-hash for used
|
||||
* later in the key exchange. No response is sent, as the client should
|
||||
* initiate the diffie-hellman key exchange */
|
||||
|
||||
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
|
||||
/* Belongs in common_kex.c where it should be moved after review */
|
||||
void recv_msg_kexinit() {
|
||||
|
||||
unsigned int kexhashbuf_len = 0;
|
||||
@@ -502,7 +536,7 @@ void recv_msg_kexinit() {
|
||||
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
|
||||
buf_setpos(ses.payload, 0);
|
||||
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
|
||||
|
||||
ses.requirenext = SSH_MSG_KEXDH_REPLY;
|
||||
} else {
|
||||
/* SERVER */
|
||||
|
||||
@@ -536,28 +570,24 @@ void recv_msg_kexinit() {
|
||||
|
||||
static void load_dh_p(mp_int * dh_p)
|
||||
{
|
||||
switch (ses.newkeys->algo_kex) {
|
||||
case DROPBEAR_KEX_DH_GROUP1:
|
||||
bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN);
|
||||
break;
|
||||
case DROPBEAR_KEX_DH_GROUP14:
|
||||
bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN);
|
||||
break;
|
||||
}
|
||||
bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes,
|
||||
ses.newkeys->algo_kex->dh_p_len);
|
||||
}
|
||||
|
||||
/* Initialises and generate one side of the diffie-hellman key exchange values.
|
||||
* See the transport rfc 4253 section 8 for details */
|
||||
/* dh_pub and dh_priv MUST be already initialised */
|
||||
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
|
||||
struct kex_dh_param *gen_kexdh_param() {
|
||||
struct kex_dh_param *param = NULL;
|
||||
|
||||
DEF_MP_INT(dh_p);
|
||||
DEF_MP_INT(dh_q);
|
||||
DEF_MP_INT(dh_g);
|
||||
|
||||
TRACE(("enter send_msg_kexdh_reply"))
|
||||
|
||||
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
|
||||
TRACE(("enter gen_kexdh_vals"))
|
||||
|
||||
param = m_malloc(sizeof(*param));
|
||||
m_mp_init_multi(¶m->pub, ¶m->priv, &dh_g, &dh_p, &dh_q, NULL);
|
||||
|
||||
/* read the prime and generator*/
|
||||
load_dh_p(&dh_p);
|
||||
@@ -568,33 +598,39 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
|
||||
|
||||
/* calculate q = (p-1)/2 */
|
||||
/* dh_priv is just a temp var here */
|
||||
if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) {
|
||||
if (mp_sub_d(&dh_p, 1, ¶m->priv) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
|
||||
if (mp_div_2(¶m->priv, &dh_q) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
/* Generate a private portion 0 < dh_priv < dh_q */
|
||||
gen_random_mpint(&dh_q, dh_priv);
|
||||
gen_random_mpint(&dh_q, ¶m->priv);
|
||||
|
||||
/* f = g^y mod p */
|
||||
if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
|
||||
if (mp_exptmod(&dh_g, ¶m->priv, &dh_p, ¶m->pub) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexdh_param(struct kex_dh_param *param)
|
||||
{
|
||||
mp_clear_multi(¶m->pub, ¶m->priv, NULL);
|
||||
m_free(param);
|
||||
}
|
||||
|
||||
/* This function is fairly common between client/server, with some substitution
|
||||
* of dh_e/dh_f etc. Hence these arguments:
|
||||
* dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is
|
||||
* vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
|
||||
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
sign_key *hostkey) {
|
||||
|
||||
mp_int dh_p;
|
||||
mp_int *dh_e = NULL, *dh_f = NULL;
|
||||
hash_state hs;
|
||||
|
||||
/* read the prime and generator*/
|
||||
m_mp_init(&dh_p);
|
||||
@@ -607,9 +643,8 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
}
|
||||
|
||||
/* K = e^y mod p = f^x mod p */
|
||||
ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init(ses.dh_K);
|
||||
if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) {
|
||||
m_mp_alloc_init_multi(&ses.dh_K, NULL);
|
||||
if (mp_exptmod(dh_pub_them, ¶m->priv, &dh_p, ses.dh_K) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
@@ -619,11 +654,11 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
/* From here on, the code needs to work with the _same_ vars on each side,
|
||||
* not vice-versaing for client/server */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
dh_e = dh_pub_us;
|
||||
dh_e = ¶m->pub;
|
||||
dh_f = dh_pub_them;
|
||||
} else {
|
||||
dh_e = dh_pub_them;
|
||||
dh_f = dh_pub_us;
|
||||
dh_f = ¶m->pub;
|
||||
}
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash */
|
||||
@@ -637,21 +672,150 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
sha1_init(&hs);
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
|
||||
#ifdef 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,
|
||||
¶m->key, ses.newkeys->algo_kex->ecc_curve->dp) != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexecdh_param(struct kex_ecdh_param *param) {
|
||||
ecc_free(¶m->key);
|
||||
m_free(param);
|
||||
|
||||
}
|
||||
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
sign_key *hostkey) {
|
||||
const struct dropbear_kex *algo_kex = ses.newkeys->algo_kex;
|
||||
/* public keys from client and server */
|
||||
ecc_key *Q_C, *Q_S, *Q_them;
|
||||
|
||||
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
|
||||
|
||||
ses.dh_K = dropbear_ecc_shared_secret(Q_them, ¶m->key);
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash
|
||||
See RFC5656 section 4 page 7 */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
Q_C = ¶m->key;
|
||||
Q_S = Q_them;
|
||||
} else {
|
||||
Q_C = Q_them;
|
||||
Q_S = ¶m->key;
|
||||
}
|
||||
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
|
||||
/* Q_C, client's ephemeral public key octet string */
|
||||
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_C);
|
||||
/* Q_S, server's ephemeral public key octet string */
|
||||
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_S);
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#ifdef 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);
|
||||
|
||||
return 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,
|
||||
sign_key *hostkey) {
|
||||
unsigned char out[CURVE25519_LEN];
|
||||
const unsigned char* Q_C = NULL;
|
||||
const unsigned char* Q_S = NULL;
|
||||
|
||||
if (buf_pub_them->len != CURVE25519_LEN)
|
||||
{
|
||||
dropbear_exit("Bad curve25519");
|
||||
}
|
||||
|
||||
curve25519_donna(out, param->priv, buf_pub_them->data);
|
||||
m_mp_alloc_init_multi(&ses.dh_K, NULL);
|
||||
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
|
||||
m_burn(out, sizeof(out));
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash.
|
||||
See RFC5656 section 4 page 7 */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
Q_C = param->pub;
|
||||
Q_S = buf_pub_them->data;
|
||||
} else {
|
||||
Q_S = param->pub;
|
||||
Q_C = buf_pub_them->data;
|
||||
}
|
||||
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
|
||||
/* Q_C, client's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
|
||||
/* Q_S, server's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
|
||||
|
||||
static void finish_kexhashbuf(void) {
|
||||
hash_state hs;
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
|
||||
hash_desc->init(&hs);
|
||||
buf_setpos(ses.kexhashbuf, 0);
|
||||
sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
|
||||
hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
|
||||
ses.kexhashbuf->len);
|
||||
sha1_done(&hs, ses.hash);
|
||||
ses.hash = buf_new(hash_desc->hashsize);
|
||||
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 (!debug_trace) {
|
||||
printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len);
|
||||
printhex("kexhash", ses.hash->data, ses.hash->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
buf_burn(ses.kexhashbuf);
|
||||
buf_free(ses.kexhashbuf);
|
||||
m_burn(&hs, sizeof(hash_state));
|
||||
ses.kexhashbuf = NULL;
|
||||
|
||||
/* first time around, we set the session_id to H */
|
||||
if (ses.session_id == NULL) {
|
||||
/* create the session_id, this never needs freeing */
|
||||
ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
|
||||
memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
|
||||
ses.session_id = buf_newcopy(ses.hash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,22 +840,29 @@ static void read_kex_algos() {
|
||||
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
|
||||
|
||||
buf_incrpos(ses.payload, 16); /* start after the cookie */
|
||||
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
|
||||
|
||||
/* kex_algorithms */
|
||||
algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
|
||||
erralgo = "kex";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("kexguess2 %d", kexguess2))
|
||||
TRACE(("kex algo %s", algo->name))
|
||||
ses.newkeys->algo_kex = algo->val;
|
||||
ses.newkeys->algo_kex = algo->data;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "hostkey";
|
||||
@@ -701,7 +872,7 @@ static void read_kex_algos() {
|
||||
ses.newkeys->algo_hostkey = algo->val;
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
if (c2s_cipher_algo == NULL) {
|
||||
erralgo = "enc c->s";
|
||||
goto error;
|
||||
@@ -709,7 +880,7 @@ static void read_kex_algos() {
|
||||
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
|
||||
|
||||
/* encryption_algorithms_server_to_client */
|
||||
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
if (s2c_cipher_algo == NULL) {
|
||||
erralgo = "enc s->c";
|
||||
goto error;
|
||||
@@ -717,7 +888,7 @@ static void read_kex_algos() {
|
||||
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
|
||||
|
||||
/* mac_algorithms_client_to_server */
|
||||
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
if (c2s_hash_algo == NULL) {
|
||||
erralgo = "mac c->s";
|
||||
goto error;
|
||||
@@ -725,7 +896,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo->name))
|
||||
|
||||
/* mac_algorithms_server_to_client */
|
||||
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
if (s2c_hash_algo == NULL) {
|
||||
erralgo = "mac s->c";
|
||||
goto error;
|
||||
@@ -733,7 +904,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo->name))
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
if (c2s_comp_algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
@@ -741,7 +912,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_comp_algo->name))
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
if (s2c_comp_algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
@@ -754,9 +925,10 @@ static void read_kex_algos() {
|
||||
/* languages_server_to_client */
|
||||
buf_eatstring(ses.payload);
|
||||
|
||||
/* first_kex_packet_follows */
|
||||
/* their first_kex_packet_follows */
|
||||
if (buf_getbool(ses.payload)) {
|
||||
ses.kexstate.firstfollows = 1;
|
||||
TRACE(("them kex firstfollows. allgood %d", allgood))
|
||||
ses.kexstate.them_firstfollows = 1;
|
||||
/* if the guess wasn't good, we ignore the packet sent */
|
||||
if (!allgood) {
|
||||
ses.ignorenext = 1;
|
||||
@@ -799,6 +971,11 @@ static void read_kex_algos() {
|
||||
|
||||
/* reserved for future extensions */
|
||||
buf_getint(ses.payload);
|
||||
|
||||
if (ses.send_kex_first_guess && allgood) {
|
||||
TRACE(("our_first_follows_matches 1"))
|
||||
ses.kexstate.our_first_follows_matches = 1;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
|
||||
@@ -29,13 +29,14 @@
|
||||
#include "dbutil.h"
|
||||
#include "auth.h"
|
||||
#include "algo.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
runopts opts; /* GLOBAL */
|
||||
|
||||
/* returns success or failure, and the keytype in *type. If we want
|
||||
* to restrict the type, type can contain a type to return */
|
||||
int readhostkey(const char * filename, sign_key * hostkey, int *type) {
|
||||
int readhostkey(const char * filename, sign_key * hostkey,
|
||||
enum signkey_type *type) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
buffer *buf;
|
||||
@@ -105,3 +106,8 @@ parse_ciphers_macs()
|
||||
}
|
||||
#endif
|
||||
|
||||
void print_version() {
|
||||
fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION);
|
||||
}
|
||||
|
||||
|
||||
|
||||
217
common-session.c
217
common-session.c
@@ -30,15 +30,15 @@
|
||||
#include "buffer.h"
|
||||
#include "dss.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "kex.h"
|
||||
#include "channel.h"
|
||||
#include "atomicio.h"
|
||||
#include "runopts.h"
|
||||
|
||||
static void checktimeouts();
|
||||
static long select_timeout();
|
||||
static int ident_readln(int fd, char* buf, int count);
|
||||
static void read_session_identification();
|
||||
|
||||
struct sshsession ses; /* GLOBAL */
|
||||
|
||||
@@ -49,10 +49,9 @@ 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;
|
||||
|
||||
TRACE(("enter session_init"))
|
||||
|
||||
@@ -60,9 +59,15 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.sock_out = sock_out;
|
||||
ses.maxfd = MAX(sock_in, sock_out);
|
||||
|
||||
ses.connect_time = 0;
|
||||
ses.last_trx_packet_time = 0;
|
||||
ses.last_packet_time = 0;
|
||||
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
|
||||
/* Sets it to lowdelay */
|
||||
update_channel_prio();
|
||||
|
||||
now = monotonic_now();
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
ses.last_packet_time_idle = now;
|
||||
ses.last_packet_time_any_sent = 0;
|
||||
ses.last_packet_time_keepalive_sent = 0;
|
||||
|
||||
if (pipe(ses.signal_pipe) < 0) {
|
||||
dropbear_exit("Signal pipe failed");
|
||||
@@ -103,7 +108,7 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.keys->recv.algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans.algo_mac = &dropbear_nohash;
|
||||
|
||||
ses.keys->algo_kex = -1;
|
||||
ses.keys->algo_kex = NULL;
|
||||
ses.keys->algo_hostkey = -1;
|
||||
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
|
||||
@@ -141,7 +146,10 @@ void session_loop(void(*loophandler)()) {
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&readfd);
|
||||
dropbear_assert(ses.payload == NULL);
|
||||
if (ses.sock_in != -1) {
|
||||
|
||||
/* during initial setup we flush out the KEXINIT packet before
|
||||
* attempting to read the remote version string, which might block */
|
||||
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
|
||||
FD_SET(ses.sock_in, &readfd);
|
||||
}
|
||||
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
|
||||
@@ -152,10 +160,9 @@ void session_loop(void(*loophandler)()) {
|
||||
SIGCHLD in svr-chansession is the only one currently. */
|
||||
FD_SET(ses.signal_pipe[0], &readfd);
|
||||
|
||||
/* set up for channels which require reading/writing */
|
||||
if (ses.dataallowed) {
|
||||
setchannelfds(&readfd, &writefd);
|
||||
}
|
||||
/* set up for channels which can be read/written */
|
||||
setchannelfds(&readfd, &writefd);
|
||||
|
||||
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
|
||||
|
||||
if (exitflag) {
|
||||
@@ -186,16 +193,15 @@ void session_loop(void(*loophandler)()) {
|
||||
/* check for auth timeout, rekeying required etc */
|
||||
checktimeouts();
|
||||
|
||||
/* process session socket's incoming/outgoing data */
|
||||
if (ses.sock_out != -1) {
|
||||
if (FD_ISSET(ses.sock_out, &writefd) && !isempty(&ses.writequeue)) {
|
||||
write_packet();
|
||||
}
|
||||
}
|
||||
|
||||
/* process session socket's incoming data */
|
||||
if (ses.sock_in != -1) {
|
||||
if (FD_ISSET(ses.sock_in, &readfd)) {
|
||||
read_packet();
|
||||
if (!ses.remoteident) {
|
||||
/* blocking read of the version string */
|
||||
read_session_identification();
|
||||
} else {
|
||||
read_packet();
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the decrypted packet. After this, the read buffer
|
||||
@@ -211,10 +217,16 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
/* process pipes etc for the channels, ses.dataallowed == 0
|
||||
* during rekeying ) */
|
||||
if (ses.dataallowed) {
|
||||
channelio(&readfd, &writefd);
|
||||
channelio(&readfd, &writefd);
|
||||
|
||||
/* process session socket's outgoing data */
|
||||
if (ses.sock_out != -1) {
|
||||
if (!isempty(&ses.writequeue)) {
|
||||
write_packet();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (loophandler) {
|
||||
loophandler();
|
||||
}
|
||||
@@ -225,7 +237,7 @@ void session_loop(void(*loophandler)()) {
|
||||
}
|
||||
|
||||
/* clean up a session on exit */
|
||||
void common_session_cleanup() {
|
||||
void session_cleanup() {
|
||||
|
||||
TRACE(("enter session_cleanup"))
|
||||
|
||||
@@ -234,31 +246,45 @@ void common_session_cleanup() {
|
||||
TRACE(("leave session_cleanup: !sessinitdone"))
|
||||
return;
|
||||
}
|
||||
|
||||
m_free(ses.session_id);
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
|
||||
if (ses.extra_session_cleanup) {
|
||||
ses.extra_session_cleanup();
|
||||
}
|
||||
|
||||
chancleanup();
|
||||
|
||||
/* Cleaning up keys must happen after other cleanup
|
||||
functions which might queue packets */
|
||||
if (ses.session_id) {
|
||||
buf_burn(ses.session_id);
|
||||
buf_free(ses.session_id);
|
||||
ses.session_id = NULL;
|
||||
}
|
||||
if (ses.hash) {
|
||||
buf_burn(ses.hash);
|
||||
buf_free(ses.hash);
|
||||
ses.hash = NULL;
|
||||
}
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
|
||||
TRACE(("leave session_cleanup"))
|
||||
}
|
||||
|
||||
void send_session_identification() {
|
||||
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
|
||||
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
buf_putbyte(writebuf, 0x0); /* packet type */
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, writebuf);
|
||||
}
|
||||
|
||||
void session_identification() {
|
||||
|
||||
static void read_session_identification() {
|
||||
/* max length of 255 chars */
|
||||
char linebuf[256];
|
||||
int len = 0;
|
||||
char done = 0;
|
||||
int i;
|
||||
|
||||
/* write our version string, this blocks */
|
||||
if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n",
|
||||
strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
/* If they send more than 50 lines, something is wrong */
|
||||
for (i = 0; i < 50; i++) {
|
||||
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
|
||||
@@ -368,11 +394,37 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
return pos+1;
|
||||
}
|
||||
|
||||
void send_msg_ignore() {
|
||||
void ignore_recv_response() {
|
||||
// Do nothing
|
||||
TRACE(("Ignored msg_request_response"))
|
||||
}
|
||||
|
||||
static void send_msg_keepalive() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_IGNORE);
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
time_t old_time_idle = ses.last_packet_time_idle;
|
||||
|
||||
struct Channel *chan = get_any_ready_channel();
|
||||
|
||||
if (chan) {
|
||||
/* Channel requests are preferable, more implementations
|
||||
handle them than SSH_MSG_GLOBAL_REQUEST */
|
||||
TRACE(("keepalive channel request %d", chan->index))
|
||||
start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING);
|
||||
} else {
|
||||
TRACE(("keepalive global request"))
|
||||
/* Some peers will reply with SSH_MSG_REQUEST_FAILURE,
|
||||
some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
|
||||
buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING,
|
||||
strlen(DROPBEAR_KEEPALIVE_STRING));
|
||||
}
|
||||
buf_putbyte(ses.writepayload, 1); /* want_reply */
|
||||
encrypt_packet();
|
||||
|
||||
ses.last_packet_time_keepalive_sent = monotonic_now();
|
||||
|
||||
/* keepalives shouldn't update idle timeout, reset it back */
|
||||
ses.last_packet_time_idle = old_time_idle;
|
||||
}
|
||||
|
||||
/* Check all timeouts which are required. Currently these are the time for
|
||||
@@ -380,13 +432,8 @@ void send_msg_ignore() {
|
||||
static void checktimeouts() {
|
||||
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
now = monotonic_now();
|
||||
|
||||
if (ses.connect_time != 0 && now - ses.connect_time >= AUTH_TIMEOUT) {
|
||||
dropbear_close("Timeout before auth");
|
||||
}
|
||||
|
||||
/* we can't rekey if we haven't done remote ident exchange yet */
|
||||
if (ses.remoteident == NULL) {
|
||||
return;
|
||||
@@ -399,13 +446,30 @@ static void checktimeouts() {
|
||||
send_msg_kexinit();
|
||||
}
|
||||
|
||||
if (opts.keepalive_secs > 0
|
||||
&& now - ses.last_trx_packet_time >= opts.keepalive_secs) {
|
||||
send_msg_ignore();
|
||||
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
|
||||
/* Avoid sending keepalives prior to auth - those are
|
||||
not valid pre-auth packet types */
|
||||
|
||||
/* Send keepalives if we've been idle */
|
||||
if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
|
||||
send_msg_keepalive();
|
||||
}
|
||||
|
||||
/* Also send an explicit keepalive message to trigger a response
|
||||
if the remote end hasn't sent us anything */
|
||||
if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
|
||||
&& now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
|
||||
send_msg_keepalive();
|
||||
}
|
||||
|
||||
if (now - ses.last_packet_time_keepalive_recv
|
||||
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
|
||||
dropbear_exit("Keepalive timeout");
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.idle_timeout_secs > 0 && ses.last_packet_time > 0
|
||||
&& now - ses.last_packet_time >= opts.idle_timeout_secs) {
|
||||
if (opts.idle_timeout_secs > 0
|
||||
&& now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
|
||||
dropbear_close("Idle timeout");
|
||||
}
|
||||
}
|
||||
@@ -416,12 +480,13 @@ static long select_timeout() {
|
||||
long ret = LONG_MAX;
|
||||
if (KEX_REKEY_TIMEOUT > 0)
|
||||
ret = MIN(KEX_REKEY_TIMEOUT, ret);
|
||||
if (AUTH_TIMEOUT > 0)
|
||||
/* AUTH_TIMEOUT is only relevant before authdone */
|
||||
if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0)
|
||||
ret = MIN(AUTH_TIMEOUT, ret);
|
||||
if (opts.keepalive_secs > 0)
|
||||
ret = MIN(opts.keepalive_secs, ret);
|
||||
if (opts.idle_timeout_secs > 0)
|
||||
ret = MIN(opts.idle_timeout_secs, ret);
|
||||
if (opts.idle_timeout_secs > 0)
|
||||
ret = MIN(opts.idle_timeout_secs, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -470,3 +535,47 @@ void fill_passwd(const char* username) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when channels are modified */
|
||||
void update_channel_prio() {
|
||||
enum dropbear_prio new_prio;
|
||||
int any = 0;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("update_channel_prio"))
|
||||
|
||||
new_prio = DROPBEAR_PRIO_BULK;
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
struct Channel *channel = ses.channels[i];
|
||||
if (!channel || channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
if (channel && channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
TRACE(("update_channel_prio: early %d", channel->index))
|
||||
}
|
||||
continue;
|
||||
}
|
||||
any = 1;
|
||||
if (channel->prio == DROPBEAR_CHANNEL_PRIO_INTERACTIVE)
|
||||
{
|
||||
TRACE(("update_channel_prio: lowdelay %d", channel->index))
|
||||
new_prio = DROPBEAR_PRIO_LOWDELAY;
|
||||
break;
|
||||
} else if (channel->prio == DROPBEAR_CHANNEL_PRIO_UNKNOWABLE
|
||||
&& new_prio == DROPBEAR_PRIO_BULK)
|
||||
{
|
||||
TRACE(("update_channel_prio: unknowable %d", channel->index))
|
||||
new_prio = DROPBEAR_PRIO_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
if (any == 0) {
|
||||
/* lowdelay during setup */
|
||||
TRACE(("update_channel_prio: not any"))
|
||||
new_prio = DROPBEAR_PRIO_LOWDELAY;
|
||||
}
|
||||
|
||||
if (new_prio != ses.socket_prio) {
|
||||
TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio))
|
||||
set_sock_priority(ses.sock_out, new_prio);
|
||||
ses.socket_prio = new_prio;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
645
config.guess
vendored
645
config.guess
vendored
@@ -1,14 +1,12 @@
|
||||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2007-01-15'
|
||||
timestamp='2013-06-10'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
@@ -17,26 +15,22 @@ timestamp='2007-01-15'
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
|
||||
# Originally written by Per Bothner <per@bothner.com>.
|
||||
# Please send patches to <config-patches@gnu.org>. Submit a context
|
||||
# diff and a properly formatted ChangeLog entry.
|
||||
# the same distribution terms that you use for the rest of that
|
||||
# program. This Exception is an additional permission under section 7
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
#
|
||||
# This script attempts to guess a canonical system name similar to
|
||||
# config.sub. If it succeeds, it prints the system name on stdout, and
|
||||
# exits with 0. Otherwise, it exits with 1.
|
||||
# Originally written by Per Bothner.
|
||||
#
|
||||
# The plan is that this can be called by configure scripts if you
|
||||
# don't specify an explicit build system type.
|
||||
# You can get the latest version of this script from:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
|
||||
#
|
||||
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
|
||||
|
||||
|
||||
me=`echo "$0" | sed -e 's,.*/,,'`
|
||||
|
||||
@@ -56,8 +50,7 @@ version="\
|
||||
GNU config.guess ($timestamp)
|
||||
|
||||
Originally written by Per Bothner.
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@@ -139,12 +132,33 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
|
||||
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
|
||||
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
|
||||
|
||||
case "${UNAME_SYSTEM}" in
|
||||
Linux|GNU|GNU/*)
|
||||
# If the system lacks a compiler, then just pick glibc.
|
||||
# We could probably try harder.
|
||||
LIBC=gnu
|
||||
|
||||
eval $set_cc_for_build
|
||||
cat <<-EOF > $dummy.c
|
||||
#include <features.h>
|
||||
#if defined(__UCLIBC__)
|
||||
LIBC=uclibc
|
||||
#elif defined(__dietlibc__)
|
||||
LIBC=dietlibc
|
||||
#else
|
||||
LIBC=gnu
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
|
||||
;;
|
||||
esac
|
||||
|
||||
# Note: order is significant - the case branches are not exclusive.
|
||||
|
||||
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
*:NetBSD:*:*)
|
||||
# NetBSD (nbsd) targets should (where applicable) match one or
|
||||
# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
|
||||
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
|
||||
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
|
||||
# switched to ELF, *-*-netbsd* would select the old
|
||||
# object file format. This provides both forward
|
||||
@@ -170,7 +184,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
|
||||
eval $set_cc_for_build
|
||||
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep __ELF__ >/dev/null
|
||||
| grep -q __ELF__
|
||||
then
|
||||
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
|
||||
# Return netbsd for either. FIX?
|
||||
@@ -180,7 +194,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
os=netbsd
|
||||
os=netbsd
|
||||
;;
|
||||
esac
|
||||
# The OS release
|
||||
@@ -201,6 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
|
||||
echo "${machine}-${os}${release}"
|
||||
exit ;;
|
||||
*:Bitrig:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
|
||||
echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:OpenBSD:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
|
||||
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
|
||||
@@ -223,7 +241,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
|
||||
;;
|
||||
*5.*)
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
|
||||
;;
|
||||
esac
|
||||
# According to Compaq, /usr/sbin/psrinfo has been available on
|
||||
@@ -269,7 +287,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# A Xn.n version is an unreleased experimental baselevel.
|
||||
# 1.2 uses "1.2" for uname -r.
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
exit ;;
|
||||
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
|
||||
exitcode=$?
|
||||
trap '' 0
|
||||
exit $exitcode ;;
|
||||
Alpha\ *:Windows_NT*:*)
|
||||
# How do we know it's Interix rather than the generic POSIX subsystem?
|
||||
# Should we change UNAME_MACHINE based on the output of uname instead
|
||||
@@ -295,12 +316,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
echo s390-ibm-zvmoe
|
||||
exit ;;
|
||||
*:OS400:*:*)
|
||||
echo powerpc-ibm-os400
|
||||
echo powerpc-ibm-os400
|
||||
exit ;;
|
||||
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
|
||||
echo arm-acorn-riscix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
arm:riscos:*:*|arm:RISCOS:*:*)
|
||||
arm*:riscos:*:*|arm*:RISCOS:*:*)
|
||||
echo arm-unknown-riscos
|
||||
exit ;;
|
||||
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
|
||||
@@ -324,14 +345,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
case `/usr/bin/uname -p` in
|
||||
sparc) echo sparc-icl-nx7; exit ;;
|
||||
esac ;;
|
||||
s390x:SunOS:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
sun4H:SunOS:5.*:*)
|
||||
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
|
||||
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
i86pc:SunOS:5.*:*)
|
||||
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
|
||||
echo i386-pc-auroraux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
|
||||
eval $set_cc_for_build
|
||||
SUN_ARCH="i386"
|
||||
# If there is a compiler, see if it is configured for 64-bit objects.
|
||||
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
|
||||
# This test works for both compilers.
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
SUN_ARCH="x86_64"
|
||||
fi
|
||||
fi
|
||||
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
sun4*:SunOS:6*:*)
|
||||
# According to config.sub, this is the proper way to canonicalize
|
||||
@@ -375,23 +415,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# MiNT. But MiNT is downward compatible to TOS, so this should
|
||||
# be no problem.
|
||||
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
exit ;;
|
||||
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
|
||||
echo m68k-milan-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
echo m68k-milan-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
|
||||
echo m68k-hades-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
echo m68k-hades-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
|
||||
echo m68k-unknown-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
echo m68k-unknown-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
m68k:machten:*:*)
|
||||
echo m68k-apple-machten${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@@ -461,8 +501,8 @@ EOF
|
||||
echo m88k-motorola-sysv3
|
||||
exit ;;
|
||||
AViiON:dgux:*:*)
|
||||
# DG/UX returns AViiON for all architectures
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
# DG/UX returns AViiON for all architectures
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
|
||||
then
|
||||
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
|
||||
@@ -475,7 +515,7 @@ EOF
|
||||
else
|
||||
echo i586-dg-dgux${UNAME_RELEASE}
|
||||
fi
|
||||
exit ;;
|
||||
exit ;;
|
||||
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
|
||||
echo m88k-dolphin-sysv3
|
||||
exit ;;
|
||||
@@ -532,7 +572,7 @@ EOF
|
||||
echo rs6000-ibm-aix3.2
|
||||
fi
|
||||
exit ;;
|
||||
*:AIX:*:[45])
|
||||
*:AIX:*:[4567])
|
||||
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
|
||||
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
|
||||
IBM_ARCH=rs6000
|
||||
@@ -575,52 +615,52 @@ EOF
|
||||
9000/[678][0-9][0-9])
|
||||
if [ -x /usr/bin/getconf ]; then
|
||||
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
|
||||
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
|
||||
case "${sc_cpu_version}" in
|
||||
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
|
||||
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
|
||||
532) # CPU_PA_RISC2_0
|
||||
case "${sc_kernel_bits}" in
|
||||
32) HP_ARCH="hppa2.0n" ;;
|
||||
64) HP_ARCH="hppa2.0w" ;;
|
||||
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
|
||||
case "${sc_cpu_version}" in
|
||||
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
|
||||
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
|
||||
532) # CPU_PA_RISC2_0
|
||||
case "${sc_kernel_bits}" in
|
||||
32) HP_ARCH="hppa2.0n" ;;
|
||||
64) HP_ARCH="hppa2.0w" ;;
|
||||
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
|
||||
esac ;;
|
||||
esac
|
||||
esac ;;
|
||||
esac
|
||||
fi
|
||||
if [ "${HP_ARCH}" = "" ]; then
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
|
||||
#define _HPUX_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#define _HPUX_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main ()
|
||||
{
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
long bits = sysconf(_SC_KERNEL_BITS);
|
||||
#endif
|
||||
long cpu = sysconf (_SC_CPU_VERSION);
|
||||
int main ()
|
||||
{
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
long bits = sysconf(_SC_KERNEL_BITS);
|
||||
#endif
|
||||
long cpu = sysconf (_SC_CPU_VERSION);
|
||||
|
||||
switch (cpu)
|
||||
{
|
||||
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
|
||||
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
|
||||
case CPU_PA_RISC2_0:
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
switch (bits)
|
||||
{
|
||||
case 64: puts ("hppa2.0w"); break;
|
||||
case 32: puts ("hppa2.0n"); break;
|
||||
default: puts ("hppa2.0"); break;
|
||||
} break;
|
||||
#else /* !defined(_SC_KERNEL_BITS) */
|
||||
puts ("hppa2.0"); break;
|
||||
#endif
|
||||
default: puts ("hppa1.0"); break;
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
switch (cpu)
|
||||
{
|
||||
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
|
||||
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
|
||||
case CPU_PA_RISC2_0:
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
switch (bits)
|
||||
{
|
||||
case 64: puts ("hppa2.0w"); break;
|
||||
case 32: puts ("hppa2.0n"); break;
|
||||
default: puts ("hppa2.0"); break;
|
||||
} break;
|
||||
#else /* !defined(_SC_KERNEL_BITS) */
|
||||
puts ("hppa2.0"); break;
|
||||
#endif
|
||||
default: puts ("hppa1.0"); break;
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
EOF
|
||||
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
|
||||
test -z "$HP_ARCH" && HP_ARCH=hppa
|
||||
@@ -640,7 +680,7 @@ EOF
|
||||
# => hppa64-hp-hpux11.23
|
||||
|
||||
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
|
||||
grep __LP64__ >/dev/null
|
||||
grep -q __LP64__
|
||||
then
|
||||
HP_ARCH="hppa2.0w"
|
||||
else
|
||||
@@ -711,22 +751,22 @@ EOF
|
||||
exit ;;
|
||||
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
|
||||
echo c1-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
|
||||
if getsysinfo -f scalar_acc
|
||||
then echo c32-convex-bsd
|
||||
else echo c2-convex-bsd
|
||||
fi
|
||||
exit ;;
|
||||
exit ;;
|
||||
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
|
||||
echo c34-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
|
||||
echo c38-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
|
||||
echo c4-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
CRAY*Y-MP:*:*:*)
|
||||
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
|
||||
exit ;;
|
||||
@@ -750,14 +790,14 @@ EOF
|
||||
exit ;;
|
||||
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
|
||||
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
|
||||
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
|
||||
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
5000:UNIX_System_V:4.*:*)
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
|
||||
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
|
||||
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
|
||||
@@ -769,37 +809,51 @@ EOF
|
||||
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:FreeBSD:*:*)
|
||||
case ${UNAME_MACHINE} in
|
||||
pc98)
|
||||
echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
case ${UNAME_PROCESSOR} in
|
||||
amd64)
|
||||
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
*)
|
||||
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
esac
|
||||
exit ;;
|
||||
i*:CYGWIN*:*)
|
||||
echo ${UNAME_MACHINE}-pc-cygwin
|
||||
exit ;;
|
||||
*:MINGW64*:*)
|
||||
echo ${UNAME_MACHINE}-pc-mingw64
|
||||
exit ;;
|
||||
*:MINGW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-mingw32
|
||||
exit ;;
|
||||
i*:MSYS*:*)
|
||||
echo ${UNAME_MACHINE}-pc-msys
|
||||
exit ;;
|
||||
i*:windows32*:*)
|
||||
# uname -m includes "-pc" on this system.
|
||||
echo ${UNAME_MACHINE}-mingw32
|
||||
# uname -m includes "-pc" on this system.
|
||||
echo ${UNAME_MACHINE}-mingw32
|
||||
exit ;;
|
||||
i*:PW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-pw32
|
||||
exit ;;
|
||||
x86:Interix*:[3456]*)
|
||||
echo i586-pc-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*)
|
||||
echo x86_64-unknown-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:Interix*:*)
|
||||
case ${UNAME_MACHINE} in
|
||||
x86)
|
||||
echo i586-pc-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
authenticamd | genuineintel | EM64T)
|
||||
echo x86_64-unknown-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
IA64)
|
||||
echo ia64-unknown-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
esac ;;
|
||||
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
|
||||
echo i${UNAME_MACHINE}-pc-mks
|
||||
exit ;;
|
||||
8664:Windows_NT:*)
|
||||
echo x86_64-pc-mks
|
||||
exit ;;
|
||||
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
|
||||
# How do we know it's Interix rather than the generic POSIX subsystem?
|
||||
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
|
||||
@@ -820,93 +874,21 @@ EOF
|
||||
exit ;;
|
||||
*:GNU:*:*)
|
||||
# the GNU system
|
||||
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
|
||||
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
|
||||
exit ;;
|
||||
*:GNU/*:*:*)
|
||||
# other systems with GNU libc and userland
|
||||
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
|
||||
exit ;;
|
||||
i*86:Minix:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-minix
|
||||
exit ;;
|
||||
arm*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
aarch64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
avr32*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
cris:Linux:*:*)
|
||||
echo cris-axis-linux-gnu
|
||||
exit ;;
|
||||
crisv32:Linux:*:*)
|
||||
echo crisv32-axis-linux-gnu
|
||||
exit ;;
|
||||
frv:Linux:*:*)
|
||||
echo frv-unknown-linux-gnu
|
||||
exit ;;
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
m32r*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
m68*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
mips:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#undef CPU
|
||||
#undef mips
|
||||
#undef mipsel
|
||||
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
|
||||
CPU=mipsel
|
||||
#else
|
||||
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
|
||||
CPU=mips
|
||||
#else
|
||||
CPU=
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
|
||||
/^CPU/{
|
||||
s: ::g
|
||||
p
|
||||
}'`"
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
|
||||
;;
|
||||
mips64:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#undef CPU
|
||||
#undef mips64
|
||||
#undef mips64el
|
||||
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
|
||||
CPU=mips64el
|
||||
#else
|
||||
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
|
||||
CPU=mips64
|
||||
#else
|
||||
CPU=
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
|
||||
/^CPU/{
|
||||
s: ::g
|
||||
p
|
||||
}'`"
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
|
||||
;;
|
||||
or32:Linux:*:*)
|
||||
echo or32-unknown-linux-gnu
|
||||
exit ;;
|
||||
ppc:Linux:*:*)
|
||||
echo powerpc-unknown-linux-gnu
|
||||
exit ;;
|
||||
ppc64:Linux:*:*)
|
||||
echo powerpc64-unknown-linux-gnu
|
||||
aarch64_be:Linux:*:*)
|
||||
UNAME_MACHINE=aarch64_be
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
alpha:Linux:*:*)
|
||||
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
|
||||
@@ -917,106 +899,132 @@ EOF
|
||||
EV6) UNAME_MACHINE=alphaev6 ;;
|
||||
EV67) UNAME_MACHINE=alphaev67 ;;
|
||||
EV68*) UNAME_MACHINE=alphaev68 ;;
|
||||
esac
|
||||
objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
|
||||
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
|
||||
esac
|
||||
objdump --private-headers /bin/sh | grep -q ld.so.1
|
||||
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
arc:Linux:*:* | arceb:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
arm*:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep -q __ARM_EABI__
|
||||
then
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
else
|
||||
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep -q __ARM_PCS_VFP
|
||||
then
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
|
||||
else
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
|
||||
fi
|
||||
fi
|
||||
exit ;;
|
||||
avr32*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
cris:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
|
||||
exit ;;
|
||||
crisv32:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
|
||||
exit ;;
|
||||
frv:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
hexagon:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
i*86:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
|
||||
exit ;;
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
m32r*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
m68*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
mips:Linux:*:* | mips64:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#undef CPU
|
||||
#undef ${UNAME_MACHINE}
|
||||
#undef ${UNAME_MACHINE}el
|
||||
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
|
||||
CPU=${UNAME_MACHINE}el
|
||||
#else
|
||||
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
|
||||
CPU=${UNAME_MACHINE}
|
||||
#else
|
||||
CPU=
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
|
||||
;;
|
||||
or1k:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
or32:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
padre:Linux:*:*)
|
||||
echo sparc-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
parisc64:Linux:*:* | hppa64:Linux:*:*)
|
||||
echo hppa64-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
parisc:Linux:*:* | hppa:Linux:*:*)
|
||||
# Look for CPU level
|
||||
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
|
||||
PA7*) echo hppa1.1-unknown-linux-gnu ;;
|
||||
PA8*) echo hppa2.0-unknown-linux-gnu ;;
|
||||
*) echo hppa-unknown-linux-gnu ;;
|
||||
PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
|
||||
PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
|
||||
*) echo hppa-unknown-linux-${LIBC} ;;
|
||||
esac
|
||||
exit ;;
|
||||
parisc64:Linux:*:* | hppa64:Linux:*:*)
|
||||
echo hppa64-unknown-linux-gnu
|
||||
ppc64:Linux:*:*)
|
||||
echo powerpc64-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
ppc:Linux:*:*)
|
||||
echo powerpc-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
ppc64le:Linux:*:*)
|
||||
echo powerpc64le-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
ppcle:Linux:*:*)
|
||||
echo powerpcle-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
s390:Linux:*:* | s390x:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-linux
|
||||
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
|
||||
exit ;;
|
||||
sh64*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
sh*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
sparc:Linux:*:* | sparc64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
tile*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
vax:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-dec-linux-gnu
|
||||
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
|
||||
exit ;;
|
||||
x86_64:Linux:*:*)
|
||||
echo x86_64-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
xtensa:Linux:*:*)
|
||||
echo xtensa-unknown-linux-gnu
|
||||
xtensa*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
i*86:Linux:*:*)
|
||||
# The BFD linker knows what the default object file format is, so
|
||||
# first see if it will tell us. cd to the root directory to prevent
|
||||
# problems with other programs or directories called `ld' in the path.
|
||||
# Set LC_ALL=C to ensure ld outputs messages in English.
|
||||
ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
|
||||
| sed -ne '/supported targets:/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/.*supported targets: *//
|
||||
s/ .*//
|
||||
p'`
|
||||
case "$ld_supported_targets" in
|
||||
elf32-i386)
|
||||
TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
|
||||
;;
|
||||
a.out-i386-linux)
|
||||
echo "${UNAME_MACHINE}-pc-linux-gnuaout"
|
||||
exit ;;
|
||||
coff-i386)
|
||||
echo "${UNAME_MACHINE}-pc-linux-gnucoff"
|
||||
exit ;;
|
||||
"")
|
||||
# Either a pre-BFD a.out linker (linux-gnuoldld) or
|
||||
# one that does not give us useful --help.
|
||||
echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
|
||||
exit ;;
|
||||
esac
|
||||
# Determine whether the default compiler is a.out or elf
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#include <features.h>
|
||||
#ifdef __ELF__
|
||||
# ifdef __GLIBC__
|
||||
# if __GLIBC__ >= 2
|
||||
LIBC=gnu
|
||||
# else
|
||||
LIBC=gnulibc1
|
||||
# endif
|
||||
# else
|
||||
LIBC=gnulibc1
|
||||
# endif
|
||||
#else
|
||||
#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
LIBC=gnu
|
||||
#else
|
||||
LIBC=gnuaout
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __dietlibc__
|
||||
LIBC=dietlibc
|
||||
#endif
|
||||
EOF
|
||||
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
|
||||
/^LIBC/{
|
||||
s: ::g
|
||||
p
|
||||
}'`"
|
||||
test x"${LIBC}" != x && {
|
||||
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
|
||||
exit
|
||||
}
|
||||
test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
|
||||
;;
|
||||
i*86:DYNIX/ptx:4*:*)
|
||||
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
|
||||
# earlier versions are messed up and put the nodename in both
|
||||
@@ -1024,11 +1032,11 @@ EOF
|
||||
echo i386-sequent-sysv4
|
||||
exit ;;
|
||||
i*86:UNIX_SV:4.2MP:2.*)
|
||||
# Unixware is an offshoot of SVR4, but it has its own version
|
||||
# number series starting with 2...
|
||||
# I am not positive that other SVR4 systems won't match this,
|
||||
# Unixware is an offshoot of SVR4, but it has its own version
|
||||
# number series starting with 2...
|
||||
# I am not positive that other SVR4 systems won't match this,
|
||||
# I just have to hope. -- rms.
|
||||
# Use sysv4.2uw... so that sysv4* matches it.
|
||||
# Use sysv4.2uw... so that sysv4* matches it.
|
||||
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
|
||||
exit ;;
|
||||
i*86:OS/2:*:*)
|
||||
@@ -1045,7 +1053,7 @@ EOF
|
||||
i*86:syllable:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-syllable
|
||||
exit ;;
|
||||
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
|
||||
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
|
||||
echo i386-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
i*86:*DOS:*:*)
|
||||
@@ -1060,7 +1068,7 @@ EOF
|
||||
fi
|
||||
exit ;;
|
||||
i*86:*:5:[678]*)
|
||||
# UnixWare 7.x, OpenUNIX and OpenServer 6.
|
||||
# UnixWare 7.x, OpenUNIX and OpenServer 6.
|
||||
case `/bin/uname -X | grep "^Machine"` in
|
||||
*486*) UNAME_MACHINE=i486 ;;
|
||||
*Pentium) UNAME_MACHINE=i586 ;;
|
||||
@@ -1088,10 +1096,13 @@ EOF
|
||||
exit ;;
|
||||
pc:*:*:*)
|
||||
# Left here for compatibility:
|
||||
# uname -m prints for DJGPP always 'pc', but it prints nothing about
|
||||
# the processor, so we play safe by assuming i386.
|
||||
echo i386-pc-msdosdjgpp
|
||||
exit ;;
|
||||
# uname -m prints for DJGPP always 'pc', but it prints nothing about
|
||||
# the processor, so we play safe by assuming i586.
|
||||
# Note: whatever this is, it MUST be the same as what config.sub
|
||||
# prints for the "djgpp" host, or else GDB configury will decide that
|
||||
# this is a cross-build.
|
||||
echo i586-pc-msdosdjgpp
|
||||
exit ;;
|
||||
Intel:Mach:3*:*)
|
||||
echo i386-pc-mach3
|
||||
exit ;;
|
||||
@@ -1126,8 +1137,18 @@ EOF
|
||||
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
|
||||
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
|
||||
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& { echo i486-ncr-sysv4; exit; } ;;
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& { echo i486-ncr-sysv4; exit; } ;;
|
||||
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
|
||||
OS_REL='.3'
|
||||
test -r /etc/.relid \
|
||||
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& { echo i486-ncr-sysv4.3${OS_REL}; exit; }
|
||||
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
|
||||
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; }
|
||||
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
|
||||
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
|
||||
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
|
||||
echo m68k-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@@ -1140,7 +1161,7 @@ EOF
|
||||
rs6000:LynxOS:2.*:*)
|
||||
echo rs6000-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
|
||||
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
|
||||
echo powerpc-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
SM[BE]S:UNIX_SV:*:*)
|
||||
@@ -1160,10 +1181,10 @@ EOF
|
||||
echo ns32k-sni-sysv
|
||||
fi
|
||||
exit ;;
|
||||
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <Richard.M.Bartel@ccMail.Census.GOV>
|
||||
echo i586-unisys-sysv4
|
||||
exit ;;
|
||||
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <Richard.M.Bartel@ccMail.Census.GOV>
|
||||
echo i586-unisys-sysv4
|
||||
exit ;;
|
||||
*:UNIX_System_V:4*:FTX*)
|
||||
# From Gerald Hewes <hewes@openmarket.com>.
|
||||
# How about differentiating between stratus architectures? -djm
|
||||
@@ -1189,11 +1210,11 @@ EOF
|
||||
exit ;;
|
||||
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
|
||||
if [ -d /usr/nec ]; then
|
||||
echo mips-nec-sysv${UNAME_RELEASE}
|
||||
echo mips-nec-sysv${UNAME_RELEASE}
|
||||
else
|
||||
echo mips-unknown-sysv${UNAME_RELEASE}
|
||||
echo mips-unknown-sysv${UNAME_RELEASE}
|
||||
fi
|
||||
exit ;;
|
||||
exit ;;
|
||||
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
|
||||
echo powerpc-be-beos
|
||||
exit ;;
|
||||
@@ -1203,6 +1224,12 @@ EOF
|
||||
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
|
||||
echo i586-pc-beos
|
||||
exit ;;
|
||||
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
|
||||
echo i586-pc-haiku
|
||||
exit ;;
|
||||
x86_64:Haiku:*:*)
|
||||
echo x86_64-unknown-haiku
|
||||
exit ;;
|
||||
SX-4:SUPER-UX:*:*)
|
||||
echo sx4-nec-superux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@@ -1229,9 +1256,21 @@ EOF
|
||||
exit ;;
|
||||
*:Darwin:*:*)
|
||||
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
|
||||
case $UNAME_PROCESSOR in
|
||||
unknown) UNAME_PROCESSOR=powerpc ;;
|
||||
esac
|
||||
eval $set_cc_for_build
|
||||
if test "$UNAME_PROCESSOR" = unknown ; then
|
||||
UNAME_PROCESSOR=powerpc
|
||||
fi
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
case $UNAME_PROCESSOR in
|
||||
i386) UNAME_PROCESSOR=x86_64 ;;
|
||||
powerpc) UNAME_PROCESSOR=powerpc64 ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:procnto*:*:* | *:QNX:[0123456789]*:*)
|
||||
@@ -1245,7 +1284,10 @@ EOF
|
||||
*:QNX:*:4*)
|
||||
echo i386-pc-qnx
|
||||
exit ;;
|
||||
NSE-?:NONSTOP_KERNEL:*:*)
|
||||
NEO-?:NONSTOP_KERNEL:*:*)
|
||||
echo neo-tandem-nsk${UNAME_RELEASE}
|
||||
exit ;;
|
||||
NSE-*:NONSTOP_KERNEL:*:*)
|
||||
echo nse-tandem-nsk${UNAME_RELEASE}
|
||||
exit ;;
|
||||
NSR-?:NONSTOP_KERNEL:*:*)
|
||||
@@ -1290,13 +1332,13 @@ EOF
|
||||
echo pdp10-unknown-its
|
||||
exit ;;
|
||||
SEI:*:*:SEIUX)
|
||||
echo mips-sei-seiux${UNAME_RELEASE}
|
||||
echo mips-sei-seiux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:DragonFly:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
|
||||
exit ;;
|
||||
*:*VMS:*:*)
|
||||
UNAME_MACHINE=`(uname -p) 2>/dev/null`
|
||||
UNAME_MACHINE=`(uname -p) 2>/dev/null`
|
||||
case "${UNAME_MACHINE}" in
|
||||
A*) echo alpha-dec-vms ; exit ;;
|
||||
I*) echo ia64-dec-vms ; exit ;;
|
||||
@@ -1311,11 +1353,14 @@ EOF
|
||||
i*86:rdos:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-rdos
|
||||
exit ;;
|
||||
i*86:AROS:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-aros
|
||||
exit ;;
|
||||
x86_64:VMkernel:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-esx
|
||||
exit ;;
|
||||
esac
|
||||
|
||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
|
||||
|
||||
eval $set_cc_for_build
|
||||
cat >$dummy.c <<EOF
|
||||
#ifdef _SEQUENT_
|
||||
@@ -1333,11 +1378,11 @@ main ()
|
||||
#include <sys/param.h>
|
||||
printf ("m68k-sony-newsos%s\n",
|
||||
#ifdef NEWSOS4
|
||||
"4"
|
||||
"4"
|
||||
#else
|
||||
""
|
||||
""
|
||||
#endif
|
||||
); exit (0);
|
||||
); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1471,9 +1516,9 @@ This script, last modified $timestamp, has failed to recognize
|
||||
the operating system you are using. It is advised that you
|
||||
download the most up to date version of the config scripts from
|
||||
|
||||
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
|
||||
and
|
||||
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
|
||||
|
||||
If the version you run ($0) is already up to date, please
|
||||
send the following data and any information you think might be
|
||||
|
||||
379
config.sub
vendored
379
config.sub
vendored
@@ -1,44 +1,40 @@
|
||||
#! /bin/sh
|
||||
# Configuration validation subroutine script.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2007-01-18'
|
||||
timestamp='2013-10-01'
|
||||
|
||||
# This file is (in principle) common to ALL GNU software.
|
||||
# The presence of a machine in this file suggests that SOME GNU software
|
||||
# can handle that machine. It does not imply ALL GNU software can.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
# the same distribution terms that you use for the rest of that
|
||||
# program. This Exception is an additional permission under section 7
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
|
||||
|
||||
# Please send patches to <config-patches@gnu.org>. Submit a context
|
||||
# diff and a properly formatted ChangeLog entry.
|
||||
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
|
||||
#
|
||||
# Configuration subroutine to validate and canonicalize a configuration type.
|
||||
# Supply the specified configuration type as an argument.
|
||||
# If it is invalid, we print an error message on stderr and exit with code 1.
|
||||
# Otherwise, we print the canonical config type on stdout and succeed.
|
||||
|
||||
# You can get the latest version of this script from:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
|
||||
|
||||
# This file is supposed to be the same for all GNU packages
|
||||
# and recognize all the CPU types, system types and aliases
|
||||
# that are meaningful with *any* GNU software.
|
||||
@@ -72,8 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
|
||||
version="\
|
||||
GNU config.sub ($timestamp)
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@@ -120,12 +115,18 @@ esac
|
||||
# Here we must recognize all the valid KERNEL-OS combinations.
|
||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
case $maybe_os in
|
||||
nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
|
||||
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
|
||||
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
|
||||
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
|
||||
knetbsd*-gnu* | netbsd*-gnu* | \
|
||||
kopensolaris*-gnu* | \
|
||||
storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
os=-$maybe_os
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
;;
|
||||
android-linux)
|
||||
os=-linux-android
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
|
||||
;;
|
||||
*)
|
||||
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
|
||||
if [ $basic_machine != $1 ]
|
||||
@@ -148,10 +149,13 @@ case $os in
|
||||
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
|
||||
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
|
||||
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
|
||||
-apple | -axis | -knuth | -cray)
|
||||
-apple | -axis | -knuth | -cray | -microblaze*)
|
||||
os=
|
||||
basic_machine=$1
|
||||
;;
|
||||
-bluegene*)
|
||||
os=-cnk
|
||||
;;
|
||||
-sim | -cisco | -oki | -wec | -winbond)
|
||||
os=
|
||||
basic_machine=$1
|
||||
@@ -166,10 +170,10 @@ case $os in
|
||||
os=-chorusos
|
||||
basic_machine=$1
|
||||
;;
|
||||
-chorusrdb)
|
||||
os=-chorusrdb
|
||||
-chorusrdb)
|
||||
os=-chorusrdb
|
||||
basic_machine=$1
|
||||
;;
|
||||
;;
|
||||
-hiux*)
|
||||
os=-hiuxwe2
|
||||
;;
|
||||
@@ -214,6 +218,12 @@ case $os in
|
||||
-isc*)
|
||||
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
|
||||
;;
|
||||
-lynx*178)
|
||||
os=-lynxos178
|
||||
;;
|
||||
-lynx*5)
|
||||
os=-lynxos5
|
||||
;;
|
||||
-lynx*)
|
||||
os=-lynxos
|
||||
;;
|
||||
@@ -238,24 +248,35 @@ case $basic_machine in
|
||||
# Some are omitted here because they have special meanings below.
|
||||
1750a | 580 \
|
||||
| a29k \
|
||||
| aarch64 | aarch64_be \
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| am33_2.0 \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
|
||||
| arc | arceb \
|
||||
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
|
||||
| avr | avr32 \
|
||||
| be32 | be64 \
|
||||
| bfin \
|
||||
| c4x | clipper \
|
||||
| c4x | c8051 | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| epiphany \
|
||||
| fido | fr30 | frv \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| hexagon \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
| ip2k | iq2000 \
|
||||
| k1om \
|
||||
| le32 | le64 \
|
||||
| lm32 \
|
||||
| m32c | m32r | m32rle | m68000 | m68k | m88k \
|
||||
| maxq | mb | microblaze | mcore | mep \
|
||||
| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
|
||||
| mips | mipsbe | mipseb | mipsel | mipsle \
|
||||
| mips16 \
|
||||
| mips64 | mips64el \
|
||||
| mips64vr | mips64vrel \
|
||||
| mips64octeon | mips64octeonel \
|
||||
| mips64orion | mips64orionel \
|
||||
| mips64r5900 | mips64r5900el \
|
||||
| mips64vr | mips64vrel \
|
||||
| mips64vr4100 | mips64vr4100el \
|
||||
| mips64vr4300 | mips64vr4300el \
|
||||
| mips64vr5000 | mips64vr5000el \
|
||||
@@ -266,31 +287,45 @@ case $basic_machine in
|
||||
| mipsisa64r2 | mipsisa64r2el \
|
||||
| mipsisa64sb1 | mipsisa64sb1el \
|
||||
| mipsisa64sr71k | mipsisa64sr71kel \
|
||||
| mipsr5900 | mipsr5900el \
|
||||
| mipstx39 | mipstx39el \
|
||||
| mn10200 | mn10300 \
|
||||
| moxie \
|
||||
| mt \
|
||||
| msp430 \
|
||||
| nios | nios2 \
|
||||
| nds32 | nds32le | nds32be \
|
||||
| nios | nios2 | nios2eb | nios2el \
|
||||
| ns16k | ns32k \
|
||||
| or32 \
|
||||
| open8 \
|
||||
| or1k | or32 \
|
||||
| pdp10 | pdp11 | pj | pjl \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle \
|
||||
| pyramid \
|
||||
| rl78 | rx \
|
||||
| score \
|
||||
| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh64 | sh64le \
|
||||
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
|
||||
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
|
||||
| spu | strongarm \
|
||||
| tahoe | thumb | tic4x | tic80 | tron \
|
||||
| v850 | v850e \
|
||||
| spu \
|
||||
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
|
||||
| ubicom32 \
|
||||
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
|
||||
| we32k \
|
||||
| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
|
||||
| z8k)
|
||||
| x86 | xc16x | xstormy16 | xtensa \
|
||||
| z8k | z80)
|
||||
basic_machine=$basic_machine-unknown
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12)
|
||||
# Motorola 68HC11/12.
|
||||
c54x)
|
||||
basic_machine=tic54x-unknown
|
||||
;;
|
||||
c55x)
|
||||
basic_machine=tic55x-unknown
|
||||
;;
|
||||
c6x)
|
||||
basic_machine=tic6x-unknown
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
;;
|
||||
@@ -300,6 +335,21 @@ case $basic_machine in
|
||||
basic_machine=mt-unknown
|
||||
;;
|
||||
|
||||
strongarm | thumb | xscale)
|
||||
basic_machine=arm-unknown
|
||||
;;
|
||||
xgate)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
;;
|
||||
xscaleeb)
|
||||
basic_machine=armeb-unknown
|
||||
;;
|
||||
|
||||
xscaleel)
|
||||
basic_machine=armel-unknown
|
||||
;;
|
||||
|
||||
# We use `pc' rather than `unknown'
|
||||
# because (1) that's what they normally are, and
|
||||
# (2) the word "unknown" tends to confuse beginning users.
|
||||
@@ -314,29 +364,38 @@ case $basic_machine in
|
||||
# Recognize the basic CPU types with company name.
|
||||
580-* \
|
||||
| a29k-* \
|
||||
| aarch64-* | aarch64_be-* \
|
||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* | avr32-* \
|
||||
| be32-* | be64-* \
|
||||
| bfin-* | bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
|
||||
| clipper-* | craynv-* | cydra-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* \
|
||||
| c8051-* | clipper-* | craynv-* | cydra-* \
|
||||
| d10v-* | d30v-* | dlx-* \
|
||||
| elxsi-* \
|
||||
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
| hexagon-* \
|
||||
| i*86-* | i860-* | i960-* | ia64-* \
|
||||
| ip2k-* | iq2000-* \
|
||||
| k1om-* \
|
||||
| le32-* | le64-* \
|
||||
| lm32-* \
|
||||
| m32c-* | m32r-* | m32rle-* \
|
||||
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
|
||||
| m88110-* | m88k-* | maxq-* | mcore-* \
|
||||
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
|
||||
| microblaze-* | microblazeel-* \
|
||||
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
|
||||
| mips16-* \
|
||||
| mips64-* | mips64el-* \
|
||||
| mips64vr-* | mips64vrel-* \
|
||||
| mips64octeon-* | mips64octeonel-* \
|
||||
| mips64orion-* | mips64orionel-* \
|
||||
| mips64r5900-* | mips64r5900el-* \
|
||||
| mips64vr-* | mips64vrel-* \
|
||||
| mips64vr4100-* | mips64vr4100el-* \
|
||||
| mips64vr4300-* | mips64vr4300el-* \
|
||||
| mips64vr5000-* | mips64vr5000el-* \
|
||||
@@ -347,31 +406,41 @@ case $basic_machine in
|
||||
| mipsisa64r2-* | mipsisa64r2el-* \
|
||||
| mipsisa64sb1-* | mipsisa64sb1el-* \
|
||||
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
|
||||
| mipsr5900-* | mipsr5900el-* \
|
||||
| mipstx39-* | mipstx39el-* \
|
||||
| mmix-* \
|
||||
| mt-* \
|
||||
| msp430-* \
|
||||
| nios-* | nios2-* \
|
||||
| nds32-* | nds32le-* | nds32be-* \
|
||||
| nios-* | nios2-* | nios2eb-* | nios2el-* \
|
||||
| none-* | np1-* | ns16k-* | ns32k-* \
|
||||
| open8-* \
|
||||
| orion-* \
|
||||
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
|
||||
| pyramid-* \
|
||||
| romp-* | rs6000-* \
|
||||
| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
|
||||
| rl78-* | romp-* | rs6000-* | rx-* \
|
||||
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
|
||||
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
|
||||
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
|
||||
| sparclite-* \
|
||||
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
|
||||
| tahoe-* | thumb-* \
|
||||
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
|
||||
| tahoe-* \
|
||||
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
|
||||
| tile*-* \
|
||||
| tron-* \
|
||||
| v850-* | v850e-* | vax-* \
|
||||
| ubicom32-* \
|
||||
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
|
||||
| vax-* \
|
||||
| we32k-* \
|
||||
| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
|
||||
| xstormy16-* | xtensa-* \
|
||||
| x86-* | x86_64-* | xc16x-* | xps100-* \
|
||||
| xstormy16-* | xtensa*-* \
|
||||
| ymp-* \
|
||||
| z8k-*)
|
||||
| z8k-* | z80-*)
|
||||
;;
|
||||
# Recognize the basic CPU types without company name, with glob match.
|
||||
xtensa*)
|
||||
basic_machine=$basic_machine-unknown
|
||||
;;
|
||||
# Recognize the various machine names and aliases which stand
|
||||
# for a CPU type and a company and sometimes even an OS.
|
||||
@@ -389,7 +458,7 @@ case $basic_machine in
|
||||
basic_machine=a29k-amd
|
||||
os=-udi
|
||||
;;
|
||||
abacus)
|
||||
abacus)
|
||||
basic_machine=abacus-unknown
|
||||
;;
|
||||
adobe68k)
|
||||
@@ -435,6 +504,10 @@ case $basic_machine in
|
||||
basic_machine=m68k-apollo
|
||||
os=-bsd
|
||||
;;
|
||||
aros)
|
||||
basic_machine=i386-pc
|
||||
os=-aros
|
||||
;;
|
||||
aux)
|
||||
basic_machine=m68k-apple
|
||||
os=-aux
|
||||
@@ -443,10 +516,35 @@ case $basic_machine in
|
||||
basic_machine=ns32k-sequent
|
||||
os=-dynix
|
||||
;;
|
||||
blackfin)
|
||||
basic_machine=bfin-unknown
|
||||
os=-linux
|
||||
;;
|
||||
blackfin-*)
|
||||
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
os=-linux
|
||||
;;
|
||||
bluegene*)
|
||||
basic_machine=powerpc-ibm
|
||||
os=-cnk
|
||||
;;
|
||||
c54x-*)
|
||||
basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
c55x-*)
|
||||
basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
c6x-*)
|
||||
basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
c90)
|
||||
basic_machine=c90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
cegcc)
|
||||
basic_machine=arm-unknown
|
||||
os=-cegcc
|
||||
;;
|
||||
convex-c1)
|
||||
basic_machine=c1-convex
|
||||
os=-bsd
|
||||
@@ -475,8 +573,8 @@ case $basic_machine in
|
||||
basic_machine=craynv-cray
|
||||
os=-unicosmp
|
||||
;;
|
||||
cr16c)
|
||||
basic_machine=cr16c-unknown
|
||||
cr16 | cr16-*)
|
||||
basic_machine=cr16-unknown
|
||||
os=-elf
|
||||
;;
|
||||
crds | unos)
|
||||
@@ -514,6 +612,10 @@ case $basic_machine in
|
||||
basic_machine=m88k-motorola
|
||||
os=-sysv3
|
||||
;;
|
||||
dicos)
|
||||
basic_machine=i686-pc
|
||||
os=-dicos
|
||||
;;
|
||||
djgpp)
|
||||
basic_machine=i586-pc
|
||||
os=-msdosdjgpp
|
||||
@@ -629,7 +731,6 @@ case $basic_machine in
|
||||
i370-ibm* | ibm*)
|
||||
basic_machine=i370-ibm
|
||||
;;
|
||||
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
|
||||
i*86v32)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||
os=-sysv32
|
||||
@@ -668,6 +769,14 @@ case $basic_machine in
|
||||
basic_machine=m68k-isi
|
||||
os=-sysv
|
||||
;;
|
||||
m68knommu)
|
||||
basic_machine=m68k-unknown
|
||||
os=-linux
|
||||
;;
|
||||
m68knommu-*)
|
||||
basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
os=-linux
|
||||
;;
|
||||
m88k-omron*)
|
||||
basic_machine=m88k-omron
|
||||
;;
|
||||
@@ -679,10 +788,21 @@ case $basic_machine in
|
||||
basic_machine=ns32k-utek
|
||||
os=-sysv
|
||||
;;
|
||||
microblaze*)
|
||||
basic_machine=microblaze-xilinx
|
||||
;;
|
||||
mingw64)
|
||||
basic_machine=x86_64-pc
|
||||
os=-mingw64
|
||||
;;
|
||||
mingw32)
|
||||
basic_machine=i386-pc
|
||||
basic_machine=i686-pc
|
||||
os=-mingw32
|
||||
;;
|
||||
mingw32ce)
|
||||
basic_machine=arm-unknown
|
||||
os=-mingw32ce
|
||||
;;
|
||||
miniframe)
|
||||
basic_machine=m68000-convergent
|
||||
;;
|
||||
@@ -711,10 +831,18 @@ case $basic_machine in
|
||||
ms1-*)
|
||||
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
|
||||
;;
|
||||
msys)
|
||||
basic_machine=i686-pc
|
||||
os=-msys
|
||||
;;
|
||||
mvs)
|
||||
basic_machine=i370-ibm
|
||||
os=-mvs
|
||||
;;
|
||||
nacl)
|
||||
basic_machine=le32-unknown
|
||||
os=-nacl
|
||||
;;
|
||||
ncr3000)
|
||||
basic_machine=i486-ncr
|
||||
os=-sysv4
|
||||
@@ -779,6 +907,12 @@ case $basic_machine in
|
||||
np1)
|
||||
basic_machine=np1-gould
|
||||
;;
|
||||
neo-tandem)
|
||||
basic_machine=neo-tandem
|
||||
;;
|
||||
nse-tandem)
|
||||
basic_machine=nse-tandem
|
||||
;;
|
||||
nsr-tandem)
|
||||
basic_machine=nsr-tandem
|
||||
;;
|
||||
@@ -809,6 +943,14 @@ case $basic_machine in
|
||||
basic_machine=i860-intel
|
||||
os=-osf
|
||||
;;
|
||||
parisc)
|
||||
basic_machine=hppa-unknown
|
||||
os=-linux
|
||||
;;
|
||||
parisc-*)
|
||||
basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
os=-linux
|
||||
;;
|
||||
pbd)
|
||||
basic_machine=sparc-tti
|
||||
;;
|
||||
@@ -853,9 +995,10 @@ case $basic_machine in
|
||||
;;
|
||||
power) basic_machine=power-ibm
|
||||
;;
|
||||
ppc) basic_machine=powerpc-unknown
|
||||
ppc | ppcbe) basic_machine=powerpc-unknown
|
||||
;;
|
||||
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
ppc-* | ppcbe-*)
|
||||
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
ppcle | powerpclittle | ppc-le | powerpc-little)
|
||||
basic_machine=powerpcle-unknown
|
||||
@@ -880,7 +1023,11 @@ case $basic_machine in
|
||||
basic_machine=i586-unknown
|
||||
os=-pw32
|
||||
;;
|
||||
rdos)
|
||||
rdos | rdos64)
|
||||
basic_machine=x86_64-pc
|
||||
os=-rdos
|
||||
;;
|
||||
rdos32)
|
||||
basic_machine=i386-pc
|
||||
os=-rdos
|
||||
;;
|
||||
@@ -949,6 +1096,9 @@ case $basic_machine in
|
||||
basic_machine=i860-stratus
|
||||
os=-sysv4
|
||||
;;
|
||||
strongarm-* | thumb-*)
|
||||
basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
sun2)
|
||||
basic_machine=m68000-sun
|
||||
;;
|
||||
@@ -1005,17 +1155,9 @@ case $basic_machine in
|
||||
basic_machine=t90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
tic54x | c54x*)
|
||||
basic_machine=tic54x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic55x | c55x*)
|
||||
basic_machine=tic55x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic6x | c6x*)
|
||||
basic_machine=tic6x-unknown
|
||||
os=-coff
|
||||
tile*)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-linux-gnu
|
||||
;;
|
||||
tx39)
|
||||
basic_machine=mipstx39-unknown
|
||||
@@ -1084,6 +1226,9 @@ case $basic_machine in
|
||||
xps | xps100)
|
||||
basic_machine=xps100-honeywell
|
||||
;;
|
||||
xscale-* | xscalee[bl]-*)
|
||||
basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
|
||||
;;
|
||||
ymp)
|
||||
basic_machine=ymp-cray
|
||||
os=-unicos
|
||||
@@ -1092,6 +1237,10 @@ case $basic_machine in
|
||||
basic_machine=z8k-unknown
|
||||
os=-sim
|
||||
;;
|
||||
z80-*-coff)
|
||||
basic_machine=z80-unknown
|
||||
os=-sim
|
||||
;;
|
||||
none)
|
||||
basic_machine=none-none
|
||||
os=-none
|
||||
@@ -1130,7 +1279,7 @@ case $basic_machine in
|
||||
we32k)
|
||||
basic_machine=we32k-att
|
||||
;;
|
||||
sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||
sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||
basic_machine=sh-unknown
|
||||
;;
|
||||
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
|
||||
@@ -1177,9 +1326,12 @@ esac
|
||||
if [ x"$os" != x"" ]
|
||||
then
|
||||
case $os in
|
||||
# First match some system type aliases
|
||||
# that might get confused with valid system types.
|
||||
# First match some system type aliases
|
||||
# that might get confused with valid system types.
|
||||
# -solaris* is a basic system type, with this one exception.
|
||||
-auroraux)
|
||||
os=-auroraux
|
||||
;;
|
||||
-solaris1 | -solaris1.*)
|
||||
os=`echo $os | sed -e 's|solaris1|sunos4|'`
|
||||
;;
|
||||
@@ -1200,21 +1352,23 @@ case $os in
|
||||
# Each alternative MUST END IN A *, to match a version number.
|
||||
# -sysv* is not here because it comes later, after sysvr4.
|
||||
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
|
||||
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
|
||||
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
|
||||
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
|
||||
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
|
||||
| -sym* | -kopensolaris* | -plan9* \
|
||||
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
|
||||
| -aos* \
|
||||
| -aos* | -aros* \
|
||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
|
||||
| -openbsd* | -solidbsd* \
|
||||
| -bitrig* | -openbsd* | -solidbsd* \
|
||||
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
|
||||
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* \
|
||||
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
|
||||
| -chorusos* | -chorusrdb* | -cegcc* \
|
||||
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
|
||||
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
|
||||
| -uxpv* | -beos* | -mpeix* | -udk* \
|
||||
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
|
||||
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
|
||||
@@ -1222,7 +1376,7 @@ case $os in
|
||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-qnx*)
|
||||
@@ -1261,7 +1415,7 @@ case $os in
|
||||
-opened*)
|
||||
os=-openedition
|
||||
;;
|
||||
-os400*)
|
||||
-os400*)
|
||||
os=-os400
|
||||
;;
|
||||
-wince*)
|
||||
@@ -1310,7 +1464,7 @@ case $os in
|
||||
-sinix*)
|
||||
os=-sysv4
|
||||
;;
|
||||
-tpf*)
|
||||
-tpf*)
|
||||
os=-tpf
|
||||
;;
|
||||
-triton*)
|
||||
@@ -1346,12 +1500,14 @@ case $os in
|
||||
-aros*)
|
||||
os=-aros
|
||||
;;
|
||||
-kaos*)
|
||||
os=-kaos
|
||||
;;
|
||||
-zvmoe)
|
||||
os=-zvmoe
|
||||
;;
|
||||
-dicos*)
|
||||
os=-dicos
|
||||
;;
|
||||
-nacl*)
|
||||
;;
|
||||
-none)
|
||||
;;
|
||||
*)
|
||||
@@ -1374,10 +1530,10 @@ else
|
||||
# system, and we'll never get to this point.
|
||||
|
||||
case $basic_machine in
|
||||
score-*)
|
||||
score-*)
|
||||
os=-elf
|
||||
;;
|
||||
spu-*)
|
||||
spu-*)
|
||||
os=-elf
|
||||
;;
|
||||
*-acorn)
|
||||
@@ -1389,8 +1545,23 @@ case $basic_machine in
|
||||
arm*-semi)
|
||||
os=-aout
|
||||
;;
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
c8051-*)
|
||||
os=-elf
|
||||
;;
|
||||
hexagon-*)
|
||||
os=-elf
|
||||
;;
|
||||
tic54x-*)
|
||||
os=-coff
|
||||
;;
|
||||
tic55x-*)
|
||||
os=-coff
|
||||
;;
|
||||
tic6x-*)
|
||||
os=-coff
|
||||
;;
|
||||
# This must come before the *-dec entry.
|
||||
pdp10-*)
|
||||
@@ -1410,14 +1581,11 @@ case $basic_machine in
|
||||
;;
|
||||
m68000-sun)
|
||||
os=-sunos3
|
||||
# This also exists in the configure program, but was not the
|
||||
# default.
|
||||
# os=-sunos4
|
||||
;;
|
||||
m68*-cisco)
|
||||
os=-aout
|
||||
;;
|
||||
mep-*)
|
||||
mep-*)
|
||||
os=-elf
|
||||
;;
|
||||
mips*-cisco)
|
||||
@@ -1426,6 +1594,9 @@ case $basic_machine in
|
||||
mips*-*)
|
||||
os=-elf
|
||||
;;
|
||||
or1k-*)
|
||||
os=-elf
|
||||
;;
|
||||
or32-*)
|
||||
os=-coff
|
||||
;;
|
||||
@@ -1444,7 +1615,7 @@ case $basic_machine in
|
||||
*-ibm)
|
||||
os=-aix
|
||||
;;
|
||||
*-knuth)
|
||||
*-knuth)
|
||||
os=-mmixware
|
||||
;;
|
||||
*-wec)
|
||||
@@ -1549,7 +1720,7 @@ case $basic_machine in
|
||||
-sunos*)
|
||||
vendor=sun
|
||||
;;
|
||||
-aix*)
|
||||
-cnk*|-aix*)
|
||||
vendor=ibm
|
||||
;;
|
||||
-beos*)
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
# of the platform checks have been taken straight from OpenSSH's configure.ac
|
||||
# Huge thanks to them for dealing with the horrible platform-specifics :)
|
||||
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(buffer.c)
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT
|
||||
AC_CONFIG_SRCDIR(buffer.c)
|
||||
|
||||
OLDCFLAGS=$CFLAGS
|
||||
# Checks for programs.
|
||||
@@ -20,7 +21,7 @@ AC_SUBST(LD)
|
||||
|
||||
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
|
||||
AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
|
||||
CFLAGS="-Os -W -Wall"
|
||||
CFLAGS="-Os -W -Wall -Wno-pointer-sign"
|
||||
fi
|
||||
|
||||
# large file support is useful for scp
|
||||
@@ -211,7 +212,7 @@ AC_ARG_ENABLE(shadow,
|
||||
# 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])
|
||||
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])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@@ -221,7 +222,8 @@ AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_TYPES([uint16_t, u_int16_t, struct sockaddr_storage])
|
||||
AC_CHECK_TYPES([uint8_t, u_int8_t, uint16_t, u_int16_t, uint32_t, u_int32_t])
|
||||
AC_CHECK_TYPES([struct sockaddr_storage])
|
||||
AC_CHECK_TYPE([socklen_t], ,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
|
||||
@@ -231,15 +233,15 @@ AC_CHECK_TYPE([socklen_t], ,[
|
||||
curl_cv_socklen_t_equiv=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
],[
|
||||
]],[[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
],[
|
||||
]])],[
|
||||
curl_cv_socklen_t_equiv="$t"
|
||||
break
|
||||
])
|
||||
@@ -259,12 +261,11 @@ AC_CHECK_TYPE([socklen_t], ,[
|
||||
# for the fake-rfc2553 stuff - straight from OpenSSH
|
||||
|
||||
AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
],
|
||||
[ struct sockaddr_storage s; ],
|
||||
]],
|
||||
[[ struct sockaddr_storage s; ]])],
|
||||
[ ac_cv_have_struct_sockaddr_storage="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_storage="no" ]
|
||||
)
|
||||
@@ -274,12 +275,11 @@ if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
],
|
||||
[ struct sockaddr_in6 s; s.sin6_family = 0; ],
|
||||
]],
|
||||
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
|
||||
[ ac_cv_have_struct_sockaddr_in6="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_in6="no" ]
|
||||
)
|
||||
@@ -289,12 +289,11 @@ if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
],
|
||||
[ struct in6_addr s; s.s6_addr[0] = 0; ],
|
||||
]],
|
||||
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
|
||||
[ ac_cv_have_struct_in6_addr="yes" ],
|
||||
[ ac_cv_have_struct_in6_addr="no" ]
|
||||
)
|
||||
@@ -304,13 +303,12 @@ if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
],
|
||||
[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ],
|
||||
]],
|
||||
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
|
||||
[ ac_cv_have_struct_addrinfo="yes" ],
|
||||
[ ac_cv_have_struct_addrinfo="no" ]
|
||||
)
|
||||
@@ -323,15 +321,15 @@ fi
|
||||
# IRIX has a const char return value for gai_strerror()
|
||||
AC_CHECK_FUNCS(gai_strerror,[
|
||||
AC_DEFINE(HAVE_GAI_STRERROR)
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
const char *gai_strerror(int);],[
|
||||
const char *gai_strerror(int);]],[[
|
||||
char *str;
|
||||
|
||||
str = gai_strerror(0);],[
|
||||
str = gai_strerror(0);]])],[
|
||||
AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
|
||||
[Define if gai_strerror() returns const char *])])])
|
||||
|
||||
@@ -363,16 +361,30 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
# OS X monotonic time
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
AC_CHECK_FUNCS(mach_absolute_time)
|
||||
|
||||
AC_ARG_ENABLE(bundled-libtom,
|
||||
[ --enable-bundled-libtom Use bundled libtomcrypt/libtommath even if a system version exists],
|
||||
[
|
||||
BUNDLED_LIBTOM=1
|
||||
AC_MSG_NOTICE(Forcing 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.],
|
||||
[
|
||||
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])] )
|
||||
fi
|
||||
],
|
||||
[
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1)
|
||||
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)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -380,6 +392,7 @@ if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom)
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBTOM_LIBS)
|
||||
AC_SUBST(BUNDLED_LIBTOM)
|
||||
|
||||
dnl Added from OpenSSH 3.6.1p2's configure.ac
|
||||
@@ -443,7 +456,7 @@ dnl lastlog and [uw]tmp are subject to a file search if all else fails
|
||||
dnl lastlog detection
|
||||
dnl NOTE: the code itself will detect if lastlog is a directory
|
||||
AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
@@ -455,13 +468,13 @@ AC_TRY_COMPILE([
|
||||
#ifdef HAVE_LOGIN_H
|
||||
# include <login.h>
|
||||
#endif
|
||||
],
|
||||
[ char *lastlog = LASTLOG_FILE; ],
|
||||
]],
|
||||
[[ char *lastlog = LASTLOG_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
@@ -470,8 +483,8 @@ AC_TRY_COMPILE([
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *lastlog = _PATH_LASTLOG; ],
|
||||
]],
|
||||
[[ char *lastlog = _PATH_LASTLOG; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
@@ -500,14 +513,14 @@ fi
|
||||
|
||||
dnl utmp detection
|
||||
AC_MSG_CHECKING([if your system defines UTMP_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *utmp = UTMP_FILE; ],
|
||||
]],
|
||||
[[ char *utmp = UTMP_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmp_path=no ]
|
||||
@@ -530,14 +543,16 @@ fi
|
||||
|
||||
dnl wtmp detection
|
||||
AC_MSG_CHECKING([if your system defines WTMP_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMP_H
|
||||
# include <utmp.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *wtmp = WTMP_FILE; ],
|
||||
]],
|
||||
[[ char *wtmp = WTMP_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmp_path=no ]
|
||||
@@ -563,7 +578,7 @@ dnl utmpx detection - I don't know any system so perverse as to require
|
||||
dnl utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
|
||||
dnl there, though.
|
||||
AC_MSG_CHECKING([if your system defines UTMPX_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMPX_H
|
||||
@@ -572,8 +587,8 @@ AC_TRY_COMPILE([
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *utmpx = UTMPX_FILE; ],
|
||||
]],
|
||||
[[ char *utmpx = UTMPX_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmpx_path=no ]
|
||||
@@ -588,17 +603,19 @@ fi
|
||||
|
||||
dnl wtmpx detection
|
||||
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMP_H
|
||||
# include <utmp.h>
|
||||
#endif
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
# include <utmpx.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *wtmpx = WTMPX_FILE; ],
|
||||
]],
|
||||
[[ char *wtmpx = WTMPX_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmpx_path=no ]
|
||||
@@ -615,15 +632,16 @@ fi
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork])
|
||||
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
|
||||
|
||||
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||
|
||||
# Solaris needs ptmx
|
||||
if test -z "$no_ptmx_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
AC_CHECK_FILE("/dev/ptmx", AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx))
|
||||
if test -e /dev/ptmx ; then
|
||||
AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx)
|
||||
fi
|
||||
else
|
||||
AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
|
||||
fi
|
||||
@@ -631,7 +649,9 @@ fi
|
||||
|
||||
if test -z "$no_ptc_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
AC_CHECK_FILE("/dev/ptc", AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts))
|
||||
if test -e /dev/ptc ; then
|
||||
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts)
|
||||
fi
|
||||
else
|
||||
AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
|
||||
fi
|
||||
@@ -640,6 +660,7 @@ 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)
|
||||
@@ -671,6 +692,7 @@ 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)
|
||||
@@ -678,18 +700,22 @@ 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/prng)
|
||||
AS_MKDIR_P(libtomcrypt/src/prngs)
|
||||
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
|
||||
fi
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_OUTPUT(Makefile)
|
||||
AC_OUTPUT(libtomcrypt/Makefile)
|
||||
AC_OUTPUT(libtommath/Makefile)
|
||||
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
75
crypto_desc.c
Normal file
75
crypto_desc.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
int dropbear_ltc_prng = -1;
|
||||
#endif
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
void crypto_init() {
|
||||
|
||||
const struct ltc_cipher_descriptor *regciphers[] = {
|
||||
#ifdef DROPBEAR_AES
|
||||
&aes_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct ltc_hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA256
|
||||
&sha256_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA384
|
||||
&sha384_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA512
|
||||
&sha512_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef 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
|
||||
ltc_mp = ltm_desc;
|
||||
dropbear_ecc_fill_dp();
|
||||
#endif
|
||||
}
|
||||
|
||||
9
crypto_desc.h
Normal file
9
crypto_desc.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _CRYPTO_DESC_H
|
||||
#define _CRYPTO_DESC_H
|
||||
|
||||
void crypto_init();
|
||||
|
||||
extern int dropbear_ltc_prng;
|
||||
|
||||
#endif /* _CRYPTO_DESC_H */
|
||||
|
||||
734
curve25519-donna.c
Normal file
734
curve25519-donna.c
Normal file
@@ -0,0 +1,734 @@
|
||||
/* 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;
|
||||
}
|
||||
38
dbclient.1
38
dbclient.1
@@ -1,6 +1,6 @@
|
||||
.TH dbclient 1
|
||||
.SH NAME
|
||||
dbclient \- lightweight SSH2 client
|
||||
dbclient \- lightweight SSH client
|
||||
.SH SYNOPSIS
|
||||
.B dbclient
|
||||
[\-Tt] [\-p
|
||||
@@ -15,26 +15,25 @@ dbclient \- lightweight SSH2 client
|
||||
.B dbclient
|
||||
[
|
||||
.I args ]
|
||||
.I [user1]@host1[/port1],[user2]@host2[/port2],...
|
||||
.I [user1]@host1[^port1],[user2]@host2[^port2],...
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dbclient
|
||||
is a SSH 2 client designed to be small enough to be used in small memory
|
||||
environments, while still being functional and secure enough for general use.
|
||||
is a small SSH client
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-p \fIport
|
||||
Remote port.
|
||||
Connect to port
|
||||
Connect to
|
||||
.I port
|
||||
on the remote host.
|
||||
on the remote host. Alternatively a port can be specified as hostname^port.
|
||||
Default is 22.
|
||||
.TP
|
||||
.B \-i \fIidfile
|
||||
Identity file.
|
||||
Read the identity from file
|
||||
Read the identity key from file
|
||||
.I idfile
|
||||
(multiple allowed).
|
||||
(multiple allowed). This file is created with dropbearkey(1) or converted
|
||||
from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
|
||||
.TP
|
||||
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Local port forwarding.
|
||||
@@ -61,10 +60,10 @@ Login as
|
||||
on the remote host.
|
||||
.TP
|
||||
.B \-t
|
||||
Allocate a pty.
|
||||
Allocate a PTY.
|
||||
.TP
|
||||
.B \-T
|
||||
Don't allocate a pty.
|
||||
Don't allocate a PTY.
|
||||
.TP
|
||||
.B \-N
|
||||
Don't request a remote shell or run any commands. Any command arguments are ignored.
|
||||
@@ -80,7 +79,8 @@ by the ssh server.
|
||||
.TP
|
||||
.B \-y
|
||||
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
|
||||
connection will abort as normal.
|
||||
connection will abort as normal. If specified a second time no host key checking
|
||||
is performed at all, this is usually undesirable.
|
||||
.TP
|
||||
.B \-A
|
||||
Forward agent connections to the remote host. dbclient will use any
|
||||
@@ -97,7 +97,7 @@ Ensure that traffic is transmitted at a certain interval in seconds. This is
|
||||
useful for working around firewalls or routers that drop connections after
|
||||
a certain period of inactivity. The trade-off is that a session may be
|
||||
closed if there is a temporary lapse of network connectivity. A setting
|
||||
if 0 disables keepalives.
|
||||
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
|
||||
.TP
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
@@ -120,13 +120,16 @@ Specify a comma separated list of authentication MACs to enable. Use \fI-m help\
|
||||
.TP
|
||||
.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 \-V
|
||||
Print the version
|
||||
|
||||
.SH MULTI-HOP
|
||||
Dropbear will also allow multiple "hops" to be specified, separated by commas. In
|
||||
this case a connection will be made to the first host, then a TCP forwarded
|
||||
connection will be made through that to the second host, and so on. Hosts other than
|
||||
the final destination will not see anything other than the encrypted SSH stream.
|
||||
A port for a host can be specified with a slash (eg matt@martello/44 ).
|
||||
A port for a host can be specified with a hash (eg matt@martello^44 ).
|
||||
This syntax can also be used with scp or rsync (specifying dbclient as the
|
||||
ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
|
||||
|
||||
@@ -136,6 +139,11 @@ Note that hostnames are resolved by the prior hop (so "canyons" would be resolve
|
||||
in the example above, the same way as other -L TCP forwarded hosts are. Host keys are
|
||||
checked locally based on the given hostname.
|
||||
|
||||
.SH ESCAPE CHARACTERS
|
||||
Typing a newline followed by the key sequence \fI~.\fR (tilde, dot) will terminate a connection.
|
||||
The sequence \fI~^Z\fR (tilde, ctrl-z) will background the connection. This behaviour only
|
||||
applies when a PTY is used.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B DROPBEAR_PASSWORD
|
||||
@@ -156,6 +164,6 @@ Mihnea Stoenescu wrote initial Dropbear client support
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbear(8), dropbearkey(8)
|
||||
dropbear(8), dropbearkey(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
|
||||
/* this is used to generate unique output from the same hashpool */
|
||||
static uint32_t counter = 0;
|
||||
@@ -77,17 +78,20 @@ process_file(hash_state *hs, const char *filename,
|
||||
while (len == 0 || readcount < len)
|
||||
{
|
||||
int readlen, wantread;
|
||||
unsigned char readbuf[2048];
|
||||
if (!already_blocked)
|
||||
unsigned char readbuf[4096];
|
||||
if (!already_blocked && !prngd)
|
||||
{
|
||||
int ret;
|
||||
struct timeval timeout = { .tv_sec = 2, .tv_usec = 0};
|
||||
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);
|
||||
ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (ret == 0)
|
||||
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;
|
||||
@@ -157,6 +161,9 @@ static void write_urandom()
|
||||
/* This is opportunistic, don't worry about failure */
|
||||
unsigned char buf[INIT_SEED_SIZE];
|
||||
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
genrandom(buf, sizeof(buf));
|
||||
fwrite(buf, sizeof(buf), 1, f);
|
||||
fclose(f);
|
||||
@@ -205,20 +212,21 @@ void seedrandom() {
|
||||
process_file(&hs, "/proc/loadavg", 0, 0);
|
||||
process_file(&hs, "/proc/sys/kernel/random/entropy_avail", 0, 0);
|
||||
|
||||
/* Mostly network visible but useful in some situations */
|
||||
process_file(&hs, "/proc/net/netstat", 0, 0);
|
||||
process_file(&hs, "/proc/net/dev", 0, 0);
|
||||
process_file(&hs, "/proc/net/tcp", 0, 0);
|
||||
/* Mostly network visible but useful in some situations.
|
||||
* Limit size to avoid slowdowns on systems with lots of routes */
|
||||
process_file(&hs, "/proc/net/netstat", 4096, 0);
|
||||
process_file(&hs, "/proc/net/dev", 4096, 0);
|
||||
process_file(&hs, "/proc/net/tcp", 4096, 0);
|
||||
/* Also includes interface lo */
|
||||
process_file(&hs, "/proc/net/rt_cache", 0, 0);
|
||||
process_file(&hs, "/proc/net/rt_cache", 4096, 0);
|
||||
process_file(&hs, "/proc/vmstat", 0, 0);
|
||||
#endif
|
||||
|
||||
pid = getpid();
|
||||
sha1_process(&hs, (void*)&pid, sizeof(pid));
|
||||
|
||||
// gettimeofday() doesn't completely fill out struct timeval on
|
||||
// OS X (10.8.3), avoid valgrind warnings by clearing it first
|
||||
/* gettimeofday() doesn't completely fill out struct timeval on
|
||||
OS X (10.8.3), avoid valgrind warnings by clearing it first */
|
||||
memset(&tv, 0x0, sizeof(tv));
|
||||
gettimeofday(&tv, NULL);
|
||||
sha1_process(&hs, (void*)&tv, sizeof(tv));
|
||||
@@ -25,7 +25,7 @@
|
||||
#ifndef _RANDOM_H_
|
||||
#define _RANDOM_H_
|
||||
|
||||
struct mp_int;
|
||||
#include "includes.h"
|
||||
|
||||
void seedrandom();
|
||||
void genrandom(unsigned char* buf, unsigned int len);
|
||||
196
dbutil.c
196
dbutil.c
@@ -48,6 +48,19 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#define _GNU_SOURCE
|
||||
/* To call clock_gettime() directly */
|
||||
#include <sys/syscall.h>
|
||||
#endif /* __linux */
|
||||
|
||||
#ifdef HAVE_MACH_MACH_TIME_H
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
@@ -138,43 +151,90 @@ void dropbear_log(int priority, const char* format, ...) {
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...) {
|
||||
|
||||
va_list param;
|
||||
struct timeval tv;
|
||||
|
||||
if (!debug_trace) {
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE (%d): ", getpid());
|
||||
fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
|
||||
void dropbear_trace2(const char* format, ...) {
|
||||
static int trace_env = -1;
|
||||
va_list param;
|
||||
struct timeval tv;
|
||||
|
||||
if (trace_env == -1) {
|
||||
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
|
||||
}
|
||||
|
||||
if (!(debug_trace && trace_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
#endif /* DEBUG_TRACE */
|
||||
|
||||
static void set_sock_priority(int sock) {
|
||||
|
||||
void set_sock_nodelay(int sock) {
|
||||
int val;
|
||||
|
||||
/* disable nagle */
|
||||
val = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
}
|
||||
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio) {
|
||||
|
||||
int iptos_val = 0, so_prio_val = 0, rc;
|
||||
|
||||
/* Don't log ENOTSOCK errors so that this can harmlessly be called
|
||||
* on a client '-J' proxy pipe */
|
||||
|
||||
/* set the TOS bit for either ipv4 or ipv6 */
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
val = IPTOS_LOWDELAY;
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
iptos_val = IPTOS_LOWDELAY;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
iptos_val = IPTOS_THROUGHPUT;
|
||||
}
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
|
||||
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
|
||||
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
/* linux specific, sets QoS class.
|
||||
* 6 looks to be optimal for interactive traffic (see tc-prio(8) ). */
|
||||
val = 6;
|
||||
setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
so_prio_val = TC_PRIO_INTERACTIVE;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
so_prio_val = TC_PRIO_BULK;
|
||||
}
|
||||
/* linux specific, sets QoS class. see tc-prio(8) */
|
||||
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
|
||||
if (rc < 0 && errno != ENOTSOCK)
|
||||
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
|
||||
strerror(errno));
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -266,7 +326,7 @@ int dropbear_listen(const char* address, const char* port,
|
||||
}
|
||||
#endif
|
||||
|
||||
set_sock_priority(sock);
|
||||
set_sock_nodelay(sock);
|
||||
|
||||
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
err = errno;
|
||||
@@ -275,7 +335,7 @@ int dropbear_listen(const char* address, const char* port,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listen(sock, 20) < 0) {
|
||||
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("listen() failed"))
|
||||
@@ -405,7 +465,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
|
||||
TRACE(("Error connecting: %s", strerror(err)))
|
||||
} else {
|
||||
/* Success */
|
||||
set_sock_priority(sock);
|
||||
set_sock_nodelay(sock);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
@@ -651,6 +711,14 @@ void printhex(const char * label, const unsigned char * buf, int len) {
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void printmpint(const char *label, mp_int *mp) {
|
||||
buffer *buf = buf_new(1000);
|
||||
buf_putmpint(buf, mp);
|
||||
printhex(label, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Strip all control characters from text (a null-terminated string), except
|
||||
@@ -725,8 +793,6 @@ int buf_getline(buffer * line, FILE * authfile) {
|
||||
|
||||
int c = EOF;
|
||||
|
||||
TRACE(("enter buf_getline"))
|
||||
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
|
||||
@@ -750,10 +816,8 @@ out:
|
||||
|
||||
/* if we didn't read anything before EOF or error, exit */
|
||||
if (c == EOF && line->pos == 0) {
|
||||
TRACE(("leave buf_getline: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
TRACE(("leave buf_getline: success"))
|
||||
buf_setpos(line, 0);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
@@ -764,6 +828,10 @@ out:
|
||||
/* make sure that the socket closes */
|
||||
void m_close(int fd) {
|
||||
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int val;
|
||||
do {
|
||||
val = close(fd);
|
||||
@@ -853,14 +921,100 @@ void disallow_core() {
|
||||
|
||||
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
|
||||
int m_str_to_uint(const char* str, unsigned int *val) {
|
||||
unsigned long l;
|
||||
errno = 0;
|
||||
*val = strtoul(str, NULL, 10);
|
||||
l = strtoul(str, NULL, 10);
|
||||
/* The c99 spec doesn't actually seem to define EINVAL, but most platforms
|
||||
* I've looked at mention it in their manpage */
|
||||
if ((*val == 0 && errno == EINVAL)
|
||||
|| (*val == ULONG_MAX && errno == ERANGE)) {
|
||||
if ((l == 0 && errno == EINVAL)
|
||||
|| (l == ULONG_MAX && errno == ERANGE)
|
||||
|| (l > UINT_MAX)) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
*val = l;
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns malloced path. Only expands ~ in first character */
|
||||
char * expand_tilde(const char *inpath) {
|
||||
struct passwd *pw = NULL;
|
||||
if (inpath[0] == '~') {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir) {
|
||||
int len = strlen(inpath) + strlen(pw->pw_dir) + 1;
|
||||
char *buf = m_malloc(len);
|
||||
snprintf(buf, len, "%s/%s", pw->pw_dir, &inpath[1]);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback */
|
||||
return m_strdup(inpath);
|
||||
}
|
||||
|
||||
int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
{
|
||||
const char *xa = a, *xb = b;
|
||||
uint8_t c = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
c |= (xa[i] ^ xb[i]);
|
||||
}
|
||||
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
|
||||
#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;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#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");
|
||||
}
|
||||
return ts.tv_sec;
|
||||
}
|
||||
#endif /* linux clock_gettime */
|
||||
|
||||
#if defined(HAVE_MACH_ABSOLUTE_TIME)
|
||||
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||
static mach_timebase_info_data_t timebase_info;
|
||||
if (timebase_info.denom == 0) {
|
||||
mach_timebase_info(&timebase_info);
|
||||
}
|
||||
return mach_absolute_time() * timebase_info.numer / timebase_info.denom
|
||||
/ 1e9;
|
||||
#endif /* osx mach_absolute_time */
|
||||
|
||||
/* Fallback for everything else - this will sometimes go backwards */
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
|
||||
29
dbutil.h
29
dbutil.h
@@ -35,14 +35,12 @@ void startsyslog();
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args)))
|
||||
#define ATTRIB_NORETURN __attribute__((noreturn))
|
||||
#define ATTRIB_SENTINEL __attribute__((sentinel))
|
||||
#else
|
||||
#define ATTRIB_PRINTF(fmt,args)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ATTRIB_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
#define ATTRIB_NORETURN
|
||||
#define ATTRIB_SENTINEL
|
||||
#endif
|
||||
|
||||
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
@@ -57,15 +55,25 @@ void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
|
||||
|
||||
#ifdef 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);
|
||||
void printmpint(const char *label, mp_int *mp);
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
|
||||
enum dropbear_prio {
|
||||
DROPBEAR_PRIO_DEFAULT = 10,
|
||||
DROPBEAR_PRIO_LOWDELAY = 11,
|
||||
DROPBEAR_PRIO_BULK = 12,
|
||||
};
|
||||
|
||||
char * stripcontrol(const char * text);
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port, int host_lookup);
|
||||
void set_sock_nodelay(int sock);
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio);
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
|
||||
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
@@ -83,7 +91,7 @@ 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) free(X); (X) = NULL;
|
||||
#define m_free(X) do {free(X); (X) = NULL;} while (0);
|
||||
void m_burn(void* data, unsigned int len);
|
||||
void setnonblocking(int fd);
|
||||
void disallow_core();
|
||||
@@ -95,4 +103,13 @@ int m_str_to_uint(const char* str, unsigned int *val);
|
||||
/* Dropbear assertion */
|
||||
#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
|
||||
|
||||
/* Returns 0 if a and b have the same contents */
|
||||
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();
|
||||
|
||||
char * expand_tilde(const char *inpath);
|
||||
|
||||
#endif /* _DBUTIL_H_ */
|
||||
|
||||
61
debian/changelog
vendored
61
debian/changelog
vendored
@@ -1,3 +1,64 @@
|
||||
dropbear (2015.67-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 28 Jan 2015 22:53:59 +0800
|
||||
|
||||
dropbear (2014.66-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 23 Oct 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.65-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 8 Aug 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.64-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sun, 27 Jul 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.63-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Feb 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2013.62) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tue, 7 Dec 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.60-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 16 Oct 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.59-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Build with DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 4 Oct 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.58-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 Apr 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.57-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Apr 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.56-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
19
debian/rules
vendored
19
debian/rules
vendored
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
DPKG_EXPORT_BUILDFLAGS = 1
|
||||
include /usr/share/dpkg/buildflags.mk
|
||||
|
||||
#export DH_OPTIONS
|
||||
DEB_HOST_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
@@ -9,13 +13,6 @@ ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
STRIP =: nostrip
|
||||
endif
|
||||
|
||||
CFLAGS =-Wall -g
|
||||
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS +=-O0
|
||||
else
|
||||
CFLAGS +=-O2
|
||||
endif
|
||||
|
||||
CONFFLAGS =
|
||||
CC =gcc
|
||||
ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
|
||||
@@ -79,12 +76,12 @@ install: deb-checkdir deb-checkuid build-stamp
|
||||
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
|
||||
# man pages
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man8
|
||||
for i in dropbear.8 dropbearkey.8; do \
|
||||
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man1
|
||||
install -m644 dropbear.8 '$(DIR)'/usr/share/man/man8/
|
||||
for i in dbclient.1 dropbearkey.1 dropbearconvert.1; do \
|
||||
install -m644 $$i '$(DIR)'/usr/share/man/man1/ || exit 1; \
|
||||
done
|
||||
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man1
|
||||
install -m644 dbclient.1 '$(DIR)'/usr/share/man/man1/
|
||||
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
|
||||
# copyright, changelog
|
||||
cat debian/copyright.in LICENSE >debian/copyright
|
||||
|
||||
4
debug.h
4
debug.h
@@ -39,7 +39,7 @@
|
||||
* 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 */
|
||||
/* #define DEBUG_TRACE */
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
@@ -63,8 +63,10 @@
|
||||
/* you don't need to touch this block */
|
||||
#ifdef DEBUG_TRACE
|
||||
#define TRACE(X) dropbear_trace X;
|
||||
#define TRACE2(X) dropbear_trace2 X;
|
||||
#else /*DEBUG_TRACE*/
|
||||
#define TRACE(X)
|
||||
#define TRACE2(X)
|
||||
#endif /*DEBUG_TRACE*/
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
|
||||
56
dropbear.8
56
dropbear.8
@@ -1,17 +1,16 @@
|
||||
.TH dropbear 8
|
||||
.SH NAME
|
||||
dropbear \- lightweight SSH2 server
|
||||
dropbear \- lightweight SSH server
|
||||
.SH SYNOPSIS
|
||||
.B dropbear
|
||||
[\-FEmwsgjki] [\-b
|
||||
.I banner\fR] [\-d
|
||||
.I dsskey\fR] [\-r
|
||||
.I rsakey\fR] [\-p
|
||||
[\-RFEmwsgjki] [\-b
|
||||
.I banner\fR]
|
||||
[\-r
|
||||
.I hostkeyfile\fR] [\-p
|
||||
.IR [address:]port ]
|
||||
.SH DESCRIPTION
|
||||
.B dropbear
|
||||
is a SSH 2 server designed to be small enough to be used in small memory
|
||||
environments, while still being functional and secure enough for general use.
|
||||
is a small SSH server
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-b \fIbanner
|
||||
@@ -20,24 +19,16 @@ Display the contents of the file
|
||||
.I banner
|
||||
before user login (default: none).
|
||||
.TP
|
||||
.B \-d \fIdsskey
|
||||
dsskeyfile.
|
||||
.B \-r \fIhostkey
|
||||
Use the contents of the file
|
||||
.I dsskey
|
||||
for the DSS host key (default: /etc/dropbear/dropbear_dss_host_key).
|
||||
Note that
|
||||
some SSH implementations
|
||||
use the term "DSA" rather than "DSS", they mean the same thing.
|
||||
.I hostkey
|
||||
for the SSH hostkey.
|
||||
This file is generated with
|
||||
.BR dropbearkey (8).
|
||||
.BR dropbearkey (1)
|
||||
or automatically with the '-R' option. See "Host Key Files" below.
|
||||
.TP
|
||||
.B \-r \fIrsakey
|
||||
rsakeyfile.
|
||||
Use the contents of the file
|
||||
.I rsakey
|
||||
for the rsa host key (default: /etc/dropbear/dropbear_rsa_host_key).
|
||||
This file is generated with
|
||||
.BR dropbearkey (8).
|
||||
.B \-R
|
||||
Generate hostkeys automatically. See "Host Key Files" below.
|
||||
.TP
|
||||
.B \-F
|
||||
Don't fork into background.
|
||||
@@ -96,10 +87,14 @@ Ensure that traffic is transmitted at a certain interval in seconds. This is
|
||||
useful for working around firewalls or routers that drop connections after
|
||||
a certain period of inactivity. The trade-off is that a session may be
|
||||
closed if there is a temporary lapse of network connectivity. A setting
|
||||
if 0 disables keepalives.
|
||||
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
|
||||
.TP
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
.TP
|
||||
.B \-V
|
||||
Print the version
|
||||
|
||||
.SH FILES
|
||||
|
||||
.TP
|
||||
@@ -143,9 +138,13 @@ key authentication.
|
||||
Host Key Files
|
||||
|
||||
Host key files are read at startup from a standard location, by default
|
||||
/etc/dropbear/dropbear_dss_host_key and /etc/dropbear/dropbear_rsa_host_key
|
||||
or specified on the commandline with -d or -r. These are of the form generated
|
||||
by dropbearkey.
|
||||
/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
|
||||
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.
|
||||
|
||||
.TP
|
||||
Message Of The Day
|
||||
@@ -180,13 +179,14 @@ in this variable. If a shell was requested this is set to an empty value.
|
||||
.B SSH_AUTH_SOCK
|
||||
Set to a forwarded ssh-agent connection.
|
||||
|
||||
|
||||
.SH NOTES
|
||||
Dropbear only supports SSH protocol version 2.
|
||||
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbearkey(8), dbclient(1)
|
||||
dropbearkey(1), dbclient(1), dropbearconvert(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
50
dropbearconvert.1
Normal file
50
dropbearconvert.1
Normal file
@@ -0,0 +1,50 @@
|
||||
.TH dropbearconvert 1
|
||||
.SH NAME
|
||||
dropbearconvert \- convert between Dropbear and OpenSSH private key formats
|
||||
.SH SYNOPSIS
|
||||
.B dropbearconvert
|
||||
.I input_type
|
||||
.I output_type
|
||||
.I input_file
|
||||
.I output_file
|
||||
.SH DESCRIPTION
|
||||
.B Dropbear
|
||||
and
|
||||
.B OpenSSH
|
||||
SSH implementations have different private key formats.
|
||||
.B dropbearconvert
|
||||
can convert between the two.
|
||||
.P
|
||||
Dropbear uses the same SSH public key format as OpenSSH, it can be extracted
|
||||
from a private key by using
|
||||
.B dropbearkey \-y
|
||||
.P
|
||||
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
|
||||
first.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B input type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.B output type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.B input file
|
||||
An existing Dropbear or OpenSSH private key file
|
||||
.TP
|
||||
.B output file
|
||||
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.SH EXAMPLE
|
||||
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.SH SEE ALSO
|
||||
dropbearkey(1), ssh-keygen(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "keyimport.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
|
||||
static int do_convert(int intype, const char* infile, int outtype,
|
||||
@@ -62,6 +64,9 @@ int main(int argc, char ** argv) {
|
||||
const char* infile;
|
||||
const char* outfile;
|
||||
|
||||
crypto_init();
|
||||
seedrandom();
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
/* It's hard for it to get in the way _too_ much */
|
||||
debug_trace = 1;
|
||||
@@ -111,7 +116,7 @@ static int do_convert(int intype, const char* infile, int outtype,
|
||||
const char* outfile) {
|
||||
|
||||
sign_key * key = NULL;
|
||||
char * keytype = NULL;
|
||||
const char * keytype = NULL;
|
||||
int ret = 1;
|
||||
|
||||
key = import_read(infile, NULL, intype);
|
||||
@@ -121,16 +126,7 @@ static int do_convert(int intype, const char* infile, int outtype,
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = "RSA";
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = "DSS";
|
||||
}
|
||||
#endif
|
||||
keytype = signkey_name_from_type(key->type, NULL);
|
||||
|
||||
fprintf(stderr, "Key is a %s key\n", keytype);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.TH dropbearkey 8
|
||||
.TH dropbearkey 1
|
||||
.SH NAME
|
||||
dropbearkey \- create private keys for the use with dropbear(8)
|
||||
dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
|
||||
.SH SYNOPSIS
|
||||
.B dropbearkey
|
||||
\-t
|
||||
@@ -12,12 +12,12 @@ dropbearkey \- create private keys for the use with dropbear(8)
|
||||
.SH DESCRIPTION
|
||||
.B dropbearkey
|
||||
generates a
|
||||
.I RSA
|
||||
.I RSA
|
||||
.I DSS,
|
||||
or
|
||||
.I DSS
|
||||
.I ECDSA
|
||||
format SSH private key, and saves it to a file for the use with the
|
||||
.BR dropbear (8)
|
||||
SSH 2 server.
|
||||
Dropbear client or server.
|
||||
Note that
|
||||
some SSH implementations
|
||||
use the term "DSA" rather than "DSS", they mean the same thing.
|
||||
@@ -27,17 +27,22 @@ use the term "DSA" rather than "DSS", they mean the same thing.
|
||||
Type of key to generate.
|
||||
Must be one of
|
||||
.I rsa
|
||||
.I ecdsa
|
||||
or
|
||||
.IR dss .
|
||||
.TP
|
||||
.B \-f \fIfile
|
||||
Write the secret key to the file
|
||||
.IR file .
|
||||
.IR file . For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.TP
|
||||
.B \-s \fIbits
|
||||
Set the key size to
|
||||
.I bits
|
||||
bits, should be multiple of 8 (optional).
|
||||
bits, should be multiple of 8 (optional).
|
||||
.SH NOTES
|
||||
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
|
||||
.P
|
||||
Dropbear does not support encrypted keys.
|
||||
.SH EXAMPLE
|
||||
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
|
||||
.SH AUTHOR
|
||||
@@ -45,6 +50,6 @@ Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbear(8), dbclient(1)
|
||||
dropbear(8), dbclient(1), dropbearconvert(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
200
dropbearkey.c
200
dropbearkey.c
@@ -51,15 +51,16 @@
|
||||
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "ecdsa.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "dbrandom.h"
|
||||
#include "gensignkey.h"
|
||||
|
||||
static void printhelp(char * progname);
|
||||
|
||||
#define RSA_SIZE (1024/8) /* 1024 bit */
|
||||
#define DSS_SIZE (1024/8) /* 1024 bit */
|
||||
|
||||
static void buf_writefile(buffer * buf, const char * filename);
|
||||
static void printpubkey(sign_key * key, int keytype);
|
||||
static void justprintpub(const char* filename);
|
||||
static int printpubfile(const char* filename);
|
||||
|
||||
/* Print a help message */
|
||||
static void printhelp(char * progname) {
|
||||
@@ -72,9 +73,28 @@ static void printhelp(char * progname) {
|
||||
#ifdef DROPBEAR_DSS
|
||||
" dss\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key\n"
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
" ecdsa\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"
|
||||
" (DSS has a fixed size of 1024 bits)\n"
|
||||
#ifdef DROPBEAR_DSS
|
||||
" DSS has a fixed size of 1024 bits\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
" ECDSA has sizes "
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
"256 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
"384 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
"521 "
|
||||
#endif
|
||||
"\n"
|
||||
#endif
|
||||
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
|
||||
#ifdef DEBUG_TRACE
|
||||
"-v verbose\n"
|
||||
@@ -82,6 +102,30 @@ static void printhelp(char * progname) {
|
||||
,progname);
|
||||
}
|
||||
|
||||
/* fails fatally */
|
||||
static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef 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"
|
||||
" multiple of 8\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
(void)0; /* quiet, compiler. ecdsa handles checks itself */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
|
||||
int dropbearkey_main(int argc, char ** argv) {
|
||||
@@ -91,16 +135,16 @@ int main(int argc, char ** argv) {
|
||||
|
||||
int i;
|
||||
char ** next = 0;
|
||||
sign_key *key = NULL;
|
||||
buffer *buf = NULL;
|
||||
char * filename = NULL;
|
||||
int keytype = -1;
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
|
||||
char * typetext = NULL;
|
||||
char * sizetext = NULL;
|
||||
unsigned int bits;
|
||||
unsigned int keysize;
|
||||
unsigned int bits = 0;
|
||||
int printpub = 0;
|
||||
|
||||
crypto_init();
|
||||
seedrandom();
|
||||
|
||||
/* get the commandline options */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i] == NULL) {
|
||||
@@ -151,8 +195,8 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
if (printpub) {
|
||||
justprintpub(filename);
|
||||
/* Not reached */
|
||||
int ret = printpubfile(filename);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/* check/parse args */
|
||||
@@ -162,21 +206,26 @@ int main(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strlen(typetext) == 3) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (strncmp(typetext, "rsa", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
TRACE(("type is rsa"))
|
||||
}
|
||||
if (strcmp(typetext, "rsa") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (strncmp(typetext, "dss", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
TRACE(("type is dss"))
|
||||
}
|
||||
#endif
|
||||
if (strcmp(typetext, "dss") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
if (keytype == -1) {
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (strcmp(typetext, "ecdsa") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_NONE) {
|
||||
fprintf(stderr, "Unknown key type '%s'\n", typetext);
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -188,75 +237,26 @@ int main(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS && bits != 1024) {
|
||||
fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
check_signkey_bits(keytype, bits);;
|
||||
}
|
||||
|
||||
keysize = bits / 8;
|
||||
} else {
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
keysize = DSS_SIZE;
|
||||
} else if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
keysize = RSA_SIZE;
|
||||
} else {
|
||||
exit(EXIT_FAILURE); /* not reached */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8,
|
||||
typetext, filename);
|
||||
|
||||
/* don't want the file readable by others */
|
||||
umask(077);
|
||||
|
||||
/* now we can generate the key */
|
||||
key = new_sign_key();
|
||||
|
||||
fprintf(stderr, "Generating key, this may take a while...\n");
|
||||
switch(keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "Internal error, bad key type\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
|
||||
{
|
||||
dropbear_exit("Failed to generate key.\n");
|
||||
}
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
buf_setpos(buf, 0);
|
||||
buf_writefile(buf, filename);
|
||||
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
|
||||
printpubkey(key, keytype);
|
||||
|
||||
sign_key_free(key);
|
||||
printpubfile(filename);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void justprintpub(const char* filename) {
|
||||
static int printpubfile(const char* filename) {
|
||||
|
||||
buffer *buf = NULL;
|
||||
sign_key *key = NULL;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
int ret;
|
||||
int err = DROPBEAR_FAILURE;
|
||||
|
||||
@@ -290,7 +290,7 @@ out:
|
||||
sign_key_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
exit(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void printpubkey(sign_key * key, int keytype) {
|
||||
@@ -319,7 +319,7 @@ static void printpubkey(sign_key * key, int keytype) {
|
||||
fprintf(stderr, "base64 failed");
|
||||
}
|
||||
|
||||
typestring = signkey_name_from_type(keytype, &err);
|
||||
typestring = signkey_name_from_type(keytype, NULL);
|
||||
|
||||
fp = sign_key_fingerprint(buf_getptr(buf, len), len);
|
||||
|
||||
@@ -339,35 +339,3 @@ static void printpubkey(sign_key * key, int keytype) {
|
||||
m_free(fp);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
/* Write a buffer to a file specified, failing if the file exists */
|
||||
static void buf_writefile(buffer * buf, const char * filename) {
|
||||
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Couldn't create new file %s\n", filename);
|
||||
perror("Reason");
|
||||
buf_burn(buf);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* write the file now */
|
||||
while (buf->pos != buf->len) {
|
||||
len = write(fd, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos);
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (len <= 0) {
|
||||
fprintf(stderr, "Failed writing file '%s'\n",filename);
|
||||
perror("Reason");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
buf_incrpos(buf, len);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
29
dss.c
29
dss.c
@@ -28,7 +28,7 @@
|
||||
#include "dss.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
/* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
|
||||
* operations, such as key reading, signing, verification. Key generation
|
||||
@@ -47,11 +47,7 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
TRACE(("enter buf_get_dss_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
key->p = m_malloc(sizeof(mp_int));
|
||||
key->q = m_malloc(sizeof(mp_int));
|
||||
key->g = m_malloc(sizeof(mp_int));
|
||||
key->y = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, key->g, key->y, NULL);
|
||||
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
|
||||
key->x = NULL;
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
|
||||
@@ -87,8 +83,7 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
key->x = m_malloc(sizeof(mp_int));
|
||||
m_mp_init(key->x);
|
||||
m_mp_alloc_init_multi(&key->x, NULL);
|
||||
ret = buf_getmpint(buf, key->x);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->x);
|
||||
@@ -101,9 +96,9 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void dss_key_free(dropbear_dss_key *key) {
|
||||
|
||||
TRACE(("enter dsa_key_free"))
|
||||
TRACE2(("enter dsa_key_free"))
|
||||
if (key == NULL) {
|
||||
TRACE(("enter dsa_key_free: key == NULL"))
|
||||
TRACE2(("enter dsa_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
if (key->p) {
|
||||
@@ -127,7 +122,7 @@ void dss_key_free(dropbear_dss_key *key) {
|
||||
m_free(key->x);
|
||||
}
|
||||
m_free(key);
|
||||
TRACE(("leave dsa_key_free"))
|
||||
TRACE2(("leave dsa_key_free"))
|
||||
}
|
||||
|
||||
/* put the dss public key into the buffer in the required format:
|
||||
@@ -161,9 +156,7 @@ void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
#ifdef 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, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
hash_state hs;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
@@ -187,7 +180,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, msghash);
|
||||
|
||||
/* create the signature - s' and r' are the received signatures in buf */
|
||||
@@ -260,9 +253,7 @@ 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, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
@@ -279,7 +270,7 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* d
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, msghash);
|
||||
|
||||
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
|
||||
8
dss.h
8
dss.h
@@ -30,8 +30,6 @@
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
|
||||
|
||||
typedef struct {
|
||||
|
||||
mp_int* p;
|
||||
@@ -43,11 +41,9 @@ typedef struct {
|
||||
|
||||
} dropbear_dss_key;
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
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, const unsigned char* data,
|
||||
unsigned int len);
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, 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);
|
||||
|
||||
275
ecc.c
Normal file
275
ecc.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
#include "ecc.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
|
||||
/* .dp members are filled out by dropbear_ecc_fill_dp() at startup */
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
struct dropbear_ecc_curve ecc_curve_nistp256 = {
|
||||
32, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
&sha256_desc, /* .hash_desc */
|
||||
"nistp256" /* .name */
|
||||
};
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
struct dropbear_ecc_curve ecc_curve_nistp384 = {
|
||||
48, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
&sha384_desc, /* .hash_desc */
|
||||
"nistp384" /* .name */
|
||||
};
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
struct dropbear_ecc_curve ecc_curve_nistp521 = {
|
||||
66, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
&sha512_desc, /* .hash_desc */
|
||||
"nistp521" /* .name */
|
||||
};
|
||||
#endif
|
||||
|
||||
struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
&ecc_curve_nistp256,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
&ecc_curve_nistp384,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
&ecc_curve_nistp521,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
void dropbear_ecc_fill_dp() {
|
||||
struct dropbear_ecc_curve **curve;
|
||||
/* libtomcrypt guarantees they're ordered by size */
|
||||
const ltc_ecc_set_type *dp = ltc_ecc_sets;
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
for (;dp->size > 0; dp++) {
|
||||
if (dp->size == (*curve)->ltc_size) {
|
||||
(*curve)->dp = dp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(*curve)->dp) {
|
||||
dropbear_exit("Missing ECC params %s", (*curve)->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) {
|
||||
struct dropbear_ecc_curve **curve = NULL;
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
if ((*curve)->dp == dp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(*curve);
|
||||
return *curve;
|
||||
}
|
||||
|
||||
ecc_key * new_ecc_key(void) {
|
||||
ecc_key *key = m_malloc(sizeof(*key));
|
||||
m_mp_alloc_init_multi((mp_int**)&key->pubkey.x, (mp_int**)&key->pubkey.y,
|
||||
(mp_int**)&key->pubkey.z, (mp_int**)&key->k, NULL);
|
||||
return key;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
mp_int *prime, *b, *t1, *t2;
|
||||
int err;
|
||||
|
||||
prime = m_malloc(sizeof(mp_int));
|
||||
b = m_malloc(sizeof(mp_int));
|
||||
t1 = m_malloc(sizeof(mp_int));
|
||||
t2 = m_malloc(sizeof(mp_int));
|
||||
|
||||
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
|
||||
|
||||
/* load prime and b */
|
||||
if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 */
|
||||
if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute x^3 */
|
||||
if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 - x^3 */
|
||||
if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 - x^3 + 3x */
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
|
||||
if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
}
|
||||
while (mp_cmp(t1, prime) != LTC_MP_LT) {
|
||||
if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
}
|
||||
|
||||
/* compare to b */
|
||||
if (mp_cmp(t1, b) != LTC_MP_EQ) {
|
||||
err = CRYPT_INVALID_PACKET;
|
||||
} else {
|
||||
err = CRYPT_OK;
|
||||
}
|
||||
|
||||
error:
|
||||
mp_clear_multi(prime, b, t1, t2, NULL);
|
||||
m_free(prime);
|
||||
m_free(b);
|
||||
m_free(t1);
|
||||
m_free(t2);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
|
||||
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key) {
|
||||
unsigned long len = key->dp->size*2 + 1;
|
||||
int err;
|
||||
buf_putint(buf, len);
|
||||
err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len);
|
||||
if (err != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
|
||||
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) {
|
||||
ecc_key *key = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
const unsigned int size = curve->dp->size;
|
||||
unsigned char first;
|
||||
|
||||
TRACE(("enter buf_get_ecc_raw_pubkey"))
|
||||
|
||||
buf_setpos(buf, 0);
|
||||
first = buf_getbyte(buf);
|
||||
if (first == 2 || first == 3) {
|
||||
dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression");
|
||||
return NULL;
|
||||
}
|
||||
if (first != 4 || buf->len != 1+2*size) {
|
||||
TRACE(("leave, wrong size"))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = new_ecc_key();
|
||||
key->dp = curve->dp;
|
||||
|
||||
if (mp_read_unsigned_bin(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) {
|
||||
TRACE(("failed to read y"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
mp_set(key->pubkey.z, 1);
|
||||
|
||||
if (ecc_is_point(key) != CRYPT_OK) {
|
||||
TRACE(("failed, not a point"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* SEC1 3.2.3.1 Check that Q != 0 */
|
||||
if (mp_cmp_d(key->pubkey.x, 0) == LTC_MP_EQ) {
|
||||
TRACE(("failed, x == 0"))
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp_d(key->pubkey.y, 0) == LTC_MP_EQ) {
|
||||
TRACE(("failed, y == 0"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
if (key) {
|
||||
ecc_free(key);
|
||||
m_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
ecc_point *result = NULL;
|
||||
mp_int *prime = NULL, *shared_secret = NULL;
|
||||
int err = DROPBEAR_FAILURE;
|
||||
|
||||
/* type valid? */
|
||||
if (private_key->type != PK_PRIVATE) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (private_key->dp != public_key->dp) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* make new point */
|
||||
result = ltc_ecc_new_point();
|
||||
if (result == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
prime = m_malloc(sizeof(*prime));
|
||||
m_mp_init(prime);
|
||||
|
||||
if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) {
|
||||
goto done;
|
||||
}
|
||||
if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (err == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
return shared_secret;
|
||||
}
|
||||
|
||||
#endif
|
||||
36
ecc.h
Normal file
36
ecc.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef _DROPBEAR_ECC_H
|
||||
#define _DROPBEAR_ECC_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
|
||||
struct dropbear_ecc_curve {
|
||||
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
|
||||
const ltc_ecc_set_type *dp; /* curve domain parameters */
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const unsigned char *name;
|
||||
};
|
||||
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp256;
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp384;
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp521;
|
||||
extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
|
||||
|
||||
void dropbear_ecc_fill_dp();
|
||||
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp);
|
||||
|
||||
/* "pubkey" refers to a point, but LTC uses ecc_key structure for both public
|
||||
and private keys */
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _DROPBEAR_ECC_H */
|
||||
421
ecdsa.c
Normal file
421
ecdsa.c
Normal file
@@ -0,0 +1,421 @@
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "ecc.h"
|
||||
#include "ecdsa.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
|
||||
int signkey_is_ecdsa(enum signkey_type type)
|
||||
{
|
||||
return type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|
||||
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|
||||
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
}
|
||||
|
||||
enum signkey_type ecdsa_signkey_type(ecc_key * key) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (key->dp == ecc_curve_nistp256.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (key->dp == ecc_curve_nistp384.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (key->dp == ecc_curve_nistp521.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
}
|
||||
#endif
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
|
||||
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
|
||||
case 256:
|
||||
dp = ecc_curve_nistp256.dp;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
case 384:
|
||||
dp = ecc_curve_nistp384.dp;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
case 521:
|
||||
dp = ecc_curve_nistp521.dp;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (!dp) {
|
||||
dropbear_exit("Key size %d isn't valid. Try "
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
"256 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
"384 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
"521 "
|
||||
#endif
|
||||
, bit_size);
|
||||
}
|
||||
|
||||
new_key = m_malloc(sizeof(*new_key));
|
||||
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
return new_key;
|
||||
}
|
||||
|
||||
ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
|
||||
unsigned char *key_ident = NULL, *identifier = NULL;
|
||||
unsigned int key_ident_len, identifier_len;
|
||||
buffer *q_buf = NULL;
|
||||
struct dropbear_ecc_curve **curve;
|
||||
ecc_key *new_key = NULL;
|
||||
|
||||
/* string "ecdsa-sha2-[identifier]" */
|
||||
key_ident = buf_getstring(buf, &key_ident_len);
|
||||
/* string "[identifier]" */
|
||||
identifier = buf_getstring(buf, &identifier_len);
|
||||
|
||||
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
|
||||
TRACE(("Bad identifier lengths"))
|
||||
goto out;
|
||||
}
|
||||
if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) {
|
||||
TRACE(("mismatching identifiers"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*curve) {
|
||||
TRACE(("couldn't match ecc curve"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* string Q */
|
||||
q_buf = buf_getstringbuf(buf);
|
||||
new_key = buf_get_ecc_raw_pubkey(q_buf, *curve);
|
||||
|
||||
out:
|
||||
m_free(key_ident);
|
||||
m_free(identifier);
|
||||
if (q_buf) {
|
||||
buf_free(q_buf);
|
||||
q_buf = NULL;
|
||||
}
|
||||
TRACE(("leave buf_get_ecdsa_pub_key"))
|
||||
return new_key;
|
||||
}
|
||||
|
||||
ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
|
||||
ecc_key *new_key = NULL;
|
||||
TRACE(("enter buf_get_ecdsa_priv_key"))
|
||||
new_key = buf_get_ecdsa_pub_key(buf);
|
||||
if (!new_key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
|
||||
ecc_free(new_key);
|
||||
m_free(new_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_key;
|
||||
}
|
||||
|
||||
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
unsigned char key_ident[30];
|
||||
|
||||
curve = curve_for_dp(key->dp);
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
buf_putstring(buf, curve->name, strlen(curve->name));
|
||||
buf_put_ecc_raw_pubkey_string(buf, key);
|
||||
}
|
||||
|
||||
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
|
||||
buf_put_ecdsa_pub_key(buf, key);
|
||||
buf_putmpint(buf, key->k);
|
||||
}
|
||||
|
||||
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
/* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
|
||||
int err = DROPBEAR_FAILURE;
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
hash_state hs;
|
||||
unsigned char hash[64];
|
||||
void *e = NULL, *p = NULL, *s = NULL, *r;
|
||||
unsigned char key_ident[30];
|
||||
buffer *sigbuf = NULL;
|
||||
|
||||
TRACE(("buf_put_ecdsa_sign"))
|
||||
curve = curve_for_dp(key->dp);
|
||||
|
||||
if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
curve->hash_desc->init(&hs);
|
||||
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
|
||||
curve->hash_desc->done(&hs, hash);
|
||||
|
||||
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ecc_key R_key; /* ephemeral key */
|
||||
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) {
|
||||
/* try again */
|
||||
ecc_free(&R_key);
|
||||
continue;
|
||||
}
|
||||
/* k = 1/k */
|
||||
if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
/* s = xr */
|
||||
if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
/* s = e + xr */
|
||||
if (ltc_mp.add(e, s, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
/* s = (e + xr)/k */
|
||||
if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
ecc_free(&R_key);
|
||||
|
||||
if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
/* enough for nistp521 */
|
||||
sigbuf = buf_new(200);
|
||||
buf_putmpint(sigbuf, (mp_int*)r);
|
||||
buf_putmpint(sigbuf, (mp_int*)s);
|
||||
buf_putbufstring(buf, sigbuf);
|
||||
|
||||
err = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (r && s && p && e) {
|
||||
ltc_deinit_multi(r, s, p, e, NULL);
|
||||
}
|
||||
|
||||
if (sigbuf) {
|
||||
buf_free(sigbuf);
|
||||
}
|
||||
|
||||
if (err == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
}
|
||||
|
||||
/* returns values in s and r
|
||||
returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int buf_get_ecdsa_verify_params(buffer *buf,
|
||||
void *r, void* s) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned int sig_len;
|
||||
unsigned int sig_pos;
|
||||
|
||||
sig_len = buf_getint(buf);
|
||||
sig_pos = buf->pos;
|
||||
if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
if (buf->pos - sig_pos != sig_len) {
|
||||
goto out;
|
||||
}
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
hash_state hs;
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
unsigned char hash[64];
|
||||
ecc_point *mG = NULL, *mQ = NULL;
|
||||
void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL,
|
||||
*e = NULL, *p = NULL, *m = NULL;
|
||||
void *mp = NULL;
|
||||
|
||||
/* verify
|
||||
*
|
||||
* w = s^-1 mod n
|
||||
* u1 = xw
|
||||
* u2 = rw
|
||||
* X = u1*G + u2*Q
|
||||
* v = X_x1 mod n
|
||||
* accept if v == r
|
||||
*/
|
||||
|
||||
TRACE(("buf_ecdsa_verify"))
|
||||
curve = curve_for_dp(key->dp);
|
||||
|
||||
mG = ltc_ecc_new_point();
|
||||
mQ = ltc_ecc_new_point();
|
||||
if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK
|
||||
|| !mG
|
||||
|| !mQ) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
if (buf_get_ecdsa_verify_params(buf, r, s) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
curve->hash_desc->init(&hs);
|
||||
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
|
||||
curve->hash_desc->done(&hs, hash);
|
||||
|
||||
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get the order */
|
||||
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get the modulus */
|
||||
if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check for zero */
|
||||
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ
|
||||
|| ltc_mp.compare_d(s, 0) == LTC_MP_EQ
|
||||
|| ltc_mp.compare(r, p) != LTC_MP_LT
|
||||
|| ltc_mp.compare(s, p) != LTC_MP_LT) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* w = s^-1 mod n */
|
||||
if (ltc_mp.invmod(s, p, w) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* u1 = ew */
|
||||
if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* u2 = rw */
|
||||
if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* find mG and mQ */
|
||||
if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK
|
||||
|| ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK
|
||||
|| ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* compute u1*mG + u2*mQ = mG */
|
||||
if (ltc_mp.ecc_mul2add == NULL) {
|
||||
if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* find the montgomery mp */
|
||||
if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* add them */
|
||||
if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* reduce */
|
||||
if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
|
||||
if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* v = X_x1 mod n */
|
||||
if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* does v == r */
|
||||
if (ltc_mp.compare(v, r) == LTC_MP_EQ) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
ltc_ecc_del_point(mG);
|
||||
ltc_ecc_del_point(mQ);
|
||||
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
|
||||
if (mp != NULL) {
|
||||
ltc_mp.montgomery_deinit(mp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* DROPBEAR_ECDSA */
|
||||
35
ecdsa.h
Normal file
35
ecdsa.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _ECDSA_H_
|
||||
#define _ECDSA_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#ifdef 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)
|
||||
#define ECDSA_DEFAULT_SIZE 256
|
||||
#else
|
||||
#define ECDSA_DEFAULT_SIZE 0
|
||||
#endif
|
||||
|
||||
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
|
||||
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);
|
||||
|
||||
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);
|
||||
/* Returns 1 on success */
|
||||
int signkey_is_ecdsa(enum signkey_type type);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ECDSA_H_ */
|
||||
17
gendss.c
17
gendss.c
@@ -26,7 +26,7 @@
|
||||
#include "dbutil.h"
|
||||
#include "signkey.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "buffer.h"
|
||||
#include "gendss.h"
|
||||
#include "dss.h"
|
||||
@@ -47,19 +47,16 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
dropbear_dss_key *key;
|
||||
|
||||
if (size != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits");
|
||||
}
|
||||
|
||||
key = m_malloc(sizeof(*key));
|
||||
|
||||
key->p = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->q = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->g = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->y = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, key->g, key->y, key->x, NULL);
|
||||
|
||||
seedrandom();
|
||||
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
|
||||
|
||||
getq(key);
|
||||
getp(key, size);
|
||||
getp(key, size/8);
|
||||
getg(key);
|
||||
getx(key);
|
||||
gety(key);
|
||||
|
||||
50
genrsa.c
50
genrsa.c
@@ -25,7 +25,7 @@
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "rsa.h"
|
||||
#include "genrsa.h"
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size);
|
||||
mp_int* rsa_e, unsigned int size_bytes);
|
||||
|
||||
/* mostly taken from libtomcrypt's rsa key generation routine */
|
||||
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
@@ -44,30 +44,32 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
DEF_MP_INT(qminus);
|
||||
DEF_MP_INT(lcm);
|
||||
|
||||
if (size < 512 || size > 4096 || (size % 8 != 0)) {
|
||||
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8");
|
||||
}
|
||||
|
||||
key = m_malloc(sizeof(*key));
|
||||
|
||||
key->e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->n = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->d = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->p = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->q = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
|
||||
m_mp_init_multi(key->e, key->n, key->d, key->p, key->q,
|
||||
&pminus, &lcm, &qminus, NULL);
|
||||
|
||||
seedrandom();
|
||||
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
|
||||
m_mp_init_multi(&pminus, &lcm, &qminus, NULL);
|
||||
|
||||
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
getrsaprime(key->p, &pminus, key->e, size/2);
|
||||
getrsaprime(key->q, &qminus, key->e, size/2);
|
||||
while (1) {
|
||||
getrsaprime(key->p, &pminus, key->e, size/16);
|
||||
getrsaprime(key->q, &qminus, key->e, size/16);
|
||||
|
||||
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((unsigned int)mp_count_bits(key->n) == size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* lcm(p-1, q-1) */
|
||||
@@ -90,21 +92,21 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
|
||||
/* return a prime suitable for p or q */
|
||||
static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size) {
|
||||
mp_int* rsa_e, unsigned int size_bytes) {
|
||||
|
||||
unsigned char *buf;
|
||||
DEF_MP_INT(temp_gcd);
|
||||
|
||||
buf = (unsigned char*)m_malloc(size+1);
|
||||
buf = (unsigned char*)m_malloc(size_bytes);
|
||||
|
||||
m_mp_init(&temp_gcd);
|
||||
do {
|
||||
/* generate a random odd number with MSB set, then find the
|
||||
the next prime above it */
|
||||
genrandom(buf, size+1);
|
||||
buf[0] |= 0x80; /* MSB set */
|
||||
genrandom(buf, size_bytes);
|
||||
buf[0] |= 0x80;
|
||||
|
||||
bytes_to_mp(prime, buf, size+1);
|
||||
bytes_to_mp(prime, buf, size_bytes);
|
||||
|
||||
/* find the next integer which is prime, 8 round of miller-rabin */
|
||||
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
|
||||
@@ -126,7 +128,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
|
||||
/* now we have a good value for result */
|
||||
mp_clear(&temp_gcd);
|
||||
m_burn(buf, size+1);
|
||||
m_burn(buf, size_bytes);
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
|
||||
135
gensignkey.c
Normal file
135
gensignkey.c
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
#include "ecdsa.h"
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "signkey.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
#define RSA_DEFAULT_SIZE 2048
|
||||
#define DSS_DEFAULT_SIZE 1024
|
||||
|
||||
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int buf_writefile(buffer * buf, const char * filename) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
int fd = -1;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
|
||||
filename, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* write the file now */
|
||||
while (buf->pos != buf->len) {
|
||||
int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos);
|
||||
if (len == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (len <= 0) {
|
||||
dropbear_log(LOG_ERR, "Failed writing file %s: %s",
|
||||
filename, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, len);
|
||||
}
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (fd >= 0) {
|
||||
if (fsync(fd) != 0) {
|
||||
dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
|
||||
}
|
||||
m_close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* returns 0 on failure */
|
||||
static int get_default_bits(enum signkey_type keytype)
|
||||
{
|
||||
switch (keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
return RSA_DEFAULT_SIZE;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
return DSS_DEFAULT_SIZE;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
return ECDSA_DEFAULT_SIZE;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
return 521;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
return 384;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
return 256;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
|
||||
{
|
||||
sign_key * key = NULL;
|
||||
buffer *buf = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
if (bits == 0)
|
||||
{
|
||||
bits = get_default_bits(keytype);
|
||||
}
|
||||
|
||||
/* now we can generate the key */
|
||||
key = new_sign_key();
|
||||
|
||||
seedrandom();
|
||||
|
||||
switch(keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
key->rsakey = gen_rsa_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
key->dsskey = gen_dss_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
{
|
||||
ecc_key *ecckey = gen_ecdsa_priv_key(bits);
|
||||
keytype = ecdsa_signkey_type(ecckey);
|
||||
*signkey_key_ptr(key, keytype) = ecckey;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
dropbear_exit("Internal error");
|
||||
}
|
||||
|
||||
seedrandom();
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
sign_key_free(key);
|
||||
key = NULL;
|
||||
buf_setpos(buf, 0);
|
||||
ret = buf_writefile(buf, filename);
|
||||
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
buf = NULL;
|
||||
return ret;
|
||||
}
|
||||
8
gensignkey.h
Normal file
8
gensignkey.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _GENSIGNKEY_H
|
||||
#define _GENSIGNKEY_H
|
||||
|
||||
#include "signkey.h"
|
||||
|
||||
int signkey_generate(enum signkey_type type, int bits, const char* filename);
|
||||
|
||||
#endif
|
||||
28
includes.h
28
includes.h
@@ -120,6 +120,10 @@
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef BUNDLED_LIBTOM
|
||||
#include "libtomcrypt/src/headers/tomcrypt.h"
|
||||
#include "libtommath/tommath.h"
|
||||
@@ -130,15 +134,35 @@
|
||||
|
||||
|
||||
#include "compat.h"
|
||||
#include "fake-rfc2553.h"
|
||||
|
||||
#ifndef HAVE_UINT16_T
|
||||
#ifndef HAVE_U_INT8_T
|
||||
typedef unsigned char u_int8_t;
|
||||
#endif /* HAVE_U_INT8_T */
|
||||
#ifndef HAVE_UINT8_T
|
||||
typedef u_int8_t uint8_t;
|
||||
#endif /* HAVE_UINT8_T */
|
||||
|
||||
#ifndef HAVE_U_INT16_T
|
||||
typedef unsigned short u_int16_t;
|
||||
#endif /* HAVE_U_INT16_T */
|
||||
#ifndef HAVE_UINT16_T
|
||||
typedef u_int16_t uint16_t;
|
||||
#endif /* HAVE_UINT16_T */
|
||||
|
||||
#ifndef HAVE_U_INT32_T
|
||||
typedef unsigned int u_int32_t;
|
||||
#endif /* HAVE_U_INT32_T */
|
||||
#ifndef HAVE_UINT32_T
|
||||
typedef u_int32_t uint32_t;
|
||||
#endif /* HAVE_UINT32_T */
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
#include <linux/types.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#endif
|
||||
|
||||
#include "fake-rfc2553.h"
|
||||
|
||||
#ifndef LOG_AUTHPRIV
|
||||
#define LOG_AUTHPRIV LOG_AUTH
|
||||
#endif
|
||||
|
||||
53
kex.h
53
kex.h
@@ -27,16 +27,33 @@
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "signkey.h"
|
||||
|
||||
void send_msg_kexinit();
|
||||
void recv_msg_kexinit();
|
||||
void send_msg_newkeys();
|
||||
void recv_msg_newkeys();
|
||||
void kexfirstinitialise();
|
||||
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv);
|
||||
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
|
||||
struct kex_dh_param *gen_kexdh_param();
|
||||
void free_kexdh_param(struct kex_dh_param *param);
|
||||
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
sign_key *hostkey);
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *gen_kexecdh_param();
|
||||
void free_kexecdh_param(struct kex_ecdh_param *param);
|
||||
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
sign_key *hostkey);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param();
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param);
|
||||
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *pub_them,
|
||||
sign_key *hostkey);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
int is_compress_trans();
|
||||
int is_compress_recv();
|
||||
@@ -51,19 +68,49 @@ struct KEXState {
|
||||
|
||||
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
|
||||
unsigned recvkexinit : 1;
|
||||
unsigned firstfollows : 1; /* true when first_kex_packet_follows is set */
|
||||
unsigned them_firstfollows : 1; /* true when first_kex_packet_follows is set */
|
||||
unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */
|
||||
unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */
|
||||
|
||||
unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed,
|
||||
ie the transport layer has been set up */
|
||||
|
||||
unsigned our_first_follows_matches : 1;
|
||||
|
||||
time_t lastkextime; /* time of the last kex */
|
||||
unsigned int datatrans; /* data transmitted since last kex */
|
||||
unsigned int datarecv; /* data received since last kex */
|
||||
|
||||
};
|
||||
|
||||
#define DH_P_1_LEN 128
|
||||
extern const unsigned char dh_p_1[DH_P_1_LEN];
|
||||
#define DH_P_14_LEN 256
|
||||
extern const unsigned char dh_p_14[DH_P_14_LEN];
|
||||
|
||||
struct kex_dh_param {
|
||||
mp_int pub; /* e */
|
||||
mp_int priv; /* x */
|
||||
};
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
struct kex_ecdh_param {
|
||||
ecc_key key;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
#define CURVE25519_LEN 32
|
||||
struct kex_curve25519_param {
|
||||
unsigned char priv[CURVE25519_LEN];
|
||||
unsigned char pub[CURVE25519_LEN];
|
||||
};
|
||||
|
||||
/* No header file for curve25519_donna */
|
||||
int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsigned char *other);
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_KEXHASHBUF 2000
|
||||
|
||||
#endif /* _KEX_H_ */
|
||||
|
||||
653
keyimport.c
653
keyimport.c
@@ -2,8 +2,6 @@
|
||||
* Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com
|
||||
* keyfiles.
|
||||
*
|
||||
* The horribleness of the code is probably mine (matt).
|
||||
*
|
||||
* Modifications copyright 2003 Matt Johnston
|
||||
*
|
||||
* PuTTY is copyright 1997-2003 Simon Tatham.
|
||||
@@ -36,6 +34,11 @@
|
||||
#include "bignum.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "ecc.h"
|
||||
|
||||
static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
|
||||
static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
|
||||
static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
|
||||
|
||||
#define PUT_32BIT(cp, value) do { \
|
||||
(cp)[3] = (unsigned char)(value); \
|
||||
@@ -109,7 +112,7 @@ static sign_key *dropbear_read(const char* filename) {
|
||||
|
||||
buffer * buf = NULL;
|
||||
sign_key *ret = NULL;
|
||||
int type;
|
||||
enum signkey_type type;
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
|
||||
@@ -125,6 +128,8 @@ static sign_key *dropbear_read(const char* filename) {
|
||||
}
|
||||
buf_free(buf);
|
||||
|
||||
ret->type = type;
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
@@ -140,25 +145,13 @@ error:
|
||||
/* returns 0 on fail, 1 on success */
|
||||
static int dropbear_write(const char*filename, sign_key * key) {
|
||||
|
||||
int keytype = -1;
|
||||
buffer * buf;
|
||||
FILE*fp;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
buf_put_priv_key(buf, key, key->type);
|
||||
|
||||
fp = fopen(filename, "w");
|
||||
if (!fp) {
|
||||
@@ -349,7 +342,7 @@ struct mpint_pos { void *start; int bytes; };
|
||||
* Code to read and write OpenSSH private keys.
|
||||
*/
|
||||
|
||||
enum { OSSH_DSA, OSSH_RSA };
|
||||
enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
|
||||
struct openssh_key {
|
||||
int type;
|
||||
int encrypted;
|
||||
@@ -392,6 +385,8 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
ret->type = OSSH_RSA;
|
||||
else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
|
||||
ret->type = OSSH_DSA;
|
||||
else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
|
||||
ret->type = OSSH_EC;
|
||||
else {
|
||||
errmsg = "Unrecognised key type";
|
||||
goto error;
|
||||
@@ -506,7 +501,7 @@ static int openssh_encrypted(const char *filename)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
{
|
||||
struct openssh_key *key;
|
||||
unsigned char *p;
|
||||
@@ -516,11 +511,13 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
char *errmsg;
|
||||
char *modptr = NULL;
|
||||
int modlen = -9999;
|
||||
int type;
|
||||
enum signkey_type type;
|
||||
|
||||
sign_key *retkey;
|
||||
buffer * blobbuf = NULL;
|
||||
|
||||
retkey = new_sign_key();
|
||||
|
||||
key = load_openssh_key(filename);
|
||||
|
||||
if (!key)
|
||||
@@ -597,17 +594,26 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
num_integers = 9;
|
||||
else if (key->type == OSSH_DSA)
|
||||
num_integers = 6;
|
||||
else if (key->type == OSSH_EC)
|
||||
num_integers = 1;
|
||||
|
||||
/*
|
||||
* Space to create key blob in.
|
||||
*/
|
||||
blobbuf = buf_new(3000);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->type == OSSH_DSA) {
|
||||
buf_putstring(blobbuf, "ssh-dss", 7);
|
||||
} else if (key->type == OSSH_RSA) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->type == OSSH_RSA) {
|
||||
buf_putstring(blobbuf, "ssh-rsa", 7);
|
||||
retkey->type = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num_integers; i++) {
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
@@ -620,11 +626,18 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
/*
|
||||
* The first integer should be zero always (I think
|
||||
* this is some sort of version indication).
|
||||
*/
|
||||
if (len != 1 || p[0] != 0) {
|
||||
/* First integer is a version indicator */
|
||||
int expected = -1;
|
||||
switch (key->type) {
|
||||
case OSSH_RSA:
|
||||
case OSSH_DSA:
|
||||
expected = 0;
|
||||
break;
|
||||
case OSSH_EC:
|
||||
expected = 1;
|
||||
break;
|
||||
}
|
||||
if (len != 1 || p[0] != expected) {
|
||||
errmsg = "Version number mismatch";
|
||||
goto error;
|
||||
}
|
||||
@@ -655,21 +668,136 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
p += len;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (key->type == OSSH_EC) {
|
||||
unsigned char* private_key_bytes = NULL;
|
||||
int private_key_len = 0;
|
||||
unsigned char* public_key_bytes = NULL;
|
||||
int public_key_len = 0;
|
||||
ecc_key *ecc = NULL;
|
||||
const struct dropbear_ecc_curve *curve = NULL;
|
||||
|
||||
/* See SEC1 v2, Appendix C.4 */
|
||||
/* OpenSSL (so OpenSSH) seems to include the optional parts. */
|
||||
|
||||
/* privateKey OCTET STRING, */
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
/* id==4 for octet string */
|
||||
if (ret < 0 || id != 4 ||
|
||||
key->keyblob+key->keyblob_len-p < len) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
private_key_bytes = p;
|
||||
private_key_len = len;
|
||||
p += len;
|
||||
|
||||
/* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, */
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
/* id==0 */
|
||||
if (ret < 0 || id != 0) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
/* id==6 for object */
|
||||
if (ret < 0 || id != 6 ||
|
||||
key->keyblob+key->keyblob_len-p < len) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (0) {}
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
else if (len == sizeof(OID_SEC256R1_BLOB)
|
||||
&& memcmp(p, OID_SEC256R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
curve = &ecc_curve_nistp256;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
else if (len == sizeof(OID_SEC384R1_BLOB)
|
||||
&& memcmp(p, OID_SEC384R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384;
|
||||
curve = &ecc_curve_nistp384;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
else if (len == sizeof(OID_SEC521R1_BLOB)
|
||||
&& memcmp(p, OID_SEC521R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
curve = &ecc_curve_nistp521;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
errmsg = "Unknown ECC key type";
|
||||
goto error;
|
||||
}
|
||||
p += len;
|
||||
|
||||
/* publicKey [1] BIT STRING OPTIONAL */
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
/* id==1 */
|
||||
if (ret < 0 || id != 1) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
/* id==3 for bit string */
|
||||
if (ret < 0 || id != 3 ||
|
||||
key->keyblob+key->keyblob_len-p < len) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
public_key_bytes = p+1;
|
||||
public_key_len = len-1;
|
||||
p += len;
|
||||
|
||||
buf_putbytes(blobbuf, public_key_bytes, public_key_len);
|
||||
ecc = buf_get_ecc_raw_pubkey(blobbuf, curve);
|
||||
if (!ecc) {
|
||||
errmsg = "Error parsing ECC key";
|
||||
goto error;
|
||||
}
|
||||
m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL);
|
||||
if (mp_read_unsigned_bin(ecc->k, private_key_bytes, private_key_len)
|
||||
!= MP_OKAY) {
|
||||
errmsg = "Error parsing ECC key";
|
||||
goto error;
|
||||
}
|
||||
|
||||
*signkey_key_ptr(retkey, retkey->type) = ecc;
|
||||
}
|
||||
#endif /* DROPBEAR_ECDSA */
|
||||
|
||||
/*
|
||||
* Now put together the actual key. Simplest way to do this is
|
||||
* to assemble our own key blobs and feed them to the createkey
|
||||
* functions; this is a bit faffy but it does mean we get all
|
||||
* the sanity checks for free.
|
||||
*/
|
||||
retkey = new_sign_key();
|
||||
buf_setpos(blobbuf, 0);
|
||||
type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_priv_key(blobbuf, retkey, &type)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
errmsg = "unable to create key structure";
|
||||
sign_key_free(retkey);
|
||||
retkey = NULL;
|
||||
goto error;
|
||||
if (key->type == OSSH_RSA || key->type == OSSH_DSA) {
|
||||
buf_setpos(blobbuf, 0);
|
||||
type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_priv_key(blobbuf, retkey, &type)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
errmsg = "unable to create key structure";
|
||||
sign_key_free(retkey);
|
||||
retkey = NULL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
errmsg = NULL; /* no error */
|
||||
@@ -682,7 +810,7 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
}
|
||||
m_burn(key->keyblob, key->keyblob_size);
|
||||
m_free(key->keyblob);
|
||||
m_burn(key, sizeof(key));
|
||||
m_burn(key, sizeof(*key));
|
||||
m_free(key);
|
||||
if (errmsg) {
|
||||
fprintf(stderr, "Error: %s\n", errmsg);
|
||||
@@ -698,207 +826,296 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
unsigned char *outblob = NULL;
|
||||
int outlen = -9999;
|
||||
struct mpint_pos numbers[9];
|
||||
int nnumbers = -1, pos, len, seqlen, i;
|
||||
int nnumbers = -1, pos = 0, len = 0, seqlen, i;
|
||||
char *header = NULL, *footer = NULL;
|
||||
char zero[1];
|
||||
int ret = 0;
|
||||
FILE *fp;
|
||||
int keytype = -1;
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
|
||||
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
|
||||
dropbear_assert(keytype != -1);
|
||||
|
||||
/*
|
||||
* Fetch the key blobs.
|
||||
*/
|
||||
keyblob = buf_new(3000);
|
||||
buf_put_priv_key(keyblob, key, keytype);
|
||||
|
||||
buf_setpos(keyblob, 0);
|
||||
/* skip the "ssh-rsa" or "ssh-dss" header */
|
||||
buf_incrpos(keyblob, buf_getint(keyblob));
|
||||
|
||||
/*
|
||||
* Find the sequence of integers to be encoded into the OpenSSH
|
||||
* key blob, and also decide on the header line.
|
||||
*/
|
||||
numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
|
||||
|
||||
if (
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
|
||||
if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
|
||||
fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* e */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
|
||||
/* n */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
|
||||
/* d */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
|
||||
/* p */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
|
||||
/* q */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
|
||||
/* now calculate some extra parameters: */
|
||||
m_mp_init(&tmpval);
|
||||
m_mp_init(&dmp1);
|
||||
m_mp_init(&dmq1);
|
||||
m_mp_init(&iqmp);
|
||||
|
||||
/* dmp1 = d mod (p-1) */
|
||||
if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for p-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmp1\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* dmq1 = d mod (q-1) */
|
||||
if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for q-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmq1\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* iqmp = (q^-1) mod p */
|
||||
if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for iqmp\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
extrablob = buf_new(2000);
|
||||
buf_putmpint(extrablob, &dmp1);
|
||||
buf_putmpint(extrablob, &dmq1);
|
||||
buf_putmpint(extrablob, &iqmp);
|
||||
buf_setpos(extrablob, 0);
|
||||
mp_clear(&dmp1);
|
||||
mp_clear(&dmq1);
|
||||
mp_clear(&iqmp);
|
||||
mp_clear(&tmpval);
|
||||
|
||||
/* dmp1 */
|
||||
numbers[6].bytes = buf_getint(extrablob);
|
||||
numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
|
||||
buf_incrpos(extrablob, numbers[6].bytes);
|
||||
|
||||
/* dmq1 */
|
||||
numbers[7].bytes = buf_getint(extrablob);
|
||||
numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
|
||||
buf_incrpos(extrablob, numbers[7].bytes);
|
||||
|
||||
/* iqmp */
|
||||
numbers[8].bytes = buf_getint(extrablob);
|
||||
numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
|
||||
buf_incrpos(extrablob, numbers[8].bytes);
|
||||
|
||||
nnumbers = 9;
|
||||
header = "-----BEGIN RSA PRIVATE KEY-----\n";
|
||||
footer = "-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
key->type == DROPBEAR_SIGNKEY_RSA ||
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
key->type == DROPBEAR_SIGNKEY_DSS ||
|
||||
#endif
|
||||
0)
|
||||
{
|
||||
/*
|
||||
* Fetch the key blobs.
|
||||
*/
|
||||
keyblob = buf_new(3000);
|
||||
buf_put_priv_key(keyblob, key, key->type);
|
||||
|
||||
/* p */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
buf_setpos(keyblob, 0);
|
||||
/* skip the "ssh-rsa" or "ssh-dss" header */
|
||||
buf_incrpos(keyblob, buf_getint(keyblob));
|
||||
|
||||
/* q */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
/*
|
||||
* Find the sequence of integers to be encoded into the OpenSSH
|
||||
* key blob, and also decide on the header line.
|
||||
*/
|
||||
numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
|
||||
|
||||
/* g */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
|
||||
/* y */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
|
||||
fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* x */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
/* e */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
|
||||
/* n */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
|
||||
/* d */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
|
||||
/* p */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
|
||||
/* q */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
|
||||
nnumbers = 6;
|
||||
header = "-----BEGIN DSA PRIVATE KEY-----\n";
|
||||
footer = "-----END DSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
/*
|
||||
* Now count up the total size of the ASN.1 encoded integers,
|
||||
* so as to determine the length of the containing SEQUENCE.
|
||||
*/
|
||||
len = 0;
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
|
||||
len += numbers[i].bytes;
|
||||
}
|
||||
seqlen = len;
|
||||
/* Now add on the SEQUENCE header. */
|
||||
len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
/* Round up to the cipher block size, ensuring we have at least one
|
||||
* byte of padding (see below). */
|
||||
outlen = len;
|
||||
if (passphrase)
|
||||
outlen = (outlen+8) &~ 7;
|
||||
|
||||
/*
|
||||
* Now we know how big outblob needs to be. Allocate it.
|
||||
*/
|
||||
outblob = (unsigned char*)m_malloc(outlen);
|
||||
|
||||
/*
|
||||
* And write the data into it.
|
||||
*/
|
||||
pos = 0;
|
||||
pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
|
||||
memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
|
||||
pos += numbers[i].bytes;
|
||||
/* now calculate some extra parameters: */
|
||||
m_mp_init(&tmpval);
|
||||
m_mp_init(&dmp1);
|
||||
m_mp_init(&dmq1);
|
||||
m_mp_init(&iqmp);
|
||||
|
||||
/* dmp1 = d mod (p-1) */
|
||||
if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for p-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmp1\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* dmq1 = d mod (q-1) */
|
||||
if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for q-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmq1\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* iqmp = (q^-1) mod p */
|
||||
if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for iqmp\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
extrablob = buf_new(2000);
|
||||
buf_putmpint(extrablob, &dmp1);
|
||||
buf_putmpint(extrablob, &dmq1);
|
||||
buf_putmpint(extrablob, &iqmp);
|
||||
buf_setpos(extrablob, 0);
|
||||
mp_clear(&dmp1);
|
||||
mp_clear(&dmq1);
|
||||
mp_clear(&iqmp);
|
||||
mp_clear(&tmpval);
|
||||
|
||||
/* dmp1 */
|
||||
numbers[6].bytes = buf_getint(extrablob);
|
||||
numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
|
||||
buf_incrpos(extrablob, numbers[6].bytes);
|
||||
|
||||
/* dmq1 */
|
||||
numbers[7].bytes = buf_getint(extrablob);
|
||||
numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
|
||||
buf_incrpos(extrablob, numbers[7].bytes);
|
||||
|
||||
/* iqmp */
|
||||
numbers[8].bytes = buf_getint(extrablob);
|
||||
numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
|
||||
buf_incrpos(extrablob, numbers[8].bytes);
|
||||
|
||||
nnumbers = 9;
|
||||
header = "-----BEGIN RSA PRIVATE KEY-----\n";
|
||||
footer = "-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->type == DROPBEAR_SIGNKEY_DSS) {
|
||||
|
||||
/* p */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
|
||||
/* q */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
|
||||
/* g */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
|
||||
/* y */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
|
||||
/* x */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
|
||||
nnumbers = 6;
|
||||
header = "-----BEGIN DSA PRIVATE KEY-----\n";
|
||||
footer = "-----END DSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
/*
|
||||
* Now count up the total size of the ASN.1 encoded integers,
|
||||
* so as to determine the length of the containing SEQUENCE.
|
||||
*/
|
||||
len = 0;
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
|
||||
len += numbers[i].bytes;
|
||||
}
|
||||
seqlen = len;
|
||||
/* Now add on the SEQUENCE header. */
|
||||
len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
/* Round up to the cipher block size, ensuring we have at least one
|
||||
* byte of padding (see below). */
|
||||
outlen = len;
|
||||
if (passphrase)
|
||||
outlen = (outlen+8) &~ 7;
|
||||
|
||||
/*
|
||||
* Now we know how big outblob needs to be. Allocate it.
|
||||
*/
|
||||
outblob = (unsigned char*)m_malloc(outlen);
|
||||
|
||||
/*
|
||||
* And write the data into it.
|
||||
*/
|
||||
pos = 0;
|
||||
pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
|
||||
memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
|
||||
pos += numbers[i].bytes;
|
||||
}
|
||||
} /* end RSA and DSS handling */
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|
||||
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|
||||
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
|
||||
|
||||
/* SEC1 V2 appendix c.4
|
||||
ECPrivateKey ::= SEQUENCE {
|
||||
version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
|
||||
privateKey OCTET STRING,
|
||||
parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
|
||||
publicKey [1] BIT STRING OPTIONAL
|
||||
}
|
||||
*/
|
||||
buffer *seq_buf = buf_new(400);
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
|
||||
const long curve_size = (*eck)->dp->size;
|
||||
int curve_oid_len = 0;
|
||||
const void* curve_oid = NULL;
|
||||
unsigned long pubkey_size = 2*curve_size+1;
|
||||
unsigned int k_size;
|
||||
|
||||
/* version. less than 10 bytes */
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 2, 1, 0));
|
||||
buf_putbyte(seq_buf, 1);
|
||||
|
||||
/* privateKey */
|
||||
k_size = mp_unsigned_bin_size((*eck)->k);
|
||||
dropbear_assert(k_size <= curve_size);
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0));
|
||||
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, k_size));
|
||||
buf_incrwritepos(seq_buf, k_size);
|
||||
|
||||
/* SECGCurveNames */
|
||||
switch (key->type)
|
||||
{
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
curve_oid_len = sizeof(OID_SEC256R1_BLOB);
|
||||
curve_oid = OID_SEC256R1_BLOB;
|
||||
break;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
curve_oid_len = sizeof(OID_SEC384R1_BLOB);
|
||||
curve_oid = OID_SEC384R1_BLOB;
|
||||
break;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
curve_oid_len = sizeof(OID_SEC521R1_BLOB);
|
||||
curve_oid = OID_SEC521R1_BLOB;
|
||||
break;
|
||||
default:
|
||||
dropbear_exit("Internal error");
|
||||
}
|
||||
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 0, 2+curve_oid_len, 0xa0));
|
||||
/* object == 6 */
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 6, curve_oid_len, 0));
|
||||
buf_putbytes(seq_buf, curve_oid, curve_oid_len);
|
||||
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 1, 2+1+pubkey_size, 0xa0));
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
|
||||
buf_putbyte(seq_buf, 0);
|
||||
int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
|
||||
if (err != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
buf_incrwritepos(seq_buf, pubkey_size);
|
||||
|
||||
buf_setpos(seq_buf, 0);
|
||||
|
||||
outblob = (unsigned char*)m_malloc(1000);
|
||||
|
||||
pos = 0;
|
||||
pos += ber_write_id_len(outblob+pos, 16, seq_buf->len, ASN1_CONSTRUCTED);
|
||||
memcpy(&outblob[pos], seq_buf->data, seq_buf->len);
|
||||
pos += seq_buf->len;
|
||||
len = pos;
|
||||
outlen = len;
|
||||
|
||||
buf_burn(seq_buf);
|
||||
buf_free(seq_buf);
|
||||
seq_buf = NULL;
|
||||
|
||||
header = "-----BEGIN EC PRIVATE KEY-----\n";
|
||||
footer = "-----END EC PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Padding on OpenSSH keys is deterministic. The number of
|
||||
|
||||
@@ -19,7 +19,7 @@ srcdir=@srcdir@
|
||||
|
||||
# Compilation flags. Note the += does not write over the user's CFLAGS!
|
||||
# The rest of the flags come from the parent Dropbear makefile
|
||||
CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../
|
||||
CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../ -DLTC_SOURCE -I$(srcdir)/../libtommath/
|
||||
|
||||
# additional warnings (newer GCC 3.4 and higher)
|
||||
ifdef GCC_34
|
||||
@@ -157,7 +157,53 @@ src/modes/lrw/lrw_decrypt.o src/modes/lrw/lrw_done.o src/modes/lrw/lrw_encrypt.o
|
||||
src/modes/lrw/lrw_getiv.o src/modes/lrw/lrw_process.o src/modes/lrw/lrw_setiv.o \
|
||||
src/modes/lrw/lrw_start.o src/modes/lrw/lrw_test.o src/modes/ofb/ofb_decrypt.o src/modes/ofb/ofb_done.o \
|
||||
src/modes/ofb/ofb_encrypt.o src/modes/ofb/ofb_getiv.o src/modes/ofb/ofb_setiv.o \
|
||||
src/modes/ofb/ofb_start.o
|
||||
src/modes/ofb/ofb_start.o src/pk/asn1/der/bit/der_decode_bit_string.o \
|
||||
src/pk/asn1/der/bit/der_encode_bit_string.o src/pk/asn1/der/bit/der_length_bit_string.o \
|
||||
src/pk/asn1/der/boolean/der_decode_boolean.o src/pk/asn1/der/boolean/der_encode_boolean.o \
|
||||
src/pk/asn1/der/boolean/der_length_boolean.o src/pk/asn1/der/choice/der_decode_choice.o \
|
||||
src/pk/asn1/der/ia5/der_decode_ia5_string.o src/pk/asn1/der/ia5/der_encode_ia5_string.o \
|
||||
src/pk/asn1/der/ia5/der_length_ia5_string.o src/pk/asn1/der/integer/der_decode_integer.o \
|
||||
src/pk/asn1/der/integer/der_encode_integer.o src/pk/asn1/der/integer/der_length_integer.o \
|
||||
src/pk/asn1/der/object_identifier/der_decode_object_identifier.o \
|
||||
src/pk/asn1/der/object_identifier/der_encode_object_identifier.o \
|
||||
src/pk/asn1/der/object_identifier/der_length_object_identifier.o \
|
||||
src/pk/asn1/der/octet/der_decode_octet_string.o src/pk/asn1/der/octet/der_encode_octet_string.o \
|
||||
src/pk/asn1/der/octet/der_length_octet_string.o \
|
||||
src/pk/asn1/der/printable_string/der_decode_printable_string.o \
|
||||
src/pk/asn1/der/printable_string/der_encode_printable_string.o \
|
||||
src/pk/asn1/der/printable_string/der_length_printable_string.o \
|
||||
src/pk/asn1/der/sequence/der_decode_sequence_ex.o \
|
||||
src/pk/asn1/der/sequence/der_decode_sequence_flexi.o \
|
||||
src/pk/asn1/der/sequence/der_decode_sequence_multi.o \
|
||||
src/pk/asn1/der/sequence/der_encode_sequence_ex.o \
|
||||
src/pk/asn1/der/sequence/der_encode_sequence_multi.o src/pk/asn1/der/sequence/der_length_sequence.o \
|
||||
src/pk/asn1/der/sequence/der_sequence_free.o src/pk/asn1/der/set/der_encode_set.o \
|
||||
src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_short_integer.o \
|
||||
src/pk/asn1/der/short_integer/der_encode_short_integer.o \
|
||||
src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \
|
||||
src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \
|
||||
src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \
|
||||
src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \
|
||||
src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \
|
||||
src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \
|
||||
src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \
|
||||
src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \
|
||||
src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \
|
||||
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \
|
||||
src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
|
||||
src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
|
||||
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
|
||||
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
|
||||
src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \
|
||||
src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \
|
||||
src/pk/katja/katja_make_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \
|
||||
src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \
|
||||
src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \
|
||||
src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \
|
||||
src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_import.o \
|
||||
src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_sign_hash.o src/pk/rsa/rsa_verify_hash.o src/prngs/fortuna.o \
|
||||
src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \
|
||||
src/prngs/sprng.o src/prngs/yarrow.o
|
||||
|
||||
HEADERS=src/headers/tomcrypt_cfg.h src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h \
|
||||
src/headers/tomcrypt_custom.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cipher.h \
|
||||
|
||||
@@ -24,7 +24,7 @@ extern "C" {
|
||||
|
||||
/* descriptor table size */
|
||||
/* Dropbear change - this should be smaller, saves some size */
|
||||
#define TAB_SIZE 4
|
||||
#define TAB_SIZE 5
|
||||
|
||||
/* error codes [will be expanded in future releases] */
|
||||
enum {
|
||||
|
||||
@@ -127,13 +127,32 @@
|
||||
#ifdef DROPBEAR_SHA256
|
||||
#define SHA256
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_SHA384
|
||||
#define SHA384
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA512
|
||||
#define SHA512
|
||||
#endif
|
||||
|
||||
#define LTC_HMAC
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
#define MECC
|
||||
#define LTC_ECC_SHAMIR
|
||||
#define LTC_ECC_TIMING_RESISTANT
|
||||
#define MPI
|
||||
#define LTM_DESC
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#define ECC256
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#define ECC384
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#define ECC521
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Various tidbits of modern neatoness */
|
||||
#define BASE64
|
||||
|
||||
|
||||
@@ -11,12 +11,9 @@
|
||||
typedef void ecc_point;
|
||||
#endif
|
||||
|
||||
/* Dropbear has its own rsa_key. We just comment this out. */
|
||||
#if 0
|
||||
#ifndef MRSA
|
||||
typedef void rsa_key;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** math descriptor */
|
||||
typedef struct {
|
||||
@@ -389,8 +386,6 @@ typedef struct {
|
||||
ecc_point *C,
|
||||
void *modulus);
|
||||
|
||||
/* Dropbear has its own rsa code */
|
||||
#if 0
|
||||
/* ---- (optional) rsa optimized math (for internal CRT) ---- */
|
||||
|
||||
/** RSA Key Generation
|
||||
@@ -416,7 +411,6 @@ typedef struct {
|
||||
int (*rsa_me)(const unsigned char *in, unsigned long inlen,
|
||||
unsigned char *out, unsigned long *outlen, int which,
|
||||
rsa_key *key);
|
||||
#endif
|
||||
} ltc_math_descriptor;
|
||||
|
||||
extern ltc_math_descriptor ltc_mp;
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
*/
|
||||
#include "tomcrypt.h"
|
||||
|
||||
ltc_math_descriptor ltc_mp;
|
||||
ltc_math_descriptor ltc_mp = {0};
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Decrypt an ECC encrypted key
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Encrypt a symmetric key with ECC
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Export an ECC key as a binary packet
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
static int is_point(ecc_key *key)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Sign a message digest
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/* verify
|
||||
*
|
||||
|
||||
@@ -329,8 +329,6 @@ login_write (struct logininfo *li)
|
||||
{
|
||||
#ifndef HAVE_CYGWIN
|
||||
if ((int)geteuid() != 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Attempt to write login records by non-root user (aborting)");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -73,10 +73,10 @@
|
||||
#else
|
||||
/* Simply select your favourite login types. */
|
||||
/* Can't do if-else because some systems use several... <sigh> */
|
||||
# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
|
||||
# if defined(HAVE_UTMPX_H) && defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
|
||||
# define USE_UTMPX
|
||||
# endif
|
||||
# if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
|
||||
# if defined(HAVE_UTMP_H) && defined(UTMP_FILE) && !defined(DISABLE_UTMP)
|
||||
# define USE_UTMP
|
||||
# endif
|
||||
# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
|
||||
|
||||
137
ltc_prng.c
Normal file
137
ltc_prng.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/* Copied from libtomcrypt/src/prngs/sprng.c and modified to
|
||||
* use Dropbear's genrandom(). */
|
||||
|
||||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
||||
*
|
||||
* LibTomCrypt is a library that provides various cryptographic
|
||||
* algorithms in a highly modular and flexible manner.
|
||||
*
|
||||
* The library is free for all purposes without any express
|
||||
* guarantee it works.
|
||||
*
|
||||
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
|
||||
*/
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
#include "dbrandom.h"
|
||||
#include "ltc_prng.h"
|
||||
|
||||
/**
|
||||
@file sprng.c
|
||||
Secure PRNG, Tom St Denis
|
||||
*/
|
||||
|
||||
/* A secure PRNG using the RNG functions. Basically this is a
|
||||
* wrapper that allows you to use a secure RNG as a PRNG
|
||||
* in the various other functions.
|
||||
*/
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
|
||||
/**
|
||||
Start the PRNG
|
||||
@param prng [out] The PRNG state to initialize
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_start(prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Add entropy to the PRNG state
|
||||
@param in The data to add
|
||||
@param inlen Length of the data to add
|
||||
@param prng PRNG state to update
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_add_entropy(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Make the PRNG ready to read from
|
||||
@param prng The PRNG to make active
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_ready(prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Read from the PRNG
|
||||
@param out Destination
|
||||
@param outlen Length of output
|
||||
@param prng The active PRNG to read from
|
||||
@return Number of octets read
|
||||
*/
|
||||
unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* UNUSED(prng))
|
||||
{
|
||||
LTC_ARGCHK(out != NULL);
|
||||
genrandom(out, outlen);
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/**
|
||||
Terminate the PRNG
|
||||
@param prng The PRNG to terminate
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_done(prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Export the PRNG state
|
||||
@param out [out] Destination
|
||||
@param outlen [in/out] Max size and resulting size of the state
|
||||
@param prng The PRNG to export
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_export(unsigned char* UNUSED(out), unsigned long* outlen, prng_state* UNUSED(prng))
|
||||
{
|
||||
LTC_ARGCHK(outlen != NULL);
|
||||
|
||||
*outlen = 0;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Import a PRNG state
|
||||
@param in The PRNG state
|
||||
@param inlen Size of the state
|
||||
@param prng The PRNG to import
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_import(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
PRNG self-test
|
||||
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
|
||||
*/
|
||||
int dropbear_prng_test(void)
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct ltc_prng_descriptor dropbear_prng_desc =
|
||||
{
|
||||
"dropbear_prng", 0,
|
||||
&dropbear_prng_start,
|
||||
&dropbear_prng_add_entropy,
|
||||
&dropbear_prng_ready,
|
||||
&dropbear_prng_read,
|
||||
&dropbear_prng_done,
|
||||
&dropbear_prng_export,
|
||||
&dropbear_prng_import,
|
||||
&dropbear_prng_test
|
||||
};
|
||||
|
||||
|
||||
#endif /* DROPBEAR_LTC_PRNG */
|
||||
13
ltc_prng.h
Normal file
13
ltc_prng.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef _LTC_PRNG_H_DROPBEAR
|
||||
#define _LTC_PRNG_H_DROPBEAR
|
||||
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
|
||||
extern const struct ltc_prng_descriptor dropbear_prng_desc;
|
||||
|
||||
#endif /* DROPBEAR_LTC_PRNG */
|
||||
|
||||
#endif /* _LTC_PRNG_H_DROPBEAR */
|
||||
76
options.h
76
options.h
@@ -5,10 +5,10 @@
|
||||
#ifndef _OPTIONS_H_
|
||||
#define _OPTIONS_H_
|
||||
|
||||
/******************************************************************
|
||||
* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
|
||||
******************************************************************/
|
||||
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
|
||||
|
||||
/* IMPORTANT: Many options will require "make clean" after changes */
|
||||
|
||||
#ifndef DROPBEAR_DEFPORT
|
||||
#define DROPBEAR_DEFPORT "22"
|
||||
@@ -26,6 +26,9 @@
|
||||
#ifndef RSA_PRIV_FILENAME
|
||||
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
|
||||
#endif
|
||||
#ifndef ECDSA_PRIV_FILENAME
|
||||
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
|
||||
#endif
|
||||
|
||||
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
|
||||
* on chosen ports and keeps accepting connections. This is the default.
|
||||
@@ -49,7 +52,7 @@
|
||||
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*/
|
||||
#define DROPBEAR_SMALL_CODE
|
||||
|
||||
/* Enable X11 Forwarding - server only */
|
||||
#define ENABLE_X11FWD
|
||||
@@ -92,8 +95,12 @@ much traffic. */
|
||||
#define DROPBEAR_AES256
|
||||
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
|
||||
/*#define DROPBEAR_BLOWFISH*/
|
||||
#define DROPBEAR_TWOFISH256
|
||||
#define DROPBEAR_TWOFISH128
|
||||
/*#define DROPBEAR_TWOFISH256*/
|
||||
/*#define DROPBEAR_TWOFISH128*/
|
||||
|
||||
/* Enable CBC mode for ciphers. This has security issues though
|
||||
* is the most compatible with older SSH implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. This is more secure than normal
|
||||
* CBC mode against certain attacks. This adds around 1kB to binary
|
||||
@@ -120,13 +127,13 @@ much traffic. */
|
||||
* which are not the standard form. */
|
||||
#define DROPBEAR_SHA1_HMAC
|
||||
#define DROPBEAR_SHA1_96_HMAC
|
||||
/*#define DROPBEAR_SHA2_256_HMAC*/
|
||||
/*#define DROPBEAR_SHA2_512_HMAC*/
|
||||
#define DROPBEAR_SHA2_256_HMAC
|
||||
#define DROPBEAR_SHA2_512_HMAC
|
||||
#define DROPBEAR_MD5_HMAC
|
||||
|
||||
/* You can also disable integrity. Don't bother disabling this if you're
|
||||
* still using a cipher, it's relatively cheap. If you disable this it's dead
|
||||
* simple to run arbitrary commands on the remote host. Beware. */
|
||||
* simple for an attacker to run arbitrary commands on the remote host. Beware. */
|
||||
/* #define DROPBEAR_NONE_INTEGRITY */
|
||||
|
||||
/* Hostkey/public key algorithms - at least one required, these are used
|
||||
@@ -135,11 +142,26 @@ much traffic. */
|
||||
* SSH2 RFC Draft requires dss, recommends rsa */
|
||||
#define DROPBEAR_RSA
|
||||
#define DROPBEAR_DSS
|
||||
/* 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
|
||||
|
||||
/* RSA can be vulnerable to timing attacks which use the time required for
|
||||
* signing to guess the private key. Blinding avoids this attack, though makes
|
||||
* signing operations slightly slower. */
|
||||
#define RSA_BLINDING
|
||||
/* 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.
|
||||
This also requires a runtime flag "-R". This adds ~4kB to binary size (or hardly
|
||||
anything if dropbearkey is linked in a "dropbearmulti" binary) */
|
||||
#define DROPBEAR_DELAY_HOSTKEY
|
||||
|
||||
/* Enable Curve25519 for key exchange. This is another elliptic
|
||||
* curve method with good security properties. Increases binary size
|
||||
* by ~8kB on x86-64 */
|
||||
#define DROPBEAR_CURVE25519
|
||||
|
||||
/* Enable elliptic curve Diffie Hellman key exchange, see note about
|
||||
* ECDSA above */
|
||||
#define DROPBEAR_ECDH
|
||||
|
||||
/* Control the memory/performance/compression tradeoff for zlib.
|
||||
* Set windowBits=8 for least memory usage, see your system's
|
||||
@@ -152,8 +174,13 @@ much traffic. */
|
||||
#define DROPBEAR_ZLIB_WINDOW_BITS 15
|
||||
#endif
|
||||
|
||||
/* Server won't allow zlib compression until after authentication. Prevents
|
||||
flaws in the zlib library being unauthenticated exploitable flaws.
|
||||
Some old ssh clients may not support the alternative zlib@openssh.com method */
|
||||
#define DROPBEAR_SERVER_DELAY_ZLIB 1
|
||||
|
||||
/* Whether to do reverse DNS lookups. */
|
||||
#define DO_HOST_LOOKUP
|
||||
/*#define DO_HOST_LOOKUP */
|
||||
|
||||
/* Whether to print the message of the day (MOTD). This doesn't add much code
|
||||
* size */
|
||||
@@ -176,7 +203,7 @@ much traffic. */
|
||||
|
||||
#define ENABLE_SVR_PASSWORD_AUTH
|
||||
/* PAM requires ./configure --enable-pam */
|
||||
/*#define ENABLE_SVR_PAM_AUTH*/
|
||||
/*#define ENABLE_SVR_PAM_AUTH */
|
||||
#define ENABLE_SVR_PUBKEY_AUTH
|
||||
|
||||
/* Whether to take public key options in
|
||||
@@ -189,6 +216,10 @@ much traffic. */
|
||||
#define ENABLE_CLI_PUBKEY_AUTH
|
||||
#define ENABLE_CLI_INTERACT_AUTH
|
||||
|
||||
/* A default argument for dbclient -i <privatekey>.
|
||||
leading "~" is expanded */
|
||||
#define DROPBEAR_DEFAULT_CLI_AUTHKEY "~/.ssh/id_dropbear"
|
||||
|
||||
/* This variable can be used to set a password for client
|
||||
* authentication on the commandline. Beware of platforms
|
||||
* that don't protect environment variables of processes etc. Also
|
||||
@@ -204,6 +235,12 @@ much traffic. */
|
||||
* return the password on standard output */
|
||||
/*#define ENABLE_CLI_ASKPASS_HELPER*/
|
||||
|
||||
/* Save a network roundtrip by sendng a real auth request immediately after
|
||||
* sending a query for the available methods. It is at the expense of < 100
|
||||
* bytes of extra network traffic. This is not yet enabled by default since it
|
||||
* could cause problems with non-compliant servers */
|
||||
/* #define DROPBEAR_CLI_IMMEDIATE_AUTH */
|
||||
|
||||
/* Source for randomness. This must be able to provide hundreds of bytes per SSH
|
||||
* connection without blocking. In addition /dev/random is used for seeding
|
||||
* rsa/dss key generation */
|
||||
@@ -240,7 +277,7 @@ much traffic. */
|
||||
/* The command to invoke for xauth when using X11 forwarding.
|
||||
* "-q" for quiet */
|
||||
#ifndef XAUTH_COMMAND
|
||||
#define XAUTH_COMMAND "/usr/bin/X11/xauth -q"
|
||||
#define XAUTH_COMMAND "/usr/bin/xauth -q"
|
||||
#endif
|
||||
|
||||
/* if you want to enable running an sftp server (such as the one included with
|
||||
@@ -284,6 +321,11 @@ much traffic. */
|
||||
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
|
||||
|
||||
179
packet.c
179
packet.c
@@ -30,7 +30,7 @@
|
||||
#include "algo.h"
|
||||
#include "buffer.h"
|
||||
#include "kex.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "service.h"
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
@@ -41,8 +41,12 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
unsigned char *output_mac);
|
||||
static int checkmac();
|
||||
|
||||
#define ZLIB_COMPRESS_INCR 100
|
||||
#define ZLIB_DECOMPRESS_INCR 100
|
||||
/* For exact details see http://www.zlib.net/zlib_tech.html
|
||||
* 5 bytes per 16kB block, plus 6 bytes for the stream.
|
||||
* We might allocate 5 unnecessary bytes here if it's an
|
||||
* exact multiple. */
|
||||
#define ZLIB_COMPRESS_EXPANSION (((RECV_MAX_PAYLOAD_LEN/16384)+1)*5 + 6)
|
||||
#define ZLIB_DECOMPRESS_INCR 1024
|
||||
#ifndef DISABLE_ZLIB
|
||||
static buffer* buf_decompress(buffer* buf, unsigned int len);
|
||||
static void buf_compress(buffer * dest, buffer * src, unsigned int len);
|
||||
@@ -53,12 +57,76 @@ void write_packet() {
|
||||
|
||||
int len, written;
|
||||
buffer * writebuf = NULL;
|
||||
time_t now;
|
||||
unsigned packet_type;
|
||||
#ifdef HAVE_WRITEV
|
||||
struct iovec *iov = NULL;
|
||||
int i;
|
||||
struct Link *l;
|
||||
int iov_max_count;
|
||||
#endif
|
||||
|
||||
TRACE(("enter write_packet"))
|
||||
TRACE2(("enter write_packet"))
|
||||
dropbear_assert(!isempty(&ses.writequeue));
|
||||
|
||||
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
|
||||
|
||||
#ifndef IOV_MAX
|
||||
#define IOV_MAX UIO_MAXIOV
|
||||
#endif
|
||||
|
||||
/* Make sure the size of the iov is below the maximum allowed by the OS. */
|
||||
iov_max_count = ses.writequeue.count;
|
||||
if (iov_max_count > IOV_MAX)
|
||||
{
|
||||
iov_max_count = IOV_MAX;
|
||||
}
|
||||
|
||||
iov = m_malloc(sizeof(*iov) * iov_max_count);
|
||||
for (l = ses.writequeue.head, i = 0; l; l = l->link, i++)
|
||||
{
|
||||
writebuf = (buffer*)l->item;
|
||||
packet_type = writebuf->data[writebuf->len-1];
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
dropbear_assert(len > 0);
|
||||
TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type,
|
||||
len, writebuf->len-1))
|
||||
iov[i].iov_base = buf_getptr(writebuf, len);
|
||||
iov[i].iov_len = len;
|
||||
}
|
||||
/* This may return EAGAIN. The main loop sometimes
|
||||
calls write_packet() without bothering to test with select() since
|
||||
it's likely to be necessary */
|
||||
written = writev(ses.sock_out, iov, iov_max_count);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
m_free(iov);
|
||||
TRACE2(("leave write_packet: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error writing: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (written == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
while (written > 0) {
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
if (len > written) {
|
||||
/* partial buffer write */
|
||||
buf_incrpos(writebuf, written);
|
||||
written = 0;
|
||||
} else {
|
||||
written -= len;
|
||||
dequeue(&ses.writequeue);
|
||||
buf_free(writebuf);
|
||||
}
|
||||
}
|
||||
|
||||
m_free(iov);
|
||||
#else /* No writev () */
|
||||
/* Get the next buffer in the queue of encrypted packets to write*/
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
|
||||
@@ -71,20 +139,13 @@ void write_packet() {
|
||||
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
|
||||
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave writepacket: EINTR"))
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE2(("leave writepacket: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error writing");
|
||||
dropbear_exit("Error writing: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
ses.last_trx_packet_time = now;
|
||||
|
||||
if (packet_type != SSH_MSG_IGNORE) {
|
||||
ses.last_packet_time = now;
|
||||
}
|
||||
|
||||
if (written == 0) {
|
||||
ses.remoteclosed();
|
||||
@@ -99,8 +160,9 @@ void write_packet() {
|
||||
/* More packet left to write, leave it in the queue for later */
|
||||
buf_incrpos(writebuf, written);
|
||||
}
|
||||
#endif /* writev */
|
||||
|
||||
TRACE(("leave write_packet"))
|
||||
TRACE2(("leave write_packet"))
|
||||
}
|
||||
|
||||
/* Non-blocking function reading available portion of a packet into the
|
||||
@@ -112,7 +174,7 @@ void read_packet() {
|
||||
unsigned int maxlen;
|
||||
unsigned char blocksize;
|
||||
|
||||
TRACE(("enter read_packet"))
|
||||
TRACE2(("enter read_packet"))
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
|
||||
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
|
||||
@@ -125,7 +187,7 @@ void read_packet() {
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
/* didn't read enough to determine the length */
|
||||
TRACE(("leave read_packet: packetinit done"))
|
||||
TRACE2(("leave read_packet: packetinit done"))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +209,7 @@ void read_packet() {
|
||||
|
||||
if (len < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE(("leave read_packet: EINTR or EAGAIN"))
|
||||
TRACE2(("leave read_packet: EINTR or EAGAIN"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error reading: %s", strerror(errno));
|
||||
@@ -163,7 +225,7 @@ void read_packet() {
|
||||
/* The main select() loop process_packet() to
|
||||
* handle the packet contents... */
|
||||
}
|
||||
TRACE(("leave read_packet"))
|
||||
TRACE2(("leave read_packet"))
|
||||
}
|
||||
|
||||
/* Function used to read the initial portion of a packet, and determine the
|
||||
@@ -196,8 +258,8 @@ static int read_packet_init() {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
if (slen < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave read_packet_init: EINTR"))
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE2(("leave read_packet_init: EINTR"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
dropbear_exit("Error reading: %s", strerror(errno));
|
||||
@@ -221,14 +283,14 @@ static int read_packet_init() {
|
||||
}
|
||||
len = buf_getint(ses.readbuf) + 4 + macsize;
|
||||
|
||||
TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
|
||||
TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
|
||||
|
||||
|
||||
/* check packet length */
|
||||
if ((len > RECV_MAX_PACKET_LEN) ||
|
||||
(len < MIN_PACKET_LEN + macsize) ||
|
||||
((len - macsize) % blocksize != 0)) {
|
||||
dropbear_exit("Integrity error (bad packet size %d)", len);
|
||||
dropbear_exit("Integrity error (bad packet size %u)", len);
|
||||
}
|
||||
|
||||
if (len > ses.readbuf->size) {
|
||||
@@ -247,7 +309,7 @@ void decrypt_packet() {
|
||||
unsigned int padlen;
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter decrypt_packet"))
|
||||
TRACE2(("enter decrypt_packet"))
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv.algo_mac->hashsize;
|
||||
|
||||
@@ -279,8 +341,8 @@ void decrypt_packet() {
|
||||
/* payload length */
|
||||
/* - 4 - 1 is for LEN and PADLEN values */
|
||||
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
|
||||
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
|
||||
dropbear_exit("Bad packet size %d", len);
|
||||
if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
|
||||
dropbear_exit("Bad packet size %u", len);
|
||||
}
|
||||
|
||||
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
|
||||
@@ -304,7 +366,7 @@ void decrypt_packet() {
|
||||
|
||||
ses.recvseq++;
|
||||
|
||||
TRACE(("leave decrypt_packet"))
|
||||
TRACE2(("leave decrypt_packet"))
|
||||
}
|
||||
|
||||
/* Checks the mac at the end of a decrypted readbuf.
|
||||
@@ -314,7 +376,7 @@ static int checkmac() {
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
unsigned int mac_size, contents_len;
|
||||
|
||||
mac_size = ses.keys->trans.algo_mac->hashsize;
|
||||
mac_size = ses.keys->recv.algo_mac->hashsize;
|
||||
contents_len = ses.readbuf->len - mac_size;
|
||||
|
||||
buf_setpos(ses.readbuf, 0);
|
||||
@@ -322,7 +384,7 @@ static int checkmac() {
|
||||
|
||||
/* compare the hash */
|
||||
buf_setpos(ses.readbuf, contents_len);
|
||||
if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
|
||||
if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
return DROPBEAR_SUCCESS;
|
||||
@@ -366,7 +428,14 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
}
|
||||
|
||||
if (zstream->avail_out == 0) {
|
||||
buf_resize(ret, ret->size + ZLIB_DECOMPRESS_INCR);
|
||||
int new_size = 0;
|
||||
if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
|
||||
/* Already been increased as large as it can go,
|
||||
* yet didn't finish up the decompression */
|
||||
dropbear_exit("bad packet, oversized decompressed");
|
||||
}
|
||||
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
|
||||
buf_resize(ret, new_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,7 +472,6 @@ static void enqueue_reply_packet() {
|
||||
ses.reply_queue_head = new_item;
|
||||
}
|
||||
ses.reply_queue_tail = new_item;
|
||||
TRACE(("leave enqueue_reply_packet"))
|
||||
}
|
||||
|
||||
void maybe_flush_reply_queue() {
|
||||
@@ -439,25 +507,21 @@ void encrypt_packet() {
|
||||
unsigned char packet_type;
|
||||
unsigned int len, encrypt_buf_size;
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
|
||||
time_t now;
|
||||
|
||||
TRACE(("enter encrypt_packet()"))
|
||||
TRACE2(("enter encrypt_packet()"))
|
||||
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
packet_type = buf_getbyte(ses.writepayload);
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
|
||||
TRACE(("encrypt_packet type is %d", packet_type))
|
||||
TRACE2(("encrypt_packet type is %d", packet_type))
|
||||
|
||||
if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))
|
||||
|| ses.kexstate.sentnewkeys) {
|
||||
if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) {
|
||||
/* During key exchange only particular packets are allowed.
|
||||
Since this packet_type isn't OK we just enqueue it to send
|
||||
after the KEX, see maybe_flush_reply_queue */
|
||||
|
||||
/* We also enqueue packets here when we have sent a MSG_NEWKEYS
|
||||
* packet but are yet to received one. For simplicity we just switch
|
||||
* over all the keys at once. This is the 'ses.kexstate.sentnewkeys'
|
||||
* case. */
|
||||
enqueue_reply_packet();
|
||||
return;
|
||||
}
|
||||
@@ -474,7 +538,7 @@ void encrypt_packet() {
|
||||
+ mac_size
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* some extra in case 'compression' makes it larger */
|
||||
+ ZLIB_COMPRESS_INCR
|
||||
+ ZLIB_COMPRESS_EXPANSION
|
||||
#endif
|
||||
/* and an extra cleartext (stripped before transmission) byte for the
|
||||
* packet type */
|
||||
@@ -487,14 +551,7 @@ void encrypt_packet() {
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compression */
|
||||
if (is_compress_trans()) {
|
||||
int compress_delta;
|
||||
buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
|
||||
compress_delta = (writebuf->len - PACKET_PAYLOAD_OFF) - ses.writepayload->len;
|
||||
|
||||
/* Handle the case where 'compress' increased the size. */
|
||||
if (compress_delta > ZLIB_COMPRESS_INCR) {
|
||||
buf_resize(writebuf, writebuf->size + compress_delta);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -559,7 +616,19 @@ void encrypt_packet() {
|
||||
ses.kexstate.datatrans += writebuf->len;
|
||||
ses.transseq++;
|
||||
|
||||
TRACE(("leave encrypt_packet()"))
|
||||
now = monotonic_now();
|
||||
ses.last_packet_time_any_sent = now;
|
||||
/* idle timeout shouldn't be affected by responses to keepalives.
|
||||
send_msg_keepalive() itself also does tricks with
|
||||
ses.last_packet_idle_time - read that if modifying this code */
|
||||
if (packet_type != SSH_MSG_REQUEST_FAILURE
|
||||
&& packet_type != SSH_MSG_UNIMPLEMENTED
|
||||
&& packet_type != SSH_MSG_IGNORE) {
|
||||
ses.last_packet_time_idle = now;
|
||||
|
||||
}
|
||||
|
||||
TRACE2(("leave encrypt_packet()"))
|
||||
}
|
||||
|
||||
|
||||
@@ -572,8 +641,6 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
unsigned long bufsize;
|
||||
hmac_state hmac;
|
||||
|
||||
TRACE(("enter writemac"))
|
||||
|
||||
if (key_state->algo_mac->hashsize > 0) {
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
@@ -602,7 +669,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
}
|
||||
TRACE(("leave writemac"))
|
||||
TRACE2(("leave writemac"))
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
@@ -613,7 +680,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
unsigned int endpos = src->pos + len;
|
||||
int result;
|
||||
|
||||
TRACE(("enter buf_compress"))
|
||||
TRACE2(("enter buf_compress"))
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -644,9 +711,9 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
/* the buffer has been filled, we must extend. This only happens in
|
||||
* unusual circumstances where the data grows in size after deflate(),
|
||||
* but it is possible */
|
||||
buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
|
||||
buf_resize(dest, dest->size + ZLIB_COMPRESS_EXPANSION);
|
||||
|
||||
}
|
||||
TRACE(("leave buf_compress"))
|
||||
TRACE2(("leave buf_compress"))
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "algo.h"
|
||||
#include "buffer.h"
|
||||
#include "kex.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "service.h"
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
@@ -44,15 +44,17 @@ void process_packet() {
|
||||
|
||||
unsigned char type;
|
||||
unsigned int i;
|
||||
time_t now;
|
||||
|
||||
TRACE(("enter process_packet"))
|
||||
TRACE2(("enter process_packet"))
|
||||
|
||||
type = buf_getbyte(ses.payload);
|
||||
TRACE(("process_packet: packet type = %d", type))
|
||||
TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len))
|
||||
|
||||
ses.lastpacket = type;
|
||||
|
||||
ses.last_packet_time = time(NULL);
|
||||
now = monotonic_now();
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
|
||||
/* These packets we can receive at any time */
|
||||
switch(type) {
|
||||
@@ -65,23 +67,49 @@ void process_packet() {
|
||||
case SSH_MSG_UNIMPLEMENTED:
|
||||
/* debugging XXX */
|
||||
TRACE(("SSH_MSG_UNIMPLEMENTED"))
|
||||
dropbear_exit("Received SSH_MSG_UNIMPLEMENTED");
|
||||
goto out;
|
||||
|
||||
case SSH_MSG_DISCONNECT:
|
||||
/* TODO cleanup? */
|
||||
dropbear_close("Disconnect received");
|
||||
}
|
||||
|
||||
/* Ignore these packet types so that keepalives don't interfere with
|
||||
idle detection. This is slightly incorrect since a tcp forwarded
|
||||
global request with failure won't trigger the idle timeout,
|
||||
but that's probably acceptable */
|
||||
if (!(type == SSH_MSG_GLOBAL_REQUEST || type == SSH_MSG_REQUEST_FAILURE)) {
|
||||
ses.last_packet_time_idle = now;
|
||||
}
|
||||
|
||||
/* This applies for KEX, where the spec says the next packet MUST be
|
||||
* NEWKEYS */
|
||||
if (ses.requirenext != 0) {
|
||||
if (ses.requirenext != type) {
|
||||
/* TODO send disconnect? */
|
||||
dropbear_exit("Unexpected packet type %d, expected %d", type,
|
||||
ses.requirenext);
|
||||
} else {
|
||||
if (ses.requirenext == type)
|
||||
{
|
||||
/* Got what we expected */
|
||||
ses.requirenext = 0;
|
||||
TRACE(("got expected packet %d during kexinit", type))
|
||||
}
|
||||
else
|
||||
{
|
||||
/* RFC4253 7.1 - various messages are allowed at this point.
|
||||
The only ones we know about have already been handled though,
|
||||
so just return "unimplemented" */
|
||||
if (type >= 1 && type <= 49
|
||||
&& type != SSH_MSG_SERVICE_REQUEST
|
||||
&& type != SSH_MSG_SERVICE_ACCEPT
|
||||
&& type != SSH_MSG_KEXINIT)
|
||||
{
|
||||
TRACE(("unknown allowed packet during kexinit"))
|
||||
recv_unimplemented();
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE(("disallowed packet during kexinit"))
|
||||
dropbear_exit("Unexpected packet type %d, expected %d", type,
|
||||
ses.requirenext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +121,12 @@ void process_packet() {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only clear the flag after we have checked ignorenext */
|
||||
if (ses.requirenext != 0 && ses.requirenext == type)
|
||||
{
|
||||
ses.requirenext = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Kindly the protocol authors gave all the preauth packets type values
|
||||
* less-than-or-equal-to 60 ( == MAX_UNAUTH_PACKET_TYPE ).
|
||||
@@ -123,7 +157,7 @@ out:
|
||||
buf_free(ses.payload);
|
||||
ses.payload = NULL;
|
||||
|
||||
TRACE(("leave process_packet"))
|
||||
TRACE2(("leave process_packet"))
|
||||
}
|
||||
|
||||
|
||||
|
||||
2
queue.c
2
queue.c
@@ -70,7 +70,6 @@ void enqueue(struct Queue* queue, void* item) {
|
||||
|
||||
struct Link* newlink;
|
||||
|
||||
TRACE(("enter enqueue"))
|
||||
newlink = (struct Link*)m_malloc(sizeof(struct Link));
|
||||
|
||||
newlink->item = item;
|
||||
@@ -85,5 +84,4 @@ void enqueue(struct Queue* queue, void* item) {
|
||||
queue->head = newlink;
|
||||
}
|
||||
queue->count++;
|
||||
TRACE(("leave enqueue"))
|
||||
}
|
||||
|
||||
2
queue.h
2
queue.h
@@ -36,7 +36,7 @@ struct Queue {
|
||||
|
||||
struct Link* head;
|
||||
struct Link* tail;
|
||||
unsigned int count; /* safety value */
|
||||
unsigned int count;
|
||||
|
||||
};
|
||||
|
||||
|
||||
40
release.sh
Executable file
40
release.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
VERSION=$(echo '#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp - | sh)
|
||||
echo Releasing version "$VERSION" ...
|
||||
if ! head -n1 CHANGES | grep -q $VERSION ; then
|
||||
echo "CHANGES needs updating"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! head -n1 debian/changelog | grep -q $VERSION ; then
|
||||
echo "debian/changelog needs updating"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
head -n1 CHANGES
|
||||
|
||||
#sleep 3
|
||||
|
||||
RELDIR=$PWD/../dropbear-$VERSION
|
||||
ARCHIVE=${RELDIR}.tar.bz2
|
||||
if test -e $RELDIR; then
|
||||
echo "$RELDIR exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -e $ARCHIVE; then
|
||||
echo "$ARCHIVE exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
hg archive "$RELDIR" || exit 2
|
||||
|
||||
(cd "$RELDIR" && autoconf && autoheader) || exit 2
|
||||
|
||||
rm -r "$RELDIR/autom4te.cache" || exit 2
|
||||
|
||||
(cd $RELDIR/.. && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
|
||||
|
||||
ls -l $ARCHIVE
|
||||
openssl sha1 $ARCHIVE
|
||||
echo "Done to $ARCHIVE"
|
||||
44
rsa.c
44
rsa.c
@@ -34,13 +34,12 @@
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
const unsigned char * data, unsigned int len,
|
||||
mp_int * rsa_em);
|
||||
buffer *data_buf, mp_int * rsa_em);
|
||||
|
||||
/* Load a public rsa key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_rsa_key.
|
||||
@@ -51,9 +50,7 @@ int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
TRACE(("enter buf_get_rsa_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
key->e = m_malloc(sizeof(mp_int));
|
||||
key->n = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->e, key->n, NULL);
|
||||
m_mp_alloc_init_multi(&key->e, &key->n, NULL);
|
||||
key->d = NULL;
|
||||
key->p = NULL;
|
||||
key->q = NULL;
|
||||
@@ -99,8 +96,7 @@ int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
key->p = NULL;
|
||||
key->q = NULL;
|
||||
|
||||
key->d = m_malloc(sizeof(mp_int));
|
||||
m_mp_init(key->d);
|
||||
m_mp_alloc_init_multi(&key->d, NULL);
|
||||
if (buf_getmpint(buf, key->d) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: d: ret == DROPBEAR_FAILURE"))
|
||||
goto out;
|
||||
@@ -109,9 +105,7 @@ int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
if (buf->pos == buf->len) {
|
||||
/* old Dropbear private keys didn't keep p and q, so we will ignore them*/
|
||||
} else {
|
||||
key->p = m_malloc(sizeof(mp_int));
|
||||
key->q = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, NULL);
|
||||
m_mp_alloc_init_multi(&key->p, &key->q, NULL);
|
||||
|
||||
if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: p: ret == DROPBEAR_FAILURE"))
|
||||
@@ -139,10 +133,10 @@ out:
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void rsa_key_free(dropbear_rsa_key *key) {
|
||||
|
||||
TRACE(("enter rsa_key_free"))
|
||||
TRACE2(("enter rsa_key_free"))
|
||||
|
||||
if (key == NULL) {
|
||||
TRACE(("leave rsa_key_free: key == NULL"))
|
||||
TRACE2(("leave rsa_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
if (key->d) {
|
||||
@@ -166,7 +160,7 @@ void rsa_key_free(dropbear_rsa_key *key) {
|
||||
m_free(key->q);
|
||||
}
|
||||
m_free(key);
|
||||
TRACE(("leave rsa_key_free"))
|
||||
TRACE2(("leave rsa_key_free"))
|
||||
}
|
||||
|
||||
/* Put the public rsa key into the buffer in the required format:
|
||||
@@ -213,9 +207,7 @@ void buf_put_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a signature in buf, made on data by the key given.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf) {
|
||||
unsigned int slen;
|
||||
DEF_MP_INT(rsa_s);
|
||||
DEF_MP_INT(rsa_mdash);
|
||||
@@ -247,7 +239,7 @@ int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* dat
|
||||
}
|
||||
|
||||
/* create the magic PKCS padded value */
|
||||
rsa_pad_em(key, data, len, &rsa_em);
|
||||
rsa_pad_em(key, data_buf, &rsa_em);
|
||||
|
||||
if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
|
||||
TRACE(("failed exptmod rsa_s"))
|
||||
@@ -270,9 +262,7 @@ out:
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf) {
|
||||
unsigned int nsize, ssize;
|
||||
unsigned int i;
|
||||
DEF_MP_INT(rsa_s);
|
||||
@@ -285,7 +275,7 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
|
||||
|
||||
m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
|
||||
|
||||
rsa_pad_em(key, data, len, &rsa_tmp1);
|
||||
rsa_pad_em(key, data_buf, &rsa_tmp1);
|
||||
|
||||
/* the actual signing of the padded data */
|
||||
|
||||
@@ -357,7 +347,9 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
|
||||
mp_clear(&rsa_s);
|
||||
|
||||
#if defined(DEBUG_RSA) && defined(DEBUG_TRACE)
|
||||
printhex("RSA sig", buf->data, buf->len);
|
||||
if (!debug_trace) {
|
||||
printhex("RSA sig", buf->data, buf->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -377,8 +369,7 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
|
||||
* rsa_em must be a pointer to an initialised mp_int.
|
||||
*/
|
||||
static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
const unsigned char * data, unsigned int len,
|
||||
mp_int * rsa_em) {
|
||||
buffer *data_buf, mp_int * rsa_em) {
|
||||
|
||||
/* ASN1 designator (including the 0x00 preceding) */
|
||||
const unsigned char rsa_asn1_magic[] =
|
||||
@@ -391,7 +382,6 @@ static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
unsigned int nsize;
|
||||
|
||||
dropbear_assert(key != NULL);
|
||||
dropbear_assert(data != NULL);
|
||||
nsize = mp_unsigned_bin_size(key->n);
|
||||
|
||||
rsa_EM = buf_new(nsize-1);
|
||||
@@ -408,7 +398,7 @@ static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
|
||||
/* The hash of the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE));
|
||||
buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE);
|
||||
|
||||
|
||||
6
rsa.h
6
rsa.h
@@ -43,11 +43,9 @@ typedef struct {
|
||||
|
||||
} dropbear_rsa_key;
|
||||
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf);
|
||||
#endif
|
||||
int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
|
||||
int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);
|
||||
|
||||
25
runopts.h
25
runopts.h
@@ -37,14 +37,18 @@ typedef struct runopts {
|
||||
int listen_fwd_all;
|
||||
#endif
|
||||
unsigned int recv_window;
|
||||
time_t keepalive_secs;
|
||||
time_t idle_timeout_secs;
|
||||
time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
|
||||
time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* TODO: add a commandline flag. Currently this is on by default if compression
|
||||
* is compiled in, but disabled for a client's non-final multihop stages. (The
|
||||
* intermediate stages are compressed streams, so are uncompressible. */
|
||||
int enable_compress;
|
||||
enum {
|
||||
DROPBEAR_COMPRESS_DELAYED, /* Server only */
|
||||
DROPBEAR_COMPRESS_ON,
|
||||
DROPBEAR_COMPRESS_OFF,
|
||||
} compress_mode;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
@@ -56,12 +60,12 @@ typedef struct runopts {
|
||||
|
||||
extern runopts opts;
|
||||
|
||||
int readhostkey(const char * filename, sign_key * hostkey, int *type);
|
||||
int readhostkey(const char * filename, sign_key * hostkey,
|
||||
enum signkey_type *type);
|
||||
void load_all_hostkeys();
|
||||
|
||||
typedef struct svr_runopts {
|
||||
|
||||
char * rsakeyfile;
|
||||
char * dsskeyfile;
|
||||
char * bannerfile;
|
||||
|
||||
int forkbg;
|
||||
@@ -99,6 +103,12 @@ typedef struct svr_runopts {
|
||||
#endif
|
||||
|
||||
sign_key *hostkey;
|
||||
|
||||
int delay_hostkey;
|
||||
|
||||
char *hostkey_files[MAX_HOSTKEYS];
|
||||
int num_hostkey_files;
|
||||
|
||||
buffer * banner;
|
||||
char * pidfile;
|
||||
|
||||
@@ -121,6 +131,7 @@ typedef struct cli_runopts {
|
||||
char *cmd;
|
||||
int wantpty;
|
||||
int always_accept_key;
|
||||
int no_hostkey_check;
|
||||
int no_cmd;
|
||||
int backgrounded;
|
||||
int is_subsystem;
|
||||
@@ -157,4 +168,6 @@ void cli_getopts(int argc, char ** argv);
|
||||
void parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
void print_version(void);
|
||||
|
||||
#endif /* _RUNOPTS_H_ */
|
||||
|
||||
8
scp.c
8
scp.c
@@ -230,7 +230,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
||||
close(pin[0]);
|
||||
close(pout[1]);
|
||||
|
||||
#ifdef USE_VFORK
|
||||
#ifndef USE_VFORK
|
||||
arg_setup(host, remuser, cmd);
|
||||
#endif
|
||||
|
||||
@@ -494,8 +494,8 @@ toremote(char *targ, int argc, char **argv)
|
||||
if (verbose_mode)
|
||||
addargs(&alist, "-v");
|
||||
#if 0
|
||||
// Disabled since dbclient won't understand them
|
||||
// and scp works fine without them.
|
||||
/* Disabled since dbclient won't understand them
|
||||
and scp works fine without them. */
|
||||
addargs(&alist, "-x");
|
||||
addargs(&alist, "-oClearAllForwardings yes");
|
||||
addargs(&alist, "-n");
|
||||
@@ -1146,7 +1146,7 @@ usage(void)
|
||||
{
|
||||
(void) fprintf(stderr,
|
||||
"usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
|
||||
" [-l limit] [-o ssh_option] [-P port] [-S program]\n"
|
||||
" [-l limit] [-P port] [-S program]\n"
|
||||
" [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
/*RCSID("OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp ");*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "includes.h"
|
||||
#include "scpmisc.h"
|
||||
|
||||
|
||||
@@ -26,7 +26,5 @@
|
||||
#define _SERVICE_H_
|
||||
|
||||
void recv_msg_service_request(); /* Server */
|
||||
void send_msg_service_request(); /* Client */
|
||||
void recv_msg_service_accept(); /* Client */
|
||||
|
||||
#endif /* _SERVICE_H_ */
|
||||
|
||||
79
session.h
79
session.h
@@ -44,9 +44,12 @@ extern int exitflag;
|
||||
|
||||
void common_session_init(int sock_in, int sock_out);
|
||||
void session_loop(void(*loophandler)());
|
||||
void common_session_cleanup();
|
||||
void session_identification();
|
||||
void session_cleanup();
|
||||
void send_session_identification();
|
||||
void send_msg_ignore();
|
||||
void ignore_recv_response();
|
||||
|
||||
void update_channel_prio();
|
||||
|
||||
const char* get_user_shell();
|
||||
void fill_passwd(const char* username);
|
||||
@@ -58,7 +61,6 @@ void svr_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
/* Client */
|
||||
void cli_session(int sock_in, int sock_out);
|
||||
void cli_session_cleanup();
|
||||
void cleantext(unsigned char* dirtytext);
|
||||
|
||||
/* crypto parameters that are stored individually for transmit and receive */
|
||||
@@ -67,7 +69,7 @@ struct key_context_directional {
|
||||
const struct dropbear_cipher_mode *crypt_mode;
|
||||
const struct dropbear_hash *algo_mac;
|
||||
int hash_index; /* lookup for libtomcrypt */
|
||||
char algo_comp; /* compression */
|
||||
int algo_comp; /* compression */
|
||||
#ifndef DISABLE_ZLIB
|
||||
z_streamp zstream;
|
||||
#endif
|
||||
@@ -79,6 +81,7 @@ struct key_context_directional {
|
||||
#endif
|
||||
} cipher_state;
|
||||
unsigned char mackey[MAX_MAC_LEN];
|
||||
int valid;
|
||||
};
|
||||
|
||||
struct key_context {
|
||||
@@ -86,8 +89,8 @@ struct key_context {
|
||||
struct key_context_directional recv;
|
||||
struct key_context_directional trans;
|
||||
|
||||
char algo_kex;
|
||||
char algo_hostkey;
|
||||
const struct dropbear_kex *algo_kex;
|
||||
int algo_hostkey;
|
||||
|
||||
int allow_compress; /* whether compression has started (useful in
|
||||
zlib@openssh.com delayed compression case) */
|
||||
@@ -104,14 +107,13 @@ struct sshsession {
|
||||
/* Is it a client or server? */
|
||||
unsigned char isserver;
|
||||
|
||||
time_t connect_time; /* time the connection was established
|
||||
(cleared after auth once we're not
|
||||
respecting AUTH_TIMEOUT any more) */
|
||||
|
||||
int sock_in;
|
||||
int sock_out;
|
||||
|
||||
unsigned char *remoteident;
|
||||
/* remotehost will be initially NULL as we delay
|
||||
* reading the remote version string. it will be set
|
||||
* by the time any recv_() packet methods are called */
|
||||
unsigned char *remoteident;
|
||||
|
||||
int maxfd; /* the maximum file descriptor to check with select() */
|
||||
|
||||
@@ -132,8 +134,8 @@ struct sshsession {
|
||||
unsigned dataallowed : 1; /* whether we can send data packets or we are in
|
||||
the middle of a KEX or something */
|
||||
|
||||
unsigned char requirenext; /* byte indicating what packet we require next,
|
||||
or 0x00 for any */
|
||||
unsigned char requirenext; /* byte indicating what packets we require next,
|
||||
or 0x00 for any. */
|
||||
|
||||
unsigned char ignorenext; /* whether to ignore the next packet,
|
||||
used for kex_follows stuff */
|
||||
@@ -143,21 +145,24 @@ struct sshsession {
|
||||
int signal_pipe[2]; /* stores endpoints of a self-pipe used for
|
||||
race-free signal handling */
|
||||
|
||||
time_t last_trx_packet_time; /* time of the last packet transmission, for
|
||||
keepalive purposes */
|
||||
/* time of the last packet send/receive, for keepalive. Not real-world clock */
|
||||
time_t last_packet_time_keepalive_sent;
|
||||
time_t last_packet_time_keepalive_recv;
|
||||
time_t last_packet_time_any_sent;
|
||||
|
||||
time_t last_packet_time; /* time of the last packet transmission or receive, for
|
||||
idle timeout purposes */
|
||||
time_t last_packet_time_idle; /* time of the last packet transmission or receive, for
|
||||
idle timeout purposes so ignores SSH_MSG_IGNORE
|
||||
or responses to keepalives. Not real-world clock */
|
||||
|
||||
|
||||
/* KEX/encryption related */
|
||||
struct KEXState kexstate;
|
||||
struct key_context *keys;
|
||||
struct key_context *newkeys;
|
||||
unsigned char *session_id; /* this is the hash from the first kex */
|
||||
/* The below are used temorarily during kex, are freed after use */
|
||||
buffer *session_id; /* this is the hash from the first kex */
|
||||
/* The below are used temporarily during kex, are freed after use */
|
||||
mp_int * dh_K; /* SSH_MSG_KEXDH_REPLY and sending SSH_MSH_NEWKEYS */
|
||||
unsigned char hash[SHA1_HASH_SIZE]; /* the hash*/
|
||||
buffer *hash; /* the session hash */
|
||||
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
|
||||
buffer* transkexinit; /* the kexinit packet we send should be kept so we
|
||||
can add it to the hash when generating keys */
|
||||
@@ -169,15 +174,11 @@ struct sshsession {
|
||||
concluded (ie, while dataallowed was unset)*/
|
||||
struct packetlist *reply_queue_head, *reply_queue_tail;
|
||||
|
||||
algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
|
||||
int *goodguess); /* The function to use to choose which algorithm
|
||||
to use from the ones presented by the remote
|
||||
side. Is specific to the client/server mode,
|
||||
hence the function-pointer callback.*/
|
||||
|
||||
void(*remoteclosed)(); /* A callback to handle closure of the
|
||||
remote connection */
|
||||
|
||||
void(*extra_session_cleanup)(); /* client or server specific cleanup */
|
||||
void(*send_kex_first_guess)();
|
||||
|
||||
struct AuthState authstate; /* Common amongst client and server, since most
|
||||
struct elements are common */
|
||||
@@ -187,8 +188,11 @@ struct sshsession {
|
||||
unsigned int chansize; /* the number of Channel*s allocated for channels */
|
||||
unsigned int chancount; /* the number of Channel*s in use */
|
||||
const struct ChanType **chantypes; /* The valid channel types */
|
||||
int channel_signal_pending; /* Flag set by sigchld handler */
|
||||
|
||||
/* TCP priority level for the main "port 22" tcp socket */
|
||||
enum dropbear_prio socket_prio;
|
||||
|
||||
|
||||
/* TCP forwarding - where manage listeners */
|
||||
struct Listener ** listeners;
|
||||
unsigned int listensize;
|
||||
@@ -218,6 +222,11 @@ struct serversession {
|
||||
/* The resolved remote address, used for lastlog etc */
|
||||
char *remotehost;
|
||||
|
||||
time_t connect_time; /* time the connection was established
|
||||
(cleared after auth once we're not
|
||||
respecting AUTH_TIMEOUT any more).
|
||||
A monotonic time, not realworld */
|
||||
|
||||
#ifdef USE_VFORK
|
||||
pid_t server_pid;
|
||||
#endif
|
||||
@@ -233,10 +242,7 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
STATE_NOTHING,
|
||||
SERVICE_AUTH_REQ_SENT,
|
||||
SERVICE_AUTH_ACCEPT_RCVD,
|
||||
SERVICE_CONN_REQ_SENT,
|
||||
SERVICE_CONN_ACCEPT_RCVD,
|
||||
USERAUTH_WAIT,
|
||||
USERAUTH_REQ_SENT,
|
||||
USERAUTH_FAIL_RCVD,
|
||||
USERAUTH_SUCCESS_RCVD,
|
||||
@@ -245,7 +251,12 @@ typedef enum {
|
||||
|
||||
struct clientsession {
|
||||
|
||||
mp_int *dh_e, *dh_x; /* Used during KEX */
|
||||
/* XXX - move these to kexstate? */
|
||||
struct kex_dh_param *dh_param;
|
||||
struct kex_ecdh_param *ecdh_param;
|
||||
struct kex_curve25519_param *curve25519_param;
|
||||
const struct dropbear_kex *param_kex_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
|
||||
|
||||
cli_kex_state kex_state; /* Used for progressing KEX */
|
||||
cli_state state; /* Used to progress auth/channelsession etc */
|
||||
unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
|
||||
@@ -259,10 +270,14 @@ struct clientsession {
|
||||
int stderrcopy;
|
||||
int stderrflags;
|
||||
|
||||
/* for escape char handling */
|
||||
int last_char;
|
||||
|
||||
int winchange; /* Set to 1 when a windowchange signal happens */
|
||||
|
||||
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
|
||||
for the last type of auth we tried */
|
||||
int ignore_next_auth_response;
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
int auth_interact_failed; /* flag whether interactive auth can still
|
||||
be used */
|
||||
|
||||
280
signkey.c
280
signkey.c
@@ -27,6 +27,21 @@
|
||||
#include "signkey.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "ecdsa.h"
|
||||
|
||||
static const char *signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
|
||||
#ifdef DROPBEAR_RSA
|
||||
"ssh-rsa",
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
"ssh-dss",
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
"ecdsa-sha2-nistp256",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp521"
|
||||
#endif /* DROPBEAR_ECDSA */
|
||||
};
|
||||
|
||||
/* malloc a new sign_key and set the dss and rsa keys to NULL */
|
||||
sign_key * new_sign_key() {
|
||||
@@ -34,71 +49,101 @@ sign_key * new_sign_key() {
|
||||
sign_key * ret;
|
||||
|
||||
ret = (sign_key*)m_malloc(sizeof(sign_key));
|
||||
#ifdef DROPBEAR_DSS
|
||||
ret->dsskey = NULL;
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
ret->rsakey = NULL;
|
||||
#endif
|
||||
ret->filename = NULL;
|
||||
ret->type = DROPBEAR_SIGNKEY_NONE;
|
||||
ret->source = SIGNKEY_SOURCE_INVALID;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
|
||||
/* Returns key name corresponding to the type. Exits fatally
|
||||
* if the type is invalid */
|
||||
const char* signkey_name_from_type(int type, int *namelen) {
|
||||
const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen) {
|
||||
if (type >= DROPBEAR_SIGNKEY_NUM_NAMED) {
|
||||
dropbear_exit("Bad key type %d", type);
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
*namelen = SSH_SIGNKEY_RSA_LEN;
|
||||
return SSH_SIGNKEY_RSA;
|
||||
if (namelen) {
|
||||
*namelen = strlen(signkey_names[type]);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
*namelen = SSH_SIGNKEY_DSS_LEN;
|
||||
return SSH_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
dropbear_exit("Bad key type %d", type);
|
||||
return NULL; /* notreached */
|
||||
return signkey_names[type];
|
||||
}
|
||||
|
||||
/* Returns DROPBEAR_SIGNKEY_RSA, DROPBEAR_SIGNKEY_DSS,
|
||||
* or DROPBEAR_SIGNKEY_NONE */
|
||||
int signkey_type_from_name(const char* name, int namelen) {
|
||||
/* Returns DROPBEAR_SIGNKEY_NONE if none match */
|
||||
enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) {
|
||||
int i;
|
||||
for (i = 0; i < DROPBEAR_SIGNKEY_NUM_NAMED; i++) {
|
||||
const char *fixed_name = signkey_names[i];
|
||||
if (namelen == strlen(fixed_name)
|
||||
&& memcmp(fixed_name, name, namelen) == 0) {
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (namelen == SSH_SIGNKEY_RSA_LEN
|
||||
&& memcmp(name, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN) == 0) {
|
||||
return DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
/* Some of the ECDSA key sizes are defined even if they're not compiled in */
|
||||
if (0
|
||||
#ifndef DROPBEAR_ECC_256
|
||||
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (namelen == SSH_SIGNKEY_DSS_LEN
|
||||
&& memcmp(name, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN) == 0) {
|
||||
return DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#ifndef DROPBEAR_ECC_384
|
||||
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|
||||
#endif
|
||||
#ifndef DROPBEAR_ECC_521
|
||||
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP521
|
||||
#endif
|
||||
) {
|
||||
TRACE(("attempt to use ecdsa type %d not compiled in", i))
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("signkey_type_from_name unexpected key type."))
|
||||
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
|
||||
/* Returns a pointer to the key part specific to "type" */
|
||||
void **
|
||||
signkey_key_ptr(sign_key *key, enum signkey_type type) {
|
||||
switch (type) {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
return (void**)&key->ecckey256;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
return (void**)&key->ecckey384;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
return (void**)&key->ecckey521;
|
||||
#endif
|
||||
#endif /* DROPBEAR_ECDSA */
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
return (void**)&key->rsakey;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
return (void**)&key->dsskey;
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
|
||||
* type should be set by the caller to specify the type to read, and
|
||||
* on return is set to the type read (useful when type = _ANY) */
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
unsigned int len;
|
||||
int keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter buf_get_pub_key"))
|
||||
TRACE2(("enter buf_get_pub_key"))
|
||||
|
||||
ident = buf_getstring(buf, &len);
|
||||
keytype = signkey_type_from_name(ident, len);
|
||||
@@ -109,7 +154,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
TRACE(("buf_get_pub_key keytype is %d", keytype))
|
||||
TRACE2(("buf_get_pub_key keytype is %d", keytype))
|
||||
|
||||
*type = keytype;
|
||||
|
||||
@@ -136,8 +181,23 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (signkey_is_ecdsa(keytype)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_pub_key(buf);
|
||||
if (*eck) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("leave buf_get_pub_key"))
|
||||
TRACE2(("leave buf_get_pub_key"))
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -146,14 +206,14 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
|
||||
* type should be set by the caller to specify the type to read, and
|
||||
* on return is set to the type read (useful when type = _ANY) */
|
||||
int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
unsigned int len;
|
||||
int keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter buf_get_priv_key"))
|
||||
TRACE2(("enter buf_get_priv_key"))
|
||||
|
||||
ident = buf_getstring(buf, &len);
|
||||
keytype = signkey_type_from_name(ident, len);
|
||||
@@ -189,19 +249,34 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (signkey_is_ecdsa(keytype)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_priv_key(buf);
|
||||
if (*eck) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("leave buf_get_priv_key"))
|
||||
TRACE2(("leave buf_get_priv_key"))
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
|
||||
|
||||
buffer *pubkeys;
|
||||
|
||||
TRACE(("enter buf_put_pub_key"))
|
||||
TRACE2(("enter buf_put_pub_key"))
|
||||
pubkeys = buf_new(MAX_PUBKEY_SIZE);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
@@ -213,21 +288,26 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
buf_put_rsa_pub_key(pubkeys, key->rsakey);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_pub_key(pubkeys, *eck);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pubkeys->len == 0) {
|
||||
dropbear_exit("Bad key types in buf_put_pub_key");
|
||||
}
|
||||
|
||||
buf_setpos(pubkeys, 0);
|
||||
buf_putstring(buf, buf_getptr(pubkeys, pubkeys->len),
|
||||
pubkeys->len);
|
||||
|
||||
buf_putbufstring(buf, pubkeys);
|
||||
buf_free(pubkeys);
|
||||
TRACE(("leave buf_put_pub_key"))
|
||||
TRACE2(("leave buf_put_pub_key"))
|
||||
}
|
||||
|
||||
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
|
||||
void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
|
||||
void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) {
|
||||
|
||||
TRACE(("enter buf_put_priv_key"))
|
||||
TRACE(("type is %d", type))
|
||||
@@ -245,13 +325,23 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
|
||||
TRACE(("leave buf_put_priv_key: rsa done"))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_priv_key(buf, *eck);
|
||||
TRACE(("leave buf_put_priv_key: ecdsa done"))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
dropbear_exit("Bad key types in put pub key");
|
||||
}
|
||||
|
||||
void sign_key_free(sign_key *key) {
|
||||
|
||||
TRACE(("enter sign_key_free"))
|
||||
TRACE2(("enter sign_key_free"))
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dss_key_free(key->dsskey);
|
||||
@@ -260,16 +350,35 @@ void sign_key_free(sign_key *key) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
rsa_key_free(key->rsakey);
|
||||
key->rsakey = NULL;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (key->ecckey256) {
|
||||
ecc_free(key->ecckey256);
|
||||
key->ecckey256 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (key->ecckey384) {
|
||||
ecc_free(key->ecckey384);
|
||||
key->ecckey384 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (key->ecckey521) {
|
||||
ecc_free(key->ecckey521);
|
||||
key->ecckey521 = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
m_free(key->filename);
|
||||
|
||||
m_free(key);
|
||||
TRACE(("leave sign_key_free"))
|
||||
TRACE2(("leave sign_key_free"))
|
||||
}
|
||||
|
||||
static char hexdig(unsigned char x) {
|
||||
|
||||
if (x > 0xf)
|
||||
return 'X';
|
||||
|
||||
@@ -333,14 +442,14 @@ static char * sign_key_sha1_fingerprint(unsigned char* keyblob,
|
||||
|
||||
sha1_done(&hs, hash);
|
||||
|
||||
/* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
|
||||
buflen = 5 + 3*SHA1_HASH_SIZE;
|
||||
/* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
|
||||
buflen = 7 + 3*SHA1_HASH_SIZE;
|
||||
ret = (char*)m_malloc(buflen);
|
||||
|
||||
strcpy(ret, "sha1 ");
|
||||
strcpy(ret, "sha1!! ");
|
||||
|
||||
for (i = 0; i < SHA1_HASH_SIZE; i++) {
|
||||
unsigned int pos = 5 + 3*i;
|
||||
unsigned int pos = 7 + 3*i;
|
||||
ret[pos] = hexdig(hash[i] >> 4);
|
||||
ret[pos+1] = hexdig(hash[i] & 0x0f);
|
||||
ret[pos+2] = ':';
|
||||
@@ -363,29 +472,33 @@ char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
|
||||
void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
|
||||
buffer *data_buf) {
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
buf_put_dss_sign(sigblob, key->dsskey, data, len);
|
||||
buf_put_dss_sign(sigblob, key->dsskey, data_buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
buf_put_rsa_sign(sigblob, key->rsakey, data, len);
|
||||
buf_put_rsa_sign(sigblob, key->rsakey, data_buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_sign(sigblob, *eck, data_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (sigblob->len == 0) {
|
||||
dropbear_exit("Non-matching signing type");
|
||||
}
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
|
||||
}
|
||||
@@ -395,40 +508,45 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
* If FAILURE is returned, the position of
|
||||
* buf is undefined. If SUCCESS is returned, buf will be positioned after the
|
||||
* signature blob */
|
||||
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
unsigned int len) {
|
||||
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
|
||||
|
||||
unsigned int bloblen;
|
||||
unsigned char * ident = NULL;
|
||||
unsigned int identlen = 0;
|
||||
unsigned char * type_name = NULL;
|
||||
unsigned int type_name_len = 0;
|
||||
enum signkey_type type;
|
||||
|
||||
TRACE(("enter buf_verify"))
|
||||
|
||||
bloblen = buf_getint(buf);
|
||||
ident = buf_getstring(buf, &identlen);
|
||||
buf_getint(buf); /* blob length */
|
||||
type_name = buf_getstring(buf, &type_name_len);
|
||||
type = signkey_type_from_name(type_name, type_name_len);
|
||||
m_free(type_name);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (bloblen == DSS_SIGNATURE_SIZE &&
|
||||
memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
|
||||
m_free(ident);
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
if (key->dsskey == NULL) {
|
||||
dropbear_exit("No DSS key to verify signature");
|
||||
}
|
||||
return buf_dss_verify(buf, key->dsskey, data, len);
|
||||
return buf_dss_verify(buf, key->dsskey, data_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
|
||||
m_free(ident);
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
if (key->rsakey == NULL) {
|
||||
dropbear_exit("No RSA key to verify signature");
|
||||
}
|
||||
return buf_rsa_verify(buf, key->rsakey, data, len);
|
||||
return buf_rsa_verify(buf, key->rsakey, data_buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
return buf_ecdsa_verify(buf, *eck, data_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ident);
|
||||
dropbear_exit("Non-matching signing type");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
53
signkey.h
53
signkey.h
@@ -29,6 +29,24 @@
|
||||
#include "dss.h"
|
||||
#include "rsa.h"
|
||||
|
||||
enum signkey_type {
|
||||
#ifdef DROPBEAR_RSA
|
||||
DROPBEAR_SIGNKEY_RSA,
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
DROPBEAR_SIGNKEY_DSS,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
DROPBEAR_SIGNKEY_ECDSA_NISTP256,
|
||||
DROPBEAR_SIGNKEY_ECDSA_NISTP384,
|
||||
DROPBEAR_SIGNKEY_ECDSA_NISTP521,
|
||||
#endif /* DROPBEAR_ECDSA */
|
||||
DROPBEAR_SIGNKEY_NUM_NAMED,
|
||||
DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */
|
||||
DROPBEAR_SIGNKEY_ANY = 80,
|
||||
DROPBEAR_SIGNKEY_NONE = 90,
|
||||
};
|
||||
|
||||
|
||||
/* Sources for signing keys */
|
||||
typedef enum {
|
||||
@@ -39,11 +57,9 @@ typedef enum {
|
||||
|
||||
struct SIGN_key {
|
||||
|
||||
int type; /* The type of key (dss or rsa) */
|
||||
enum signkey_type type;
|
||||
signkey_source source;
|
||||
char *filename;
|
||||
/* the buffer? for encrypted keys, so we can later get
|
||||
* the private key portion */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dropbear_dss_key * dsskey;
|
||||
@@ -51,27 +67,38 @@ struct SIGN_key {
|
||||
#ifdef DROPBEAR_RSA
|
||||
dropbear_rsa_key * rsakey;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
ecc_key * ecckey256;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
ecc_key * ecckey384;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
ecc_key * ecckey521;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct SIGN_key sign_key;
|
||||
|
||||
sign_key * new_sign_key();
|
||||
const char* signkey_name_from_type(int type, int *namelen);
|
||||
int signkey_type_from_name(const char* name, int namelen);
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, int *type);
|
||||
int buf_get_priv_key(buffer* buf, sign_key *key, int *type);
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, int type);
|
||||
void buf_put_priv_key(buffer* buf, sign_key *key, int type);
|
||||
const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen);
|
||||
enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen);
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type);
|
||||
int buf_get_priv_key(buffer* buf, sign_key *key, enum signkey_type *type);
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type);
|
||||
void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type);
|
||||
void sign_key_free(sign_key *key);
|
||||
void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len);
|
||||
void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type, buffer *data_buf);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
unsigned int len);
|
||||
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf);
|
||||
char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen);
|
||||
#endif
|
||||
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
|
||||
const unsigned char* algoname, unsigned int algolen,
|
||||
buffer * line, char ** fingerprint);
|
||||
|
||||
void** signkey_key_ptr(sign_key *key, enum signkey_type type);
|
||||
|
||||
#endif /* _SIGNKEY_H_ */
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "channel.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "listener.h"
|
||||
#include "auth.h"
|
||||
|
||||
|
||||
100
svr-algo.c
100
svr-algo.c
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
* SSH client implementation
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* 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 "algo.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
* also in localalgos[], or return NULL on failure.
|
||||
* (*goodguess) is set to 1 if the preferred client/server algos match,
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess)
|
||||
{
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int count, i, j;
|
||||
algo_type * ret = NULL;
|
||||
|
||||
*goodguess = 0;
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
/* Debug this */
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out; /* just a sanity check, no other use */
|
||||
}
|
||||
|
||||
/* remotealgos will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotealgos[0] = algolist;
|
||||
count = 1;
|
||||
/* Iterate through, replacing ','s with NULs, to split it into
|
||||
* words. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotealgos[count] = &algolist[i+1];
|
||||
count++;
|
||||
}
|
||||
if (count >= MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
for (i = 0; i < count; i++) {
|
||||
|
||||
len = strlen(remotealgos[i]);
|
||||
|
||||
for (j = 0; localalgos[j].name != NULL; j++) {
|
||||
if (localalgos[j].usable) {
|
||||
if (len == strlen(localalgos[j].name) &&
|
||||
strncmp(localalgos[j].name, remotealgos[i], len) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
/* set the algo to return */
|
||||
ret = &localalgos[j];
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
88
svr-auth.c
88
svr-auth.c
@@ -33,11 +33,10 @@
|
||||
#include "packet.h"
|
||||
#include "auth.h"
|
||||
#include "runopts.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
static void authclear();
|
||||
static int checkusername(unsigned char *username, unsigned int userlen);
|
||||
static void send_msg_userauth_banner();
|
||||
|
||||
/* initialise the first time for a session, resetting all parameters */
|
||||
void svr_authinitialise() {
|
||||
@@ -82,24 +81,17 @@ static void authclear() {
|
||||
|
||||
/* Send a banner message if specified to the client. The client might
|
||||
* ignore this, but possibly serves as a legal "no trespassing" sign */
|
||||
static void send_msg_userauth_banner() {
|
||||
void send_msg_userauth_banner(buffer *banner) {
|
||||
|
||||
TRACE(("enter send_msg_userauth_banner"))
|
||||
if (svr_opts.banner == NULL) {
|
||||
TRACE(("leave send_msg_userauth_banner: banner is NULL"))
|
||||
return;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER);
|
||||
buf_putstring(ses.writepayload, buf_getptr(svr_opts.banner,
|
||||
svr_opts.banner->len), svr_opts.banner->len);
|
||||
buf_putbufstring(ses.writepayload, banner);
|
||||
buf_putstring(ses.writepayload, "en", 2);
|
||||
|
||||
encrypt_packet();
|
||||
buf_free(svr_opts.banner);
|
||||
svr_opts.banner = NULL;
|
||||
|
||||
TRACE(("leave send_msg_userauth_banner"))
|
||||
}
|
||||
@@ -110,6 +102,7 @@ void recv_msg_userauth_request() {
|
||||
|
||||
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
|
||||
unsigned int userlen, servicelen, methodlen;
|
||||
int valid_user = 0;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_request"))
|
||||
|
||||
@@ -121,10 +114,11 @@ void recv_msg_userauth_request() {
|
||||
|
||||
/* send the banner if it exists, it will only exist once */
|
||||
if (svr_opts.banner) {
|
||||
send_msg_userauth_banner();
|
||||
send_msg_userauth_banner(svr_opts.banner);
|
||||
buf_free(svr_opts.banner);
|
||||
svr_opts.banner = NULL;
|
||||
}
|
||||
|
||||
|
||||
username = buf_getstring(ses.payload, &userlen);
|
||||
servicename = buf_getstring(ses.payload, &servicelen);
|
||||
methodname = buf_getstring(ses.payload, &methodlen);
|
||||
@@ -141,12 +135,12 @@ void recv_msg_userauth_request() {
|
||||
dropbear_exit("unknown service in auth");
|
||||
}
|
||||
|
||||
/* check username is good before continuing */
|
||||
if (checkusername(username, userlen) == DROPBEAR_FAILURE) {
|
||||
/* username is invalid/no shell/etc - send failure */
|
||||
TRACE(("sending checkusername failure"))
|
||||
send_msg_userauth_failure(0, 1);
|
||||
goto out;
|
||||
/* check username is good before continuing.
|
||||
* the 'incrfail' varies depending on the auth method to
|
||||
* avoid giving away which users exist on the system through
|
||||
* the time delay. */
|
||||
if (checkusername(username, userlen) == DROPBEAR_SUCCESS) {
|
||||
valid_user = 1;
|
||||
}
|
||||
|
||||
/* user wants to know what methods are supported */
|
||||
@@ -154,7 +148,8 @@ void recv_msg_userauth_request() {
|
||||
strncmp(methodname, AUTH_METHOD_NONE,
|
||||
AUTH_METHOD_NONE_LEN) == 0) {
|
||||
TRACE(("recv_msg_userauth_request: 'none' request"))
|
||||
if (svr_opts.allowblankpass
|
||||
if (valid_user
|
||||
&& svr_opts.allowblankpass
|
||||
&& !svr_opts.noauthpass
|
||||
&& !(svr_opts.norootpass && ses.authstate.pw_uid == 0)
|
||||
&& ses.authstate.pw_passwd[0] == '\0')
|
||||
@@ -168,6 +163,7 @@ void recv_msg_userauth_request() {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 'none' has no failure delay */
|
||||
send_msg_userauth_failure(0, 0);
|
||||
goto out;
|
||||
}
|
||||
@@ -180,8 +176,10 @@ void recv_msg_userauth_request() {
|
||||
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN) == 0) {
|
||||
svr_auth_password();
|
||||
goto out;
|
||||
if (valid_user) {
|
||||
svr_auth_password();
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -193,8 +191,10 @@ void recv_msg_userauth_request() {
|
||||
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN) == 0) {
|
||||
svr_auth_pam();
|
||||
goto out;
|
||||
if (valid_user) {
|
||||
svr_auth_pam();
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -204,12 +204,17 @@ void recv_msg_userauth_request() {
|
||||
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PUBKEY,
|
||||
AUTH_METHOD_PUBKEY_LEN) == 0) {
|
||||
svr_auth_pubkey();
|
||||
if (valid_user) {
|
||||
svr_auth_pubkey();
|
||||
} else {
|
||||
/* pubkey has no failure delay */
|
||||
send_msg_userauth_failure(0, 0);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* nothing matched, we just fail */
|
||||
/* nothing matched, we just fail with a delay */
|
||||
send_msg_userauth_failure(0, 1);
|
||||
|
||||
out:
|
||||
@@ -226,6 +231,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
|
||||
char* listshell = NULL;
|
||||
char* usershell = NULL;
|
||||
uid_t uid;
|
||||
TRACE(("enter checkusername"))
|
||||
if (userlen > MAX_USERNAME_LEN) {
|
||||
return DROPBEAR_FAILURE;
|
||||
@@ -251,7 +257,17 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Login attempt for nonexistent user from %s",
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* check if we are running as non-root, and login user is different from the server */
|
||||
uid = geteuid();
|
||||
if (uid != 0 && uid != ses.authstate.pw_uid) {
|
||||
TRACE(("running as nonroot, only server uid is allowed"))
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Login attempt with wrong user %s from %s",
|
||||
ses.authstate.pw_name,
|
||||
svr_ses.addrstring);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
@@ -259,7 +275,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) {
|
||||
TRACE(("leave checkusername: root login disabled"))
|
||||
dropbear_log(LOG_WARNING, "root login rejected");
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
@@ -288,7 +303,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
TRACE(("no matching shell"))
|
||||
dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
goodshell:
|
||||
@@ -298,7 +312,6 @@ goodshell:
|
||||
TRACE(("uid = %d", ses.authstate.pw_uid))
|
||||
TRACE(("leave checkusername"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/* Send a failure message to the client, in responds to a userauth_request.
|
||||
@@ -330,12 +343,10 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
|
||||
}
|
||||
|
||||
buf_setpos(typebuf, 0);
|
||||
buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len),
|
||||
typebuf->len);
|
||||
buf_putbufstring(ses.writepayload, typebuf);
|
||||
|
||||
TRACE(("auth fail: methods %d, '%s'", ses.authstate.authtypes,
|
||||
buf_getptr(typebuf, typebuf->len)));
|
||||
TRACE(("auth fail: methods %d, '%.*s'", ses.authstate.authtypes,
|
||||
typebuf->len, typebuf->data))
|
||||
|
||||
buf_free(typebuf);
|
||||
|
||||
@@ -345,8 +356,8 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
if (incrfail) {
|
||||
unsigned int delay;
|
||||
genrandom((unsigned char*)&delay, sizeof(delay));
|
||||
/* We delay for 300ms +- 50ms, 0.1ms granularity */
|
||||
delay = 250000 + (delay % 1000)*100;
|
||||
/* We delay for 300ms +- 50ms */
|
||||
delay = 250000 + (delay % 100000);
|
||||
usleep(delay);
|
||||
ses.authstate.failcount++;
|
||||
}
|
||||
@@ -381,8 +392,7 @@ void send_msg_userauth_success() {
|
||||
/* authdone must be set after encrypt_packet() for
|
||||
* delayed-zlib mode */
|
||||
ses.authstate.authdone = 1;
|
||||
ses.connect_time = 0;
|
||||
|
||||
svr_ses.connect_time = 0;
|
||||
|
||||
if (ses.authstate.pw_uid == 0) {
|
||||
ses.allowprivport = 1;
|
||||
|
||||
@@ -142,6 +142,22 @@ pamConvFunc(int num_msg,
|
||||
(*respp) = resp;
|
||||
break;
|
||||
|
||||
case PAM_ERROR_MSG:
|
||||
case PAM_TEXT_INFO:
|
||||
|
||||
if (msg_len > 0) {
|
||||
buffer * pam_err = buf_new(msg_len + 4);
|
||||
buf_setpos(pam_err, 0);
|
||||
buf_putbytes(pam_err, "\r\n", 2);
|
||||
buf_putbytes(pam_err, (*msg)->msg, msg_len);
|
||||
buf_putbytes(pam_err, "\r\n", 2);
|
||||
buf_setpos(pam_err, 0);
|
||||
|
||||
send_msg_userauth_banner(pam_err);
|
||||
buf_free(pam_err);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE(("Unknown message type"))
|
||||
rc = PAM_CONV_ERR;
|
||||
@@ -196,14 +212,14 @@ void svr_auth_pam() {
|
||||
|
||||
/* Init pam */
|
||||
if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) {
|
||||
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* just to set it to something */
|
||||
if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) {
|
||||
dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -216,7 +232,7 @@ void svr_auth_pam() {
|
||||
/* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */
|
||||
|
||||
if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) {
|
||||
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Bad PAM password attempt for '%s' from %s",
|
||||
@@ -227,7 +243,7 @@ void svr_auth_pam() {
|
||||
}
|
||||
|
||||
if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) {
|
||||
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Bad PAM password attempt for '%s' from %s",
|
||||
|
||||
@@ -33,6 +33,17 @@
|
||||
|
||||
#ifdef ENABLE_SVR_PASSWORD_AUTH
|
||||
|
||||
static int constant_time_strcmp(const char* a, const char* b) {
|
||||
size_t la = strlen(a);
|
||||
size_t lb = strlen(b);
|
||||
|
||||
if (la != lb) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return constant_time_memcmp(a, b, la);
|
||||
}
|
||||
|
||||
/* Process a password auth request, sending success or failure messages as
|
||||
* appropriate */
|
||||
void svr_auth_password() {
|
||||
@@ -66,6 +77,14 @@ void svr_auth_password() {
|
||||
m_burn(password, passwordlen);
|
||||
m_free(password);
|
||||
|
||||
if (testcrypt == NULL) {
|
||||
/* crypt() with an invalid salt like "!!" */
|
||||
dropbear_log(LOG_WARNING, "User account '%s' is locked",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for empty password */
|
||||
if (passwdcrypt[0] == '\0') {
|
||||
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
|
||||
@@ -74,7 +93,7 @@ void svr_auth_password() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(testcrypt, passwdcrypt) == 0) {
|
||||
if (constant_time_strcmp(testcrypt, passwdcrypt) == 0) {
|
||||
/* successful authentication */
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"Password auth succeeded for '%s' from %s",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user