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.PrintWriter;
  42: import java.io.StringWriter;
  43: 
  44: import java.nio.ByteBuffer;
  45: 
  46: /**
  47:  * An SSL handshake message. SSL handshake messages have the following
  48:  * form:
  49:  *
  50:  * <pre>
  51: struct
  52: {
  53:   HandshakeType msg_type;
  54:   uint24        length;
  55:   select (msg_type)
  56:   {
  57:     case hello_request:       HelloRequest;
  58:     case client_hello:        ClientHello;
  59:     case server_hello:        ServerHello;
  60:     case certificate:         Certificate;
  61:     case server_key_exchange: ServerKeyExchange;
  62:     case certificate_request: CertificateRequest;
  63:     case server_hello_done:   ServerHelloDone;
  64:     case certificate_verify:  CertificateVerify;
  65:     case client_key_exchange: ClientKeyExchange;
  66:     case finished:            Finished;
  67:   } body;
  68: };</pre>
  69:  */
  70: public final class Handshake implements Constructed
  71: {
  72: 
  73:   // Fields.
  74:   // -------------------------------------------------------------------------
  75: 
  76:   private final ByteBuffer buffer;
  77:   private final CipherSuite suite;
  78:   private final ProtocolVersion version;
  79: 
  80:   // Constructors.
  81:   // -------------------------------------------------------------------------
  82: 
  83:   public Handshake (final ByteBuffer buffer)
  84:   {
  85:     this (buffer, null, ProtocolVersion.TLS_1_1);
  86:   }
  87: 
  88:   public Handshake (final ByteBuffer buffer, final CipherSuite suite,
  89:                     final ProtocolVersion version)
  90:   {
  91:     this.buffer = buffer;
  92:     this.suite = suite;
  93:     this.version = version;
  94:   }
  95: 
  96:   // Instance methods.
  97:   // -------------------------------------------------------------------------
  98: 
  99:   /**
 100:    * Returns the handshake type.
 101:    *
 102:    * @return The handshake type.
 103:    */
 104:   public Type type()
 105:   {
 106:     return Type.forInteger (buffer.get (0) & 0xFF);
 107:   }
 108: 
 109:   /**
 110:    * Returns the message length.
 111:    *
 112:    * @return The message length.
 113:    */
 114:   public int length ()
 115:   {
 116:     // Length is a uint24.
 117:     return buffer.getInt (0) & 0xFFFFFF;
 118:   }
 119: 
 120:   /**
 121:    * Returns the handshake message body. Depending on the handshake
 122:    * type, some implementation of the Body interface is returned.
 123:    *
 124:    * @return The handshake body.
 125:    */
 126:   public Body body()
 127:   {
 128:     Type type = type ();
 129:     ByteBuffer bodyBuffer = bodyBuffer ();
 130:     switch (type)
 131:       {
 132:       case HELLO_REQUEST:
 133:         return new HelloRequest ();
 134: 
 135:       case CLIENT_HELLO:
 136:         return new ClientHello (bodyBuffer);
 137: 
 138:       case SERVER_HELLO:
 139:         return new ServerHello (bodyBuffer);
 140: 
 141:       case CERTIFICATE:
 142:         return new Certificate (bodyBuffer, CertificateType.X509);
 143: 
 144:       case SERVER_KEY_EXCHANGE:
 145:         return new ServerKeyExchange (bodyBuffer, suite);
 146: 
 147:       case CERTIFICATE_REQUEST:
 148:         return new CertificateRequest (bodyBuffer);
 149: 
 150:       case SERVER_HELLO_DONE:
 151:         return new ServerHelloDone ();
 152: 
 153:       case CERTIFICATE_VERIFY:
 154:         return new CertificateVerify (bodyBuffer, suite.signatureAlgorithm ());
 155: 
 156:       case CLIENT_KEY_EXCHANGE:
 157:         return new ClientKeyExchange (bodyBuffer, suite, version);
 158: 
 159:       case FINISHED:
 160:         return new Finished (bodyBuffer, version);
 161: 
 162:       case CERTIFICATE_URL:
 163:       case CERTIFICATE_STATUS:
 164:         throw new UnsupportedOperationException ("FIXME");
 165:       }
 166:     throw new IllegalArgumentException ("unknown handshake type " + type);
 167:   }
 168: 
 169:   /**
 170:    * Returns a subsequence of the underlying buffer, containing only
 171:    * the bytes that compose the handshake body.
 172:    *
 173:    * @return The body's byte buffer.
 174:    */
 175:   public ByteBuffer bodyBuffer ()
 176:   {
 177:     int length = length ();
 178:     return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice ();
 179:   }
 180: 
 181:   /**
 182:    * Sets the handshake body type.
 183:    *
 184:    * @param type The handshake type.
 185:    */
 186:   public void setType (final Type type)
 187:   {
 188:     buffer.put (0, (byte) type.getValue ());
 189:   }
 190: 
 191:   /**
 192:    * Sets the length of the handshake body.
 193:    *
 194:    * @param length The handshake body length.
 195:    * @throws java.nio.ReadOnlyBufferException If the underlying buffer
 196:    * is not writable.
 197:    * @throws IllegalArgumentException of <code>length</code> is not
 198:    * between 0 and 16777215, inclusive.
 199:    */
 200:   public void setLength (final int length)
 201:   {
 202:     if (length < 0 || length > 0xFFFFFF)
 203:       throw new IllegalArgumentException ("length " + length + " out of range;"
 204:                                           + " must be between 0 and 16777215");
 205:     buffer.put (1, (byte) (length >>> 16));
 206:     buffer.put (2, (byte) (length >>>  8));
 207:     buffer.put (3, (byte)  length);
 208:   }
 209: 
 210:   public String toString()
 211:   {
 212:     return toString (null);
 213:   }
 214: 
 215:   public String toString (final String prefix)
 216:   {
 217:     StringWriter str = new StringWriter();
 218:     PrintWriter out = new PrintWriter(str);
 219:     if (prefix != null) out.print (prefix);
 220:     out.println("struct {");
 221:     if (prefix != null) out.print (prefix);
 222:     out.print ("  type: ");
 223:     out.print (type ());
 224:     out.println (";");
 225:     Body body = body ();
 226:     out.println (body.toString (prefix != null ? (prefix + "  ") : "  "));
 227:     if (prefix != null) out.print (prefix);
 228:     out.print ("} Handshake;");
 229:     return str.toString();
 230:   }
 231: 
 232:   // Inner class.
 233:   // -------------------------------------------------------------------------
 234: 
 235:   public static interface Body extends Constructed
 236:   {
 237:     int length ();
 238: 
 239:     String toString (String prefix);
 240:   }
 241: 
 242:   public static enum Type
 243:   {
 244:     HELLO_REQUEST       ( 0),
 245:     CLIENT_HELLO        ( 1),
 246:     SERVER_HELLO        ( 2),
 247:     CERTIFICATE         (11),
 248:     SERVER_KEY_EXCHANGE (12),
 249:     CERTIFICATE_REQUEST (13),
 250:     SERVER_HELLO_DONE   (14),
 251:     CERTIFICATE_VERIFY  (15),
 252:     CLIENT_KEY_EXCHANGE (16),
 253:     FINISHED            (20),
 254:     CERTIFICATE_URL     (21),
 255:     CERTIFICATE_STATUS  (22);
 256: 
 257:     private final int value;
 258: 
 259:     private Type(int value)
 260:     {
 261:       this.value = value;
 262:     }
 263: 
 264:     // Class methods.
 265:     // -----------------------------------------------------------------------
 266: 
 267:     /**
 268:      * Convert a raw handshake type value to a type enum value.
 269:      *
 270:      * @return The corresponding enum value for the raw integer value.
 271:      * @throws IllegalArgumentException If the value is not a known handshake
 272:      *  type.
 273:      */
 274:     public static Type forInteger (final int value)
 275:     {
 276:       switch (value & 0xFF)
 277:         {
 278:         case 0:  return HELLO_REQUEST;
 279:         case 1:  return CLIENT_HELLO;
 280:         case 2:  return SERVER_HELLO;
 281:         case 11: return CERTIFICATE;
 282:         case 12: return SERVER_KEY_EXCHANGE;
 283:         case 13: return CERTIFICATE_REQUEST;
 284:         case 14: return SERVER_HELLO_DONE;
 285:         case 15: return CERTIFICATE_VERIFY;
 286:         case 16: return CLIENT_KEY_EXCHANGE;
 287:         case 20: return FINISHED;
 288:         case 21: return CERTIFICATE_URL;
 289:         case 22: return CERTIFICATE_STATUS;
 290:         default: throw new IllegalArgumentException ("unsupported value type " + value);
 291:         }
 292:     }
 293: 
 294:     public int getValue()
 295:     {
 296:       return value;
 297:     }
 298:   }
 299: }