comparison app/src/main/java/ch/ethz/ssh2/auth/AuthenticationManager.java @ 438:d29cce60f393

migrate from Eclipse to Android Studio
author Carl Byington <carl@five-ten-sg.com>
date Thu, 03 Dec 2015 11:23:55 -0800
parents src/ch/ethz/ssh2/auth/AuthenticationManager.java@a1a2e33b3565
children
comparison
equal deleted inserted replaced
437:208b31032318 438:d29cce60f393
1 /*
2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
3 * Please refer to the LICENSE.txt for licensing details.
4 */
5 package ch.ethz.ssh2.auth;
6
7 import java.io.IOException;
8 import java.io.InterruptedIOException;
9 import java.security.KeyPair;
10 import java.security.PrivateKey;
11 import java.security.SecureRandom;
12 import java.security.interfaces.DSAPrivateKey;
13 import java.security.interfaces.DSAPublicKey;
14 import java.security.interfaces.ECPrivateKey;
15 import java.security.interfaces.ECPublicKey;
16 import java.security.interfaces.RSAPrivateKey;
17 import java.security.interfaces.RSAPublicKey;
18 import java.util.HashSet;
19 import java.util.Set;
20 import java.util.concurrent.ArrayBlockingQueue;
21 import java.util.concurrent.BlockingQueue;
22
23 import ch.ethz.ssh2.InteractiveCallback;
24 import ch.ethz.ssh2.PacketTypeException;
25 import ch.ethz.ssh2.crypto.PEMDecoder;
26 import ch.ethz.ssh2.packets.PacketServiceAccept;
27 import ch.ethz.ssh2.packets.PacketServiceRequest;
28 import ch.ethz.ssh2.packets.PacketUserauthBanner;
29 import ch.ethz.ssh2.packets.PacketUserauthFailure;
30 import ch.ethz.ssh2.packets.PacketUserauthInfoRequest;
31 import ch.ethz.ssh2.packets.PacketUserauthInfoResponse;
32 import ch.ethz.ssh2.packets.PacketUserauthRequestInteractive;
33 import ch.ethz.ssh2.packets.PacketUserauthRequestNone;
34 import ch.ethz.ssh2.packets.PacketUserauthRequestPassword;
35 import ch.ethz.ssh2.packets.PacketUserauthRequestPublicKey;
36 import ch.ethz.ssh2.packets.Packets;
37 import ch.ethz.ssh2.packets.TypesWriter;
38 import ch.ethz.ssh2.signature.DSASHA1Verify;
39 import ch.ethz.ssh2.signature.ECDSASHA2Verify;
40 import ch.ethz.ssh2.signature.RSASHA1Verify;
41 import ch.ethz.ssh2.transport.ClientTransportManager;
42 import ch.ethz.ssh2.transport.MessageHandler;
43
44 /**
45 * @author Christian Plattner
46 * @version $Id: AuthenticationManager.java 161 2014-05-01 18:01:55Z dkocher@sudo.ch $
47 */
48 public class AuthenticationManager implements MessageHandler {
49 private ClientTransportManager tm;
50
51 private final BlockingQueue<byte[]> packets
52 = new ArrayBlockingQueue<byte[]>(5);
53
54 private boolean connectionClosed = false;
55
56 private String banner;
57
58 private Set<String> remainingMethods
59 = new HashSet<String>();
60
61 private boolean isPartialSuccess = false;
62
63 private boolean authenticated = false;
64 private boolean initDone = false;
65
66 public AuthenticationManager(ClientTransportManager tm) {
67 this.tm = tm;
68 }
69
70 private byte[] deQueue() throws IOException {
71 if (connectionClosed) {
72 throw(IOException) new IOException("The connection is closed.").initCause(tm.getReasonClosedCause());
73 }
74
75 // Wait for packet
76 try {
77 return packets.take();
78 }
79 catch (InterruptedException e) {
80 throw new InterruptedIOException(e.getMessage());
81 }
82 }
83
84 byte[] getNextMessage() throws IOException {
85 while (true) {
86 byte[] message = deQueue();
87
88 switch (message[0]) {
89 case Packets.SSH_MSG_USERAUTH_BANNER:
90 // The server may send an SSH_MSG_USERAUTH_BANNER message at any
91 // time after this authentication protocol starts and before
92 // authentication is successful.
93 PacketUserauthBanner sb = new PacketUserauthBanner(message);
94 banner = sb.getBanner();
95 break;
96
97 default:
98 return message;
99 }
100 }
101 }
102
103 public Set<String> getRemainingMethods(String user) throws IOException {
104 initialize(user);
105 return remainingMethods;
106 }
107
108 public String getBanner() {
109 return banner;
110 }
111
112 public boolean getPartialSuccess() {
113 return isPartialSuccess;
114 }
115
116 private boolean initialize(String user) throws IOException {
117 if (initDone == false) {
118 tm.registerMessageHandler(this, 0, 255);
119 PacketServiceRequest sr = new PacketServiceRequest("ssh-userauth");
120 tm.sendMessage(sr.getPayload());
121 final PacketServiceAccept accept = new PacketServiceAccept(this.getNextMessage());
122 PacketUserauthRequestNone auth = new PacketUserauthRequestNone("ssh-connection", user);
123 tm.sendMessage(auth.getPayload());
124 byte[] message = this.getNextMessage();
125 initDone = true;
126
127 switch (message[0]) {
128 case Packets.SSH_MSG_USERAUTH_SUCCESS:
129 authenticated = true;
130 tm.removeMessageHandler(this);
131 return true;
132
133 case Packets.SSH_MSG_USERAUTH_FAILURE:
134 PacketUserauthFailure puf = new PacketUserauthFailure(message);
135 remainingMethods = puf.getAuthThatCanContinue();
136 isPartialSuccess = puf.isPartialSuccess();
137 return false;
138 }
139
140 throw new PacketTypeException(message[0]);
141 }
142
143 return authenticated;
144 }
145
146 public boolean authenticatePublicKey(String user, AgentProxy proxy) throws IOException {
147 initialize(user);
148 boolean success;
149
150 for (AgentIdentity identity : proxy.getIdentities()) {
151 success = authenticatePublicKey(user, identity);
152
153 if (success) {
154 return true;
155 }
156 }
157
158 return false;
159 }
160
161 private boolean authenticatePublicKey(String user, AgentIdentity identity) throws IOException {
162 if (!remainingMethods.contains("publickey")) {
163 throw new IOException("Authentication method not supported");
164 }
165
166 byte[] pubKeyBlob = identity.getPublicKeyBlob();
167
168 if (pubKeyBlob == null) {
169 return false;
170 }
171
172 TypesWriter tw = new TypesWriter();
173 byte[] H = tm.getSessionIdentifier();
174 tw.writeString(H, 0, H.length);
175 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
176 tw.writeString(user);
177 tw.writeString("ssh-connection");
178 tw.writeString("publickey");
179 tw.writeBoolean(true);
180 tw.writeString(identity.getAlgName());
181 tw.writeString(pubKeyBlob, 0, pubKeyBlob.length);
182 byte[] msg = tw.getBytes();
183 byte[] response = identity.sign(msg);
184 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey(
185 "ssh-connection", user, identity.getAlgName(), pubKeyBlob, response);
186 tm.sendMessage(ua.getPayload());
187 byte[] message = getNextMessage();
188 final int type = message[0];
189
190 switch (type) {
191 case Packets.SSH_MSG_USERAUTH_SUCCESS:
192 authenticated = true;
193 tm.removeMessageHandler(this);
194 return true;
195
196 case Packets.SSH_MSG_USERAUTH_FAILURE:
197 PacketUserauthFailure puf = new PacketUserauthFailure(message);
198 remainingMethods = puf.getAuthThatCanContinue();
199 isPartialSuccess = puf.isPartialSuccess();
200 return false;
201 }
202
203 throw new PacketTypeException(type);
204 }
205
206 public boolean authenticatePublicKey(String user, char[] PEMPrivateKey, String password, SecureRandom rnd)
207 throws IOException {
208 KeyPair pair = PEMDecoder.decode(PEMPrivateKey, password);
209 return authenticatePublicKey(user, pair, rnd);
210 }
211
212 public boolean authenticatePublicKey(String user, KeyPair pair, SecureRandom rnd)
213 throws IOException {
214 PrivateKey key = pair.getPrivate();
215
216 try {
217 initialize(user);
218
219 if (!remainingMethods.contains("publickey")) {
220 throw new IOException("Authentication method publickey not supported by the server at this stage.");
221 }
222
223 if (key instanceof DSAPrivateKey) {
224 DSAPrivateKey pk = (DSAPrivateKey) key;
225 byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pair.getPublic());
226 TypesWriter tw = new TypesWriter();
227 byte[] H = tm.getSessionIdentifier();
228 tw.writeString(H, 0, H.length);
229 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
230 tw.writeString(user);
231 tw.writeString("ssh-connection");
232 tw.writeString("publickey");
233 tw.writeBoolean(true);
234 tw.writeString("ssh-dss");
235 tw.writeString(pk_enc, 0, pk_enc.length);
236 byte[] msg = tw.getBytes();
237 byte[] ds = DSASHA1Verify.generateSignature(msg, pk, rnd);
238 byte[] ds_enc = DSASHA1Verify.encodeSSHDSASignature(ds);
239 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
240 "ssh-dss", pk_enc, ds_enc);
241 tm.sendMessage(ua.getPayload());
242 }
243 else if (key instanceof RSAPrivateKey) {
244 RSAPrivateKey pk = (RSAPrivateKey) key;
245 byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pair.getPublic());
246 TypesWriter tw = new TypesWriter();
247 {
248 byte[] H = tm.getSessionIdentifier();
249 tw.writeString(H, 0, H.length);
250 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
251 tw.writeString(user);
252 tw.writeString("ssh-connection");
253 tw.writeString("publickey");
254 tw.writeBoolean(true);
255 tw.writeString("ssh-rsa");
256 tw.writeString(pk_enc, 0, pk_enc.length);
257 }
258 byte[] msg = tw.getBytes();
259 byte[] ds = RSASHA1Verify.generateSignature(msg, pk);
260 byte[] rsa_sig_enc = RSASHA1Verify.encodeSSHRSASignature(ds);
261 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
262 "ssh-rsa", pk_enc, rsa_sig_enc);
263 tm.sendMessage(ua.getPayload());
264 }
265 else if (key instanceof ECPrivateKey) {
266 ECPrivateKey pk = (ECPrivateKey) key;
267 final String algo = ECDSASHA2Verify.ECDSA_SHA2_PREFIX
268 + ECDSASHA2Verify.getCurveName(pk.getParams());
269 byte[] pk_enc = ECDSASHA2Verify.encodeSSHECDSAPublicKey((ECPublicKey) pair.getPublic());
270 TypesWriter tw = new TypesWriter();
271 {
272 byte[] H = tm.getSessionIdentifier();
273 tw.writeString(H, 0, H.length);
274 tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
275 tw.writeString(user);
276 tw.writeString("ssh-connection");
277 tw.writeString("publickey");
278 tw.writeBoolean(true);
279 tw.writeString(algo);
280 tw.writeString(pk_enc, 0, pk_enc.length);
281 }
282 byte[] msg = tw.getBytes();
283 byte[] ds = ECDSASHA2Verify.generateSignature(msg, pk);
284 byte[] ec_sig_enc = ECDSASHA2Verify.encodeSSHECDSASignature(ds, pk.getParams());
285 PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
286 algo, pk_enc, ec_sig_enc);
287 tm.sendMessage(ua.getPayload());
288 }
289 else {
290 throw new IOException("Unknown private key type returned by the PEM decoder.");
291 }
292
293 byte[] message = getNextMessage();
294 final int type = message[0];
295
296 switch (type) {
297 case Packets.SSH_MSG_USERAUTH_SUCCESS:
298 authenticated = true;
299 tm.removeMessageHandler(this);
300 return true;
301
302 case Packets.SSH_MSG_USERAUTH_FAILURE:
303 PacketUserauthFailure puf = new PacketUserauthFailure(message);
304 remainingMethods = puf.getAuthThatCanContinue();
305 isPartialSuccess = puf.isPartialSuccess();
306 return false;
307 }
308
309 throw new PacketTypeException(type);
310 }
311 catch (IOException e) {
312 tm.close(e, false);
313 throw e;
314 }
315 }
316
317 public boolean authenticateNone(String user) throws IOException {
318 try {
319 initialize(user);
320 return authenticated;
321 }
322 catch (IOException e) {
323 tm.close(e, false);
324 throw e;
325 }
326 }
327
328 public boolean authenticatePassword(String user, String pass) throws IOException {
329 try {
330 initialize(user);
331
332 if (!remainingMethods.contains("password")) {
333 throw new IOException("Authentication method not supported");
334 }
335
336 PacketUserauthRequestPassword ua = new PacketUserauthRequestPassword("ssh-connection", user, pass);
337 tm.sendMessage(ua.getPayload());
338 byte[] message = getNextMessage();
339 final int type = message[0];
340
341 switch (type) {
342 case Packets.SSH_MSG_USERAUTH_SUCCESS:
343 authenticated = true;
344 tm.removeMessageHandler(this);
345 return true;
346
347 case Packets.SSH_MSG_USERAUTH_FAILURE:
348 PacketUserauthFailure puf = new PacketUserauthFailure(message);
349 remainingMethods = puf.getAuthThatCanContinue();
350 isPartialSuccess = puf.isPartialSuccess();
351 return false;
352 }
353
354 throw new PacketTypeException(type);
355 }
356 catch (IOException e) {
357 tm.close(e, false);
358 throw e;
359 }
360 }
361
362 public boolean authenticateInteractive(String user, String[] submethods, InteractiveCallback cb) throws IOException {
363 try {
364 initialize(user);
365
366 if (!remainingMethods.contains("keyboard-interactive")) {
367 throw new IOException(
368 "Authentication method keyboard-interactive not supported by the server at this stage.");
369 }
370
371 PacketUserauthRequestInteractive ua = new PacketUserauthRequestInteractive("ssh-connection", user,
372 submethods);
373 tm.sendMessage(ua.getPayload());
374
375 while (true) {
376 byte[] message = getNextMessage();
377 final int type = message[0];
378
379 switch (type) {
380 case Packets.SSH_MSG_USERAUTH_SUCCESS:
381 authenticated = true;
382 tm.removeMessageHandler(this);
383 return true;
384
385 case Packets.SSH_MSG_USERAUTH_FAILURE:
386 PacketUserauthFailure puf = new PacketUserauthFailure(message);
387 remainingMethods = puf.getAuthThatCanContinue();
388 isPartialSuccess = puf.isPartialSuccess();
389 return false;
390
391 case Packets.SSH_MSG_USERAUTH_INFO_REQUEST:
392 PacketUserauthInfoRequest info = new PacketUserauthInfoRequest(message);
393 String[] responses;
394
395 try {
396 responses = cb.replyToChallenge(info.getName(), info.getInstruction(), info.getNumPrompts(),
397 info.getPrompt(), info.getEcho());
398 }
399 catch (Exception e) {
400 throw new IOException("Exception in callback.", e);
401 }
402
403 PacketUserauthInfoResponse puir = new PacketUserauthInfoResponse(responses);
404 tm.sendMessage(puir.getPayload());
405 continue;
406 }
407
408 throw new PacketTypeException(type);
409 }
410 }
411 catch (IOException e) {
412 tm.close(e, false);
413 throw e;
414 }
415 }
416
417 public void handleFailure(final IOException failure) {
418 connectionClosed = true;
419 }
420
421 public void handleMessage(byte[] message) throws IOException {
422 packets.add(message);
423 }
424 }