Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SSHD-700] Fix the issues of the agent forwarding implementation of IETF. #34

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ public final class SshAgentConstants {
public static final byte SSH_AGENT_CONSTRAIN_LIFETIME = 1;
public static final byte SSH_AGENT_CONSTRAIN_CONFIRM = 2;

// Packet types defined by IETF (https://tools.ietf.org/html/draft-ietf-secsh-agent-02)
// Messages sent by the client
public static final int SSH_AGENT_LIST_KEYS = 204;
public static final int SSH_AGENT_PRIVATE_KEY_OP = 205;
// Messages sent by the agent
public static final byte SSH_AGENT_KEY_LIST = 104;
public static final byte SSH_AGENT_OPERATION_COMPLETE = 105;

private SshAgentConstants() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentConstants;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.util.GenericUtils;
Expand All @@ -42,13 +43,23 @@
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public abstract class AbstractAgentProxy extends AbstractLoggingBean implements SshAgent, ExecutorServiceConfigurer {

private ExecutorService executor;
private boolean shutdownExecutor;
private String channelType = FactoryManager.AGENT_FORWARDING_TYPE_OPENSSH;

protected AbstractAgentProxy() {
super();
}

public String getChannelType() {
return channelType;
}

public void setChannelType(String channelType) {
this.channelType = channelType;
}

@Override
public ExecutorService getExecutorService() {
return executor;
Expand All @@ -71,10 +82,17 @@ public void setShutdownOnExit(boolean shutdown) {

@Override
public List<Pair<PublicKey, String>> getIdentities() throws IOException {
Buffer buffer = createBuffer(SshAgentConstants.SSH2_AGENTC_REQUEST_IDENTITIES, 1);
int cmd = SshAgentConstants.SSH2_AGENTC_REQUEST_IDENTITIES;
int okcmd = SshAgentConstants.SSH2_AGENT_IDENTITIES_ANSWER;
if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) {
cmd = SshAgentConstants.SSH_AGENT_LIST_KEYS;
okcmd = SshAgentConstants.SSH_AGENT_KEY_LIST;
}

Buffer buffer = createBuffer((byte) cmd, 1);
buffer = request(prepare(buffer));
int type = buffer.getUByte();
if (type != SshAgentConstants.SSH2_AGENT_IDENTITIES_ANSWER) {
if (type != okcmd) {
throw new SshException("Bad agent identities answer: " + SshAgentConstants.getCommandMessageName(type));
}

Expand All @@ -99,24 +117,43 @@ public List<Pair<PublicKey, String>> getIdentities() throws IOException {

@Override
public byte[] sign(PublicKey key, byte[] data) throws IOException {
Buffer buffer = createBuffer(SshAgentConstants.SSH2_AGENTC_SIGN_REQUEST);
int cmd = SshAgentConstants.SSH2_AGENTC_SIGN_REQUEST;
int okcmd = SshAgentConstants.SSH2_AGENT_SIGN_RESPONSE;
if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) {
cmd = SshAgentConstants.SSH_AGENT_PRIVATE_KEY_OP;
okcmd = SshAgentConstants.SSH_AGENT_OPERATION_COMPLETE;
}

Buffer buffer = createBuffer((byte) cmd);
if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) {
buffer.putString("sign");
}
buffer.putPublicKey(key);
buffer.putBytes(data);
buffer.putInt(0);
buffer = request(prepare(buffer));

int responseType = buffer.getUByte();
if (responseType != SshAgentConstants.SSH2_AGENT_SIGN_RESPONSE) {
if (responseType != okcmd) {
throw new SshException("Bad signing response type: " + SshAgentConstants.getCommandMessageName(responseType));
}

Buffer buf = new ByteArrayBuffer(buffer.getBytes());
String algorithm = buf.getString();
byte[] signature = buf.getBytes();
if (log.isDebugEnabled()) {
log.debug("sign({})[{}] {}: {}",
KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key),
algorithm, BufferUtils.toHex(':', signature));
byte[] signature = buffer.getBytes();
if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) {
if (log.isDebugEnabled()) {
log.debug("sign({})[{}] : {}",
KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key),
BufferUtils.toHex(':', signature));
}
} else {
Buffer buf = new ByteArrayBuffer(signature);
String algorithm = buf.getString();
signature = buf.getBytes();
if (log.isDebugEnabled()) {
log.debug("sign({})[{}] {}: {}",
KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key),
algorithm, BufferUtils.toHex(':', signature));
}
}

return signature;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.common.AbstractAgentProxy;
import org.apache.sshd.client.channel.AbstractClientChannel;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.channel.ChannelOutputStream;
import org.apache.sshd.common.channel.Window;
Expand All @@ -44,7 +46,7 @@ public AgentForwardedChannel(String channelType) {
}

public SshAgent getAgent() {
return new AbstractAgentProxy() {
AbstractAgentProxy rtn = new AbstractAgentProxy() {
private final AtomicBoolean open = new AtomicBoolean(true);

@Override
Expand All @@ -65,6 +67,8 @@ public void close() throws IOException {
}
}
};
rtn.setChannelType(PropertyResolverUtils.getString(getSession(), FactoryManager.AGENT_FORWARDING_TYPE));
return rtn;
}

protected Buffer request(Buffer buffer) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,42 @@
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentFactory;
import org.apache.sshd.agent.SshAgentServer;
import org.apache.sshd.agent.unix.AprLibrary;
import org.apache.sshd.agent.unix.UnixAgentFactory;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.channel.Channel;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.server.session.ServerSession;

/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class ProxyAgentFactory implements SshAgentFactory {
private static boolean useUnixAgentFactory;
private final Map<String, AgentServerProxy> proxies = new ConcurrentHashMap<>();

static {
if (OsUtils.isUNIX() || Boolean.getBoolean("org.apache.sshd.agent.PreferUnixAgentFactory")) {
try {
useUnixAgentFactory = AprLibrary.getInstance() != null;
} catch (Exception ignore) {
}
}
}

public ProxyAgentFactory() {
super();
}

@Override
public List<NamedFactory<Channel>> getChannelForwardingFactories(FactoryManager manager) {
return UnixAgentFactory.DEFAULT_FORWARDING_CHANNELS;
return useUnixAgentFactory ? UnixAgentFactory.DEFAULT_FORWARDING_CHANNELS
: LocalAgentFactory.DEFAULT_FORWARDING_CHANNELS;
}

@Override
Expand Down
16 changes: 16 additions & 0 deletions sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,22 @@ public interface FactoryManager
*/
String IGNORE_MESSAGE_SIZE = "ignore-message-size";

/**
* The request type of agent forwarding. The value may be {@value #AGENT_FORWARDING_TYPE_IETF} or
* {@value #AGENT_FORWARDING_TYPE_OPENSSH}.
*/
String AGENT_FORWARDING_TYPE = "agent-fw-auth-type";

/**
* The agent forwarding type defined by IETF (https://tools.ietf.org/html/draft-ietf-secsh-agent-02).
*/
String AGENT_FORWARDING_TYPE_IETF = "auth-agent-req";

/**
* The agent forwarding type defined by OpenSSH.
*/
String AGENT_FORWARDING_TYPE_OPENSSH = "auth-agent-req@openssh.com";

/**
* Value of {@value #IGNORE_MESSAGE_SIZE} if none configured
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ protected int getPtyModeValue(PtyMode mode) {

protected RequestHandler.Result handleAgentForwarding(String requestType, Buffer buffer, boolean wantReply) throws IOException {
ServerSession session = getServerSession();
PropertyResolverUtils.updateProperty(session, FactoryManager.AGENT_FORWARDING_TYPE, requestType);
FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No session factory manager");
ForwardingFilter filter = manager.getTcpipForwardingFilter();
SshAgentFactory factory = manager.getAgentFactory();
Expand Down