2002/03/27 20:13:44
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:45:17 +0000 (06:45 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:45:17 +0000 (06:45 +0000)
darcs-hash:20040130064517-2ba56-d9ad719817bef2d2efe96d030caaaab27248e8ae.gz

src/org/xwt/TinySSL.java

index 3d38660..516fee6 100644 (file)
@@ -73,9 +73,14 @@ import java.text.*;
    dev-crypto mailing list while I was writing this.
 
    Revision History:
+
    1.0  07-Dec-01  Initial Release
+
    1.01 15-Mar-02  Added PKCS1 class to avoid dependancy on java.security.SecureRandom
 
+   1.02 27-Mar-02  Fixed a bug which would hang the connection when more than one
+                   Handshake message appeared in the same TLS Record
+
 */
 
 public class TinySSL extends Socket {
@@ -85,7 +90,7 @@ public class TinySSL extends Socket {
     public static void main(String[] args) {
         Log.on = true;
         try {
-            Socket s = new TinySSL("www.paypal.com", 443);
+            Socket s = new TinySSL("www.verisign.com", 443);
             PrintWriter pw = new PrintWriter(s.getOutputStream());
             BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
             pw.println("GET / HTTP/1.0");
@@ -190,7 +195,7 @@ public class TinySSL extends Socket {
        
         public int read(byte[] b, int off, int len) throws IOException {
             if (pendlen == 0) {
-                pend = readRecord(false);
+                pend = readRecord();
                 if (pend == null) return -1;
                 pendstart = 0;
                 pendlen = pend.length;
@@ -203,13 +208,17 @@ public class TinySSL extends Socket {
         }
 
         /** reads and decrypts exactly one record; blocks if unavailable */        
-        public byte[] readRecord(boolean returnHandshakes) throws IOException {
+        public byte[] readRecord() throws IOException {
 
             // we only catch EOFException here, because anywhere else
             // would be "unusual", and we *want* and EOFException in
             // those cases
             byte type;
-            try { type = raw.readByte(); } catch (EOFException e) { return null; }
+            try { type = raw.readByte();
+            } catch (EOFException e) {
+                if (Log.on) Log.log(this, "got EOFException reading packet type");
+                return null;
+            }
 
             byte ver_major = raw.readByte();
             byte ver_minor = raw.readByte();
@@ -220,7 +229,11 @@ public class TinySSL extends Socket {
             raw.readFully(ret);
             
             // simply ignore ChangeCipherSpec messages -- we change as soon as we send ours
-            if (type == 20) { seq_num = 0; return readRecord(returnHandshakes); }
+            if (type == 20) {
+                if (Log.on) Log.log(this, "got ChangeCipherSpec; ignoring");
+                seq_num = 0;
+                return readRecord();
+            }
 
             byte[] decrypted_payload;
 
@@ -241,35 +254,53 @@ public class TinySSL extends Socket {
             }
 
             if (type == 21) {
-                if (decrypted_payload[1] != 0)
+                if (decrypted_payload[1] > 1) {
                     throw new SSLException("got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
-                return null;
+                } else if (decrypted_payload[1] == 0) {
+                    if (Log.on) Log.log(this, "server requested connection closure; returning null");
+                    return null;
+                } else {
+                    if (Log.on) Log.log(this, "got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
+                    return readRecord();
+                }
 
             } else if (type == 22) {
-                if (!returnHandshakes) {
-                    if (Log.on) Log.log(this, "after completion of handshake, server sent another handshake message!");
-                    return readRecord(false);
-                }
+                if (Log.on) Log.log(this, "read a handshake");
 
             } else if (type != 23) {
                 if (Log.on) Log.log(this, "unexpected record type: " + type + "; skipping");
-                return readRecord(returnHandshakes);
+                return readRecord();
 
             }
                 
             if (Log.on) Log.log(this, "  returning " + decrypted_payload.length + " byte record payload");
             return decrypted_payload;
         }
-        
+
+        private byte[] readHandshake() throws IOException {
+            // acquire a handshake message
+            byte type = (byte)read();
+            int len = ((read() & 0xff) << 16) | ((read() & 0xff) << 8) | (read() & 0xff);
+            byte[] rec = new byte[len + 4];
+            rec[0] = type;
+            rec[1] = (byte)(((len & 0x00ff0000) >> 16) & 0xff);
+            rec[2] = (byte)(((len & 0x0000ff00) >> 8) & 0xff);
+            rec[3] = (byte)((len & 0x000000ff) & 0xff);
+            if (len > 0) read(rec, 4, len);
+            return rec;
+        }
+
         /** This reads the ServerHello, Certificate, and ServerHelloDone handshake messages */
         public void readServerHandshakes() throws IOException {
             for(;;) {
-                byte[] rec = readRecord(true);
+
+                byte[] rec = readHandshake();
                 handshakes = concat(new byte[][] { handshakes, rec });
                 DataInputStream stream = new DataInputStream(new ByteArrayInputStream(rec, 4, rec.length - 4));
 
                 switch(rec[0]) {
                 case 2: // ServerHello
+                    if (Log.on) Log.log(this, "got ServerHello");
                     byte ver_major = rec[4];
                     byte ver_minor = rec[5];
                     System.arraycopy(rec, 6, server_random, 0, server_random.length);
@@ -294,6 +325,7 @@ public class TinySSL extends Socket {
                     break;
                     
                 case 11: // Server's certificate(s)
+                    if (Log.on) Log.log(this, "got Server Certificate(s)");
                     int numcertbytes = ((rec[4] & 0xff) << 16) | ((rec[5] & 0xff) << 8) | (rec[6] & 0xff);
                     int numcerts = 0;
                     X509CertificateStructure last_cert = null;
@@ -369,10 +401,15 @@ public class TinySSL extends Socket {
                     break;
 
                 case 12: 
+                    if (Log.on) Log.log(this, "got ServerKeyExchange");
                     serverKeyExchange = rec;
                     break;
 
-                case 13: cert_requested = true; break;
+                case 13:
+                    if (Log.on) Log.log(this, "got Request for Client Certificates");
+                    cert_requested = true;
+                    break;
+                    
                 case 14: if (Log.on) Log.log(this, "  ServerHelloDone"); return;
                 default: throw new SSLException("unknown handshake of type " + rec[0]);
                 }
@@ -380,7 +417,8 @@ public class TinySSL extends Socket {
         }
      
         public void readServerFinished() throws IOException {
-            byte[] rec = readRecord(true);
+            
+            byte[] rec = readHandshake();
             if (rec[0] != 20) throw new SSLException("expecting server Finished message, but got message of type " + rec[0]);
 
             byte[] expectedFinished = concat(new byte[][] {