33 import javax.net.ssl.SSLException; |
32 import javax.net.ssl.SSLException; |
34 import sun.misc.HexDumpEncoder; |
33 import sun.misc.HexDumpEncoder; |
35 |
34 |
36 |
35 |
37 /** |
36 /** |
38 * SSL 3.0 records, as written to a TCP stream. |
37 * {@code OutputRecord} takes care of the management of SSL/TLS/DTLS output |
39 * |
38 * records, including buffering, encryption, handshake messages marshal, etc. |
40 * Each record has a message area that starts out with data supplied by the |
|
41 * application. It may grow/shrink due to compression and will be modified |
|
42 * in place for mac-ing and encryption. |
|
43 * |
|
44 * Handshake records have additional needs, notably accumulation of a set |
|
45 * of hashes which are used to establish that handshaking was done right. |
|
46 * Handshake records usually have several handshake messages each, and we |
|
47 * need message-level control over what's hashed. |
|
48 * |
39 * |
49 * @author David Brownell |
40 * @author David Brownell |
50 */ |
41 */ |
51 class OutputRecord extends ByteArrayOutputStream implements Record { |
42 abstract class OutputRecord extends ByteArrayOutputStream |
52 |
43 implements Record, Closeable { |
53 private HandshakeHash handshakeHash; |
44 |
54 private int lastHashed; |
45 /* Class and subclass dynamic debugging support */ |
55 private boolean firstMessage; |
46 static final Debug debug = Debug.getInstance("ssl"); |
56 final private byte contentType; |
47 |
57 private int headerOffset; |
48 Authenticator writeAuthenticator; |
|
49 CipherBox writeCipher; |
|
50 |
|
51 HandshakeHash handshakeHash; |
|
52 boolean firstMessage; |
58 |
53 |
59 // current protocol version, sent as record version |
54 // current protocol version, sent as record version |
60 ProtocolVersion protocolVersion; |
55 ProtocolVersion protocolVersion; |
61 |
56 |
62 // version for the ClientHello message. Only relevant if this is a |
57 // version for the ClientHello message. Only relevant if this is a |
63 // client handshake record. If set to ProtocolVersion.SSL20Hello, |
58 // client handshake record. If set to ProtocolVersion.SSL20Hello, |
64 // the V3 client hello is converted to V2 format. |
59 // the V3 client hello is converted to V2 format. |
65 private ProtocolVersion helloVersion; |
60 ProtocolVersion helloVersion; |
66 |
61 |
67 /* Class and subclass dynamic debugging support */ |
62 // Is it the first application record to write? |
68 static final Debug debug = Debug.getInstance("ssl"); |
63 boolean isFirstAppOutputRecord = true; |
69 |
64 |
70 /* |
65 // packet size |
71 * Default constructor makes a record supporting the maximum |
66 int packetSize; |
72 * SSL record size. It allocates the header bytes directly. |
67 |
73 * |
68 // fragment size |
74 * The structure of the byte buffer looks like: |
69 int fragmentSize; |
75 * |
70 |
76 * |---------+--------+-------+---------------------------------| |
71 // closed or not? |
77 * | unused | header | IV | content, MAC/TAG, padding, etc. | |
72 boolean isClosed; |
78 * | headerPlusMaxIVSize | |
|
79 * |
|
80 * unused: unused part of the buffer of size |
|
81 * |
|
82 * headerPlusMaxIVSize - header size - IV size |
|
83 * |
|
84 * When this object is created, we don't know the protocol |
|
85 * version number, IV length, etc., so reserve space in front |
|
86 * to avoid extra data movement (copies). |
|
87 * header: the header of an SSL record |
|
88 * IV: the optional IV/nonce field, it is only required for block |
|
89 * (TLS 1.1 or later) and AEAD cipher suites. |
|
90 * |
|
91 * @param type the content type for the record |
|
92 */ |
|
93 OutputRecord(byte type, int size) { |
|
94 super(size); |
|
95 this.protocolVersion = ProtocolVersion.DEFAULT; |
|
96 this.helloVersion = ProtocolVersion.DEFAULT_HELLO; |
|
97 firstMessage = true; |
|
98 count = headerPlusMaxIVSize; |
|
99 contentType = type; |
|
100 lastHashed = count; |
|
101 headerOffset = headerPlusMaxIVSize - headerSize; |
|
102 } |
|
103 |
|
104 OutputRecord(byte type) { |
|
105 this(type, recordSize(type)); |
|
106 } |
|
107 |
|
108 /** |
|
109 * Get the size of the buffer we need for records of the specified |
|
110 * type. |
|
111 */ |
|
112 private static int recordSize(byte type) { |
|
113 if ((type == ct_change_cipher_spec) || (type == ct_alert)) { |
|
114 return maxAlertRecordSize; |
|
115 } else { |
|
116 return maxRecordSize; |
|
117 } |
|
118 } |
|
119 |
|
120 /* |
|
121 * Updates the SSL version of this record. |
|
122 */ |
|
123 synchronized void setVersion(ProtocolVersion protocolVersion) { |
|
124 this.protocolVersion = protocolVersion; |
|
125 } |
|
126 |
|
127 /* |
|
128 * Updates helloVersion of this record. |
|
129 */ |
|
130 synchronized void setHelloVersion(ProtocolVersion helloVersion) { |
|
131 this.helloVersion = helloVersion; |
|
132 } |
|
133 |
|
134 /* |
|
135 * Reset the record so that it can be refilled, starting |
|
136 * immediately after the header. |
|
137 */ |
|
138 @Override |
|
139 public synchronized void reset() { |
|
140 super.reset(); |
|
141 count = headerPlusMaxIVSize; |
|
142 lastHashed = count; |
|
143 headerOffset = headerPlusMaxIVSize - headerSize; |
|
144 } |
|
145 |
|
146 /* |
|
147 * For handshaking, we need to be able to hash every byte above the |
|
148 * record marking layer. This is where we're guaranteed to see those |
|
149 * bytes, so this is where we can hash them. |
|
150 */ |
|
151 void setHandshakeHash(HandshakeHash handshakeHash) { |
|
152 assert(contentType == ct_handshake); |
|
153 this.handshakeHash = handshakeHash; |
|
154 } |
|
155 |
|
156 /* |
|
157 * We hash (the plaintext) on demand. There is one place where |
|
158 * we want to access the hash in the middle of a record: client |
|
159 * cert message gets hashed, and part of the same record is the |
|
160 * client cert verify message which uses that hash. So we track |
|
161 * how much of each record we've hashed so far. |
|
162 */ |
|
163 void doHashes() { |
|
164 int len = count - lastHashed; |
|
165 |
|
166 if (len > 0) { |
|
167 hashInternal(buf, lastHashed, len); |
|
168 lastHashed = count; |
|
169 } |
|
170 } |
|
171 |
|
172 /* |
|
173 * Need a helper function so we can hash the V2 hello correctly |
|
174 */ |
|
175 private void hashInternal(byte buf [], int offset, int len) { |
|
176 if (debug != null && Debug.isOn("data")) { |
|
177 try { |
|
178 HexDumpEncoder hd = new HexDumpEncoder(); |
|
179 |
|
180 System.out.println("[write] MD5 and SHA1 hashes: len = " |
|
181 + len); |
|
182 hd.encodeBuffer(new ByteArrayInputStream(buf, |
|
183 lastHashed, len), System.out); |
|
184 } catch (IOException e) { } |
|
185 } |
|
186 |
|
187 handshakeHash.update(buf, lastHashed, len); |
|
188 lastHashed = count; |
|
189 } |
|
190 |
|
191 /* |
|
192 * Return true iff the record is empty -- to avoid doing the work |
|
193 * of sending empty records over the network. |
|
194 */ |
|
195 boolean isEmpty() { |
|
196 return count == headerPlusMaxIVSize; |
|
197 } |
|
198 |
|
199 /* |
|
200 * Return true if the record is of an alert of the given description. |
|
201 * |
|
202 * Per SSL/TLS specifications, alert messages convey the severity of the |
|
203 * message (warning or fatal) and a description of the alert. An alert |
|
204 * is defined with a two bytes struct, {byte level, byte description}, |
|
205 * following after the header bytes. |
|
206 */ |
|
207 boolean isAlert(byte description) { |
|
208 if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) { |
|
209 return buf[headerPlusMaxIVSize + 1] == description; |
|
210 } |
|
211 |
|
212 return false; |
|
213 } |
|
214 |
|
215 /* |
|
216 * Encrypt ... length may grow due to block cipher padding, or |
|
217 * message authentication code or tag. |
|
218 */ |
|
219 void encrypt(Authenticator authenticator, CipherBox box) |
|
220 throws IOException { |
|
221 |
|
222 // In case we are automatically flushing a handshake stream, make |
|
223 // sure we have hashed the message first. |
|
224 // |
|
225 // when we support compression, hashing can't go here |
|
226 // since it'll need to be done on the uncompressed data, |
|
227 // and the MAC applies to the compressed data. |
|
228 if (contentType == ct_handshake) { |
|
229 doHashes(); |
|
230 } |
|
231 |
|
232 // Requires message authentication code for stream and block |
|
233 // cipher suites. |
|
234 if (authenticator instanceof MAC) { |
|
235 MAC signer = (MAC)authenticator; |
|
236 if (signer.MAClen() != 0) { |
|
237 byte[] hash = signer.compute(contentType, buf, |
|
238 headerPlusMaxIVSize, count - headerPlusMaxIVSize, false); |
|
239 write(hash); |
|
240 } |
|
241 } |
|
242 |
|
243 if (!box.isNullCipher()) { |
|
244 // Requires explicit IV/nonce for CBC/AEAD cipher suites for |
|
245 // TLS 1.1 or later. |
|
246 if ((protocolVersion.v >= ProtocolVersion.TLS11.v) && |
|
247 (box.isCBCMode() || box.isAEADMode())) { |
|
248 byte[] nonce = box.createExplicitNonce(authenticator, |
|
249 contentType, count - headerPlusMaxIVSize); |
|
250 int offset = headerPlusMaxIVSize - nonce.length; |
|
251 System.arraycopy(nonce, 0, buf, offset, nonce.length); |
|
252 headerOffset = offset - headerSize; |
|
253 } else { |
|
254 headerOffset = headerPlusMaxIVSize - headerSize; |
|
255 } |
|
256 |
|
257 // encrypt the content |
|
258 int offset = headerPlusMaxIVSize; |
|
259 if (!box.isAEADMode()) { |
|
260 // The explicit IV can be encrypted. |
|
261 offset = headerOffset + headerSize; |
|
262 } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode |
|
263 |
|
264 count = offset + box.encrypt(buf, offset, count - offset); |
|
265 } |
|
266 } |
|
267 |
|
268 /* |
|
269 * Tell how full the buffer is ... for filling it with application or |
|
270 * handshake data. |
|
271 */ |
|
272 final int availableDataBytes() { |
|
273 int dataSize = count - headerPlusMaxIVSize; |
|
274 return maxDataSize - dataSize; |
|
275 } |
|
276 |
|
277 /* |
|
278 * Increases the capacity if necessary to ensure that it can hold |
|
279 * at least the number of elements specified by the minimum |
|
280 * capacity argument. |
|
281 * |
|
282 * Note that the increased capacity is only can be used for held |
|
283 * record buffer. Please DO NOT update the availableDataBytes() |
|
284 * according to the expended buffer capacity. |
|
285 * |
|
286 * @see availableDataBytes() |
|
287 */ |
|
288 private void ensureCapacity(int minCapacity) { |
|
289 // overflow-conscious code |
|
290 if (minCapacity > buf.length) { |
|
291 buf = Arrays.copyOf(buf, minCapacity); |
|
292 } |
|
293 } |
|
294 |
|
295 /* |
|
296 * Return the type of SSL record that's buffered here. |
|
297 */ |
|
298 final byte contentType() { |
|
299 return contentType; |
|
300 } |
|
301 |
|
302 /* |
|
303 * Write the record out on the stream. Note that you must have (in |
|
304 * order) compressed the data, appended the MAC, and encrypted it in |
|
305 * order for the record to be understood by the other end. (Some of |
|
306 * those steps will be null early in handshaking.) |
|
307 * |
|
308 * Note that this does no locking for the connection, it's required |
|
309 * that synchronization be done elsewhere. Also, this does its work |
|
310 * in a single low level write, for efficiency. |
|
311 */ |
|
312 void write(OutputStream s, boolean holdRecord, |
|
313 ByteArrayOutputStream heldRecordBuffer) throws IOException { |
|
314 |
|
315 /* |
|
316 * Don't emit content-free records. (Even change cipher spec |
|
317 * messages have a byte of data!) |
|
318 */ |
|
319 if (count == headerPlusMaxIVSize) { |
|
320 return; |
|
321 } |
|
322 |
|
323 int length = count - headerOffset - headerSize; |
|
324 // "should" really never write more than about 14 Kb... |
|
325 if (length < 0) { |
|
326 throw new SSLException("output record size too small: " |
|
327 + length); |
|
328 } |
|
329 |
|
330 if (debug != null |
|
331 && (Debug.isOn("record") || Debug.isOn("handshake"))) { |
|
332 if ((debug != null && Debug.isOn("record")) |
|
333 || contentType() == ct_change_cipher_spec) |
|
334 System.out.println(Thread.currentThread().getName() |
|
335 // v3.0/v3.1 ... |
|
336 + ", WRITE: " + protocolVersion |
|
337 + " " + InputRecord.contentName(contentType()) |
|
338 + ", length = " + length); |
|
339 } |
|
340 |
|
341 /* |
|
342 * If this is the initial ClientHello on this connection and |
|
343 * we're not trying to resume a (V3) session then send a V2 |
|
344 * ClientHello instead so we can detect V2 servers cleanly. |
|
345 */ |
|
346 if (firstMessage && useV2Hello()) { |
|
347 byte[] v3Msg = new byte[length - 4]; |
|
348 System.arraycopy(buf, headerPlusMaxIVSize + 4, |
|
349 v3Msg, 0, v3Msg.length); |
|
350 headerOffset = 0; // reset the header offset |
|
351 V3toV2ClientHello(v3Msg); |
|
352 handshakeHash.reset(); |
|
353 lastHashed = 2; |
|
354 doHashes(); |
|
355 if (debug != null && Debug.isOn("record")) { |
|
356 System.out.println( |
|
357 Thread.currentThread().getName() |
|
358 + ", WRITE: SSLv2 client hello message" |
|
359 + ", length = " + (count - 2)); // 2 byte SSLv2 header |
|
360 } |
|
361 } else { |
|
362 /* |
|
363 * Fill out the header, write it and the message. |
|
364 */ |
|
365 buf[headerOffset + 0] = contentType; |
|
366 buf[headerOffset + 1] = protocolVersion.major; |
|
367 buf[headerOffset + 2] = protocolVersion.minor; |
|
368 buf[headerOffset + 3] = (byte)(length >> 8); |
|
369 buf[headerOffset + 4] = (byte)(length); |
|
370 } |
|
371 firstMessage = false; |
|
372 |
|
373 /* |
|
374 * The upper levels may want us to delay sending this packet so |
|
375 * multiple TLS Records can be sent in one (or more) TCP packets. |
|
376 * If so, add this packet to the heldRecordBuffer. |
|
377 * |
|
378 * NOTE: all writes have been synchronized by upper levels. |
|
379 */ |
|
380 int debugOffset = 0; |
|
381 if (holdRecord) { |
|
382 /* |
|
383 * If holdRecord is true, we must have a heldRecordBuffer. |
|
384 * |
|
385 * Don't worry about the override of writeBuffer(), because |
|
386 * when holdRecord is true, the implementation in this class |
|
387 * will be used. |
|
388 */ |
|
389 writeBuffer(heldRecordBuffer, |
|
390 buf, headerOffset, count - headerOffset, debugOffset); |
|
391 } else { |
|
392 // It's time to send, do we have buffered data? |
|
393 // May or may not have a heldRecordBuffer. |
|
394 if (heldRecordBuffer != null && heldRecordBuffer.size() > 0) { |
|
395 int heldLen = heldRecordBuffer.size(); |
|
396 |
|
397 // Ensure the capacity of this buffer. |
|
398 int newCount = count + heldLen - headerOffset; |
|
399 ensureCapacity(newCount); |
|
400 |
|
401 // Slide everything in the buffer to the right. |
|
402 System.arraycopy(buf, headerOffset, |
|
403 buf, heldLen, count - headerOffset); |
|
404 |
|
405 // Prepend the held record to the buffer. |
|
406 System.arraycopy( |
|
407 heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen); |
|
408 count = newCount; |
|
409 headerOffset = 0; |
|
410 |
|
411 // Clear the held buffer. |
|
412 heldRecordBuffer.reset(); |
|
413 |
|
414 // The held buffer has been dumped, set the debug dump offset. |
|
415 debugOffset = heldLen; |
|
416 } |
|
417 writeBuffer(s, buf, headerOffset, |
|
418 count - headerOffset, debugOffset); |
|
419 } |
|
420 |
|
421 reset(); |
|
422 } |
|
423 |
|
424 /* |
|
425 * Actually do the write here. For SSLEngine's HS data, |
|
426 * we'll override this method and let it take the appropriate |
|
427 * action. |
|
428 */ |
|
429 void writeBuffer(OutputStream s, byte [] buf, int off, int len, |
|
430 int debugOffset) throws IOException { |
|
431 s.write(buf, off, len); |
|
432 s.flush(); |
|
433 |
|
434 // Output only the record from the specified debug offset. |
|
435 if (debug != null && Debug.isOn("packet")) { |
|
436 try { |
|
437 HexDumpEncoder hd = new HexDumpEncoder(); |
|
438 |
|
439 System.out.println("[Raw write]: length = " + |
|
440 (len - debugOffset)); |
|
441 hd.encodeBuffer(new ByteArrayInputStream(buf, |
|
442 off + debugOffset, len - debugOffset), System.out); |
|
443 } catch (IOException e) { } |
|
444 } |
|
445 } |
|
446 |
|
447 /* |
|
448 * Return whether the buffer contains a ClientHello message that should |
|
449 * be converted to V2 format. |
|
450 */ |
|
451 private boolean useV2Hello() { |
|
452 return firstMessage |
|
453 && (helloVersion == ProtocolVersion.SSL20Hello) |
|
454 && (contentType == ct_handshake) |
|
455 && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello) |
|
456 // 5: recode header size |
|
457 && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0); |
|
458 // V3 session ID is empty |
|
459 // 4: handshake header size |
|
460 // 2: client_version in ClientHello |
|
461 // 32: random in ClientHello |
|
462 } |
|
463 |
|
464 /* |
|
465 * Detect "old" servers which are capable of SSL V2.0 protocol ... for |
|
466 * example, Netscape Commerce 1.0 servers. The V3 message is in the |
|
467 * header and the bytes passed as parameter. This routine translates |
|
468 * the V3 message into an equivalent V2 one. |
|
469 * |
|
470 * Note that the translation will strip off all hello extensions as |
|
471 * SSL V2.0 does not support hello extension. |
|
472 */ |
|
473 private void V3toV2ClientHello(byte v3Msg []) throws SSLException { |
|
474 int v3SessionIdLenOffset = 2 + 32; // version + nonce |
|
475 int v3SessionIdLen = v3Msg[v3SessionIdLenOffset]; |
|
476 int v3CipherSpecLenOffset = v3SessionIdLenOffset + 1 + v3SessionIdLen; |
|
477 int v3CipherSpecLen = ((v3Msg[v3CipherSpecLenOffset] & 0xff) << 8) + |
|
478 (v3Msg[v3CipherSpecLenOffset + 1] & 0xff); |
|
479 int cipherSpecs = v3CipherSpecLen / 2; // 2 bytes each in V3 |
|
480 |
|
481 /* |
|
482 * Copy over the cipher specs. We don't care about actually translating |
|
483 * them for use with an actual V2 server since we only talk V3. |
|
484 * Therefore, just copy over the V3 cipher spec values with a leading |
|
485 * 0. |
|
486 */ |
|
487 int v3CipherSpecOffset = v3CipherSpecLenOffset + 2; // skip length |
|
488 int v2CipherSpecLen = 0; |
|
489 count = 11; |
|
490 boolean containsRenegoInfoSCSV = false; |
|
491 for (int i = 0; i < cipherSpecs; i++) { |
|
492 byte byte1, byte2; |
|
493 |
|
494 byte1 = v3Msg[v3CipherSpecOffset++]; |
|
495 byte2 = v3Msg[v3CipherSpecOffset++]; |
|
496 v2CipherSpecLen += V3toV2CipherSuite(byte1, byte2); |
|
497 if (!containsRenegoInfoSCSV && |
|
498 byte1 == (byte)0x00 && byte2 == (byte)0xFF) { |
|
499 containsRenegoInfoSCSV = true; |
|
500 } |
|
501 } |
|
502 |
|
503 if (!containsRenegoInfoSCSV) { |
|
504 v2CipherSpecLen += V3toV2CipherSuite((byte)0x00, (byte)0xFF); |
|
505 } |
|
506 |
|
507 /* |
|
508 * Build the first part of the V3 record header from the V2 one |
|
509 * that's now buffered up. (Lengths are fixed up later). |
|
510 */ |
|
511 buf[2] = HandshakeMessage.ht_client_hello; |
|
512 buf[3] = v3Msg[0]; // major version |
|
513 buf[4] = v3Msg[1]; // minor version |
|
514 buf[5] = (byte)(v2CipherSpecLen >>> 8); |
|
515 buf[6] = (byte)v2CipherSpecLen; |
|
516 buf[7] = 0; |
|
517 buf[8] = 0; // always no session |
|
518 buf[9] = 0; |
|
519 buf[10] = 32; // nonce length (always 32 in V3) |
|
520 |
|
521 /* |
|
522 * Copy in the nonce. |
|
523 */ |
|
524 System.arraycopy(v3Msg, 2, buf, count, 32); |
|
525 count += 32; |
|
526 |
|
527 /* |
|
528 * Set the length of the message. |
|
529 */ |
|
530 count -= 2; // don't include length field itself |
|
531 buf[0] = (byte)(count >>> 8); |
|
532 buf[0] |= 0x80; |
|
533 buf[1] = (byte)(count); |
|
534 count += 2; |
|
535 } |
|
536 |
73 |
537 /* |
74 /* |
538 * Mappings from V3 cipher suite encodings to their pure V2 equivalents. |
75 * Mappings from V3 cipher suite encodings to their pure V2 equivalents. |
539 * This is taken from the SSL V3 specification, Appendix E. |
76 * This is taken from the SSL V3 specification, Appendix E. |
540 */ |
77 */ |
541 private static int[] V3toV2CipherMap1 = |
78 private static int[] V3toV2CipherMap1 = |
542 {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07}; |
79 {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07}; |
543 private static int[] V3toV2CipherMap3 = |
80 private static int[] V3toV2CipherMap3 = |
544 {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0}; |
81 {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0}; |
545 |
82 |
|
83 OutputRecord() { |
|
84 this.writeCipher = CipherBox.NULL; |
|
85 this.firstMessage = true; |
|
86 this.fragmentSize = Record.maxDataSize; |
|
87 |
|
88 // Please set packetSize and protocolVersion in the implementation. |
|
89 } |
|
90 |
|
91 void setVersion(ProtocolVersion protocolVersion) { |
|
92 this.protocolVersion = protocolVersion; |
|
93 } |
|
94 |
546 /* |
95 /* |
547 * See which matching pure-V2 cipher specs we need to include. |
96 * Updates helloVersion of this record. |
548 * We are including these not because we are actually prepared |
|
549 * to talk V2 but because the Oracle Web Server insists on receiving |
|
550 * at least 1 "pure V2" cipher suite that it supports and returns an |
|
551 * illegal_parameter alert unless one is present. Rather than mindlessly |
|
552 * claiming to implement all documented pure V2 cipher suites the code below |
|
553 * just claims to implement the V2 cipher suite that is "equivalent" |
|
554 * in terms of cipher algorithm & exportability with the actual V3 cipher |
|
555 * suite that we do support. |
|
556 */ |
97 */ |
557 private int V3toV2CipherSuite(byte byte1, byte byte2) { |
98 synchronized void setHelloVersion(ProtocolVersion helloVersion) { |
558 buf[count++] = 0; |
99 this.helloVersion = helloVersion; |
559 buf[count++] = byte1; |
100 } |
560 buf[count++] = byte2; |
101 |
561 |
102 /* |
562 if (((byte2 & 0xff) > 0xA) || |
103 * For handshaking, we need to be able to hash every byte above the |
563 (V3toV2CipherMap1[byte2] == -1)) { |
104 * record marking layer. This is where we're guaranteed to see those |
|
105 * bytes, so this is where we can hash them. |
|
106 */ |
|
107 void setHandshakeHash(HandshakeHash handshakeHash) { |
|
108 this.handshakeHash = handshakeHash; |
|
109 } |
|
110 |
|
111 /* |
|
112 * Return true iff the record is empty -- to avoid doing the work |
|
113 * of sending empty records over the network. |
|
114 */ |
|
115 boolean isEmpty() { |
|
116 return false; |
|
117 } |
|
118 |
|
119 boolean seqNumIsHuge() { |
|
120 return (writeAuthenticator != null) && |
|
121 writeAuthenticator.seqNumIsHuge(); |
|
122 } |
|
123 |
|
124 // SSLEngine and SSLSocket |
|
125 abstract void encodeAlert(byte level, byte description) throws IOException; |
|
126 |
|
127 // SSLEngine and SSLSocket |
|
128 abstract void encodeHandshake(byte[] buffer, |
|
129 int offset, int length) throws IOException; |
|
130 |
|
131 // SSLEngine and SSLSocket |
|
132 abstract void encodeChangeCipherSpec() throws IOException; |
|
133 |
|
134 // apply to SSLEngine only |
|
135 Ciphertext encode(ByteBuffer[] sources, int offset, int length, |
|
136 ByteBuffer destination) throws IOException { |
|
137 throw new UnsupportedOperationException(); |
|
138 } |
|
139 |
|
140 // apply to SSLEngine only |
|
141 void encodeV2NoCipher() throws IOException { |
|
142 throw new UnsupportedOperationException(); |
|
143 } |
|
144 |
|
145 // apply to SSLSocket only |
|
146 void deliver(byte[] source, int offset, int length) throws IOException { |
|
147 throw new UnsupportedOperationException(); |
|
148 } |
|
149 |
|
150 // apply to SSLSocket only |
|
151 void setDeliverStream(OutputStream outputStream) { |
|
152 throw new UnsupportedOperationException(); |
|
153 } |
|
154 |
|
155 // apply to SSLEngine only |
|
156 Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException { |
|
157 throw new UnsupportedOperationException(); |
|
158 } |
|
159 |
|
160 void changeWriteCiphers(Authenticator writeAuthenticator, |
|
161 CipherBox writeCipher) throws IOException { |
|
162 |
|
163 encodeChangeCipherSpec(); |
|
164 |
|
165 /* |
|
166 * Dispose of any intermediate state in the underlying cipher. |
|
167 * For PKCS11 ciphers, this will release any attached sessions, |
|
168 * and thus make finalization faster. |
|
169 * |
|
170 * Since MAC's doFinal() is called for every SSL/TLS packet, it's |
|
171 * not necessary to do the same with MAC's. |
|
172 */ |
|
173 writeCipher.dispose(); |
|
174 |
|
175 this.writeAuthenticator = writeAuthenticator; |
|
176 this.writeCipher = writeCipher; |
|
177 this.isFirstAppOutputRecord = true; |
|
178 } |
|
179 |
|
180 void changePacketSize(int packetSize) { |
|
181 this.packetSize = packetSize; |
|
182 } |
|
183 |
|
184 void changeFragmentSize(int fragmentSize) { |
|
185 this.fragmentSize = fragmentSize; |
|
186 } |
|
187 |
|
188 int getMaxPacketSize() { |
|
189 return packetSize; |
|
190 } |
|
191 |
|
192 // apply to DTLS SSLEngine |
|
193 void initHandshaker() { |
|
194 // blank |
|
195 } |
|
196 |
|
197 @Override |
|
198 synchronized public void close() throws IOException { |
|
199 if (!isClosed) { |
|
200 isClosed = true; |
|
201 writeCipher.dispose(); |
|
202 } |
|
203 } |
|
204 |
|
205 // |
|
206 // shared helpers |
|
207 // |
|
208 |
|
209 // Encrypt a fragment and wrap up a record. |
|
210 // |
|
211 // To be consistent with the spec of SSLEngine.wrap() methods, the |
|
212 // destination ByteBuffer's position is updated to reflect the amount |
|
213 // of data produced. The limit remains the same. |
|
214 static long encrypt(Authenticator authenticator, |
|
215 CipherBox encCipher, byte contentType, ByteBuffer destination, |
|
216 int headerOffset, int dstLim, int headerSize, |
|
217 ProtocolVersion protocolVersion, boolean isDTLS) { |
|
218 |
|
219 byte[] sequenceNumber = null; |
|
220 int dstContent = destination.position(); |
|
221 |
|
222 // Acquire the current sequence number before using. |
|
223 if (isDTLS) { |
|
224 sequenceNumber = authenticator.sequenceNumber(); |
|
225 } |
|
226 |
|
227 // "flip" but skip over header again, add MAC & encrypt |
|
228 if (authenticator instanceof MAC) { |
|
229 MAC signer = (MAC)authenticator; |
|
230 if (signer.MAClen() != 0) { |
|
231 byte[] hash = signer.compute(contentType, destination, false); |
|
232 |
|
233 /* |
|
234 * position was advanced to limit in MAC compute above. |
|
235 * |
|
236 * Mark next area as writable (above layers should have |
|
237 * established that we have plenty of room), then write |
|
238 * out the hash. |
|
239 */ |
|
240 destination.limit(destination.limit() + hash.length); |
|
241 destination.put(hash); |
|
242 |
|
243 // reset the position and limit |
|
244 destination.limit(destination.position()); |
|
245 destination.position(dstContent); |
|
246 } |
|
247 } |
|
248 |
|
249 if (!encCipher.isNullCipher()) { |
|
250 if (protocolVersion.useTLS11PlusSpec() && |
|
251 (encCipher.isCBCMode() || encCipher.isAEADMode())) { |
|
252 byte[] nonce = encCipher.createExplicitNonce( |
|
253 authenticator, contentType, destination.remaining()); |
|
254 destination.position(headerOffset + headerSize); |
|
255 destination.put(nonce); |
|
256 } |
|
257 if (!encCipher.isAEADMode()) { |
|
258 // The explicit IV in TLS 1.1 and later can be encrypted. |
|
259 destination.position(headerOffset + headerSize); |
|
260 } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode |
|
261 |
|
262 // Encrypt may pad, so again the limit may be changed. |
|
263 encCipher.encrypt(destination, dstLim); |
|
264 } else { |
|
265 destination.position(destination.limit()); |
|
266 } |
|
267 |
|
268 // Finish out the record header. |
|
269 int fragLen = destination.limit() - headerOffset - headerSize; |
|
270 |
|
271 destination.put(headerOffset, contentType); // content type |
|
272 destination.put(headerOffset + 1, protocolVersion.major); |
|
273 destination.put(headerOffset + 2, protocolVersion.minor); |
|
274 if (!isDTLS) { |
|
275 // fragment length |
|
276 destination.put(headerOffset + 3, (byte)(fragLen >> 8)); |
|
277 destination.put(headerOffset + 4, (byte)fragLen); |
|
278 } else { |
|
279 // epoch and sequence_number |
|
280 destination.put(headerOffset + 3, sequenceNumber[0]); |
|
281 destination.put(headerOffset + 4, sequenceNumber[1]); |
|
282 destination.put(headerOffset + 5, sequenceNumber[2]); |
|
283 destination.put(headerOffset + 6, sequenceNumber[3]); |
|
284 destination.put(headerOffset + 7, sequenceNumber[4]); |
|
285 destination.put(headerOffset + 8, sequenceNumber[5]); |
|
286 destination.put(headerOffset + 9, sequenceNumber[6]); |
|
287 destination.put(headerOffset + 10, sequenceNumber[7]); |
|
288 |
|
289 // fragment length |
|
290 destination.put(headerOffset + 11, (byte)(fragLen >> 8)); |
|
291 destination.put(headerOffset + 12, (byte)fragLen); |
|
292 |
|
293 // Increase the sequence number for next use. |
|
294 authenticator.increaseSequenceNumber(); |
|
295 } |
|
296 |
|
297 // Update destination position to reflect the amount of data produced. |
|
298 destination.position(destination.limit()); |
|
299 |
|
300 return Authenticator.toLong(sequenceNumber); |
|
301 } |
|
302 |
|
303 // Encrypt a fragment and wrap up a record. |
|
304 // |
|
305 // Uses the internal expandable buf variable and the current |
|
306 // protocolVersion variable. |
|
307 void encrypt(Authenticator authenticator, |
|
308 CipherBox encCipher, byte contentType, int headerSize) { |
|
309 |
|
310 int position = headerSize + writeCipher.getExplicitNonceSize(); |
|
311 |
|
312 // "flip" but skip over header again, add MAC & encrypt |
|
313 int macLen = 0; |
|
314 if (authenticator instanceof MAC) { |
|
315 MAC signer = (MAC)authenticator; |
|
316 macLen = signer.MAClen(); |
|
317 if (macLen != 0) { |
|
318 byte[] hash = signer.compute(contentType, |
|
319 buf, position, (count - position), false); |
|
320 |
|
321 write(hash, 0, hash.length); |
|
322 } |
|
323 } |
|
324 |
|
325 if (!encCipher.isNullCipher()) { |
|
326 // Requires explicit IV/nonce for CBC/AEAD cipher suites for |
|
327 // TLS 1.1 or later. |
|
328 if (protocolVersion.useTLS11PlusSpec() && |
|
329 (encCipher.isCBCMode() || encCipher.isAEADMode())) { |
|
330 |
|
331 byte[] nonce = encCipher.createExplicitNonce( |
|
332 authenticator, contentType, (count - position)); |
|
333 int noncePos = position - nonce.length; |
|
334 System.arraycopy(nonce, 0, buf, noncePos, nonce.length); |
|
335 } |
|
336 |
|
337 if (!encCipher.isAEADMode()) { |
|
338 // The explicit IV in TLS 1.1 and later can be encrypted. |
|
339 position = headerSize; |
|
340 } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode |
|
341 |
|
342 // increase buf capacity if necessary |
|
343 int fragSize = count - position; |
|
344 int packetSize = |
|
345 encCipher.calculatePacketSize(fragSize, macLen, headerSize); |
|
346 if (packetSize > (buf.length - position)) { |
|
347 byte[] newBuf = new byte[position + packetSize]; |
|
348 System.arraycopy(buf, 0, newBuf, 0, count); |
|
349 buf = newBuf; |
|
350 } |
|
351 |
|
352 // Encrypt may pad, so again the count may be changed. |
|
353 count = position + |
|
354 encCipher.encrypt(buf, position, (count - position)); |
|
355 } |
|
356 |
|
357 // Fill out the header, write it and the message. |
|
358 int fragLen = count - headerSize; |
|
359 buf[0] = contentType; |
|
360 buf[1] = protocolVersion.major; |
|
361 buf[2] = protocolVersion.minor; |
|
362 buf[3] = (byte)((fragLen >> 8) & 0xFF); |
|
363 buf[4] = (byte)(fragLen & 0xFF); |
|
364 } |
|
365 |
|
366 static ByteBuffer encodeV2ClientHello( |
|
367 byte[] fragment, int offset, int length) throws IOException { |
|
368 |
|
369 int v3SessIdLenOffset = offset + 34; // 2: client_version |
|
370 // 32: random |
|
371 |
|
372 int v3SessIdLen = fragment[v3SessIdLenOffset]; |
|
373 int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen; |
|
374 int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) + |
|
375 (fragment[v3CSLenOffset + 1] & 0xff); |
|
376 int cipherSpecs = v3CSLen / 2; // 2: cipher spec size |
|
377 |
|
378 // Estimate the max V2ClientHello message length |
|
379 // |
|
380 // 11: header size |
|
381 // (cipherSpecs * 6): cipher_specs |
|
382 // 6: one cipher suite may need 6 bytes, see V3toV2CipherSuite. |
|
383 // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV |
|
384 // signaling cipher suite |
|
385 // 32: challenge size |
|
386 int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32; |
|
387 |
|
388 // Create a ByteBuffer backed by an accessible byte array. |
|
389 byte[] dstBytes = new byte[v2MaxMsgLen]; |
|
390 ByteBuffer dstBuf = ByteBuffer.wrap(dstBytes); |
|
391 |
|
392 /* |
|
393 * Copy over the cipher specs. We don't care about actually |
|
394 * translating them for use with an actual V2 server since |
|
395 * we only talk V3. Therefore, just copy over the V3 cipher |
|
396 * spec values with a leading 0. |
|
397 */ |
|
398 int v3CSOffset = v3CSLenOffset + 2; // skip length field |
|
399 int v2CSLen = 0; |
|
400 |
|
401 dstBuf.position(11); |
|
402 boolean containsRenegoInfoSCSV = false; |
|
403 for (int i = 0; i < cipherSpecs; i++) { |
|
404 byte byte1, byte2; |
|
405 |
|
406 byte1 = fragment[v3CSOffset++]; |
|
407 byte2 = fragment[v3CSOffset++]; |
|
408 v2CSLen += V3toV2CipherSuite(dstBuf, byte1, byte2); |
|
409 if (!containsRenegoInfoSCSV && |
|
410 byte1 == (byte)0x00 && byte2 == (byte)0xFF) { |
|
411 containsRenegoInfoSCSV = true; |
|
412 } |
|
413 } |
|
414 |
|
415 if (!containsRenegoInfoSCSV) { |
|
416 v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF); |
|
417 } |
|
418 |
|
419 /* |
|
420 * Copy in the nonce. |
|
421 */ |
|
422 dstBuf.put(fragment, (offset + 2), 32); |
|
423 |
|
424 /* |
|
425 * Build the first part of the V3 record header from the V2 one |
|
426 * that's now buffered up. (Lengths are fixed up later). |
|
427 */ |
|
428 int msgLen = dstBuf.position() - 2; // Exclude the legth field itself |
|
429 dstBuf.position(0); |
|
430 dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF))); // pos: 0 |
|
431 dstBuf.put((byte)(msgLen & 0xFF)); // pos: 1 |
|
432 dstBuf.put(HandshakeMessage.ht_client_hello); // pos: 2 |
|
433 dstBuf.put(fragment[offset]); // major version, pos: 3 |
|
434 dstBuf.put(fragment[offset + 1]); // minor version, pos: 4 |
|
435 dstBuf.put((byte)(v2CSLen >>> 8)); // pos: 5 |
|
436 dstBuf.put((byte)(v2CSLen & 0xFF)); // pos: 6 |
|
437 dstBuf.put((byte)0x00); // session_id_length, pos: 7 |
|
438 dstBuf.put((byte)0x00); // pos: 8 |
|
439 dstBuf.put((byte)0x00); // challenge_length, pos: 9 |
|
440 dstBuf.put((byte)32); // pos: 10 |
|
441 |
|
442 dstBuf.position(0); |
|
443 dstBuf.limit(msgLen + 2); |
|
444 |
|
445 return dstBuf; |
|
446 } |
|
447 |
|
448 private static int V3toV2CipherSuite(ByteBuffer dstBuf, |
|
449 byte byte1, byte byte2) { |
|
450 dstBuf.put((byte)0); |
|
451 dstBuf.put(byte1); |
|
452 dstBuf.put(byte2); |
|
453 |
|
454 if (((byte2 & 0xff) > 0xA) || (V3toV2CipherMap1[byte2] == -1)) { |
564 return 3; |
455 return 3; |
565 } |
456 } |
566 |
457 |
567 buf[count++] = (byte)V3toV2CipherMap1[byte2]; |
458 dstBuf.put((byte)V3toV2CipherMap1[byte2]); |
568 buf[count++] = 0; |
459 dstBuf.put((byte)0); |
569 buf[count++] = (byte)V3toV2CipherMap3[byte2]; |
460 dstBuf.put((byte)V3toV2CipherMap3[byte2]); |
570 |
461 |
571 return 6; |
462 return 6; |
572 } |
463 } |
573 } |
464 } |