Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: mindbright/ssh/SSH.java


1   /******************************************************************************
2    *
3    * Copyright (c) 1998,99 by Mindbright Technology AB, Stockholm, Sweden.
4    *                 www.mindbright.se, info@mindbright.se
5    *
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation; either version 2 of the License, or
9    * (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   *****************************************************************************
17   * $Author: nallen $
18   * $Date: 2001/11/12 16:31:16 $
19   * $Name:  $
20   *****************************************************************************/
21  package mindbright.ssh;
22  
23  import java.io.*;
24  import java.math.BigInteger;
25  
26  import mindbright.security.*;
27  
28  public abstract class SSH {
29  
30    public static boolean DEBUG     = false;
31    public static boolean DEBUGMORE = false;
32  
33    public final static boolean NETSCAPE_SECURITY_MODEL = false;
34  
35    public final static int    SSH_VER_MAJOR = 1;
36    public final static int    SSH_VER_MINOR = 5;
37    public final static String VER_SSHPKG    = "v1.2.1";
38    public final static String VER_MINDTERM  = "MindTerm " + VER_SSHPKG;
39    public final static String VER_MINDTUNL  = "MindTunnel " + VER_SSHPKG;
40    public final static String CVS_NAME      = "$Name:  $";
41    public final static String CVS_DATE      = "$Date: 2001/11/12 16:31:16 $";
42  
43    public final static int    DEFAULTPORT        = 22;
44    public final static int    SESSION_KEY_LENGTH = 256; // !!! Must be multiple of 8
45    public final static int    SERVER_KEY_LENGTH  = 768;
46    public final static int    HOST_KEY_LENGTH    = 1024;
47  
48    public final static int    PROTOFLAG_SCREEN_NUMBER  = 1;
49    public final static int    PROTOFLAG_HOST_IN_FWD_OPEN  = 2;
50  
51    public final static int    MSG_ANY                        = -1; // !!! Not part of protocol
52    public final static int    MSG_NONE                       = 0;
53    public final static int    MSG_DISCONNECT                 = 1;
54    public final static int    SMSG_PUBLIC_KEY                = 2;
55    public final static int    CMSG_SESSION_KEY               = 3;
56    public final static int    CMSG_USER                      = 4;
57    public final static int    CMSG_AUTH_RHOSTS               = 5;
58    public final static int    CMSG_AUTH_RSA                  = 6;
59    public final static int    SMSG_AUTH_RSA_CHALLENGE        = 7;
60    public final static int    CMSG_AUTH_RSA_RESPONSE         = 8;
61    public final static int    CMSG_AUTH_PASSWORD             = 9;
62    public final static int    CMSG_REQUEST_PTY               = 10;
63    public final static int    CMSG_WINDOW_SIZE               = 11;
64    public final static int    CMSG_EXEC_SHELL                = 12;
65    public final static int    CMSG_EXEC_CMD                  = 13;
66    public final static int    SMSG_SUCCESS                   = 14;
67    public final static int    SMSG_FAILURE                   = 15;
68    public final static int    CMSG_STDIN_DATA                = 16;
69    public final static int    SMSG_STDOUT_DATA               = 17;
70    public final static int    SMSG_STDERR_DATA               = 18;
71    public final static int    CMSG_EOF                       = 19;
72    public final static int    SMSG_EXITSTATUS                = 20;
73    public final static int    MSG_CHANNEL_OPEN_CONFIRMATION  = 21;
74    public final static int    MSG_CHANNEL_OPEN_FAILURE       = 22;
75    public final static int    MSG_CHANNEL_DATA               = 23;
76    public final static int    MSG_CHANNEL_CLOSE              = 24;
77    public final static int    MSG_CHANNEL_CLOSE_CONFIRMATION = 25;
78    public final static int    MSG_CHANNEL_INPUT_EOF          = 24;
79    public final static int    MSG_CHANNEL_OUTPUT_CLOSED      = 25;
80    // OBSOLETE                CMSG_X11_REQUEST_FORWARDING    = 26;
81    public final static int    SMSG_X11_OPEN                  = 27;
82    public final static int    CMSG_PORT_FORWARD_REQUEST      = 28;
83    public final static int    MSG_PORT_OPEN                  = 29;
84    public final static int    CMSG_AGENT_REQUEST_FORWARDING  = 30;
85    public final static int    SMSG_AGENT_OPEN                = 31;
86    public final static int    MSG_IGNORE                     = 32;
87    public final static int    CMSG_EXIT_CONFIRMATION         = 33;
88    public final static int    CMSG_X11_REQUEST_FORWARDING    = 34;
89    public final static int    CMSG_AUTH_RHOSTS_RSA           = 35;
90    public final static int    MSG_DEBUG                      = 36;
91    public final static int    CMSG_REQUEST_COMPRESSION       = 37;
92    public final static int    CMSG_MAX_PACKET_SIZE           = 38;
93    public final static int    CMSG_AUTH_TIS                  = 39;
94    public final static int    SMSG_AUTH_TIS_CHALLENGE        = 40;
95    public final static int    CMSG_AUTH_TIS_RESPONSE         = 41;
96  
97    public final static int    CMSG_AUTH_SDI                  = 16; // !!! OUCH
98    public final static int    CMSG_ACM_OK                    = 64;
99    public final static int    CMSG_ACM_ACCESS_DENIED         = 65;
100   public final static int    CMSG_ACM_NEXT_CODE_REQUIRED    = 66;
101   public final static int    CMSG_ACM_NEXT_CODE             = 67;
102   public final static int    CMSG_ACM_NEW_PIN_REQUIRED      = 68;
103   public final static int    CMSG_ACM_NEW_PIN_ACCEPTED      = 69;
104   public final static int    CMSG_ACM_NEW_PIN_REJECTED      = 70;
105   public final static int    CMSG_ACM_NEW_PIN               = 71;
106 
107   public final static int    IDX_CIPHER_CLASS = 0;
108   public final static int    IDX_CIPHER_NAME  = 1;
109 
110   public final static String[][] cipherClasses = {
111     { "NoEncrypt", "none"     }, // No encryption
112     { "IDEA",      "idea"     }, // IDEA in CFB mode
113     { "DES",       "des"      }, // DES in CBC mode
114     { "DES3",      "3des"     }, // Triple-DES in CBC mode
115     { null,        "tss"      }, // An experimental stream cipher
116     { "RC4",       "rc4"      }, // RC4
117     { "Blowfish",  "blowfish" },  // Bruce Schneier's Blowfish
118     { null,        "reserved" }  // (not implemented now, might be though... see above)
119   };
120   public final static int    CIPHER_NONE     = 0; // No encryption
121   public final static int    CIPHER_IDEA     = 1; // IDEA in CFB mode
122   public final static int    CIPHER_DES      = 2; // DES in CBC mode
123   public final static int    CIPHER_3DES     = 3; // Triple-DES in CBC mode
124   public final static int    CIPHER_TSS      = 4; // An experimental stream cipher
125   public final static int    CIPHER_RC4      = 5; // RC4
126   public final static int    CIPHER_BLOWFISH = 6; // Bruce Schneier's Blowfish */
127   public final static int    CIPHER_RESERVED = 7; // Reserved for 40 bit crippled encryption,
128                                                   // Bernard Perrot <perrot@lal.in2p3.fr>
129   public final static int    CIPHER_NOTSUPPORTED = 8; // Indicates an unsupported cipher
130   public final static int    CIPHER_DEFAULT  = CIPHER_3DES; // Triple-DES is default block-cipher
131 
132   public final static String[] authTypeDesc = {
133     "_N/A_",
134     "rhosts",
135     "rsa",
136     "passwd",
137     "rhostsrsa",
138     "tis",
139     "kerberos",
140     "kerbtgt",
141     "sdi-token"
142   };
143   public final static int    AUTH_RHOSTS       = 1;
144   public final static int    AUTH_RSA          = 2;
145   public final static int    AUTH_PASSWORD     = 3;
146   public final static int    AUTH_RHOSTS_RSA   = 4;
147   public final static int    AUTH_TIS          = 5;
148   public final static int    AUTH_KERBEROS     = 6;
149   public final static int    PASS_KERBEROS_TGT = 7;
150 
151   public final static int    AUTH_SDI          = 8;
152 
153 
154   public final static int    AUTH_NOTSUPPORTED = authTypeDesc.length;
155   public final static int    AUTH_DEFAULT      = AUTH_PASSWORD;
156 
157 
158   final static String[] proxyTypes = { "none", "http", "socks4",
159                "socks5-proxy-dns",
160                "socks5-local-dns" };
161 
162   final static int[] defaultProxyPorts  = { 0, 8080, 1080, 1080, 1080 };
163 
164 
165   public final static int    PROXY_NONE         = 0;
166   public final static int    PROXY_HTTP         = 1;
167   public final static int    PROXY_SOCKS4       = 2;
168   public final static int    PROXY_SOCKS5_DNS   = 3;
169   public final static int    PROXY_SOCKS5_IP    = 4;
170   public final static int    PROXY_NOTSUPPORTED = proxyTypes.length;
171 
172 
173   public final static int    TTY_OP_END       = 0;
174   public final static int    TTY_OP_ISPEED   = 192;
175   public final static int    TTY_OP_OSPEED   = 193;
176 
177   // These are special "channels" not associated with a channel-number
178   // in "SSH-sense".
179   //
180   public final static int    MAIN_CHAN_NUM    = -1;
181   public final static int    CONNECT_CHAN_NUM = -2;
182   public final static int    LISTEN_CHAN_NUM  = -3;
183   public final static int    UNKNOWN_CHAN_NUM = -4;
184 
185   // Default name of file containing set of known hosts
186   //
187   public final static String KNOWN_HOSTS_FILE = "known_hosts";
188 
189   // When verifying the server's host-key to the set of known hosts, the
190   // possible outcome is one of these.
191   //
192   public final static int SRV_HOSTKEY_KNOWN   = 0;
193   public final static int SRV_HOSTKEY_NEW     = 1;
194   public final static int SRV_HOSTKEY_CHANGED = 2;
195 
196   public static SecureRandom secureRandom;
197 
198   //
199   //
200   protected byte[] sessionKey;
201   protected byte[] sessionId;
202 
203   //
204   //
205   protected Cipher sndCipher;
206   protected Cipher rcvCipher;
207   protected int    cipherType;
208 
209   // Server data fields
210   //
211   protected byte[]  srvCookie;
212   protected KeyPair srvServerKey;
213   protected KeyPair srvHostKey;
214   protected int     protocolFlags;
215   protected int     supportedCiphers;
216   protected int     supportedAuthTypes;
217 
218   protected boolean isAnSSHClient = true;
219 
220   public static String getVersionId(boolean client) {
221       String idStr = "SSH-" + SSH_VER_MAJOR + "." + SSH_VER_MINOR + "-";
222       idStr += (client ? VER_MINDTERM : VER_MINDTUNL);
223       return idStr;
224   }
225 
226   public static String[] getProxyTypes() {
227     return proxyTypes;
228   }
229 
230   public static int getProxyType(String typeName) throws IllegalArgumentException {
231     int i;
232     for(i = 0; i < proxyTypes.length; i++) {
233       if(proxyTypes[i].equalsIgnoreCase(typeName))
234   break;
235     }
236     if(i == PROXY_NOTSUPPORTED)
237       throw new IllegalArgumentException("Proxytype " + typeName + " not supported");
238 
239     return i;
240   }
241 
242   public static String listSupportedProxyTypes() {
243     String list = "";
244     int    i;
245     for(i = 0; i < proxyTypes.length; i++) {
246       list += proxyTypes[i] + " ";
247     }
248     return list;
249   }
250 
251   public static String getCipherName(int cipherType) {
252     return cipherClasses[cipherType][IDX_CIPHER_NAME];
253   }
254 
255   public static int getCipherType(String cipherName) {
256     int i;
257     for(i = 0; i < cipherClasses.length; i++) {
258       String clN = cipherClasses[i][IDX_CIPHER_CLASS];
259       String ciN = cipherClasses[i][IDX_CIPHER_NAME];
260       if(ciN.equalsIgnoreCase(cipherName)) {
261   if(cipherClasses[i][0] == null)
262     i = cipherClasses.length;
263   break;
264       }
265     }
266     return i;
267   }
268 
269   public static String getAuthName(int authType) {
270     return authTypeDesc[authType];
271   }
272 
273   public static int getAuthType(String authName) throws IllegalArgumentException {
274     int i;
275     for(i = 1; i < SSH.authTypeDesc.length; i++) {
276       if(SSH.authTypeDesc[i].equalsIgnoreCase(authName))
277   break;
278     }
279     if(i == AUTH_NOTSUPPORTED)
280       throw new IllegalArgumentException("Authtype " + authName + " not supported");
281 
282     return i;
283   }
284 
285   static int cntListSize(String authList) {
286     int cnt = 1;
287     int i   = 0, n;
288     while(i < authList.length() && (n = authList.indexOf(',', i)) != -1) {
289       i = n + 1;
290       cnt++;
291     }
292     return cnt;
293   }
294 
295   public static int[] getAuthTypes(String authList) throws IllegalArgumentException {
296     int len = cntListSize(authList);
297     int[] authTypes = new int[len];
298     int r, l = 0;
299     String type;
300 
301     for(int i = 0; i < len; i++) {
302       r = authList.indexOf(',', l);
303       if(r == -1)
304   r = authList.length();
305       type = authList.substring(l, r).trim();
306       authTypes[i] = getAuthType(type);
307       l = r + 1;
308     }
309 
310     return authTypes;
311   }
312 
313   public static String listSupportedCiphers() {
314     String list = "";
315     int    i;
316     for(i = 0; i < cipherClasses.length; i++) {
317       if(cipherClasses[i][0] != null)
318   list += cipherClasses[i][1] + " ";
319     }
320     return list;
321   }
322 
323   public static String[] getCiphers() {
324     int i, n = 0;
325     for(i = 0; i < cipherClasses.length; i++) {
326       if(cipherClasses[i][0] != null)
327   n++;
328     }
329     String[] ciphers = new String[n];
330     n = 0;
331     for(i = 0; i < cipherClasses.length; i++) {
332       if(cipherClasses[i][0] != null)
333   ciphers[n++] = cipherClasses[i][1];
334     }
335     return ciphers;
336   }
337 
338   public static String listSupportedAuthTypes() {
339     String list = "";
340     int    i;
341     for(i = 1; i < authTypeDesc.length; i++) {
342       list += authTypeDesc[i] + " ";
343     }
344     return list;
345   }
346 
347   public static String[] getAuthTypeList() {
348     String[] auths = new String[authTypeDesc.length];
349     for(int i = 1; i < authTypeDesc.length; i++) {
350       auths[i - 1] = authTypeDesc[i];
351     }
352     auths[authTypeDesc.length - 1] = "custom...";
353     return auths;
354   }
355 
356   boolean isCipherSupported(int cipherType) {
357     int cipherMask = (0x01 << cipherType);
358     if((cipherMask & supportedCiphers) != 0)
359       return true;
360     return false;
361   }
362 
363   boolean isAuthTypeSupported(int authType) {
364     int authTypeMask = (0x01 << authType);
365     if((authTypeMask & supportedAuthTypes) != 0)
366       return true;
367     return false;
368   }
369 
370   boolean isProtocolFlagSet(int protFlag) {
371     int protFlagMask = (0x01 << protFlag);
372     if((protFlagMask & protocolFlags) != 0)
373       return true;
374     return false;
375   }
376 
377   public static void initSeedGenerator() {
378     if(secureRandom != null)
379       return;
380     secureRandom = new SecureRandom();
381   }
382 
383   public static SecureRandom secureRandom() {
384     if(secureRandom == null) {
385       secureRandom = new SecureRandom();
386     }
387     return secureRandom;
388   }
389 
390   public static void log(String msg) {
391     if(DEBUG) System.out.println(msg);
392   }
393 
394   public static void logExtra(String msg) {
395     if(DEBUGMORE) System.out.println(msg);
396   }
397 
398   public static void logDebug(String msg) {
399     if(DEBUG) System.out.println(msg);
400   }
401 
402   public static void logIgnore(SSHPduInputStream pdu) {
403     if(DEBUG) System.out.println("MSG_IGNORE received...(len = " + pdu.length + ")");
404   }
405 
406   void generateSessionId() throws IOException {
407     byte[]        message;
408     byte[]        srvKey = ((RSAPublicKey)srvServerKey.getPublic()).getN().toByteArray();
409     byte[]        hstKey = ((RSAPublicKey)srvHostKey.getPublic()).getN().toByteArray();
410     int           i, len = srvKey.length + hstKey.length + srvCookie.length;
411 
412     if(srvKey[0] == 0)
413       len -= 1;
414     if(hstKey[0] == 0)
415       len -= 1;
416 
417     message = new byte[len];
418 
419     if(hstKey[0] == 0) {
420       System.arraycopy(hstKey, 1, message, 0, hstKey.length - 1);
421       len = hstKey.length - 1;
422     } else {
423       System.arraycopy(hstKey, 0, message, 0, hstKey.length);
424       len = hstKey.length;
425     }
426 
427     if(srvKey[0] == 0) {
428       System.arraycopy(srvKey, 1, message, len, srvKey.length - 1);
429       len += srvKey.length - 1;
430     } else {
431       System.arraycopy(srvKey, 0, message, len, srvKey.length);
432       len += srvKey.length;
433     }
434 
435     System.arraycopy(srvCookie, 0, message, len, srvCookie.length);
436 
437     try {
438       MessageDigest md5;
439       md5 = MessageDigest.getInstance("MD5");
440       md5.update(message);
441       sessionId = md5.digest();
442     } catch(Exception e) {
443       throw new IOException("MD5 not implemented, can't generate session-id");
444     }
445   }
446 
447   protected void initClientCipher() throws IOException {
448     initCipher(false);
449   }
450 
451   protected void initServerCipher() throws IOException {
452     initCipher(true);
453   }
454 
455   protected void initCipher(boolean server) throws IOException {
456     sndCipher = Cipher.getInstance(cipherClasses[cipherType][0]);
457     rcvCipher = Cipher.getInstance(cipherClasses[cipherType][0]);
458 
459     if(sndCipher == null) {
460       throw new IOException("Cipher " + cipherClasses[cipherType][1] + " not found, can't use it");
461     }
462 
463     if(cipherType == CIPHER_RC4) {
464       if(server) {
465   int    len = sessionKey.length / 2;
466   byte[] key = new byte[len];
467   System.arraycopy(sessionKey, 0, key, 0, len);
468   sndCipher.setKey(key);
469   System.arraycopy(sessionKey, len, key, 0, len);
470   rcvCipher.setKey(key);
471       } else {
472   int    len = sessionKey.length / 2;
473   byte[] key = new byte[len];
474   System.arraycopy(sessionKey, 0, key, 0, len);
475   rcvCipher.setKey(key);
476   System.arraycopy(sessionKey, len, key, 0, len);
477   sndCipher.setKey(key);
478       }
479     } else {
480       sndCipher.setKey(sessionKey);
481       rcvCipher.setKey(sessionKey);
482     }
483   }
484 
485   public static String generateKeyFiles(KeyPair kp, String fileName, String passwd, String comment)
486     throws IOException {
487     SSHRSAKeyFile.createKeyFile(kp, passwd, fileName, comment);
488     RSAPublicKey pubKey = (RSAPublicKey)kp.getPublic();
489     SSHRSAPublicKeyString pks = new SSHRSAPublicKeyString("", comment,
490                 pubKey.getE(), pubKey.getN());
491     pks.toFile(fileName + ".pub");
492     return pks.toString();
493   }
494 
495   public static KeyPair generateRSAKeyPair(int bits, SecureRandom secRand) {
496     KeyPair    kp;
497     RSACipher  cipher;
498     BigInteger p;
499     BigInteger q;
500     BigInteger t;
501     BigInteger p_1;
502     BigInteger q_1;
503     BigInteger phi;
504     BigInteger G;
505     BigInteger F;
506     BigInteger e;
507     BigInteger d;
508     BigInteger u;
509     BigInteger n;
510     BigInteger one = new BigInteger("1");
511 
512     for(;;) {
513       int l = secRand.secureLevel;
514       secRand.secureLevel = 2;
515       p = new BigInteger(bits / 2, 64, secRand);
516       q = new BigInteger(bits - (bits / 2), 64, secRand);
517       secRand.secureLevel = l;
518 
519       if(p.compareTo(q) == 0) {
520   continue;
521       } else if(q.compareTo(p) < 0) {
522   t = q;
523   q = p;
524   p = t;
525       }
526 
527       t = p.gcd(q);
528       if(t.compareTo(one) != 0) {
529   continue;
530       }
531 
532       p_1 = p.subtract(one);
533       q_1 = q.subtract(one);
534       phi = p_1.multiply(q_1);
535       G   = p_1.gcd(q_1);
536       F   = phi.divide(G);
537 
538       e   = one.shiftLeft(5);
539       e   = e.subtract(one);
540       do {
541   e = e.add(one.add(one));
542   t = e.gcd(phi);
543       } while(t.compareTo(one) != 0);
544 
545       // !!! d = e.modInverse(F);
546       d = e.modInverse(phi);
547       n = p.multiply(q);
548       u = p.modInverse(q);
549 
550       kp = new KeyPair(new RSAPublicKey(e, n),
551            new RSAPrivateKey(e, n, d, u, p, q));
552 
553       // !!!
554       break;
555     }
556 
557     return kp;
558   }
559 
560   /* !!! USED FOR DEBUG !!!
561   void printSrvKeys() {
562     BigInteger big;
563     byte[] theId = new byte[sessionId.length + 1];
564     theId[0] = 0;
565     System.arraycopy(sessionId, 0, theId, 1, sessionId.length);
566     big = new BigInteger(theId);
567     System.out.println("sessionId: " + big.toString(16));
568     byte[] theKey = new byte[sessionKey.length + 1];
569     theKey[0] = 0;
570     System.arraycopy(sessionKey, 0, theKey, 1, sessionKey.length);
571     big = new BigInteger(theKey);
572     System.out.println("sessionkey: " + big.toString(16));
573 
574     System.out.println("srvkey n: " + ((RSAPublicKey)srvServerKey.getPublic()).getN().toString(16));
575     System.out.println("srvkey e: " + ((RSAPublicKey)srvServerKey.getPublic()).getE().toString(16));
576     System.out.println("srvkey bits: " +  ((RSAPublicKey)srvServerKey.getPublic()).bitLength());
577     System.out.println("hstkey n: " + ((RSAPublicKey)srvHostKey.getPublic()).getN().toString(16));
578     System.out.println("hstkey e: " + ((RSAPublicKey)srvHostKey.getPublic()).getE().toString(16));
579     System.out.println("hstkey bits: " +  ((RSAPublicKey)srvHostKey.getPublic()).bitLength());
580   }
581   */
582 
583 }
584