net.schmizz.sshj.transport.Proposal Maven / Gradle / Ivy
/*
* Copyright 2010 Shikhar Bhushan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file may incorporate work covered by the following copyright and
* permission notice:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package net.schmizz.sshj.transport;
import net.schmizz.sshj.Config;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.Message;
import net.schmizz.sshj.common.SSHPacket;
import java.util.Arrays;
import java.util.List;
class Proposal {
private final List kex;
private final List sig;
private final List c2sCipher;
private final List s2cCipher;
private final List c2sMAC;
private final List s2cMAC;
private final List c2sComp;
private final List s2cComp;
private final SSHPacket packet;
public Proposal(Config config) {
kex = Factory.Named.Util.getNames(config.getKeyExchangeFactories());
sig = Factory.Named.Util.getNames(config.getSignatureFactories());
c2sCipher = s2cCipher = Factory.Named.Util.getNames(config.getCipherFactories());
c2sMAC = s2cMAC = Factory.Named.Util.getNames(config.getMACFactories());
c2sComp = s2cComp = Factory.Named.Util.getNames(config.getCompressionFactories());
packet = new SSHPacket(Message.KEXINIT);
// Put cookie
packet.ensureCapacity(16);
config.getRandomFactory().create().fill(packet.array(), packet.wpos(), 16);
packet.wpos(packet.wpos() + 16);
// Put algorithm lists
packet.putString(toCommaString(kex));
packet.putString(toCommaString(sig));
packet.putString(toCommaString(c2sCipher));
packet.putString(toCommaString(s2cCipher));
packet.putString(toCommaString(c2sMAC));
packet.putString(toCommaString(s2cMAC));
packet.putString(toCommaString(c2sComp));
packet.putString(toCommaString(s2cComp));
packet.putString("");
packet.putString("");
packet.putBoolean(false); // Optimistic next packet does not follow
packet.putInt(0); // "Reserved" for future by spec
}
public Proposal(SSHPacket packet) {
this.packet = packet;
final int savedPos = packet.rpos();
packet.rpos(packet.rpos() + 17); // Skip message ID & cookie
kex = fromCommaString(packet.readString());
sig = fromCommaString(packet.readString());
c2sCipher = fromCommaString(packet.readString());
s2cCipher = fromCommaString(packet.readString());
c2sMAC = fromCommaString(packet.readString());
s2cMAC = fromCommaString(packet.readString());
c2sComp = fromCommaString(packet.readString());
s2cComp = fromCommaString(packet.readString());
packet.rpos(savedPos);
}
public List getKeyExchangeAlgorithms() {
return kex;
}
public List getSignatureAlgorithms() {
return sig;
}
public List getClient2ServerCipherAlgorithms() {
return c2sCipher;
}
public List getServer2ClientCipherAlgorithms() {
return s2cCipher;
}
public List getClient2ServerMACAlgorithms() {
return c2sMAC;
}
public List getServer2ClientMACAlgorithms() {
return s2cMAC;
}
public List getClient2ServerCompressionAlgorithms() {
return c2sComp;
}
public List getServer2ClientCompressionAlgorithms() {
return s2cComp;
}
public SSHPacket getPacket() {
return new SSHPacket(packet);
}
public NegotiatedAlgorithms negotiate(Proposal other)
throws TransportException {
return new NegotiatedAlgorithms(
firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()), //
firstMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()), //
firstMatch(this.getClient2ServerCipherAlgorithms(), other.getClient2ServerCipherAlgorithms()), //
firstMatch(this.getServer2ClientCipherAlgorithms(), other.getServer2ClientCipherAlgorithms()), //
firstMatch(this.getClient2ServerMACAlgorithms(), other.getClient2ServerMACAlgorithms()), //
firstMatch(this.getServer2ClientMACAlgorithms(), other.getServer2ClientMACAlgorithms()), //
firstMatch(this.getClient2ServerCompressionAlgorithms(), other.getClient2ServerCompressionAlgorithms()), //
firstMatch(this.getServer2ClientCompressionAlgorithms(), other.getServer2ClientCompressionAlgorithms()) //
);
}
private static String firstMatch(List a, List b)
throws TransportException {
for (String aa : a)
for (String bb : b)
if (aa.equals(bb))
return aa;
throw new TransportException("Unable to reach a settlement: " + a + " and " + b);
}
private static String toCommaString(List sl) {
StringBuilder sb = new StringBuilder();
int i = 0;
for (String s : sl) {
if (i++ != 0)
sb.append(",");
sb.append(s);
}
return sb.toString();
}
private static List fromCommaString(String s) {
return Arrays.asList(s.split(","));
}
}