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 
Handshake(final ByteBuffer buffer)83   public Handshake (final ByteBuffer buffer)
84   {
85     this (buffer, null, ProtocolVersion.TLS_1_1);
86   }
87 
Handshake(final ByteBuffer buffer, final CipherSuite suite, final ProtocolVersion version)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    */
type()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    */
length()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    */
body()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    */
bodyBuffer()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    */
setType(final Type type)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    */
setLength(final int length)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 
toString()210   public String toString()
211   {
212     return toString (null);
213   }
214 
toString(final String prefix)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   {
length()237     int length ();
238 
toString(String prefix)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 
Type(int value)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      */
forInteger(final int value)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 
getValue()294     public int getValue()
295     {
296       return value;
297     }
298   }
299 }
300