public boolean next()

in sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java [105:268]


    public boolean next(int cmd, Buffer buffer) throws Exception {
        ServerSession session = getServerSession();
        boolean debugEnabled = log.isDebugEnabled();
        if (debugEnabled) {
            log.debug("next({})[{}] process command={} (expected={})",
                    this, session, KeyExchange.getGroupKexOpcodeName(cmd),
                    KeyExchange.getGroupKexOpcodeName(expected));
        }

        if ((cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST_OLD)
                && (expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST)) {
            oldRequest = true;
            min = CoreModuleProperties.PROP_DHGEX_SERVER_MIN_KEY.get(session)
                    .orElse(SecurityUtils.getMinDHGroupExchangeKeySize());
            prf = buffer.getInt();
            max = CoreModuleProperties.PROP_DHGEX_SERVER_MAX_KEY.get(session)
                    .orElse(SecurityUtils.getMaxDHGroupExchangeKeySize());

            if ((max < min) || (prf < min) || (max < prf)) {
                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                        "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
            }

            dh = chooseDH(min, prf, max);

            setF(dh.getE());

            BigInteger pValue = dh.getP();
            validateFValue(pValue);

            hash = dh.getHash();
            hash.init();

            if (debugEnabled) {
                log.debug("next({})[{}] send (old request) SSH_MSG_KEX_DH_GEX_GROUP - min={}, prf={}, max={}",
                        this, session, min, prf, max);
            }

            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP);
            buffer.putMPInt(pValue);
            buffer.putMPInt(dh.getG());
            session.writePacket(buffer);

            expected = SshConstants.SSH_MSG_KEX_DH_GEX_INIT;
            return false;
        }

        if ((cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST)
                && (expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST)) {
            min = buffer.getInt();
            prf = buffer.getInt();
            max = buffer.getInt();

            if ((prf < min) || (max < prf)) {
                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                        "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
            }

            dh = chooseDH(min, prf, max);

            setF(dh.getE());

            BigInteger pValue = dh.getP();
            validateFValue(pValue);

            hash = dh.getHash();
            hash.init();

            if (debugEnabled) {
                log.debug("next({})[{}] Send SSH_MSG_KEX_DH_GEX_GROUP - min={}, prf={}, max={}",
                        this, session, min, prf, max);
            }
            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP);
            buffer.putMPInt(pValue);
            buffer.putMPInt(dh.getG());
            session.writePacket(buffer);

            expected = SshConstants.SSH_MSG_KEX_DH_GEX_INIT;
            return false;
        }

        if (cmd != expected) {
            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                    "Protocol error: expected packet " + KeyExchange.getGroupKexOpcodeName(expected)
                                                                                     + ", got "
                                                                                     + KeyExchange.getGroupKexOpcodeName(cmd));
        }

        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_INIT) {
            byte[] e = updateE(buffer.getMPIntAsBytes());
            BigInteger pValue = dh.getP();
            validateEValue(pValue);

            dh.setF(e);

            k = normalize(dh.getK());

            KeyPair kp = Objects.requireNonNull(session.getHostKey(), "No server key pair available");
            String algo = session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);
            Signature sig = ValidateUtils.checkNotNull(
                    NamedFactory.create(session.getSignatureFactories(), algo),
                    "Unknown negotiated server keys: %s", algo);
            sig.initSigner(session, kp.getPrivate());

            buffer = new ByteArrayBuffer();
            buffer.putRawPublicKey(kp.getPublic());

            byte[] k_s = buffer.getCompactData();

            buffer.clear();
            buffer.putBytes(v_c);
            buffer.putBytes(v_s);
            buffer.putBytes(i_c);
            buffer.putBytes(i_s);
            buffer.putBytes(k_s);

            if (oldRequest) {
                buffer.putInt(prf);
            } else {
                buffer.putInt(min);
                buffer.putInt(prf);
                buffer.putInt(max);
            }

            buffer.putMPInt(pValue);
            buffer.putMPInt(dh.getG());
            buffer.putMPInt(e);
            byte[] f = getF();
            buffer.putMPInt(f);
            buffer.putBytes(k);

            hash.update(buffer.array(), 0, buffer.available());
            h = hash.digest();
            sig.update(session, h);

            buffer.clear();
            buffer.putString(algo);
            byte[] sigBytes = sig.sign(session);
            buffer.putBytes(sigBytes);

            byte[] sigH = buffer.getCompactData();
            if (log.isTraceEnabled()) {
                log.trace("next({})[{}][K_S]:  {}", this, session, BufferUtils.toHex(k_s));
                log.trace("next({})[{}][f]:    {}", this, session, BufferUtils.toHex(f));
                log.trace("next({})[{}][sigH]: {}", this, session, BufferUtils.toHex(sigH));
            }

            // Send response
            if (debugEnabled) {
                log.debug("next({})[{}] Send SSH_MSG_KEX_DH_GEX_REPLY - old={}, min={}, prf={}, max={}",
                        this, session, oldRequest, min, prf, max);
            }

            buffer = session.prepareBuffer(
                    SshConstants.SSH_MSG_KEX_DH_GEX_REPLY, BufferUtils.clear(buffer));
            buffer.putBytes(k_s);
            buffer.putBytes(f);
            buffer.putBytes(sigH);
            session.writePacket(buffer);
            return true;
        }

        return false;
    }