0
|
1 package com.five_ten_sg.connectbot.service;
|
|
2
|
|
3 import java.io.IOException;
|
|
4 import java.security.KeyPair;
|
|
5 import java.security.PrivateKey;
|
|
6 import java.security.PublicKey;
|
|
7 import java.security.interfaces.DSAPrivateKey;
|
|
8 import java.security.interfaces.DSAPublicKey;
|
|
9 import java.security.interfaces.ECPrivateKey;
|
|
10 import java.security.interfaces.ECPublicKey;
|
|
11 import java.security.interfaces.RSAPrivateKey;
|
|
12 import java.security.interfaces.RSAPublicKey;
|
|
13 import java.util.HashMap;
|
|
14 import java.util.Map;
|
|
15 import java.util.Map.Entry;
|
|
16 import java.util.concurrent.locks.Condition;
|
|
17 import java.util.concurrent.locks.Lock;
|
|
18 import java.util.concurrent.locks.ReentrantLock;
|
|
19
|
|
20 import com.five_ten_sg.connectbot.service.TerminalManager;
|
|
21 import com.five_ten_sg.connectbot.service.TerminalManager.KeyHolder;
|
|
22 import android.app.Service;
|
|
23 import android.content.ComponentName;
|
|
24 import android.content.Intent;
|
|
25 import android.content.ServiceConnection;
|
|
26 import android.os.IBinder;
|
|
27 import android.os.RemoteException;
|
|
28 import android.util.Log;
|
|
29
|
|
30 import com.madgag.ssh.android.authagent.AndroidAuthAgent;
|
344
|
31 import ch.ethz.ssh2.crypto.SecureRandomFix;
|
273
|
32 import ch.ethz.ssh2.signature.DSASHA1Verify;
|
|
33 import ch.ethz.ssh2.signature.ECDSASHA2Verify;
|
|
34 import ch.ethz.ssh2.signature.RSASHA1Verify;
|
0
|
35
|
344
|
36
|
0
|
37 public class AuthAgentService extends Service {
|
|
38 private static final String TAG = "ConnectBot.AuthAgentService";
|
|
39 protected TerminalManager manager;
|
|
40 final Lock lock = new ReentrantLock();
|
|
41 final Condition managerReady = lock.newCondition();
|
|
42
|
|
43 private ServiceConnection connection = new ServiceConnection() {
|
|
44 public void onServiceConnected(ComponentName className, IBinder service) {
|
|
45 Log.d(TAG, "Terminal manager available! Hurrah");
|
|
46 manager = ((TerminalManager.TerminalBinder) service).getService();
|
|
47 lock.lock();
|
|
48
|
|
49 try {
|
|
50 managerReady.signal();
|
|
51 }
|
|
52 finally {
|
|
53 lock.unlock();
|
|
54 }
|
|
55 }
|
|
56 public void onServiceDisconnected(ComponentName className) {
|
|
57 manager = null;
|
|
58 Log.d(TAG, "Terminal manager gone...");
|
|
59 }
|
|
60 };
|
|
61
|
|
62 @Override
|
|
63 public IBinder onBind(Intent intent) {
|
|
64 Log.d(TAG, "onBind() called");
|
|
65 bindService(new Intent(this, TerminalManager.class), connection, BIND_AUTO_CREATE);
|
|
66 return mBinder;
|
|
67 }
|
|
68
|
|
69 private final AndroidAuthAgent.Stub mBinder = new AndroidAuthAgent.Stub() {
|
|
70 public Map getIdentities() throws RemoteException {
|
|
71 Log.d(TAG, "getIdentities() called");
|
|
72 waitForTerminalManager();
|
|
73 Log.d(TAG, "getIdentities() manager.loadedKeypairs : " + manager.loadedKeypairs);
|
|
74 return sshEncodedPubKeysFrom(manager.loadedKeypairs);
|
|
75 }
|
|
76 public byte[] sign(byte[] publicKey, byte[] data) throws RemoteException {
|
|
77 Log.d(TAG, "sign() called");
|
|
78 waitForTerminalManager();
|
|
79 KeyPair pair = keyPairFor(publicKey);
|
|
80 Log.d(TAG, "sign() - signing keypair found : " + pair);
|
|
81
|
|
82 if (pair == null) {
|
|
83 return null;
|
|
84 }
|
|
85
|
|
86 PrivateKey privKey = pair.getPrivate();
|
|
87
|
|
88 if (privKey instanceof RSAPrivateKey) {
|
|
89 return sshEncodedSignatureFor(data, (RSAPrivateKey) privKey);
|
|
90 }
|
|
91 else if (privKey instanceof DSAPrivateKey) {
|
|
92 return sshEncodedSignatureFor(data, (DSAPrivateKey) privKey);
|
|
93 }
|
296
|
94 else if (privKey instanceof ECPrivateKey) {
|
|
95 return sshEncodedSignatureFor(data, (ECPrivateKey) privKey);
|
|
96 }
|
0
|
97
|
|
98 return null;
|
|
99 }
|
|
100 private void waitForTerminalManager() throws RemoteException {
|
|
101 lock.lock();
|
|
102
|
|
103 try {
|
|
104 while (manager == null) {
|
|
105 Log.d(TAG, "Waiting for TerminalManager...");
|
|
106 managerReady.await();
|
|
107 }
|
|
108 }
|
|
109 catch (InterruptedException e) {
|
|
110 throw new RemoteException();
|
|
111 }
|
|
112 finally {
|
|
113 lock.unlock();
|
|
114 }
|
|
115
|
|
116 Log.d(TAG, "Got TerminalManager : " + manager);
|
|
117 }
|
|
118 private Map<String, byte[]> sshEncodedPubKeysFrom(Map<String, KeyHolder> keypairs) {
|
|
119 Map<String, byte[]> pubkeys = new HashMap<String, byte[]> (keypairs.size());
|
|
120
|
|
121 for (Entry<String, KeyHolder> entry : keypairs.entrySet()) {
|
|
122 byte[] encodedKey = sshEncodedPubKeyFrom(entry.getValue().pair);
|
|
123
|
|
124 if (encodedKey != null) {
|
|
125 pubkeys.put(entry.getKey(), encodedKey);
|
|
126 }
|
|
127 }
|
|
128
|
|
129 return pubkeys;
|
|
130 }
|
|
131 private byte[] sshEncodedPubKeyFrom(KeyPair pair) {
|
|
132 try {
|
|
133 PrivateKey privKey = pair.getPrivate();
|
|
134
|
|
135 if (privKey instanceof RSAPrivateKey) {
|
|
136 RSAPublicKey pubkey = (RSAPublicKey)pair.getPublic();
|
|
137 return RSASHA1Verify.encodeSSHRSAPublicKey(pubkey);
|
|
138 }
|
|
139 else if (privKey instanceof DSAPrivateKey) {
|
|
140 DSAPublicKey pubkey = (DSAPublicKey)pair.getPublic();
|
|
141 return DSASHA1Verify.encodeSSHDSAPublicKey(pubkey);
|
|
142 }
|
296
|
143 else if (privKey instanceof ECPrivateKey) {
|
|
144 ECPublicKey pubkey = (ECPublicKey) pair.getPublic();
|
|
145 return ECDSASHA2Verify.encodeSSHECDSAPublicKey(pubkey);
|
|
146 }
|
0
|
147 }
|
|
148 catch (IOException e) {
|
|
149 Log.e(TAG, "Couldn't encode " + pair, e);
|
|
150 }
|
|
151
|
|
152 return null;
|
|
153 }
|
|
154 private byte[] sshEncodedSignatureFor(byte[] data, RSAPrivateKey privKey) {
|
|
155 try {
|
|
156 byte[] signature = RSASHA1Verify.generateSignature(data, privKey);
|
|
157 return RSASHA1Verify.encodeSSHRSASignature(signature);
|
|
158 }
|
|
159 catch (IOException e) {
|
|
160 throw new RuntimeException(e);
|
|
161 }
|
|
162 }
|
|
163 private byte[] sshEncodedSignatureFor(byte[] data, DSAPrivateKey privKey) {
|
|
164 try {
|
344
|
165 byte[] signature = DSASHA1Verify.generateSignature(data, privKey, new SecureRandomFix());
|
0
|
166 return DSASHA1Verify.encodeSSHDSASignature(signature);
|
|
167 }
|
|
168 catch (IOException e) {
|
|
169 throw new RuntimeException(e);
|
|
170 }
|
|
171 }
|
296
|
172 private byte[] sshEncodedSignatureFor(byte[] data, ECPrivateKey privKey) {
|
|
173 try {
|
|
174 byte[] signature = ECDSASHA2Verify.generateSignature(data, privKey);
|
297
|
175 return ECDSASHA2Verify.encodeSSHECDSASignature(signature, privKey.getParams());
|
296
|
176 }
|
|
177 catch (IOException e) {
|
|
178 throw new RuntimeException(e);
|
|
179 }
|
|
180 }
|
0
|
181 private KeyPair keyPairFor(byte[] publicKey) {
|
|
182 String nickname = manager.getKeyNickname(publicKey);
|
|
183
|
|
184 if (nickname == null) {
|
|
185 Log.w(TAG, "No key-pair found for public-key.");
|
|
186 return null;
|
|
187 }
|
|
188
|
|
189 // check manager.loadedKeypairs.get(nickname).bean.isConfirmUse() and promptForPubkeyUse(nickname) ?
|
|
190 return manager.getKey(nickname);
|
|
191 }
|
|
192 };
|
|
193 }
|