comparison src/com/five_ten_sg/connectbot/service/AuthAgentService.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children 91a31873c42a
comparison
equal deleted inserted replaced
-1:000000000000 0:0ce5cc452d02
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;
32 import com.trilead.ssh2.signature.DSASHA1Verify;
33 import com.trilead.ssh2.signature.ECDSASHA2Verify;
34 import com.trilead.ssh2.signature.RSASHA1Verify;
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 }
93
94 return null;
95 }
96 private void waitForTerminalManager() throws RemoteException {
97 lock.lock();
98
99 try {
100 while (manager == null) {
101 Log.d(TAG, "Waiting for TerminalManager...");
102 managerReady.await();
103 }
104 }
105 catch (InterruptedException e) {
106 throw new RemoteException();
107 }
108 finally {
109 lock.unlock();
110 }
111
112 Log.d(TAG, "Got TerminalManager : " + manager);
113 }
114 private Map<String, byte[]> sshEncodedPubKeysFrom(Map<String, KeyHolder> keypairs) {
115 Map<String, byte[]> pubkeys = new HashMap<String, byte[]> (keypairs.size());
116
117 for (Entry<String, KeyHolder> entry : keypairs.entrySet()) {
118 byte[] encodedKey = sshEncodedPubKeyFrom(entry.getValue().pair);
119
120 if (encodedKey != null) {
121 pubkeys.put(entry.getKey(), encodedKey);
122 }
123 }
124
125 return pubkeys;
126 }
127 private byte[] sshEncodedPubKeyFrom(KeyPair pair) {
128 try {
129 PrivateKey privKey = pair.getPrivate();
130
131 if (privKey instanceof RSAPrivateKey) {
132 RSAPublicKey pubkey = (RSAPublicKey)pair.getPublic();
133 return RSASHA1Verify.encodeSSHRSAPublicKey(pubkey);
134 }
135 else if (privKey instanceof DSAPrivateKey) {
136 DSAPublicKey pubkey = (DSAPublicKey)pair.getPublic();
137 return DSASHA1Verify.encodeSSHDSAPublicKey(pubkey);
138 }
139 }
140 catch (IOException e) {
141 Log.e(TAG, "Couldn't encode " + pair, e);
142 }
143
144 return null;
145 }
146 private byte[] sshEncodedSignatureFor(byte[] data, RSAPrivateKey privKey) {
147 try {
148 byte[] signature = RSASHA1Verify.generateSignature(data, privKey);
149 return RSASHA1Verify.encodeSSHRSASignature(signature);
150 }
151 catch (IOException e) {
152 throw new RuntimeException(e);
153 }
154 }
155 private byte[] sshEncodedSignatureFor(byte[] data, DSAPrivateKey privKey) {
156 try {
157 byte[] signature = DSASHA1Verify.generateSignature(data, privKey, new SecureRandom());
158 return DSASHA1Verify.encodeSSHDSASignature(signature);
159 }
160 catch (IOException e) {
161 throw new RuntimeException(e);
162 }
163 }
164 private KeyPair keyPairFor(byte[] publicKey) {
165 String nickname = manager.getKeyNickname(publicKey);
166
167 if (nickname == null) {
168 Log.w(TAG, "No key-pair found for public-key.");
169 return null;
170 }
171
172 // check manager.loadedKeypairs.get(nickname).bean.isConfirmUse() and promptForPubkeyUse(nickname) ?
173 return manager.getKey(nickname);
174 }
175 };
176 }