Source for gnu.javax.net.ssl.provider.Handshake

   1: /* Handshake.java -- SSL Handshake message.
   2:    Copyright (C) 2006  Free Software Foundation, Inc.
   3: 
   4: This file is a part of GNU Classpath.
   5: 
   6: GNU Classpath 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 (at
   9: your option) any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: USA
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.  */
  37: 
  38: 
  39: package gnu.javax.net.ssl.provider;
  40: 
  41: import java.io.BufferedReader;
  42: import java.io.ByteArrayInputStream;
  43: import java.io.ByteArrayOutputStream;
  44: import java.io.EOFException;
  45: import java.io.InputStream;
  46: import java.io.IOException;
  47: import java.io.OutputStream;
  48: import java.io.PrintWriter;
  49: import java.io.StringReader;
  50: import java.io.StringWriter;
  51: 
  52: import java.nio.ByteBuffer;
  53: 
  54: import java.security.PublicKey;
  55: 
  56: import java.util.ArrayList;
  57: import java.util.Collections;
  58: 
  59: import javax.net.ssl.SSLProtocolException;
  60: 
  61: /**
  62:  * An SSL handshake message. SSL handshake messages have the following
  63:  * form:
  64:  *
  65:  * <pre>
  66: struct
  67: {
  68:   HandshakeType msg_type;
  69:   uint24        length;
  70:   select (msg_type)
  71:   {
  72:     case hello_request:       HelloRequest;
  73:     case client_hello:        ClientHello;
  74:     case server_hello:        ServerHello;
  75:     case certificate:         Certificate;
  76:     case server_key_exchange: ServerKeyExchange;
  77:     case certificate_request: CertificateRequest;
  78:     case server_hello_done:   ServerHelloDone;
  79:     case certificate_verify:  CertificateVerify;
  80:     case client_key_exchange: ClientKeyExchange;
  81:     case finished:            Finished;
  82:   } body;
  83: };</pre>
  84:  */
  85: public final class Handshake implements Constructed
  86: {
  87: 
  88:   // Fields.
  89:   // -------------------------------------------------------------------------
  90: 
  91:   private final ByteBuffer buffer;
  92:   private final CipherSuite suite;
  93:   private final ProtocolVersion version;
  94: 
  95:   // Constructors.
  96:   // -------------------------------------------------------------------------
  97: 
  98:   public Handshake (final ByteBuffer buffer)
  99:   {
 100:     this (buffer, null, ProtocolVersion.TLS_1_1);
 101:   }
 102: 
 103:   public Handshake (final ByteBuffer buffer, final CipherSuite suite,
 104:                     final ProtocolVersion version)
 105:   {
 106:     this.buffer = buffer;
 107:     this.suite = suite;
 108:     this.version = version;
 109:   }
 110: 
 111:   // Instance methods.
 112:   // -------------------------------------------------------------------------
 113: 
 114:   /**
 115:    * Returns the handshake type.
 116:    *
 117:    * @return The handshake type.
 118:    */
 119:   public Type type()
 120:   {
 121:     return Type.forInteger (buffer.get (0) & 0xFF);
 122:   }
 123: 
 124:   /**
 125:    * Returns the message length.
 126:    *
 127:    * @return The message length.
 128:    */
 129:   public int length ()
 130:   {
 131:     // Length is a uint24.
 132:     return buffer.getInt (0) & 0xFFFFFF;
 133:   }
 134: 
 135:   /**
 136:    * Returns the handshake message body. Depending on the handshake
 137:    * type, some implementation of the Body interface is returned.
 138:    *
 139:    * @return The handshake body.
 140:    */
 141:   public Body body()
 142:   {
 143:     Type type = type ();
 144:     ByteBuffer bodyBuffer = bodyBuffer ();
 145:     switch (type)
 146:       {
 147:       case HELLO_REQUEST:
 148:         return new HelloRequest ();
 149: 
 150:       case CLIENT_HELLO:
 151:         return new ClientHello (bodyBuffer);
 152: 
 153:       case SERVER_HELLO:
 154:         return new ServerHello (bodyBuffer);
 155: 
 156:       case CERTIFICATE:
 157:         return new Certificate (bodyBuffer, CertificateType.X509);
 158: 
 159:       case SERVER_KEY_EXCHANGE:
 160:         return new ServerKeyExchange (bodyBuffer, suite);
 161: 
 162:       case CERTIFICATE_REQUEST:
 163:         return new CertificateRequest (bodyBuffer);
 164: 
 165:       case SERVER_HELLO_DONE:
 166:         return new ServerHelloDone ();
 167: 
 168:       case CERTIFICATE_VERIFY:
 169:         return new CertificateVerify (bodyBuffer, suite.signatureAlgorithm ());
 170: 
 171:       case CLIENT_KEY_EXCHANGE:
 172:         return new ClientKeyExchange (bodyBuffer, suite, version);
 173: 
 174:       case FINISHED:
 175:         return new Finished (bodyBuffer, version);
 176: 
 177:       case CERTIFICATE_URL:
 178:       case CERTIFICATE_STATUS:
 179:         throw new UnsupportedOperationException ("FIXME");
 180:       }
 181:     throw new IllegalArgumentException ("unknown handshake type " + type);
 182:   }
 183: 
 184:   /**
 185:    * Returns a subsequence of the underlying buffer, containing only
 186:    * the bytes that compose the handshake body.
 187:    *
 188:    * @return The body's byte buffer.
 189:    */
 190:   public ByteBuffer bodyBuffer ()
 191:   {
 192:     int length = length ();
 193:     return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice ();
 194:   }
 195: 
 196:   /**
 197:    * Sets the handshake body type.
 198:    *
 199:    * @param type The handshake type.
 200:    */
 201:   public void setType (final Type type)
 202:   {
 203:     buffer.put (0, (byte) type.getValue ());
 204:   }
 205: 
 206:   /**
 207:    * Sets the length of the handshake body.
 208:    *
 209:    * @param length The handshake body length.
 210:    * @throws java.nio.ReadOnlyBufferException If the underlying buffer
 211:    * is not writable.
 212:    * @throws IllegalArgumentException of <code>length</code> is not
 213:    * between 0 and 16777215, inclusive.
 214:    */
 215:   public void setLength (final int length)
 216:   {
 217:     if (length < 0 || length > 0xFFFFFF)
 218:       throw new IllegalArgumentException ("length " + length + " out of range;"
 219:                                           + " must be between 0 and 16777215");
 220:     buffer.put (1, (byte) (length >>> 16));
 221:     buffer.put (2, (byte) (length >>>  8));
 222:     buffer.put (3, (byte)  length);
 223:   }
 224: 
 225:   public String toString()
 226:   {
 227:     return toString (null);
 228:   }
 229: 
 230:   public String toString (final String prefix)
 231:   {
 232:     StringWriter str = new StringWriter();
 233:     PrintWriter out = new PrintWriter(str);
 234:     if (prefix != null) out.print (prefix);
 235:     out.println("struct {");
 236:     if (prefix != null) out.print (prefix);
 237:     out.print ("  type: ");
 238:     out.print (type ());
 239:     out.println (";");
 240:     Body body = body ();
 241:     out.println (body.toString (prefix != null ? (prefix + "  ") : "  "));
 242:     if (prefix != null) out.print (prefix);
 243:     out.print ("} Handshake;");
 244:     return str.toString();
 245:   }
 246: 
 247:   // Inner class.
 248:   // -------------------------------------------------------------------------
 249: 
 250:   public static interface Body extends Constructed
 251:   {
 252:     int length ();
 253: 
 254:     String toString (String prefix);
 255:   }
 256: 
 257:   public static enum Type
 258:   {
 259:     HELLO_REQUEST       ( 0),
 260:     CLIENT_HELLO        ( 1),
 261:     SERVER_HELLO        ( 2),
 262:     CERTIFICATE         (11),
 263:     SERVER_KEY_EXCHANGE (12),
 264:     CERTIFICATE_REQUEST (13),
 265:     SERVER_HELLO_DONE   (14),
 266:     CERTIFICATE_VERIFY  (15),
 267:     CLIENT_KEY_EXCHANGE (16),
 268:     FINISHED            (20),
 269:     CERTIFICATE_URL     (21),
 270:     CERTIFICATE_STATUS  (22);
 271: 
 272:     private final int value;
 273: 
 274:     private Type(int value)
 275:     {
 276:       this.value = value;
 277:     }
 278: 
 279:     // Class methods.
 280:     // -----------------------------------------------------------------------
 281: 
 282:     /**
 283:      * Convert a raw handshake type value to a type enum value.
 284:      * 
 285:      * @return The corresponding enum value for the raw integer value.
 286:      * @throws IllegalArgumentException If the value is not a known handshake
 287:      *  type.
 288:      */
 289:     public static Type forInteger (final int value)
 290:     {
 291:       switch (value & 0xFF)
 292:         {
 293:         case 0:  return HELLO_REQUEST;
 294:         case 1:  return CLIENT_HELLO;
 295:         case 2:  return SERVER_HELLO;
 296:         case 11: return CERTIFICATE;
 297:         case 12: return SERVER_KEY_EXCHANGE;
 298:         case 13: return CERTIFICATE_REQUEST;
 299:         case 14: return SERVER_HELLO_DONE;
 300:         case 15: return CERTIFICATE_VERIFY;
 301:         case 16: return CLIENT_KEY_EXCHANGE;
 302:         case 20: return FINISHED;
 303:         case 21: return CERTIFICATE_URL;
 304:         case 22: return CERTIFICATE_STATUS;
 305:         default: throw new IllegalArgumentException ("unsupported value type " + value);
 306:         }
 307:     }
 308: 
 309:     public int getValue()
 310:     {
 311:       return value;
 312:     }
 313:   }
 314: }