@electerm/ssh2 1.11.2 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +141 -14
- package/lib/index.js +1 -0
- package/lib/keygen.js +582 -0
- package/lib/protocol/Protocol.js +72 -13
- package/lib/protocol/SFTP.js +190 -2
- package/lib/protocol/constants.js +5 -2
- package/lib/protocol/crypto/build/Makefile +347 -0
- package/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto/src/binding.o.d +247 -0
- package/lib/protocol/crypto/build/Release/.deps/Release/sshcrypto.node.d +1 -0
- package/lib/protocol/crypto/build/Release/obj.target/sshcrypto/src/binding.o +0 -0
- package/lib/protocol/crypto/build/Release/sshcrypto.node +0 -0
- package/lib/protocol/crypto/build/binding.Makefile +6 -0
- package/lib/protocol/crypto/build/gyp-mac-tool +772 -0
- package/lib/protocol/crypto/build/sshcrypto.target.mk +194 -0
- package/lib/protocol/handlers.misc.js +76 -5
- package/lib/protocol/kex.js +100 -23
- package/lib/protocol/keyParser.js +7 -6
- package/lib/protocol/zlib.js +6 -2
- package/lib/server.js +14 -1
- package/package.json +7 -4
package/lib/protocol/Protocol.js
CHANGED
|
@@ -44,12 +44,14 @@ const { bindingAvailable, NullCipher, NullDecipher } = require('./crypto.js');
|
|
|
44
44
|
const {
|
|
45
45
|
COMPAT_CHECKS,
|
|
46
46
|
DISCONNECT_REASON,
|
|
47
|
+
eddsaSupported,
|
|
47
48
|
MESSAGE,
|
|
48
49
|
SIGNALS,
|
|
49
50
|
TERMINAL_MODE,
|
|
50
51
|
} = require('./constants.js');
|
|
51
52
|
const {
|
|
52
|
-
|
|
53
|
+
DEFAULT_KEXINIT_CLIENT,
|
|
54
|
+
DEFAULT_KEXINIT_SERVER,
|
|
53
55
|
KexInit,
|
|
54
56
|
kexinit,
|
|
55
57
|
onKEXPayload,
|
|
@@ -138,8 +140,13 @@ class Protocol {
|
|
|
138
140
|
let onHandshakeComplete = config.onHandshakeComplete;
|
|
139
141
|
if (typeof onHandshakeComplete !== 'function')
|
|
140
142
|
onHandshakeComplete = noop;
|
|
143
|
+
let firstHandshake;
|
|
141
144
|
this._onHandshakeComplete = (...args) => {
|
|
142
145
|
this._debug && this._debug('Handshake completed');
|
|
146
|
+
if (firstHandshake === undefined)
|
|
147
|
+
firstHandshake = true;
|
|
148
|
+
else
|
|
149
|
+
firstHandshake = false;
|
|
143
150
|
|
|
144
151
|
// Process packets queued during a rekey where necessary
|
|
145
152
|
const oldQueue = this._queue;
|
|
@@ -165,6 +172,9 @@ class Protocol {
|
|
|
165
172
|
this._debug && this._debug('... finished draining outbound queue');
|
|
166
173
|
}
|
|
167
174
|
|
|
175
|
+
if (firstHandshake && this._server && this._kex.remoteExtInfoEnabled)
|
|
176
|
+
sendExtInfo(this);
|
|
177
|
+
|
|
168
178
|
onHandshakeComplete(...args);
|
|
169
179
|
};
|
|
170
180
|
this._queue = undefined;
|
|
@@ -205,11 +215,21 @@ class Protocol {
|
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
let offer = config.offer;
|
|
208
|
-
if (typeof offer !== 'object' || offer === null)
|
|
209
|
-
offer =
|
|
210
|
-
else if (offer.constructor !== KexInit)
|
|
218
|
+
if (typeof offer !== 'object' || offer === null) {
|
|
219
|
+
offer = (this._server ? DEFAULT_KEXINIT_SERVER : DEFAULT_KEXINIT_CLIENT);
|
|
220
|
+
} else if (offer.constructor !== KexInit) {
|
|
221
|
+
if (this._server) {
|
|
222
|
+
offer.kex = offer.kex.concat(['kex-strict-s-v00@openssh.com']);
|
|
223
|
+
} else {
|
|
224
|
+
offer.kex = offer.kex.concat([
|
|
225
|
+
'ext-info-c',
|
|
226
|
+
'kex-strict-c-v00@openssh.com',
|
|
227
|
+
]);
|
|
228
|
+
}
|
|
211
229
|
offer = new KexInit(offer);
|
|
230
|
+
}
|
|
212
231
|
this._kex = undefined;
|
|
232
|
+
this._strictMode = undefined;
|
|
213
233
|
this._kexinit = undefined;
|
|
214
234
|
this._offer = offer;
|
|
215
235
|
this._cipher = new NullCipher(0, this._onWrite);
|
|
@@ -608,7 +628,7 @@ class Protocol {
|
|
|
608
628
|
|
|
609
629
|
sendPacket(this, this._packetRW.write.finalize(packet));
|
|
610
630
|
}
|
|
611
|
-
authPK(username, pubKey, cbSign) {
|
|
631
|
+
authPK(username, pubKey, keyAlgo, cbSign) {
|
|
612
632
|
if (this._server)
|
|
613
633
|
throw new Error('Client-only method called in server mode');
|
|
614
634
|
|
|
@@ -627,8 +647,15 @@ class Protocol {
|
|
|
627
647
|
}
|
|
628
648
|
pubKey = pubKey.getPublicSSH();
|
|
629
649
|
|
|
650
|
+
if (typeof keyAlgo === 'function') {
|
|
651
|
+
cbSign = keyAlgo;
|
|
652
|
+
keyAlgo = undefined;
|
|
653
|
+
}
|
|
654
|
+
if (!keyAlgo)
|
|
655
|
+
keyAlgo = keyType;
|
|
656
|
+
|
|
630
657
|
const userLen = Buffer.byteLength(username);
|
|
631
|
-
const algoLen = Buffer.byteLength(
|
|
658
|
+
const algoLen = Buffer.byteLength(keyAlgo);
|
|
632
659
|
const pubKeyLen = pubKey.length;
|
|
633
660
|
const sessionID = this._kex.sessionID;
|
|
634
661
|
const sesLen = sessionID.length;
|
|
@@ -662,7 +689,7 @@ class Protocol {
|
|
|
662
689
|
packet[p += 9] = (cbSign ? 1 : 0);
|
|
663
690
|
|
|
664
691
|
writeUInt32BE(packet, algoLen, ++p);
|
|
665
|
-
packet.utf8Write(
|
|
692
|
+
packet.utf8Write(keyAlgo, p += 4, algoLen);
|
|
666
693
|
|
|
667
694
|
writeUInt32BE(packet, pubKeyLen, p += algoLen);
|
|
668
695
|
packet.set(pubKey, p += 4);
|
|
@@ -705,7 +732,7 @@ class Protocol {
|
|
|
705
732
|
packet[p += 9] = 1;
|
|
706
733
|
|
|
707
734
|
writeUInt32BE(packet, algoLen, ++p);
|
|
708
|
-
packet.utf8Write(
|
|
735
|
+
packet.utf8Write(keyAlgo, p += 4, algoLen);
|
|
709
736
|
|
|
710
737
|
writeUInt32BE(packet, pubKeyLen, p += algoLen);
|
|
711
738
|
packet.set(pubKey, p += 4);
|
|
@@ -713,7 +740,7 @@ class Protocol {
|
|
|
713
740
|
writeUInt32BE(packet, 4 + algoLen + 4 + sigLen, p += pubKeyLen);
|
|
714
741
|
|
|
715
742
|
writeUInt32BE(packet, algoLen, p += 4);
|
|
716
|
-
packet.utf8Write(
|
|
743
|
+
packet.utf8Write(keyAlgo, p += 4, algoLen);
|
|
717
744
|
|
|
718
745
|
writeUInt32BE(packet, sigLen, p += algoLen);
|
|
719
746
|
packet.set(signature, p += 4);
|
|
@@ -728,7 +755,7 @@ class Protocol {
|
|
|
728
755
|
sendPacket(this, this._packetRW.write.finalize(packet));
|
|
729
756
|
});
|
|
730
757
|
}
|
|
731
|
-
authHostbased(username, pubKey, hostname, userlocal, cbSign) {
|
|
758
|
+
authHostbased(username, pubKey, hostname, userlocal, keyAlgo, cbSign) {
|
|
732
759
|
// TODO: Make DRY by sharing similar code with authPK()
|
|
733
760
|
if (this._server)
|
|
734
761
|
throw new Error('Client-only method called in server mode');
|
|
@@ -740,8 +767,15 @@ class Protocol {
|
|
|
740
767
|
const keyType = pubKey.type;
|
|
741
768
|
pubKey = pubKey.getPublicSSH();
|
|
742
769
|
|
|
770
|
+
if (typeof keyAlgo === 'function') {
|
|
771
|
+
cbSign = keyAlgo;
|
|
772
|
+
keyAlgo = undefined;
|
|
773
|
+
}
|
|
774
|
+
if (!keyAlgo)
|
|
775
|
+
keyAlgo = keyType;
|
|
776
|
+
|
|
743
777
|
const userLen = Buffer.byteLength(username);
|
|
744
|
-
const algoLen = Buffer.byteLength(
|
|
778
|
+
const algoLen = Buffer.byteLength(keyAlgo);
|
|
745
779
|
const pubKeyLen = pubKey.length;
|
|
746
780
|
const sessionID = this._kex.sessionID;
|
|
747
781
|
const sesLen = sessionID.length;
|
|
@@ -768,7 +802,7 @@ class Protocol {
|
|
|
768
802
|
data.utf8Write('hostbased', p += 4, 9);
|
|
769
803
|
|
|
770
804
|
writeUInt32BE(data, algoLen, p += 9);
|
|
771
|
-
data.utf8Write(
|
|
805
|
+
data.utf8Write(keyAlgo, p += 4, algoLen);
|
|
772
806
|
|
|
773
807
|
writeUInt32BE(data, pubKeyLen, p += algoLen);
|
|
774
808
|
data.set(pubKey, p += 4);
|
|
@@ -795,7 +829,7 @@ class Protocol {
|
|
|
795
829
|
|
|
796
830
|
writeUInt32BE(packet, 4 + algoLen + 4 + sigLen, p += reqDataLen);
|
|
797
831
|
writeUInt32BE(packet, algoLen, p += 4);
|
|
798
|
-
packet.utf8Write(
|
|
832
|
+
packet.utf8Write(keyAlgo, p += 4, algoLen);
|
|
799
833
|
writeUInt32BE(packet, sigLen, p += algoLen);
|
|
800
834
|
packet.set(signature, p += 4);
|
|
801
835
|
|
|
@@ -2082,4 +2116,29 @@ function modesToBytes(modes) {
|
|
|
2082
2116
|
return bytes;
|
|
2083
2117
|
}
|
|
2084
2118
|
|
|
2119
|
+
function sendExtInfo(proto) {
|
|
2120
|
+
let serverSigAlgs =
|
|
2121
|
+
'ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521'
|
|
2122
|
+
+ 'rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss';
|
|
2123
|
+
if (eddsaSupported)
|
|
2124
|
+
serverSigAlgs = `ssh-ed25519,${serverSigAlgs}`;
|
|
2125
|
+
const algsLen = Buffer.byteLength(serverSigAlgs);
|
|
2126
|
+
|
|
2127
|
+
let p = proto._packetRW.write.allocStart;
|
|
2128
|
+
const packet = proto._packetRW.write.alloc(1 + 4 + 4 + 15 + 4 + algsLen);
|
|
2129
|
+
|
|
2130
|
+
packet[p] = MESSAGE.EXT_INFO;
|
|
2131
|
+
|
|
2132
|
+
writeUInt32BE(packet, 1, ++p);
|
|
2133
|
+
|
|
2134
|
+
writeUInt32BE(packet, 15, p += 4);
|
|
2135
|
+
packet.utf8Write('server-sig-algs', p += 4, 15);
|
|
2136
|
+
|
|
2137
|
+
writeUInt32BE(packet, algsLen, p += 15);
|
|
2138
|
+
packet.utf8Write(serverSigAlgs, p += 4, algsLen);
|
|
2139
|
+
|
|
2140
|
+
proto._debug && proto._debug('Outbound: Sending EXT_INFO');
|
|
2141
|
+
sendPacket(proto, proto._packetRW.write.finalize(packet));
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2085
2144
|
module.exports = Protocol;
|
package/lib/protocol/SFTP.js
CHANGED
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
Readable: ReadableStream,
|
|
8
8
|
Writable: WritableStream
|
|
9
9
|
} = require('stream');
|
|
10
|
-
const { inherits, isDate } = require('util');
|
|
10
|
+
const { inherits, types: { isDate } } = require('util');
|
|
11
11
|
|
|
12
12
|
const FastBuffer = Buffer[Symbol.species];
|
|
13
13
|
|
|
@@ -1588,7 +1588,17 @@ class SFTP extends EventEmitter {
|
|
|
1588
1588
|
writeUInt32BE(buf, pathLen, p += 20);
|
|
1589
1589
|
buf.utf8Write(path, p += 4, pathLen);
|
|
1590
1590
|
|
|
1591
|
-
this._requests[reqid] = {
|
|
1591
|
+
this._requests[reqid] = {
|
|
1592
|
+
cb: (err, names) => {
|
|
1593
|
+
if (typeof cb !== 'function')
|
|
1594
|
+
return;
|
|
1595
|
+
if (err)
|
|
1596
|
+
return cb(err);
|
|
1597
|
+
if (!names || !names.length)
|
|
1598
|
+
return cb(new Error('Response missing expanded path'));
|
|
1599
|
+
cb(undefined, names[0].filename);
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1592
1602
|
|
|
1593
1603
|
const isBuffered = sendOrBuffer(this, buf);
|
|
1594
1604
|
if (this._debug) {
|
|
@@ -1681,6 +1691,146 @@ class SFTP extends EventEmitter {
|
|
|
1681
1691
|
this._debug(`SFTP: Outbound: ${status} copy-data`);
|
|
1682
1692
|
}
|
|
1683
1693
|
}
|
|
1694
|
+
ext_home_dir(username, cb) {
|
|
1695
|
+
if (this.server)
|
|
1696
|
+
throw new Error('Client-only method called in server mode');
|
|
1697
|
+
|
|
1698
|
+
const ext = this._extensions['home-directory'];
|
|
1699
|
+
if (ext !== '1')
|
|
1700
|
+
throw new Error('Server does not support this extended request');
|
|
1701
|
+
|
|
1702
|
+
if (typeof username !== 'string')
|
|
1703
|
+
throw new TypeError('username is not a string');
|
|
1704
|
+
|
|
1705
|
+
/*
|
|
1706
|
+
uint32 id
|
|
1707
|
+
string "home-directory"
|
|
1708
|
+
string username
|
|
1709
|
+
*/
|
|
1710
|
+
let p = 0;
|
|
1711
|
+
const usernameLen = Buffer.byteLength(username);
|
|
1712
|
+
const buf = Buffer.allocUnsafe(
|
|
1713
|
+
4 + 1
|
|
1714
|
+
+ 4
|
|
1715
|
+
+ 4 + 14
|
|
1716
|
+
+ 4 + usernameLen
|
|
1717
|
+
);
|
|
1718
|
+
|
|
1719
|
+
writeUInt32BE(buf, buf.length - 4, p);
|
|
1720
|
+
p += 4;
|
|
1721
|
+
|
|
1722
|
+
buf[p] = REQUEST.EXTENDED;
|
|
1723
|
+
++p;
|
|
1724
|
+
|
|
1725
|
+
const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID;
|
|
1726
|
+
writeUInt32BE(buf, reqid, p);
|
|
1727
|
+
p += 4;
|
|
1728
|
+
|
|
1729
|
+
writeUInt32BE(buf, 14, p);
|
|
1730
|
+
p += 4;
|
|
1731
|
+
buf.utf8Write('home-directory', p, 14);
|
|
1732
|
+
p += 14;
|
|
1733
|
+
|
|
1734
|
+
writeUInt32BE(buf, usernameLen, p);
|
|
1735
|
+
p += 4;
|
|
1736
|
+
buf.utf8Write(username, p, usernameLen);
|
|
1737
|
+
p += usernameLen;
|
|
1738
|
+
|
|
1739
|
+
this._requests[reqid] = {
|
|
1740
|
+
cb: (err, names) => {
|
|
1741
|
+
if (typeof cb !== 'function')
|
|
1742
|
+
return;
|
|
1743
|
+
if (err)
|
|
1744
|
+
return cb(err);
|
|
1745
|
+
if (!names || !names.length)
|
|
1746
|
+
return cb(new Error('Response missing home directory'));
|
|
1747
|
+
cb(undefined, names[0].filename);
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
|
|
1751
|
+
const isBuffered = sendOrBuffer(this, buf);
|
|
1752
|
+
if (this._debug) {
|
|
1753
|
+
const status = (isBuffered ? 'Buffered' : 'Sending');
|
|
1754
|
+
this._debug(`SFTP: Outbound: ${status} home-directory`);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
ext_users_groups(uids, gids, cb) {
|
|
1758
|
+
if (this.server)
|
|
1759
|
+
throw new Error('Client-only method called in server mode');
|
|
1760
|
+
|
|
1761
|
+
const ext = this._extensions['users-groups-by-id@openssh.com'];
|
|
1762
|
+
if (ext !== '1')
|
|
1763
|
+
throw new Error('Server does not support this extended request');
|
|
1764
|
+
|
|
1765
|
+
if (!Array.isArray(uids))
|
|
1766
|
+
throw new TypeError('uids is not an array');
|
|
1767
|
+
for (const val of uids) {
|
|
1768
|
+
if (!Number.isInteger(val) || val < 0 || val > (2 ** 32 - 1))
|
|
1769
|
+
throw new Error('uid values must all be 32-bit unsigned integers');
|
|
1770
|
+
}
|
|
1771
|
+
if (!Array.isArray(gids))
|
|
1772
|
+
throw new TypeError('gids is not an array');
|
|
1773
|
+
for (const val of gids) {
|
|
1774
|
+
if (!Number.isInteger(val) || val < 0 || val > (2 ** 32 - 1))
|
|
1775
|
+
throw new Error('gid values must all be 32-bit unsigned integers');
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
/*
|
|
1779
|
+
uint32 id
|
|
1780
|
+
string "users-groups-by-id@openssh.com"
|
|
1781
|
+
string uids
|
|
1782
|
+
uint32 uid1
|
|
1783
|
+
...
|
|
1784
|
+
string gids
|
|
1785
|
+
uint32 gid1
|
|
1786
|
+
...
|
|
1787
|
+
*/
|
|
1788
|
+
let p = 0;
|
|
1789
|
+
const buf = Buffer.allocUnsafe(
|
|
1790
|
+
4 + 1
|
|
1791
|
+
+ 4
|
|
1792
|
+
+ 4 + 30
|
|
1793
|
+
+ 4 + (4 * uids.length)
|
|
1794
|
+
+ 4 + (4 * gids.length)
|
|
1795
|
+
);
|
|
1796
|
+
|
|
1797
|
+
writeUInt32BE(buf, buf.length - 4, p);
|
|
1798
|
+
p += 4;
|
|
1799
|
+
|
|
1800
|
+
buf[p] = REQUEST.EXTENDED;
|
|
1801
|
+
++p;
|
|
1802
|
+
|
|
1803
|
+
const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID;
|
|
1804
|
+
writeUInt32BE(buf, reqid, p);
|
|
1805
|
+
p += 4;
|
|
1806
|
+
|
|
1807
|
+
writeUInt32BE(buf, 30, p);
|
|
1808
|
+
p += 4;
|
|
1809
|
+
buf.utf8Write('users-groups-by-id@openssh.com', p, 30);
|
|
1810
|
+
p += 30;
|
|
1811
|
+
|
|
1812
|
+
writeUInt32BE(buf, 4 * uids.length, p);
|
|
1813
|
+
p += 4;
|
|
1814
|
+
for (const val of uids) {
|
|
1815
|
+
writeUInt32BE(buf, val, p);
|
|
1816
|
+
p += 4;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
writeUInt32BE(buf, 4 * gids.length, p);
|
|
1820
|
+
p += 4;
|
|
1821
|
+
for (const val of gids) {
|
|
1822
|
+
writeUInt32BE(buf, val, p);
|
|
1823
|
+
p += 4;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
this._requests[reqid] = { extended: 'users-groups-by-id@openssh.com', cb };
|
|
1827
|
+
|
|
1828
|
+
const isBuffered = sendOrBuffer(this, buf);
|
|
1829
|
+
if (this._debug) {
|
|
1830
|
+
const status = (isBuffered ? 'Buffered' : 'Sending');
|
|
1831
|
+
this._debug(`SFTP: Outbound: ${status} users-groups-by-id@openssh.com`);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1684
1834
|
// ===========================================================================
|
|
1685
1835
|
// Server-specific ===========================================================
|
|
1686
1836
|
// ===========================================================================
|
|
@@ -2928,6 +3078,44 @@ const CLIENT_HANDLERS = {
|
|
|
2928
3078
|
req.cb(undefined, limits);
|
|
2929
3079
|
return;
|
|
2930
3080
|
}
|
|
3081
|
+
case 'users-groups-by-id@openssh.com': {
|
|
3082
|
+
/*
|
|
3083
|
+
string usernames
|
|
3084
|
+
string username1
|
|
3085
|
+
...
|
|
3086
|
+
string groupnames
|
|
3087
|
+
string groupname1
|
|
3088
|
+
...
|
|
3089
|
+
*/
|
|
3090
|
+
const usernameCount = bufferParser.readUInt32BE();
|
|
3091
|
+
if (usernameCount === undefined)
|
|
3092
|
+
break;
|
|
3093
|
+
const usernames = new Array(usernameCount);
|
|
3094
|
+
for (let i = 0; i < usernames.length; ++i)
|
|
3095
|
+
usernames[i] = bufferParser.readString(true);
|
|
3096
|
+
|
|
3097
|
+
const groupnameCount = bufferParser.readUInt32BE();
|
|
3098
|
+
if (groupnameCount === undefined)
|
|
3099
|
+
break;
|
|
3100
|
+
const groupnames = new Array(groupnameCount);
|
|
3101
|
+
for (let i = 0; i < groupnames.length; ++i)
|
|
3102
|
+
groupnames[i] = bufferParser.readString(true);
|
|
3103
|
+
if (groupnames.length > 0
|
|
3104
|
+
&& groupnames[groupnames.length - 1] === undefined) {
|
|
3105
|
+
break;
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
if (sftp._debug) {
|
|
3109
|
+
sftp._debug(
|
|
3110
|
+
'SFTP: Inbound: Received EXTENDED_REPLY '
|
|
3111
|
+
+ `(id:${reqID}, ${req.extended})`
|
|
3112
|
+
);
|
|
3113
|
+
}
|
|
3114
|
+
bufferParser.clear();
|
|
3115
|
+
if (typeof req.cb === 'function')
|
|
3116
|
+
req.cb(undefined, usernames, groupnames);
|
|
3117
|
+
return;
|
|
3118
|
+
}
|
|
2931
3119
|
default:
|
|
2932
3120
|
// Unknown extended request
|
|
2933
3121
|
sftp._debug && sftp._debug(
|
|
@@ -159,6 +159,7 @@ const COMPAT = {
|
|
|
159
159
|
OLD_EXIT: 1 << 1,
|
|
160
160
|
DYN_RPORT_BUG: 1 << 2,
|
|
161
161
|
BUG_DHGEX_LARGE: 1 << 3,
|
|
162
|
+
IMPLY_RSA_SHA2_SIGALGS: 1 << 4,
|
|
162
163
|
};
|
|
163
164
|
|
|
164
165
|
module.exports = {
|
|
@@ -170,6 +171,7 @@ module.exports = {
|
|
|
170
171
|
DEBUG: 4,
|
|
171
172
|
SERVICE_REQUEST: 5,
|
|
172
173
|
SERVICE_ACCEPT: 6,
|
|
174
|
+
EXT_INFO: 7, // RFC 8308
|
|
173
175
|
|
|
174
176
|
// Transport layer protocol -- algorithm negotiation (20-29)
|
|
175
177
|
KEXINIT: 20,
|
|
@@ -327,9 +329,10 @@ module.exports = {
|
|
|
327
329
|
COMPAT,
|
|
328
330
|
COMPAT_CHECKS: [
|
|
329
331
|
[ 'Cisco-1.25', COMPAT.BAD_DHGEX ],
|
|
330
|
-
[ /^Cisco-1
|
|
332
|
+
[ /^Cisco-1[.]/, COMPAT.BUG_DHGEX_LARGE ],
|
|
331
333
|
[ /^[0-9.]+$/, COMPAT.OLD_EXIT ], // old SSH.com implementations
|
|
332
|
-
[ /^OpenSSH_5
|
|
334
|
+
[ /^OpenSSH_5[.][0-9]+/, COMPAT.DYN_RPORT_BUG ],
|
|
335
|
+
[ /^OpenSSH_7[.]4/, COMPAT.IMPLY_RSA_SHA2_SIGALGS ],
|
|
333
336
|
],
|
|
334
337
|
|
|
335
338
|
// KEX proposal-related
|