ChannelAgentForwarding.java
/*
* Copyright (c) 2006-2018 ymnk, JCraft,Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. The names of the authors may not be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jcraft.jsch;
import java.io.IOException;
import java.util.Vector;
class ChannelAgentForwarding extends Channel {
private static final int LOCAL_WINDOW_SIZE_MAX = 0x20000;
private static final int LOCAL_MAXIMUM_PACKET_SIZE = 0x4000;
private static final byte SSH_AGENTC_REQUEST_RSA_IDENTITIES = 1;
private static final byte SSH_AGENT_RSA_IDENTITIES_ANSWER = 2;
private static final byte SSH_AGENTC_RSA_CHALLENGE = 3;
private static final byte SSH_AGENT_RSA_RESPONSE = 4;
private static final byte SSH_AGENT_FAILURE = 5;
private static final byte SSH_AGENT_SUCCESS = 6;
private static final byte SSH_AGENTC_ADD_RSA_IDENTITY = 7;
private static final byte SSH_AGENTC_REMOVE_RSA_IDENTITY = 8;
private static final byte SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES = 9;
private static final byte SSH2_AGENTC_REQUEST_IDENTITIES = 11;
private static final byte SSH2_AGENT_IDENTITIES_ANSWER = 12;
private static final byte SSH2_AGENTC_SIGN_REQUEST = 13;
private static final byte SSH2_AGENT_SIGN_RESPONSE = 14;
private static final byte SSH2_AGENTC_ADD_IDENTITY = 17;
private static final byte SSH2_AGENTC_REMOVE_IDENTITY = 18;
private static final byte SSH2_AGENTC_REMOVE_ALL_IDENTITIES = 19;
private static final byte SSH2_AGENT_FAILURE = 30;
// static private final int SSH_AGENT_OLD_SIGNATURE=0x1;
private static final int SSH_AGENT_RSA_SHA2_256 = 0x2;
private static final int SSH_AGENT_RSA_SHA2_512 = 0x4;
private Buffer rbuf = null;
private Buffer wbuf = null;
private Packet packet = null;
private Buffer mbuf = null;
ChannelAgentForwarding() {
super();
lwsize_max = LOCAL_WINDOW_SIZE_MAX;
lwsize = LOCAL_WINDOW_SIZE_MAX;
lmpsize = LOCAL_MAXIMUM_PACKET_SIZE;
type = Util.str2byte("auth-agent@openssh.com");
rbuf = new Buffer();
rbuf.reset();
// wbuf=new Buffer(rmpsize);
// packet=new Packet(wbuf);
mbuf = new Buffer();
connected = true;
}
@Override
void run() {
try {
sendOpenConfirmation();
} catch (Exception e) {
close = true;
disconnect();
}
}
@Override
void write(byte[] foo, int s, int l) throws IOException {
if (packet == null) {
wbuf = new Buffer(rmpsize);
packet = new Packet(wbuf);
}
rbuf.shift();
if (rbuf.buffer.length < rbuf.index + l) {
byte[] newbuf = new byte[rbuf.s + l];
System.arraycopy(rbuf.buffer, 0, newbuf, 0, rbuf.buffer.length);
rbuf.buffer = newbuf;
}
rbuf.putByte(foo, s, l);
int mlen = rbuf.getInt();
if (mlen > rbuf.getLength()) {
rbuf.s -= 4;
return;
}
int typ = rbuf.getByte();
Session _session = null;
try {
_session = getSession();
} catch (JSchException e) {
throw new IOException(e.toString(), e);
}
IdentityRepository irepo = _session.getIdentityRepository();
UserInfo userinfo = _session.getUserInfo();
mbuf.reset();
if (typ == SSH2_AGENTC_REQUEST_IDENTITIES) {
mbuf.putByte(SSH2_AGENT_IDENTITIES_ANSWER);
Vector<Identity> identities = irepo.getIdentities();
synchronized (identities) {
int count = 0;
for (int i = 0; i < identities.size(); i++) {
Identity identity = identities.elementAt(i);
if (identity.getPublicKeyBlob() != null)
count++;
}
mbuf.putInt(count);
for (int i = 0; i < identities.size(); i++) {
Identity identity = identities.elementAt(i);
byte[] pubkeyblob = identity.getPublicKeyBlob();
if (pubkeyblob == null)
continue;
mbuf.putString(pubkeyblob);
mbuf.putString(Util.empty);
}
}
} else if (typ == SSH_AGENTC_REQUEST_RSA_IDENTITIES) {
mbuf.putByte(SSH_AGENT_RSA_IDENTITIES_ANSWER);
mbuf.putInt(0);
} else if (typ == SSH2_AGENTC_SIGN_REQUEST) {
byte[] blob = rbuf.getString();
byte[] data = rbuf.getString();
int flags = rbuf.getInt();
// if((flags & SSH_AGENT_OLD_SIGNATURE)!=0){ // old OpenSSH 2.0, 2.1
// datafellows = SSH_BUG_SIGBLOB;
// }
Vector<Identity> identities = irepo.getIdentities();
Identity identity = null;
synchronized (identities) {
for (int i = 0; i < identities.size(); i++) {
Identity _identity = identities.elementAt(i);
if (_identity.getPublicKeyBlob() == null)
continue;
if (!Util.array_equals(blob, _identity.getPublicKeyBlob())) {
continue;
}
if (_identity.isEncrypted()) {
if (userinfo == null)
continue;
while (_identity.isEncrypted()) {
if (!userinfo.promptPassphrase("Passphrase for " + _identity.getName())) {
break;
}
String _passphrase = userinfo.getPassphrase();
if (_passphrase == null) {
break;
}
byte[] passphrase = Util.str2byte(_passphrase);
try {
if (_identity.setPassphrase(passphrase)) {
break;
}
} catch (JSchException e) {
break;
}
}
}
if (!_identity.isEncrypted()) {
identity = _identity;
break;
}
}
}
byte[] signature = null;
if (identity != null) {
Buffer kbuf = new Buffer(blob);
String keytype = Util.byte2str(kbuf.getString());
if (keytype.equals("ssh-rsa")) {
if ((flags & SSH_AGENT_RSA_SHA2_256) != 0) {
signature = identity.getSignature(data, "rsa-sha2-256");
} else if ((flags & SSH_AGENT_RSA_SHA2_512) != 0) {
signature = identity.getSignature(data, "rsa-sha2-512");
} else {
signature = identity.getSignature(data, "ssh-rsa");
}
} else {
signature = identity.getSignature(data);
}
}
if (signature == null) {
mbuf.putByte(SSH2_AGENT_FAILURE);
} else {
mbuf.putByte(SSH2_AGENT_SIGN_RESPONSE);
mbuf.putString(signature);
}
} else if (typ == SSH2_AGENTC_REMOVE_IDENTITY) {
byte[] blob = rbuf.getString();
irepo.remove(blob);
mbuf.putByte(SSH_AGENT_SUCCESS);
} else if (typ == SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES) {
mbuf.putByte(SSH_AGENT_SUCCESS);
} else if (typ == SSH2_AGENTC_REMOVE_ALL_IDENTITIES) {
irepo.removeAll();
mbuf.putByte(SSH_AGENT_SUCCESS);
} else if (typ == SSH2_AGENTC_ADD_IDENTITY) {
int fooo = rbuf.getLength();
byte[] tmp = new byte[fooo];
rbuf.getByte(tmp);
boolean result = irepo.add(tmp);
mbuf.putByte(result ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
} else {
rbuf.skip(rbuf.getLength() - 1);
mbuf.putByte(SSH_AGENT_FAILURE);
}
byte[] response = new byte[mbuf.getLength()];
mbuf.getByte(response);
send(response);
}
private void send(byte[] message) {
packet.reset();
wbuf.putByte((byte) Session.SSH_MSG_CHANNEL_DATA);
wbuf.putInt(recipient);
wbuf.putInt(4 + message.length);
wbuf.putString(message);
try {
getSession().write(packet, this, 4 + message.length);
} catch (Exception e) {
}
}
@Override
void eof_remote() {
super.eof_remote();
eof();
}
}