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