206 * Client initiates handshake by telling server what it wants, and what it
207 * can support (prioritized by what's first in the ciphe suite list).
208 *
209 * By RFC2246:7.4.1.2 it's explicitly anticipated that this message
210 * will have more data added at the end ... e.g. what CAs the client trusts.
211 * Until we know how to parse it, we will just read what we know
212 * about, and let our caller handle the jumps over unknown data.
213 */
214 static final
215 class ClientHello extends HandshakeMessage
216 {
217 int messageType() { return ht_client_hello; }
218
219 ProtocolVersion protocolVersion;
220 RandomCookie clnt_random;
221 SessionId sessionId;
222 private CipherSuiteList cipherSuites;
223 byte[] compression_methods;
224
225 HelloExtensions extensions = new HelloExtensions();
226
227 private final static byte[] NULL_COMPRESSION = new byte[] {0};
228
229 ClientHello(SecureRandom generator, ProtocolVersion protocolVersion) {
230 this.protocolVersion = protocolVersion;
231 clnt_random = new RandomCookie(generator);
232 compression_methods = NULL_COMPRESSION;
233 // sessionId, cipher_suites TBS later
234 }
235
236 CipherSuiteList getCipherSuites() {
237 return cipherSuites;
238 }
239
240 // Set the ciphersuites.
241 // This method may only be called once.
242 void setCipherSuites(CipherSuiteList cipherSuites) {
243 this.cipherSuites = cipherSuites;
244 if (cipherSuites.containsEC()) {
245 extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
246 extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT);
247 }
248 }
249
250 int messageLength() {
251 /*
252 * Add fixed size parts of each field...
253 * version + random + session + cipher + compress
254 */
255 return (2 + 32 + 1 + 2 + 1
256 + sessionId.length() /* ... + variable parts */
257 + (cipherSuites.size() * 2)
258 + compression_methods.length)
259 + extensions.length();
260 }
261
262 ClientHello(HandshakeInStream s, int messageLength) throws IOException {
263 protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8());
264 clnt_random = new RandomCookie(s);
265 sessionId = new SessionId(s.getBytes8());
266 cipherSuites = new CipherSuiteList(s);
267 compression_methods = s.getBytes8();
268 if (messageLength() != messageLength) {
269 extensions = new HelloExtensions(s);
270 }
271 }
272
273 void send(HandshakeOutStream s) throws IOException {
274 s.putInt8(protocolVersion.major);
275 s.putInt8(protocolVersion.minor);
276 clnt_random.send(s);
277 s.putBytes8(sessionId.getId());
278 cipherSuites.send(s);
279 s.putBytes8(compression_methods);
280 extensions.send(s);
281 }
282
283 void print(PrintStream s) throws IOException {
284 s.println("*** ClientHello, " + protocolVersion);
285
286 if (debug != null && Debug.isOn("verbose")) {
287 s.print ("RandomCookie: "); clnt_random.print(s);
288
289 s.print("Session ID: ");
290 s.println(sessionId);
291
292 s.println("Cipher Suites: " + cipherSuites);
293
294 Debug.println(s, "Compression Methods", compression_methods);
295 extensions.print(s);
296 s.println("***");
297 }
298 }
299 }
300
301 /*
|
206 * Client initiates handshake by telling server what it wants, and what it
207 * can support (prioritized by what's first in the ciphe suite list).
208 *
209 * By RFC2246:7.4.1.2 it's explicitly anticipated that this message
210 * will have more data added at the end ... e.g. what CAs the client trusts.
211 * Until we know how to parse it, we will just read what we know
212 * about, and let our caller handle the jumps over unknown data.
213 */
214 static final
215 class ClientHello extends HandshakeMessage
216 {
217 int messageType() { return ht_client_hello; }
218
219 ProtocolVersion protocolVersion;
220 RandomCookie clnt_random;
221 SessionId sessionId;
222 private CipherSuiteList cipherSuites;
223 byte[] compression_methods;
224
225 HelloExtensions extensions = new HelloExtensions();
226 boolean disableHelloExtensions;
227
228 private final static byte[] NULL_COMPRESSION = new byte[] {0};
229
230 ClientHello(SecureRandom generator, ProtocolVersion protocolVersion) {
231 this.protocolVersion = protocolVersion;
232 clnt_random = new RandomCookie(generator);
233 compression_methods = NULL_COMPRESSION;
234 // sessionId, cipher_suites TBS later
235
236 if (System.getProperty("sun.security.ssl.disableHelloExtensions", "no").equalsIgnoreCase("no")) {
237 this.disableHelloExtensions = false;
238 } else {
239 this.disableHelloExtensions = true;
240 }
241 }
242
243 CipherSuiteList getCipherSuites() {
244 return cipherSuites;
245 }
246
247 // Set the ciphersuites.
248 // This method may only be called once.
249 void setCipherSuites(CipherSuiteList cipherSuites) {
250 this.cipherSuites = cipherSuites;
251 if (cipherSuites.containsEC()) {
252 extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
253 extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT);
254 }
255 }
256
257 String serverName;
258 /**
259 * <p>Sets the name of the server being connected to, for reasons of sending
260 * an SNI (Server Name Indication) Hello Extension. Server name indication
261 * allows multiple domains to be hosted on the same server, by indicating
262 * the domain being requested before the server sends its certificate.</p>
263 * <p>Sending of server name extensions can be disabled by using:</p>
264 * <code>System.setProperty("sun.security.ssl.disableHelloExtensions","no")</code>
265 * @param serverName - String representing the name expected on the server's
266 * certificate, for example "asdf.example.com"
267 */
268 void setServerName(String serverName) {
269 this.serverName = serverName;
270 extensions.add(new ServerNameExtension(serverName));
271 }
272
273 int messageLength() {
274 /*
275 * Add fixed size parts of each field...
276 * version + random + session + cipher + compress
277 */
278 return (2 + 32 + 1 + 2 + 1
279 + sessionId.length() /* ... + variable parts */
280 + (cipherSuites.size() * 2)
281 + compression_methods.length)
282 + extensions.length();
283 }
284
285 ClientHello(HandshakeInStream s, int messageLength) throws IOException {
286 protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8());
287 clnt_random = new RandomCookie(s);
288 sessionId = new SessionId(s.getBytes8());
289 cipherSuites = new CipherSuiteList(s);
290 compression_methods = s.getBytes8();
291 if (messageLength() != messageLength) {
292 extensions = new HelloExtensions(s);
293 }
294 }
295
296 void send(HandshakeOutStream s) throws IOException {
297 s.putInt8(protocolVersion.major);
298 s.putInt8(protocolVersion.minor);
299 clnt_random.send(s);
300 s.putBytes8(sessionId.getId());
301 cipherSuites.send(s);
302 s.putBytes8(compression_methods);
303 if (this.disableHelloExtensions == false) {
304 extensions.send(s);
305 }
306 }
307
308 void print(PrintStream s) throws IOException {
309 s.println("*** ClientHello, " + protocolVersion);
310
311 if (debug != null && Debug.isOn("verbose")) {
312 s.print ("RandomCookie: "); clnt_random.print(s);
313
314 s.print("Session ID: ");
315 s.println(sessionId);
316
317 s.println("Cipher Suites: " + cipherSuites);
318
319 Debug.println(s, "Compression Methods", compression_methods);
320 extensions.print(s);
321 s.println("***");
322 }
323 }
324 }
325
326 /*
|