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