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;
}