connectbot-commits

[Prev] Thread [Next]  |  [Prev] Date [Next]

[connectbot commit] r331 - Add authentication agent forwarding codesite-noreply Thu Jun 25 17:00:36 2009

Author: [EMAIL PROTECTED]
Date: Thu Jun 25 15:46:30 2009
New Revision: 331

Added:
    trunk/connectbot/src/com/trilead/ssh2/AuthAgentCallback.java
    trunk/connectbot/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java
     
trunk/connectbot/src/com/trilead/ssh2/packets/PacketChannelAuthAgentReq.java
Modified:
    trunk/connectbot/res/values/arrays.xml
    trunk/connectbot/res/values/strings.xml
    trunk/connectbot/res/xml/host_prefs.xml
    trunk/connectbot/src/com/trilead/ssh2/Session.java
    trunk/connectbot/src/com/trilead/ssh2/channel/ChannelManager.java
    trunk/connectbot/src/org/connectbot/bean/HostBean.java
    trunk/connectbot/src/org/connectbot/service/TerminalBridge.java
    trunk/connectbot/src/org/connectbot/service/TerminalManager.java
    trunk/connectbot/src/org/connectbot/transport/AbsTransport.java
    trunk/connectbot/src/org/connectbot/transport/SSH.java
    trunk/connectbot/src/org/connectbot/util/HostDatabase.java
    trunk/connectbot/src/org/connectbot/util/PubkeyUtils.java

Log:
Add authentication agent forwarding

Modified: trunk/connectbot/res/values/arrays.xml
==============================================================================
--- trunk/connectbot/res/values/arrays.xml      (original)
+++ trunk/connectbot/res/values/arrays.xml      Thu Jun 25 15:46:30 2009
@@ -86,6 +86,18 @@
                <item>-1</item>
        </string-array>

+       <string-array name="list_authagent">
+               <item>No</item>
+               <item>With confirmation</item>
+               <item>Yes</item>
+       </string-array>
+
+       <string-array name="list_authagent_values">
+               <item>no</item>
+               <item>confirm</item>
+               <item>yes</item>
+       </string-array>
+
        <string-array name="list_portforward_types">
                <item>@string/portforward_local</item>
                <item>@string/portforward_remote</item>

Modified: trunk/connectbot/res/values/strings.xml
==============================================================================
--- trunk/connectbot/res/values/strings.xml     (original)
+++ trunk/connectbot/res/values/strings.xml     Thu Jun 25 15:46:30 2009
@@ -71,6 +71,9 @@
        <!-- Prompt for the password to unlock a certain pubkey. -->
        <string name="prompt_pubkey_password">Password for key '%1$s'</string>

+       <!-- Prompt for whether to allow SSH Authentication Agent to use the  
specified key -->
+       <string name="prompt_allow_agent_to_use_key">Allow remote host to\nuse  
key '%1$s'?</string>
+
        <!-- The header of the warning a user gets when the host key has 
changed.  
Note that this can be a very serious attack, so we try to be as "loud" to  
the user as possible. -->
        <string name="host_verification_failure_warning_header">WARNING: REMOTE 
 
HOST IDENTIFICATION HAS CHANGED!</string>
        <!-- The body of the warning a user gets when the host key has changed. 
 
Note that this can be a very serious attack, so we try to be as "loud" to  
the user as possible. -->
@@ -215,6 +218,9 @@

        <!-- Host pubkey usage preference title -->
        <string name="hostpref_pubkeyid_title">Use pubkey 
authentication</string>
+
+       <!-- Preference title for the SSH Authentication Agent Forwarding for a 
 
host connection -->
+       <string name="hostpref_authagent_title">Use SSH auth agent</string>

        <!-- Host post-login automation preference title -->
        <string name="hostpref_postlogin_title">Post-login automation</string>

Modified: trunk/connectbot/res/xml/host_prefs.xml
==============================================================================
--- trunk/connectbot/res/xml/host_prefs.xml     (original)
+++ trunk/connectbot/res/xml/host_prefs.xml     Thu Jun 25 15:46:30 2009
@@ -43,7 +43,14 @@
                android:entries="@array/list_pubkeyids"
                android:entryValues="@array/list_pubkeyids_value"
                />
-               
+
+       <ListPreference
+               android:key="useauthagent"
+               android:title="@string/hostpref_authagent_title"
+               android:entries="@array/list_authagent"
+               android:entryValues="@array/list_authagent_values"
+               />
+
        <EditTextPreference
                android:key="postlogin"
                android:title="@string/hostpref_postlogin_title"

Added: trunk/connectbot/src/com/trilead/ssh2/AuthAgentCallback.java
==============================================================================
--- (empty file)
+++ trunk/connectbot/src/com/trilead/ssh2/AuthAgentCallback.java        Thu Jun 
25  
15:46:30 2009
@@ -0,0 +1,45 @@
+package com.trilead.ssh2;
+
+import java.util.Map;
+
+/**
+ * AuthAgentCallback.
+ *
+ * @author Kenny Root
+ * @version $Id$
+ */
+public interface AuthAgentCallback {
+
+       /**
+        * @return array of blobs containing the OpenSSH-format encoded public  
keys
+        */
+       Map<String,byte[]> retrieveIdentities();
+
+       /**
+        * @param key A <code>RSAPrivateKey</code> or <code>DSAPrivateKey</code>
+        *            containing a DSA or RSA private key of
+        *            the user in Trilead object format.
+        * @param comment comment associated with this key
+        * @return success or failure
+        */
+       boolean addIdentity(Object key, String comment);
+
+       /**
+        * @param publicKey byte blob containing the OpenSSH-format encoded  
public key
+        * @return success or failure
+        */
+       boolean removeIdentity(byte[] publicKey);
+
+       /**
+        * @return success or failure
+        */
+       boolean removeAllIdentities();
+
+       /**
+        * @param publicKey byte blob containing the OpenSSH-format encoded  
public key
+        * @return A <code>RSAPrivateKey</code> or <code>DSAPrivateKey</code>
+        *         containing a DSA or RSA private key of
+        *         the user in Trilead object format.
+        */
+       Object getPrivateKey(byte[] publicKey);
+}

