@@ -742,7 +742,16 @@ const createKeyExchange = (() => {
742742 true
743743 ) ;
744744
745- packet [ p ] = MESSAGE . KEXDH_REPLY ;
745+ switch ( this . type ) {
746+ case 'group' :
747+ packet [ p ] = MESSAGE . KEXDH_REPLY ;
748+ break ;
749+ case 'groupex' :
750+ packet [ p ] = MESSAGE . KEXDH_GEX_REPLY ;
751+ break ;
752+ default :
753+ packet [ p ] = MESSAGE . KEXECDH_REPLY ;
754+ }
746755
747756 writeUInt32BE ( packet , serverPublicHostKey . length , ++ p ) ;
748757 packet . set ( serverPublicHostKey , p += 4 ) ;
@@ -1359,7 +1368,7 @@ const createKeyExchange = (() => {
13591368 this . _public = this . _dh . generateKeys ( ) ;
13601369 }
13611370 }
1362- setDHParams ( prime , generator ) {
1371+ setDHParams ( prime , generator = Buffer . from ( [ 0x02 ] ) ) {
13631372 if ( ! Buffer . isBuffer ( prime ) )
13641373 throw new Error ( 'Invalid prime value' ) ;
13651374 if ( ! Buffer . isBuffer ( generator ) )
@@ -1380,6 +1389,8 @@ const createKeyExchange = (() => {
13801389 switch ( this . _step ) {
13811390 case 1 :
13821391 if ( this . _protocol . _server ) {
1392+
1393+ // Server
13831394 if ( type !== MESSAGE . KEXDH_GEX_REQUEST ) {
13841395 return doFatalError (
13851396 this . _protocol ,
@@ -1389,72 +1400,133 @@ const createKeyExchange = (() => {
13891400 DISCONNECT_REASON . KEY_EXCHANGE_FAILED
13901401 ) ;
13911402 }
1392- // TODO: allow user implementation to provide safe prime and
1393- // generator on demand to support group exchange on server side
1394- return doFatalError (
1395- this . _protocol ,
1396- 'Group exchange not implemented for server' ,
1397- 'handshake' ,
1398- DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1403+
1404+ this . _protocol . _debug && this . _protocol . _debug (
1405+ 'Received DH GEX Request'
13991406 ) ;
1400- }
14011407
1402- if ( type !== MESSAGE . KEXDH_GEX_GROUP ) {
1403- return doFatalError (
1404- this . _protocol ,
1405- `Received packet ${ type } instead of ${ MESSAGE . KEXDH_GEX_GROUP } ` ,
1406- 'handshake' ,
1407- DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1408+ /*
1409+ byte SSH_MSG_KEY_DH_GEX_REQUEST
1410+ uint32 min, minimal size in bits of an acceptable group
1411+ uint32 n, preferred size in bits of the group the server
1412+ will send
1413+ uint32 max, maximal size in bits of an acceptable group
1414+ */
1415+ bufferParser . init ( payload , 1 ) ;
1416+ let minBits ;
1417+ let prefBits ;
1418+ let maxBits ;
1419+ if ( ( minBits = bufferParser . readUInt32BE ( ) ) === undefined
1420+ || ( prefBits = bufferParser . readUInt32BE ( ) ) === undefined
1421+ || ( maxBits = bufferParser . readUInt32BE ( ) ) === undefined ) {
1422+ bufferParser . clear ( ) ;
1423+ return doFatalError (
1424+ this . _protocol ,
1425+ 'Received malformed KEXDH_GEX_REQUEST' ,
1426+ 'handshake' ,
1427+ DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1428+ ) ;
1429+ }
1430+ bufferParser . clear ( ) ;
1431+
1432+ const primeGenerator =
1433+ this . _protocol . _getDHParams ( minBits , prefBits , maxBits ) ;
1434+ if ( ! Array . isArray ( primeGenerator ) ) {
1435+ return doFatalError (
1436+ this . _protocol ,
1437+ 'No matching prime for KEXDH_GEX_REQUEST' ,
1438+ 'handshake' ,
1439+ DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1440+ ) ;
1441+ }
1442+
1443+ this . _minBits = minBits ;
1444+ this . _prefBits = prefBits ;
1445+ this . _maxBits = maxBits ;
1446+
1447+ this . setDHParams ( ...primeGenerator ) ;
1448+ this . generateKeys ( ) ;
1449+ const dh = this . getDHParams ( ) ;
1450+
1451+ this . _protocol . _debug && this . _protocol . _debug (
1452+ 'Outbound: Sending KEXDH_GEX_GROUP'
14081453 ) ;
1409- }
14101454
1411- this . _protocol . _debug && this . _protocol . _debug (
1412- 'Received DH GEX Group'
1413- ) ;
1455+ let p = this . _protocol . _packetRW . write . allocStartKEX ;
1456+ const packet =
1457+ this . _protocol . _packetRW . write . alloc (
1458+ 1 + 4 + dh . prime . length + 4 + dh . generator . length , true ) ;
1459+ packet [ p ] = MESSAGE . KEXDH_GEX_GROUP ;
1460+ writeUInt32BE ( packet , dh . prime . length , ++ p ) ;
1461+ packet . set ( dh . prime , p += 4 ) ;
1462+ writeUInt32BE ( packet , dh . generator . length ,
1463+ p += dh . prime . length ) ;
1464+ packet . set ( dh . generator , p += 4 ) ;
1465+ this . _protocol . _cipher . encrypt (
1466+ this . _protocol . _packetRW . write . finalize ( packet , true )
1467+ ) ;
14141468
1415- /*
1416- byte SSH_MSG_KEX_DH_GEX_GROUP
1417- mpint p, safe prime
1418- mpint g, generator for subgroup in GF(p)
1419- */
1420- bufferParser . init ( payload , 1 ) ;
1421- let prime ;
1422- let gen ;
1423- if ( ( prime = bufferParser . readString ( ) ) === undefined
1424- || ( gen = bufferParser . readString ( ) ) === undefined ) {
1425- bufferParser . clear ( ) ;
1426- return doFatalError (
1427- this . _protocol ,
1428- 'Received malformed KEXDH_GEX_GROUP' ,
1429- 'handshake' ,
1430- DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1469+ } else {
1470+
1471+ // Client
1472+ if ( type !== MESSAGE . KEXDH_GEX_GROUP ) {
1473+ return doFatalError (
1474+ this . _protocol ,
1475+ `Received packet ${ type } instead of ${ MESSAGE . KEXDH_GEX_GROUP } ` ,
1476+ 'handshake' ,
1477+ DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1478+ ) ;
1479+ }
1480+
1481+ this . _protocol . _debug && this . _protocol . _debug (
1482+ 'Received DH GEX Group'
14311483 ) ;
1432- }
1433- bufferParser . clear ( ) ;
14341484
1435- // TODO: validate prime
1436- this . setDHParams ( prime , gen ) ;
1437- this . generateKeys ( ) ;
1438- const pubkey = this . getPublicKey ( ) ;
1485+ /*
1486+ byte SSH_MSG_KEX_DH_GEX_GROUP
1487+ mpint p, safe prime
1488+ mpint g, generator for subgroup in GF(p)
1489+ */
1490+ bufferParser . init ( payload , 1 ) ;
1491+ let prime ;
1492+ let gen ;
1493+ if ( ( prime = bufferParser . readString ( ) ) === undefined
1494+ || ( gen = bufferParser . readString ( ) ) === undefined ) {
1495+ bufferParser . clear ( ) ;
1496+ return doFatalError (
1497+ this . _protocol ,
1498+ 'Received malformed KEXDH_GEX_GROUP' ,
1499+ 'handshake' ,
1500+ DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1501+ ) ;
1502+ }
1503+ bufferParser . clear ( ) ;
14391504
1440- this . _protocol . _debug && this . _protocol . _debug (
1441- 'Outbound: Sending KEXDH_GEX_INIT'
1442- ) ;
1505+ // TODO: validate prime
1506+ this . setDHParams ( prime , gen ) ;
1507+ this . generateKeys ( ) ;
1508+ const pubkey = this . getPublicKey ( ) ;
14431509
1444- let p = this . _protocol . _packetRW . write . allocStartKEX ;
1445- const packet =
1446- this . _protocol . _packetRW . write . alloc ( 1 + 4 + pubkey . length , true ) ;
1447- packet [ p ] = MESSAGE . KEXDH_GEX_INIT ;
1448- writeUInt32BE ( packet , pubkey . length , ++ p ) ;
1449- packet . set ( pubkey , p += 4 ) ;
1450- this . _protocol . _cipher . encrypt (
1451- this . _protocol . _packetRW . write . finalize ( packet , true )
1452- ) ;
1510+ this . _protocol . _debug && this . _protocol . _debug (
1511+ 'Outbound: Sending KEXDH_GEX_INIT'
1512+ ) ;
14531513
1514+ let p = this . _protocol . _packetRW . write . allocStartKEX ;
1515+ const packet =
1516+ this . _protocol . _packetRW . write . alloc ( 1 + 4 + pubkey . length , true ) ;
1517+ packet [ p ] = MESSAGE . KEXDH_GEX_INIT ;
1518+ writeUInt32BE ( packet , pubkey . length , ++ p ) ;
1519+ packet . set ( pubkey , p += 4 ) ;
1520+ this . _protocol . _cipher . encrypt (
1521+ this . _protocol . _packetRW . write . finalize ( packet , true )
1522+ ) ;
1523+ }
14541524 ++ this . _step ;
14551525 break ;
14561526 case 2 :
14571527 if ( this . _protocol . _server ) {
1528+
1529+ // Server
14581530 if ( type !== MESSAGE . KEXDH_GEX_INIT ) {
14591531 return doFatalError (
14601532 this . _protocol ,
@@ -1463,30 +1535,90 @@ const createKeyExchange = (() => {
14631535 DISCONNECT_REASON . KEY_EXCHANGE_FAILED
14641536 ) ;
14651537 }
1538+
14661539 this . _protocol . _debug && this . _protocol . _debug (
14671540 'Received DH GEX Init'
14681541 ) ;
1469- return doFatalError (
1470- this . _protocol ,
1471- 'Group exchange not implemented for server' ,
1472- 'handshake' ,
1473- DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1542+
1543+ /*
1544+ byte SSH_MSG_KEX_DH_GEX_INIT
1545+ mpint e
1546+ */
1547+ bufferParser . init ( payload , 1 ) ;
1548+ let dhData ;
1549+ if ( ( dhData = bufferParser . readString ( ) ) === undefined ) {
1550+ bufferParser . clear ( ) ;
1551+ return doFatalError (
1552+ this . _protocol ,
1553+ 'Received malformed KEXDH_GEX_INIT' ,
1554+ 'handshake' ,
1555+ DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1556+ ) ;
1557+ }
1558+ bufferParser . clear ( ) ;
1559+
1560+ this . _dhData = dhData ;
1561+
1562+ let hostKey =
1563+ this . _protocol . _hostKeys [ this . negotiated . serverHostKey ] ;
1564+ if ( Array . isArray ( hostKey ) )
1565+ hostKey = hostKey [ 0 ] ;
1566+ this . _hostKey = hostKey ;
1567+
1568+ this . finish ( ) ;
1569+
1570+ } else {
1571+
1572+ // Client
1573+ if ( type !== MESSAGE . KEXDH_GEX_REPLY ) {
1574+ return doFatalError (
1575+ this . _protocol ,
1576+ `Received packet ${ type } instead of ${ MESSAGE . KEXDH_GEX_REPLY } ` ,
1577+ 'handshake' ,
1578+ DISCONNECT_REASON . KEY_EXCHANGE_FAILED
1579+ ) ;
1580+ }
1581+
1582+ this . _protocol . _debug && this . _protocol . _debug (
1583+ 'Received DH GEX Reply'
14741584 ) ;
1475- } else if ( type !== MESSAGE . KEXDH_GEX_REPLY ) {
1585+ this . _step = 1 ;
1586+ payload [ 0 ] = MESSAGE . KEXDH_REPLY ;
1587+ this . parse = KeyExchange . prototype . parse ;
1588+ this . parse ( payload ) ;
1589+ }
1590+
1591+ ++ this . _step ;
1592+ break ;
1593+
1594+ case 3 :
1595+
1596+ if ( type !== MESSAGE . NEWKEYS ) {
14761597 return doFatalError (
14771598 this . _protocol ,
1478- `Received packet ${ type } instead of ${ MESSAGE . KEXDH_GEX_REPLY } ` ,
1599+ `Received packet ${ type } instead of ${ MESSAGE . NEWKEYS } ` ,
14791600 'handshake' ,
14801601 DISCONNECT_REASON . KEY_EXCHANGE_FAILED
14811602 ) ;
14821603 }
14831604 this . _protocol . _debug && this . _protocol . _debug (
1484- 'Received DH GEX Reply'
1605+ 'Inbound: NEWKEYS'
1606+ ) ;
1607+ this . _receivedNEWKEYS = true ;
1608+ ++ this . _step ;
1609+ if ( this . _protocol . _server || this . _hostVerified )
1610+ return this . finish ( ) ;
1611+
1612+ // Signal to current decipher that we need to change to a new decipher
1613+ // for the next packet
1614+ return false ;
1615+ default :
1616+ return doFatalError (
1617+ this . _protocol ,
1618+ `Received unexpected packet ${ type } after NEWKEYS` ,
1619+ 'handshake' ,
1620+ DISCONNECT_REASON . KEY_EXCHANGE_FAILED
14851621 ) ;
1486- this . _step = 1 ;
1487- payload [ 0 ] = MESSAGE . KEXDH_REPLY ;
1488- this . parse = KeyExchange . prototype . parse ;
1489- this . parse ( payload ) ;
14901622 }
14911623 }
14921624 }
0 commit comments