Modified: trunk/connectbot/src/com/trilead/ssh2/Session.java
==============================================================================
--- trunk/connectbot/src/com/trilead/ssh2/Session.java  (original)
+++ trunk/connectbot/src/com/trilead/ssh2/Session.java  Thu Jun 25 15:46:30  
2009
@@ -353,7 +353,28 @@

                cm.requestChannelTrileadPing(cn);
        }
-       
+
+       /**
+        * Request authentication agent forwarding.
+        * @param agent object that implements the callbacks
+        *
+        * @throws IOException in case of any problem or when the session is  
closed
+        */
+       public synchronized boolean 
requestAuthAgentForwarding(AuthAgentCallback  
agent) throws IOException
+       {
+               synchronized (this)
+               {
+                       /*
+                        * The following is just a nicer error, we would catch 
it anyway
+                        * later in the channel code
+                        */
+                       if (flag_closed)
+                               throw new IOException("This session is 
closed.");
+               }
+
+               return cm.requestChannelAgentForwarding(cn, agent);
+       }
+
        public InputStream getStdout()
        {
                return cn.getStdoutStream();

Added:  
trunk/connectbot/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java
==============================================================================
--- (empty file)
+++  
trunk/connectbot/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java       
 
Thu Jun 25 15:46:30 2009
@@ -0,0 +1,408 @@
+package com.trilead.ssh2.channel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import android.util.Log;
+
+import com.trilead.ssh2.AuthAgentCallback;
+import com.trilead.ssh2.log.Logger;
+import com.trilead.ssh2.packets.TypesReader;
+import com.trilead.ssh2.packets.TypesWriter;
+import com.trilead.ssh2.signature.DSAPrivateKey;
+import com.trilead.ssh2.signature.DSASHA1Verify;
+import com.trilead.ssh2.signature.DSASignature;
+import com.trilead.ssh2.signature.RSAPrivateKey;
+import com.trilead.ssh2.signature.RSASHA1Verify;
+import com.trilead.ssh2.signature.RSASignature;
+
+/**
+ * AuthAgentForwardThread.
+ *
+ * @author Kenny Root
+ * @version $Id$
+ */
+public class AuthAgentForwardThread extends Thread implements  
IChannelWorkerThread
+{
+       public static final int SSH_AGENT_CONSTRAIN_LIFETIME = 1;
+       public static final int SSH_AGENT_CONSTRAIN_CONFIRM = 2;
+
+       private static final byte[] SSH_AGENT_FAILURE = {0, 0, 0, 1, 5};
+       private static final byte[] SSH_AGENT_SUCCESS = {0, 0, 0, 1, 6};
+//     public static final int SSH_AGENT_FAILURE = 5;
+//     public static final int SSH_AGENT_SUCCESS = 6;
+
+       public static final int SSH2_AGENTC_REQUEST_IDENTITIES = 11;
+       public static final int SSH2_AGENT_IDENTITIES_ANSWER = 12;
+
+       public static final int SSH2_AGENTC_SIGN_REQUEST = 13;
+       public static final int SSH2_AGENT_SIGN_RESPONSE = 14;
+
+       public static final int SSH2_AGENTC_ADD_IDENTITY = 17;
+       public static final int SSH2_AGENTC_REMOVE_IDENTITY = 18;
+       public static final int SSH2_AGENTC_REMOVE_ALL_IDENTITIES = 19;
+
+       public static final int SSH_AGENTC_ADD_SMARTCARD_KEY = 20;
+       public static final int SSH_AGENTC_REMOVE_SMARTCARD_KEY = 21;
+
+       public static final int SSH_AGENTC_LOCK = 22;
+       public static final int SSH_AGENTC_UNLOCK = 23;
+
+       public static final int SSH2_AGENTC_ADD_ID_CONSTRAINED = 25;
+       public static final int SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED = 26;
+
+       public static final int SSH_AGENT_OLD_SIGNATURE = 1;
+
+       private static final Logger log =  
Logger.getLogger(RemoteAcceptThread.class);
+
+       AuthAgentCallback authAgent;
+       OutputStream os;
+       InputStream is;
+       Channel c;
+       byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE];
+
+       public AuthAgentForwardThread(Channel c, AuthAgentCallback authAgent)
+       {
+               this.c = c;
+               this.authAgent = authAgent;
+
+               if (log.isEnabled())
+                       log.log(20, "AuthAgentForwardThread started");
+       }
+
+       @Override
+       public void run()
+       {
+               try
+               {
+                       c.cm.registerThread(this);
+               } catch (IOException e) {
+                       stopWorking();
+                       return;
+               }
+
+               try
+               {
+                       c.cm.sendOpenConfirmation(c);
+
+                       is = c.getStdoutStream();
+                       os = c.getStdinStream();
+
+                       int totalSize = 4;
+                       int readSoFar = 0;
+
+                       while (true) {
+                               int len;
+
+                               try
+                               {
+                                       len = is.read(buffer, readSoFar, 
buffer.length - readSoFar);
+                               }
+                               catch (IOException e) {
+                                       stopWorking();
+                                       return;
+                               }
+
+                               if (len <= 0)
+                                       break;
+
+                               readSoFar += len;
+
+                               Log.d("AuthAgent", "read " + readSoFar + " 
bytes");
+
+                               if (readSoFar >= 4) {
+                                       TypesReader tr = new 
TypesReader(buffer, 0, 4);
+                                       totalSize = tr.readUINT32() + 4;
+                                       Log.d("AuthAgent", "message is " + 
totalSize + " bytes");
+                               }
+
+                               if (totalSize == readSoFar) {
+//                                     debugPacket(buffer, readSoFar);
+                                       TypesReader tr = new 
TypesReader(buffer, 4, readSoFar - 4);
+                                       int messageType = tr.readByte();
+
+                                       Log.d("AuthAgent", "Got a message type 
" + messageType);
+                                       switch (messageType) {
+                                       case SSH2_AGENTC_REQUEST_IDENTITIES:
+                                               sendIdentities();
+                                               break;
+                                       case SSH2_AGENTC_ADD_IDENTITY:
+                                               addIdentity(tr);
+                                               break;
+                                       case SSH2_AGENTC_REMOVE_IDENTITY:
+                                               removeIdentity(tr);
+                                               break;
+                                       case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
+                                               removeAllIdentities(tr);
+                                               break;
+                                       case SSH2_AGENTC_SIGN_REQUEST:
+                                               processSignRequest(tr);
+                                               break;
+                                       default:
+                                               os.write(SSH_AGENT_FAILURE);
+                                               break;
+                                       }
+
+                                       readSoFar = 0;
+                               }
+                               // TODO write actual agent forwarding stuff!
+//                             log.log(0, "Received an agent request; sending 
failure");
+//                             os.write(AGENT_FAILURE);
+                       }
+
+                       c.cm.closeChannel(c, "EOF on both streams reached.", 
true);
+               }
+               catch (IOException e)
+               {
+                       log.log(50, "IOException in agent forwarder: " + 
e.getMessage());
+
+                       try
+                       {
+                               is.close();
+                       }
+                       catch (IOException e1)
+                       {
+                       }
+                       try
+                       {
+                               os.close();
+                       }
+                       catch (IOException e2)
+                       {
+                       }
+                       try
+                       {
+                               c.cm.closeChannel(c, "IOException in agent 
forwarder (" +  
e.getMessage() + ")", true);
+                       }
+                       catch (IOException e3)
+                       {
+                       }
+               }
+       }
+
+       public void stopWorking() {
+               try
+               {
+                       /* This will lead to an IOException in the is.read() 
call */
+                       is.close();
+               }
+               catch (IOException e)
+               {
+               }
+       }
+
+       private void sendIdentities() throws IOException
+       {
+               Map<String,byte[]> keys = authAgent.retrieveIdentities();
+
+               TypesWriter tw = new TypesWriter();
+               tw.writeByte(SSH2_AGENT_IDENTITIES_ANSWER);
+               int numKeys = 0;
+               if (keys != null)
+                       numKeys = keys.size();
+               tw.writeUINT32(numKeys);
+
+               if (keys != null) {
+                       for (Entry<String,byte[]> entry : keys.entrySet()) {
+                               byte[] keyBytes = entry.getValue();
+                               tw.writeString(keyBytes, 0, keyBytes.length);
+                               tw.writeString(entry.getKey());
+                       }
+               }
+
+               Log.d("AuthAgent", "Sending " + numKeys + " to server");
+               sendPacket(tw.getBytes());
+       }
+
+       /**
+        * @param tr
+        */
+       private void addIdentity(TypesReader tr) {
+               try
+               {
+                       String type = tr.readString();
+
+                       Object key;
+                       String comment;
+
+                       if (type.equals("ssh-rsa")) {
+                               BigInteger n = tr.readMPINT();
+                               BigInteger e = tr.readMPINT();
+                               BigInteger d = tr.readMPINT();
+                               tr.readMPINT(); // iqmp
+                               tr.readMPINT(); // p
+                               tr.readMPINT(); // q
+                               comment = tr.readString();
+
+                               key = new RSAPrivateKey(d, e, n);
+                       } else if (type.equals("ssh-dss")) {
+                               BigInteger p = tr.readMPINT();
+                               BigInteger q = tr.readMPINT();
+                               BigInteger g = tr.readMPINT();
+                               BigInteger y = tr.readMPINT();
+                               BigInteger x = tr.readMPINT();
+                               comment = tr.readString();
+
+                               key = new DSAPrivateKey(p, q, g, y, x);
+                       } else {
+                               os.write(SSH_AGENT_FAILURE);
+                               return;
+                       }
+
+                       if (authAgent.addIdentity(key, comment))
+                               os.write(SSH_AGENT_SUCCESS);
+                       else
+                               os.write(SSH_AGENT_FAILURE);
+               }
+               catch (IOException e)
+               {
+                       try
+                       {
+                               os.write(SSH_AGENT_FAILURE);
+                       }
+                       catch (IOException e1)
+                       {
+                       }
+               }
+       }
+
+       /**
+        * @param tr
+        */
+       private void removeIdentity(TypesReader tr) {
+               try
+               {
+                       byte[] publicKey = tr.readByteString();
+                       if (authAgent.removeIdentity(publicKey))
+                               os.write(SSH_AGENT_SUCCESS);
+                       else
+                               os.write(SSH_AGENT_FAILURE);
+               }
+               catch (IOException e)
+               {
+                       try
+                       {
+                               os.write(SSH_AGENT_FAILURE);
+                       }
+                       catch (IOException e1)
+                       {
+                       }
+               }
+       }
+
+       /**
+        * @param tr
+        */
+       private void removeAllIdentities(TypesReader tr) {
+               try
+               {
+                       if (authAgent.removeAllIdentities())
+                               os.write(SSH_AGENT_SUCCESS);
+                       else
+                               os.write(SSH_AGENT_FAILURE);
+               }
+               catch (IOException e)
+               {
+                       try
+                       {
+                               os.write(SSH_AGENT_FAILURE);
+                       }
+                       catch (IOException e1)
+                       {
+                       }
+               }
+       }
+
+       private void processSignRequest(TypesReader tr)
+       {
+               try
+               {
+                       byte[] publicKey = tr.readByteString();
+                       byte[] challenge = tr.readByteString();
+
+                       int flags = tr.readUINT32();
+
+                       Object trileadKey = authAgent.getPrivateKey(publicKey);
+
+                       if (trileadKey == null) {
+                               Log.d("AuthAgent", "Key not known to us; 
failing signature. Public  
key:");
+//                             debugPacket(publicKey);
+                               os.write(SSH_AGENT_FAILURE);
+                               return;
+                       }
+
+                       byte[] response;
+
+                       if (trileadKey instanceof RSAPrivateKey) {
+                               RSASignature signature = 
RSASHA1Verify.generateSignature(challenge,
+                                               (RSAPrivateKey) trileadKey);
+                               response = 
RSASHA1Verify.encodeSSHRSASignature(signature);
+                       } else if (trileadKey instanceof DSAPrivateKey) {
+                               if ((flags & SSH_AGENT_OLD_SIGNATURE) != 0)
+                                       Log.d("AuthAgent", "Want old signature 
type");
+                               DSASignature signature = 
DSASHA1Verify.generateSignature(challenge,
+                                               (DSAPrivateKey) trileadKey, new 
SecureRandom());
+                               response = 
DSASHA1Verify.encodeSSHDSASignature(signature);
+                       } else {
+                               Log.d("AuthAgent", "Unknown key type; failing 
signature request");
+                               os.write(SSH_AGENT_FAILURE);
+                               return;
+                       }
+
+                       TypesWriter tw = new TypesWriter();
+                       tw.writeByte(SSH2_AGENT_SIGN_RESPONSE);
+                       tw.writeString(response, 0, response.length);
+
+                       sendPacket(tw.getBytes());
+               }
+               catch (IOException e) {
+                       try
+                       {
+                               os.write(SSH_AGENT_FAILURE);
+                       }
+                       catch (IOException e1) {
+                       }
+               }
+       }
+
+       /**
+        * @param tw
+        * @throws IOException
+        */
+       private void sendPacket(byte[] message) throws IOException {
+               TypesWriter packet = new TypesWriter();
+               packet.writeUINT32(message.length);
+               packet.writeBytes(message);
+//             debugPacket(packet.getBytes());
+               os.write(packet.getBytes());
+       }
+
+//     private static final char[] hexDigits =  
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 
'F'};
+//
+//     private void debugPacket(byte[] packet) {
+//             debugPacket(packet, packet.length);
+//     }
+//
+//     private void debugPacket(byte[] packet, int len) {
+//             StringBuilder sb = new StringBuilder();
+//             sb.append("Packet dump:");
+//
+//             for (int i = 0; i < len; i++) {
+//                     if (packet[i] < 32 || packet[i] > 0x7e) {
+//                             sb.append(" 0x");
+//                             sb.append(hexDigits[(packet[i] >> 4) & 0xF]);
+//                             sb.append(hexDigits[packet[i] & 0xF]);
+//                     } else {
+//                             sb.append("    ");
+//                             sb.append((char)packet[i]);
+//                     }
+//             }
+//
+//             Log.d("AuthAgent", sb.toString());
+//     }
+}

Modified: trunk/connectbot/src/com/trilead/ssh2/channel/ChannelManager.java
==============================================================================
--- trunk/connectbot/src/com/trilead/ssh2/channel/ChannelManager.java    
(original)
+++ trunk/connectbot/src/com/trilead/ssh2/channel/ChannelManager.java   Thu  
Jun 25 15:46:30 2009
@@ -5,8 +5,10 @@
  import java.util.HashMap;
  import java.util.Vector;

+import com.trilead.ssh2.AuthAgentCallback;
  import com.trilead.ssh2.ChannelCondition;
  import com.trilead.ssh2.log.Logger;
+import com.trilead.ssh2.packets.PacketChannelAuthAgentReq;
  import com.trilead.ssh2.packets.PacketChannelOpenConfirmation;
  import com.trilead.ssh2.packets.PacketChannelOpenFailure;
  import com.trilead.ssh2.packets.PacketChannelTrileadPing;
@@ -50,6 +52,8 @@

        private HashMap remoteForwardings = new HashMap();

+       private AuthAgentCallback authAgent;
+
        private Vector listenerThreads = new Vector();

        private boolean listenerThreadsAllowed = true;
@@ -530,6 +534,38 @@

        }

+       /**
+        * @param agent
+        * @throws IOException
+        */
+       public boolean requestChannelAgentForwarding(Channel c, 
AuthAgentCallback  
authAgent) throws IOException {
+               synchronized (this)
+               {
+                       if (this.authAgent != null)
+                               throw new IllegalStateException("Auth agent 
already exists");
+
+                       this.authAgent = authAgent;
+               }
+
+               synchronized (channels)
+               {
+                       globalSuccessCounter = globalFailedCounter = 0;
+               }
+
+               if (log.isEnabled())
+                       log.log(50, "Requesting agent forwarding");
+
+               PacketChannelAuthAgentReq aar = new  
PacketChannelAuthAgentReq(c.remoteID);
+               tm.sendMessage(aar.getPayload());
+
+               if (waitForChannelRequestResult(c) == false) {
+                       authAgent = null;
+                       return false;
+               }
+
+               return true;
+       }
+
        public void registerThread(IChannelWorkerThread thr) throws IOException
        {
                synchronized (listenerThreads)
@@ -1270,6 +1306,25 @@

                        rat.setDaemon(true);
                        rat.start();
+
+                       return;
+               }
+
+               if ("[EMAIL PROTECTED]".equals(channelType)) {
+                       Channel c = new Channel(this);
+
+                       synchronized (c)
+                       {
+                               c.remoteID = remoteID;
+                               c.remoteWindow = remoteWindow & 0xFFFFffffL; /* 
properly convert  
UINT32 to long */
+                               c.remoteMaxPacketSize = remoteMaxPacketSize;
+                               c.localID = addChannel(c);
+                       }
+
+                       AuthAgentForwardThread aat = new 
AuthAgentForwardThread(c, authAgent);
+
+                       aat.setDaemon(true);
+                       aat.start();

                        return;
                }

Added:  
trunk/connectbot/src/com/trilead/ssh2/packets/PacketChannelAuthAgentReq.java
==============================================================================
--- (empty file)
+++  
trunk/connectbot/src/com/trilead/ssh2/packets/PacketChannelAuthAgentReq.java    
 
Thu Jun 25 15:46:30 2009
@@ -0,0 +1,33 @@
+package com.trilead.ssh2.packets;
+
+/**
+ * PacketGlobalAuthAgent.
+ *
+ * @author Kenny Root, [EMAIL PROTECTED]
+ * @version $Id$
+ */
+public class PacketChannelAuthAgentReq
+{
+       byte[] payload;
+
+       public int recipientChannelID;
+
+       public PacketChannelAuthAgentReq(int recipientChannelID)
+       {
+               this.recipientChannelID = recipientChannelID;
+       }
+
+       public byte[] getPayload()
+       {
+               if (payload == null)
+               {
+                       TypesWriter tw = new TypesWriter();
+                       tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST);
+                       tw.writeUINT32(recipientChannelID);
+                       tw.writeString("[EMAIL PROTECTED]");
+                       tw.writeBoolean(true); // want reply
+                       payload = tw.getBytes();
+               }
+               return payload;
+       }
+}

Modified: trunk/connectbot/src/org/connectbot/bean/HostBean.java
==============================================================================
--- trunk/connectbot/src/org/connectbot/bean/HostBean.java      (original)
+++ trunk/connectbot/src/org/connectbot/bean/HostBean.java      Thu Jun 25  
15:46:30 2009
@@ -41,6 +41,7 @@
        private long lastConnect = -1;
        private String color;
        private boolean useKeys = true;
+       private String useAuthAgent = HostDatabase.AUTHAGENT_NO;
        private String postLogin = null;
        private long pubkeyId = -1;
        private boolean wantSession = true;
@@ -140,6 +141,12 @@
        public boolean getUseKeys() {
                return useKeys;
        }
+       public void setUseAuthAgent(String useAuthAgent) {
+               this.useAuthAgent = useAuthAgent;
+       }
+       public String getUseAuthAgent() {
+               return useAuthAgent;
+       }
        public void setPostLogin(String postLogin) {
                this.postLogin = postLogin;
        }
@@ -202,6 +209,7 @@
                values.put(HostDatabase.FIELD_HOST_LASTCONNECT, lastConnect);
                values.put(HostDatabase.FIELD_HOST_COLOR, color);
                values.put(HostDatabase.FIELD_HOST_USEKEYS, 
Boolean.toString(useKeys));
+               values.put(HostDatabase.FIELD_HOST_USEAUTHAGENT, useAuthAgent);
                values.put(HostDatabase.FIELD_HOST_POSTLOGIN, postLogin);
                values.put(HostDatabase.FIELD_HOST_PUBKEYID, pubkeyId);
                values.put(HostDatabase.FIELD_HOST_WANTSESSION,  
Boolean.toString(wantSession));

Modified: trunk/connectbot/src/org/connectbot/service/TerminalBridge.java
==============================================================================
--- trunk/connectbot/src/org/connectbot/service/TerminalBridge.java      
(original)
+++ trunk/connectbot/src/org/connectbot/service/TerminalBridge.java     Thu Jun 
 
25 15:46:30 2009
@@ -272,8 +272,9 @@
                transport.setManager(manager);
                transport.setHost(host);

-               // Should be more abstract?
+               // TODO make this more abstract so we don't litter on 
AbsTransport
                transport.setCompression(host.getCompression());
+               transport.setUseAuthAgent(host.getUseAuthAgent());
                transport.setEmulation(emulation);

                if (transport.canForwardPorts()) {

Modified: trunk/connectbot/src/org/connectbot/service/TerminalManager.java
==============================================================================
--- trunk/connectbot/src/org/connectbot/service/TerminalManager.java     
(original)
+++ trunk/connectbot/src/org/connectbot/service/TerminalManager.java    Thu  
Jun 25 15:46:30 2009
@@ -21,12 +21,14 @@
  import java.io.IOException;
  import java.security.PrivateKey;
  import java.security.PublicKey;
+import java.util.Arrays;
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Timer;
  import java.util.TimerTask;
+import java.util.Map.Entry;

  import org.connectbot.ConsoleActivity;
  import org.connectbot.R;
@@ -83,7 +85,7 @@

        public Handler disconnectHandler = null;

-       public HashMap<String, Object> loadedPubkeys = new HashMap<String,  
Object>();
+       public Map<String, KeyHolder> loadedKeypairs = new HashMap<String,  
KeyHolder>();

        public Resources res;

@@ -137,8 +139,7 @@
                                PublicKey pubKey = 
PubkeyUtils.decodePublic(pubkey.getPublicKey(),  
pubkey.getType());
                                Object trileadKey = 
PubkeyUtils.convertToTrilead(privKey, pubKey);

-                               loadedPubkeys.put(pubkey.getNickname(), 
trileadKey);
-                               Log.d(TAG, String.format("Added key '%s' to 
in-memory cache",  
pubkey.getNickname()));
+                               addKey(pubkey.getNickname(), trileadKey);
                        } catch (Exception e) {
                                Log.d(TAG, String.format("Problem adding key 
'%s' to in-memory cache",  
pubkey.getNickname()), e);
                        }
@@ -312,27 +313,73 @@
        }

        public boolean isKeyLoaded(String nickname) {
-               return loadedPubkeys.containsKey(nickname);
+               return loadedKeypairs.containsKey(nickname);
        }

        public void addKey(String nickname, Object trileadKey) {
-               loadedPubkeys.remove(nickname);
-               loadedPubkeys.put(nickname, trileadKey);
+               removeKey(nickname);
+
+               byte[] sshPubKey = PubkeyUtils.extractOpenSSHPublic(trileadKey);
+
+               KeyHolder keyHolder = new KeyHolder();
+               keyHolder.trileadKey = trileadKey;
+               keyHolder.openSSHPubkey = sshPubKey;
+
+               loadedKeypairs.put(nickname, keyHolder);
+
+               Log.d(TAG, String.format("Added key '%s' to in-memory cache", 
nickname));
+       }
+
+       public boolean removeKey(String nickname) {
+               Log.d(TAG, String.format("Removed key '%s' to in-memory cache", 
 
nickname));
+               return loadedKeypairs.remove(nickname) != null;
        }

-       public void removeKey(String nickname) {
-               loadedPubkeys.remove(nickname);
+       public boolean removeKey(byte[] publicKey) {
+               String nickname = null;
+               for (Entry<String,KeyHolder> entry : loadedKeypairs.entrySet()) 
{
+                       if (Arrays.equals(entry.getValue().openSSHPubkey, 
publicKey)) {
+                               nickname = entry.getKey();
+                               break;
+                       }
+               }
+
+               if (nickname != null) {
+                       Log.d(TAG, String.format("Removed key '%s' to in-memory 
cache",  
nickname));
+                       return removeKey(nickname);
+               } else
+                       return false;
        }

        public Object getKey(String nickname) {
-               return loadedPubkeys.get(nickname);
+               if (loadedKeypairs.containsKey(nickname)) {
+                       KeyHolder keyHolder = loadedKeypairs.get(nickname);
+                       return keyHolder.trileadKey;
+               } else
+                       return null;
+       }
+
+       public Object getKey(byte[] publicKey) {
+               for (KeyHolder keyHolder : loadedKeypairs.values()) {
+                       if (Arrays.equals(keyHolder.openSSHPubkey, publicKey))
+                               return keyHolder.trileadKey;
+               }
+               return null;
+       }
+
+       public String getKeyNickname(byte[] publicKey) {
+               for (Entry<String,KeyHolder> entry : loadedKeypairs.entrySet()) 
{
+                       if (Arrays.equals(entry.getValue().openSSHPubkey, 
publicKey))
+                               return entry.getKey();
+               }
+               return null;
        }

        private void stopWithDelay() {
                // TODO add in a way to check whether keys loaded are encrypted 
and only
                // set timer when we have an encrypted key loaded

-               if (loadedPubkeys.size() > 0) {
+               if (loadedKeypairs.size() > 0) {
                        synchronized (this) {
                                if (idleTimer == null)
                                        idleTimer = new Timer(true);
@@ -534,5 +581,10 @@

        public boolean isResizeAllowed() {
                return resizeAllowed;
+       }
+
+       public class KeyHolder {
+               public Object trileadKey;
+               public byte[] openSSHPubkey;
        }
  }

Modified: trunk/connectbot/src/org/connectbot/transport/AbsTransport.java
==============================================================================
--- trunk/connectbot/src/org/connectbot/transport/AbsTransport.java      
(original)
+++ trunk/connectbot/src/org/connectbot/transport/AbsTransport.java     Thu Jun 
 
25 15:46:30 2009
@@ -133,6 +133,10 @@
                // do nothing
        }

+       public void setUseAuthAgent(String useAuthAgent) {
+               // do nothing
+       }
+
        public void setEmulation(String emulation) {
                this.emulation = emulation;
        }

Modified: trunk/connectbot/src/org/connectbot/transport/SSH.java
==============================================================================
--- trunk/connectbot/src/org/connectbot/transport/SSH.java      (original)
+++ trunk/connectbot/src/org/connectbot/transport/SSH.java      Thu Jun 25  
15:46:30 2009
@@ -32,6 +32,7 @@
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
+import java.util.Map.Entry;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;

@@ -41,6 +42,7 @@
  import org.connectbot.bean.PubkeyBean;
  import org.connectbot.service.TerminalBridge;
  import org.connectbot.service.TerminalManager;
+import org.connectbot.service.TerminalManager.KeyHolder;
  import org.connectbot.util.HostDatabase;
  import org.connectbot.util.PubkeyDatabase;
  import org.connectbot.util.PubkeyUtils;
@@ -49,6 +51,7 @@
  import android.net.Uri;
  import android.util.Log;

+import com.trilead.ssh2.AuthAgentCallback;
  import com.trilead.ssh2.ChannelCondition;
  import com.trilead.ssh2.Connection;
  import com.trilead.ssh2.ConnectionInfo;
@@ -60,12 +63,18 @@
  import com.trilead.ssh2.ServerHostKeyVerifier;
  import com.trilead.ssh2.Session;
  import com.trilead.ssh2.crypto.PEMDecoder;
+import com.trilead.ssh2.signature.DSAPrivateKey;
+import com.trilead.ssh2.signature.DSAPublicKey;
+import com.trilead.ssh2.signature.DSASHA1Verify;
+import com.trilead.ssh2.signature.RSAPrivateKey;
+import com.trilead.ssh2.signature.RSAPublicKey;
+import com.trilead.ssh2.signature.RSASHA1Verify;

  /**
   * @author Kenny Root
   *
   */
-public class SSH extends AbsTransport implements ConnectionMonitor,  
InteractiveCallback {
+public class SSH extends AbsTransport implements ConnectionMonitor,  
InteractiveCallback, AuthAgentCallback {
        public SSH() {
                super();
        }
@@ -121,6 +130,8 @@
        private int width;
        private int height;

+       private String useAuthAgent = HostDatabase.AUTHAGENT_NO;
+
        public class HostKeyVerifier implements ServerHostKeyVerifier {
                public boolean verifyServerHostKey(String hostname, int port,
                                String serverHostKeyAlgorithm, byte[] 
serverHostKey) throws  
IOException {
@@ -216,8 +227,8 @@
                                        // try each of the in-memory keys
                                        bridge.outputLine(manager.res
                                                        
.getString(R.string.terminal_auth_pubkey_any));
-                                       for(String nickname : 
manager.loadedPubkeys.keySet()) {
-                                               Object trileadKey = 
manager.loadedPubkeys.get(nickname);
+                                       for(String nickname : 
manager.loadedKeypairs.keySet()) {
+                                               Object trileadKey = 
manager.loadedKeypairs.get(nickname).trileadKey;
                                                
if(this.tryPublicKey(host.getUsername(), nickname, trileadKey)) {
                                                        finishConnection();
                                                        break;
@@ -361,6 +372,9 @@
                try {
                        session = connection.openSession();

+                       if (!useAuthAgent.equals(HostDatabase.AUTHAGENT_NO))
+                               session.requestAuthAgentForwarding(this);
+
                        session.requestPTY(getEmulation(), columns, rows, 
width, height, null);
                        session.startShell();

@@ -807,5 +821,66 @@
                                context.getString(R.string.format_username),
                                context.getString(R.string.format_hostname),
                                context.getString(R.string.format_port));
+       }
+
+       @Override
+       public void setUseAuthAgent(String useAuthAgent) {
+               this.useAuthAgent = useAuthAgent;
+       }
+
+       public Map<String,byte[]> retrieveIdentities() {
+               Map<String,byte[]> pubKeys = new  
HashMap<String,byte[]>(manager.loadedKeypairs.size());
+
+               for (Entry<String,KeyHolder> entry : 
manager.loadedKeypairs.entrySet()) {
+                       Object trileadKey = entry.getValue().trileadKey;
+
+                       try {
+                               if (trileadKey instanceof RSAPrivateKey) {
+                                       RSAPublicKey pubkey = ((RSAPrivateKey) 
trileadKey).getPublicKey();
+                                       pubKeys.put(entry.getKey(),  
RSASHA1Verify.encodeSSHRSAPublicKey(pubkey));
+                               } else if (trileadKey instanceof DSAPrivateKey) 
{
+                                       DSAPublicKey pubkey = ((DSAPrivateKey) 
trileadKey).getPublicKey();
+                                       pubKeys.put(entry.getKey(),  
DSASHA1Verify.encodeSSHDSAPublicKey(pubkey));
+                               } else
+                                       continue;
+                       } catch (IOException e) {
+                               continue;
+                       }
+               }
+
+               return pubKeys;
+       }
+
+       public Object getPrivateKey(byte[] publicKey) {
+               String nickname = manager.getKeyNickname(publicKey);
+
+               if (nickname == null)
+                       return null;
+
+               if (useAuthAgent.equals(HostDatabase.AUTHAGENT_NO)) {
+                       Log.e(TAG, "");
+                       return null;
+               } else if (useAuthAgent.equals(HostDatabase.AUTHAGENT_CONFIRM)) 
{
+                       Boolean result = 
bridge.promptHelper.requestBooleanPrompt(null,
+                                       
manager.res.getString(R.string.prompt_allow_agent_to_use_key,
+                                                       nickname));
+                       if (result == null || !result)
+                               return null;
+               }
+               return manager.getKey(nickname);
+       }
+
+       public boolean addIdentity(Object key, String comment) {
+               manager.addKey(comment, key);
+               return true;
+       }
+
+       public boolean removeAllIdentities() {
+               manager.loadedKeypairs.clear();
+               return true;
+       }
+
+       public boolean removeIdentity(byte[] publicKey) {
+               return manager.removeKey(publicKey);
        }
  }

Modified: trunk/connectbot/src/org/connectbot/util/HostDatabase.java
==============================================================================
--- trunk/connectbot/src/org/connectbot/util/HostDatabase.java  (original)
+++ trunk/connectbot/src/org/connectbot/util/HostDatabase.java  Thu Jun 25  
15:46:30 2009
@@ -49,7 +49,7 @@
        public final static String TAG = "ConnectBot.HostDatabase";

        public final static String DB_NAME = "hosts";
-       public final static int DB_VERSION = 18;
+       public final static int DB_VERSION = 19;

        public final static String TABLE_HOSTS = "hosts";
        public final static String FIELD_HOST_NICKNAME = "nickname";
@@ -62,6 +62,7 @@
        public final static String FIELD_HOST_LASTCONNECT = "lastconnect";
        public final static String FIELD_HOST_COLOR = "color";
        public final static String FIELD_HOST_USEKEYS = "usekeys";
+       public final static String FIELD_HOST_USEAUTHAGENT = "useauthagent";
        public final static String FIELD_HOST_POSTLOGIN = "postlogin";
        public final static String FIELD_HOST_PUBKEYID = "pubkeyid";
        public final static String FIELD_HOST_WANTSESSION = "wantsession";
@@ -102,6 +103,10 @@
        public final static String DELKEY_DEL = "del";
        public final static String DELKEY_BACKSPACE = "backspace";

+       public final static String AUTHAGENT_NO = "no";
+       public final static String AUTHAGENT_CONFIRM = "confirm";
+       public final static String AUTHAGENT_YES = "yes";
+
        public final static String ENCODING_DEFAULT =  
Charset.defaultCharset().name();

        public final static long PUBKEYID_NEVER = -2;
@@ -129,6 +134,7 @@
                                + FIELD_HOST_LASTCONNECT + " INTEGER, "
                                + FIELD_HOST_COLOR + " TEXT, "
                                + FIELD_HOST_USEKEYS + " TEXT, "
+                               + FIELD_HOST_USEAUTHAGENT + " TEXT, "
                                + FIELD_HOST_POSTLOGIN + " TEXT, "
                                + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + 
PUBKEYID_ANY + ", "
                                + FIELD_HOST_DELKEY + " TEXT DEFAULT '" + 
DELKEY_DEL + "', "
@@ -226,6 +232,9 @@
                                                + FIELD_COLOR_BG + " INTEGER)");
                                db.execSQL("CREATE INDEX " + 
TABLE_COLOR_DEFAULTS + FIELD_COLOR_SCHEME  
+ "index ON "
                                                + TABLE_COLOR_DEFAULTS + " (" + 
FIELD_COLOR_SCHEME + ");");
+                       case 18:
+                               db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                                               + " ADD COLUMN " + 
FIELD_HOST_USEAUTHAGENT + " TEXT DEFAULT '" +  
AUTHAGENT_NO + "'");
                        }
                } catch (SQLiteException e) {
                        // The database has entered an unknown state. Try to 
recover.
@@ -374,6 +383,7 @@
                        COL_LASTCONNECT = 
c.getColumnIndexOrThrow(FIELD_HOST_LASTCONNECT),
                        COL_COLOR = c.getColumnIndexOrThrow(FIELD_HOST_COLOR),
                        COL_USEKEYS = 
c.getColumnIndexOrThrow(FIELD_HOST_USEKEYS),
+                       COL_USEAUTHAGENT = 
c.getColumnIndexOrThrow(FIELD_HOST_USEAUTHAGENT),
                        COL_POSTLOGIN = 
c.getColumnIndexOrThrow(FIELD_HOST_POSTLOGIN),
                        COL_PUBKEYID = 
c.getColumnIndexOrThrow(FIELD_HOST_PUBKEYID),
                        COL_WANTSESSION = 
c.getColumnIndexOrThrow(FIELD_HOST_WANTSESSION),
@@ -393,6 +403,7 @@
                        host.setLastConnect(c.getLong(COL_LASTCONNECT));
                        host.setColor(c.getString(COL_COLOR));
                        
host.setUseKeys(Boolean.valueOf(c.getString(COL_USEKEYS)));
+                       host.setUseAuthAgent(c.getString(COL_USEAUTHAGENT));
                        host.setPostLogin(c.getString(COL_POSTLOGIN));
                        host.setPubkeyId(c.getLong(COL_PUBKEYID));
                        
host.setWantSession(Boolean.valueOf(c.getString(COL_WANTSESSION)));

Modified: trunk/connectbot/src/org/connectbot/util/PubkeyUtils.java
==============================================================================
--- trunk/connectbot/src/org/connectbot/util/PubkeyUtils.java   (original)
+++ trunk/connectbot/src/org/connectbot/util/PubkeyUtils.java   Thu Jun 25  
15:46:30 2009
@@ -267,6 +267,29 @@
                throw new InvalidKeyException("Unknown key type");
        }

+       /*
+        * OpenSSH compatibility methods
+        */
+
+       /**
+        * @param trileadKey
+        * @return OpenSSH-encoded pubkey
+        */
+       public static byte[] extractOpenSSHPublic(Object trileadKey) {
+               try {
+                       if (trileadKey instanceof 
com.trilead.ssh2.signature.RSAPrivateKey)
+                               return RSASHA1Verify.encodeSSHRSAPublicKey(
+                                               
((com.trilead.ssh2.signature.RSAPrivateKey)  
trileadKey).getPublicKey());
+                       else if (trileadKey instanceof 
com.trilead.ssh2.signature.DSAPrivateKey)
+                               return DSASHA1Verify.encodeSSHDSAPublicKey(
+                                               
((com.trilead.ssh2.signature.DSAPrivateKey)  
trileadKey).getPublicKey());
+                       else
+                               return null;
+               } catch (IOException e) {
+                       return null;
+               }
+       }
+
        public static String exportPEM(PrivateKey key, String secret) throws  
NoSuchAlgorithmException, InvalidParameterSpecException,  
NoSuchPaddingException, InvalidKeyException,  
InvalidAlgorithmParameterException, InvalidKeySpecException,  
IllegalBlockSizeException, IOException {
                StringBuilder sb = new StringBuilder();


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"ConnectBot Commits" group.
To post to this group, send email to [EMAIL PROTECTED]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/connectbot-commits?hl=en
-~----------~----~----~----~------~----~------~--~---