1 /*
2 * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.ssl;
27
28 import java.io.*;
29 import java.nio.*;
30 import java.util.Arrays;
31
32 import javax.net.ssl.SSLException;
33 import sun.security.util.HexDumpEncoder;
34
35
36 /**
37 * {@code OutputRecord} takes care of the management of SSL/TLS/DTLS output
38 * records, including buffering, encryption, handshake messages marshal, etc.
39 *
40 * @author David Brownell
41 */
42 abstract class OutputRecord extends ByteArrayOutputStream
43 implements Record, Closeable {
44
45 /* Class and subclass dynamic debugging support */
46 static final Debug debug = Debug.getInstance("ssl");
47
48 Authenticator writeAuthenticator;
49 CipherBox writeCipher;
50
51 HandshakeHash handshakeHash;
52 boolean firstMessage;
53
54 // current protocol version, sent as record version
55 ProtocolVersion protocolVersion;
56
57 // version for the ClientHello message. Only relevant if this is a
58 // client handshake record. If set to ProtocolVersion.SSL20Hello,
59 // the V3 client hello is converted to V2 format.
60 ProtocolVersion helloVersion;
61
62 // Is it the first application record to write?
63 boolean isFirstAppOutputRecord = true;
64
65 // packet size
66 int packetSize;
67
68 // fragment size
69 int fragmentSize;
70
71 // closed or not?
72 boolean isClosed;
73
74 /*
75 * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
76 * This is taken from the SSL V3 specification, Appendix E.
77 */
78 private static int[] V3toV2CipherMap1 =
79 {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
80 private static int[] V3toV2CipherMap3 =
81 {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
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
95 /*
96 * Updates helloVersion of this record.
97 */
98 synchronized void setHelloVersion(ProtocolVersion helloVersion) {
99 this.helloVersion = helloVersion;
100 }
101
102 /*
103 * For handshaking, we need to be able to hash every byte above the
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 // apply to DTLS SSLEngine
198 void launchRetransmission() {
199 // blank
200 }
201
202 @Override
203 public synchronized void close() throws IOException {
204 if (!isClosed) {
205 isClosed = true;
206 writeCipher.dispose();
207 }
208 }
209
210 //
211 // shared helpers
212 //
213
214 // Encrypt a fragment and wrap up a record.
215 //
216 // To be consistent with the spec of SSLEngine.wrap() methods, the
217 // destination ByteBuffer's position is updated to reflect the amount
218 // of data produced. The limit remains the same.
219 static long encrypt(Authenticator authenticator,
220 CipherBox encCipher, byte contentType, ByteBuffer destination,
221 int headerOffset, int dstLim, int headerSize,
222 ProtocolVersion protocolVersion, boolean isDTLS) {
223
224 byte[] sequenceNumber = null;
225 int dstContent = destination.position();
226
227 // Acquire the current sequence number before using.
228 if (isDTLS) {
229 sequenceNumber = authenticator.sequenceNumber();
230 }
231
232 // The sequence number may be shared for different purpose.
233 boolean sharedSequenceNumber = false;
234
235 // "flip" but skip over header again, add MAC & encrypt
236 if (authenticator instanceof MAC) {
237 MAC signer = (MAC)authenticator;
238 if (signer.MAClen() != 0) {
239 byte[] hash = signer.compute(contentType, destination, false);
240
241 /*
242 * position was advanced to limit in MAC compute above.
243 *
244 * Mark next area as writable (above layers should have
245 * established that we have plenty of room), then write
246 * out the hash.
247 */
248 destination.limit(destination.limit() + hash.length);
249 destination.put(hash);
250
251 // reset the position and limit
252 destination.limit(destination.position());
253 destination.position(dstContent);
254
255 // The signer has used and increased the sequence number.
256 if (isDTLS) {
257 sharedSequenceNumber = true;
258 }
259 }
260 }
261
262 if (!encCipher.isNullCipher()) {
263 if (protocolVersion.useTLS11PlusSpec() &&
264 (encCipher.isCBCMode() || encCipher.isAEADMode())) {
265 byte[] nonce = encCipher.createExplicitNonce(
266 authenticator, contentType, destination.remaining());
267 destination.position(headerOffset + headerSize);
268 destination.put(nonce);
269 }
270 if (!encCipher.isAEADMode()) {
271 // The explicit IV in TLS 1.1 and later can be encrypted.
272 destination.position(headerOffset + headerSize);
273 } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
274
275 // Encrypt may pad, so again the limit may be changed.
276 encCipher.encrypt(destination, dstLim);
277
278 // The cipher has used and increased the sequence number.
279 if (isDTLS && encCipher.isAEADMode()) {
280 sharedSequenceNumber = true;
281 }
282 } else {
283 destination.position(destination.limit());
284 }
285
286 // Finish out the record header.
287 int fragLen = destination.limit() - headerOffset - headerSize;
288
289 destination.put(headerOffset, contentType); // content type
290 destination.put(headerOffset + 1, protocolVersion.major);
291 destination.put(headerOffset + 2, protocolVersion.minor);
292 if (!isDTLS) {
293 // fragment length
294 destination.put(headerOffset + 3, (byte)(fragLen >> 8));
295 destination.put(headerOffset + 4, (byte)fragLen);
296 } else {
297 // epoch and sequence_number
298 destination.put(headerOffset + 3, sequenceNumber[0]);
299 destination.put(headerOffset + 4, sequenceNumber[1]);
300 destination.put(headerOffset + 5, sequenceNumber[2]);
301 destination.put(headerOffset + 6, sequenceNumber[3]);
302 destination.put(headerOffset + 7, sequenceNumber[4]);
303 destination.put(headerOffset + 8, sequenceNumber[5]);
304 destination.put(headerOffset + 9, sequenceNumber[6]);
305 destination.put(headerOffset + 10, sequenceNumber[7]);
306
307 // fragment length
308 destination.put(headerOffset + 11, (byte)(fragLen >> 8));
309 destination.put(headerOffset + 12, (byte)fragLen);
310
311 // Increase the sequence number for next use if it is not shared.
312 if (!sharedSequenceNumber) {
313 authenticator.increaseSequenceNumber();
314 }
315 }
316
317 // Update destination position to reflect the amount of data produced.
318 destination.position(destination.limit());
319
320 return Authenticator.toLong(sequenceNumber);
321 }
322
323 // Encrypt a fragment and wrap up a record.
324 //
325 // Uses the internal expandable buf variable and the current
326 // protocolVersion variable.
327 void encrypt(Authenticator authenticator,
328 CipherBox encCipher, byte contentType, int headerSize) {
329
330 int position = headerSize + writeCipher.getExplicitNonceSize();
331
332 // "flip" but skip over header again, add MAC & encrypt
333 int macLen = 0;
334 if (authenticator instanceof MAC) {
335 MAC signer = (MAC)authenticator;
336 macLen = signer.MAClen();
337 if (macLen != 0) {
338 byte[] hash = signer.compute(contentType,
339 buf, position, (count - position), false);
340
341 write(hash, 0, hash.length);
342 }
343 }
344
345 if (!encCipher.isNullCipher()) {
346 // Requires explicit IV/nonce for CBC/AEAD cipher suites for
347 // TLS 1.1 or later.
348 if (protocolVersion.useTLS11PlusSpec() &&
349 (encCipher.isCBCMode() || encCipher.isAEADMode())) {
350
351 byte[] nonce = encCipher.createExplicitNonce(
352 authenticator, contentType, (count - position));
353 int noncePos = position - nonce.length;
354 System.arraycopy(nonce, 0, buf, noncePos, nonce.length);
355 }
356
357 if (!encCipher.isAEADMode()) {
358 // The explicit IV in TLS 1.1 and later can be encrypted.
359 position = headerSize;
360 } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
361
362 // increase buf capacity if necessary
363 int fragSize = count - position;
364 int packetSize =
365 encCipher.calculatePacketSize(fragSize, macLen, headerSize);
366 if (packetSize > (buf.length - position)) {
367 byte[] newBuf = new byte[position + packetSize];
368 System.arraycopy(buf, 0, newBuf, 0, count);
369 buf = newBuf;
370 }
371
372 // Encrypt may pad, so again the count may be changed.
373 count = position +
374 encCipher.encrypt(buf, position, (count - position));
375 }
376
377 // Fill out the header, write it and the message.
378 int fragLen = count - headerSize;
379 buf[0] = contentType;
380 buf[1] = protocolVersion.major;
381 buf[2] = protocolVersion.minor;
382 buf[3] = (byte)((fragLen >> 8) & 0xFF);
383 buf[4] = (byte)(fragLen & 0xFF);
384 }
385
386 static ByteBuffer encodeV2ClientHello(
387 byte[] fragment, int offset, int length) throws IOException {
388
389 int v3SessIdLenOffset = offset + 34; // 2: client_version
390 // 32: random
391
392 int v3SessIdLen = fragment[v3SessIdLenOffset];
393 int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen;
394 int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) +
395 (fragment[v3CSLenOffset + 1] & 0xff);
396 int cipherSpecs = v3CSLen / 2; // 2: cipher spec size
397
398 // Estimate the max V2ClientHello message length
399 //
400 // 11: header size
401 // (cipherSpecs * 6): cipher_specs
402 // 6: one cipher suite may need 6 bytes, see V3toV2CipherSuite.
403 // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
404 // signaling cipher suite
405 // 32: challenge size
406 int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32;
407
408 // Create a ByteBuffer backed by an accessible byte array.
432 }
433 }
434
435 if (!containsRenegoInfoSCSV) {
436 v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF);
437 }
438
439 /*
440 * Copy in the nonce.
441 */
442 dstBuf.put(fragment, (offset + 2), 32);
443
444 /*
445 * Build the first part of the V3 record header from the V2 one
446 * that's now buffered up. (Lengths are fixed up later).
447 */
448 int msgLen = dstBuf.position() - 2; // Exclude the legth field itself
449 dstBuf.position(0);
450 dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF))); // pos: 0
451 dstBuf.put((byte)(msgLen & 0xFF)); // pos: 1
452 dstBuf.put(HandshakeMessage.ht_client_hello); // pos: 2
453 dstBuf.put(fragment[offset]); // major version, pos: 3
454 dstBuf.put(fragment[offset + 1]); // minor version, pos: 4
455 dstBuf.put((byte)(v2CSLen >>> 8)); // pos: 5
456 dstBuf.put((byte)(v2CSLen & 0xFF)); // pos: 6
457 dstBuf.put((byte)0x00); // session_id_length, pos: 7
458 dstBuf.put((byte)0x00); // pos: 8
459 dstBuf.put((byte)0x00); // challenge_length, pos: 9
460 dstBuf.put((byte)32); // pos: 10
461
462 dstBuf.position(0);
463 dstBuf.limit(msgLen + 2);
464
465 return dstBuf;
466 }
467
468 private static int V3toV2CipherSuite(ByteBuffer dstBuf,
469 byte byte1, byte byte2) {
470 dstBuf.put((byte)0);
471 dstBuf.put(byte1);
472 dstBuf.put(byte2);
|
1 /*
2 * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.ssl;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.Closeable;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.nio.ByteBuffer;
33 import sun.security.ssl.SSLCipher.SSLWriteCipher;
34
35 /**
36 * {@code OutputRecord} takes care of the management of SSL/(D)TLS
37 * output records, including buffering, encryption, handshake
38 * messages marshal, etc.
39 *
40 * @author David Brownell
41 */
42 abstract class OutputRecord
43 extends ByteArrayOutputStream implements Record, Closeable {
44 SSLWriteCipher writeCipher;
45 // Needed for KeyUpdate
46 TransportContext tc;
47
48 final HandshakeHash handshakeHash;
49 boolean firstMessage;
50
51 // current protocol version, sent as record version
52 ProtocolVersion protocolVersion;
53
54 // version for the ClientHello message. Only relevant if this is a
55 // client handshake record. If set to ProtocolVersion.SSL20Hello,
56 // the V3 client hello is converted to V2 format.
57 ProtocolVersion helloVersion;
58
59 // Is it the first application record to write?
60 boolean isFirstAppOutputRecord = true;
61
62 // packet size
63 int packetSize;
64
65 // fragment size
66 int fragmentSize;
67
68 // closed or not?
69 boolean isClosed;
70
71 /*
72 * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
73 * This is taken from the SSL V3 specification, Appendix E.
74 */
75 private static final int[] V3toV2CipherMap1 =
76 {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
77 private static final int[] V3toV2CipherMap3 =
78 {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
79
80 OutputRecord(HandshakeHash handshakeHash, SSLWriteCipher writeCipher) {
81 this.writeCipher = writeCipher;
82 this.firstMessage = true;
83 this.fragmentSize = Record.maxDataSize;
84
85 this.handshakeHash = handshakeHash;
86
87 // Please set packetSize and protocolVersion in the implementation.
88 }
89
90 void setVersion(ProtocolVersion protocolVersion) {
91 this.protocolVersion = protocolVersion;
92 }
93
94 /*
95 * Updates helloVersion of this record.
96 */
97 synchronized void setHelloVersion(ProtocolVersion helloVersion) {
98 this.helloVersion = helloVersion;
99 }
100
101 /*
102 * Return true iff the record is empty -- to avoid doing the work
103 * of sending empty records over the network.
104 */
105 boolean isEmpty() {
106 return false;
107 }
108
109 boolean seqNumIsHuge() {
110 return (writeCipher.authenticator != null) &&
111 writeCipher.authenticator.seqNumIsHuge();
112 }
113
114 // SSLEngine and SSLSocket
115 abstract void encodeAlert(byte level, byte description) throws IOException;
116
117 // SSLEngine and SSLSocket
118 abstract void encodeHandshake(byte[] buffer,
119 int offset, int length) throws IOException;
120
121 // SSLEngine and SSLSocket
122 abstract void encodeChangeCipherSpec() throws IOException;
123
124 // apply to SSLEngine only
125 Ciphertext encode(
126 ByteBuffer[] srcs, int srcsOffset, int srcsLength,
127 ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
128
129 throw new UnsupportedOperationException();
130 }
131
132 // apply to SSLEngine only
133 void encodeV2NoCipher() throws IOException {
134 throw new UnsupportedOperationException();
135 }
136
137 // apply to SSLSocket only
138 void deliver(
139 byte[] source, int offset, int length) throws IOException {
140 throw new UnsupportedOperationException();
141 }
142
143 // apply to SSLSocket only
144 void setDeliverStream(OutputStream outputStream) {
145 throw new UnsupportedOperationException();
146 }
147
148 void changeWriteCiphers(SSLWriteCipher writeCipher,
149 boolean useChangeCipherSpec) throws IOException {
150 if (useChangeCipherSpec) {
151 encodeChangeCipherSpec();
152 }
153
154 /*
155 * Dispose of any intermediate state in the underlying cipher.
156 * For PKCS11 ciphers, this will release any attached sessions,
157 * and thus make finalization faster.
158 *
159 * Since MAC's doFinal() is called for every SSL/TLS packet, it's
160 * not necessary to do the same with MAC's.
161 */
162 writeCipher.dispose();
163
164 this.writeCipher = writeCipher;
165 this.isFirstAppOutputRecord = true;
166 }
167
168 void changePacketSize(int packetSize) {
169 this.packetSize = packetSize;
170 }
171
172 void changeFragmentSize(int fragmentSize) {
173 this.fragmentSize = fragmentSize;
174 }
175
176 int getMaxPacketSize() {
177 return packetSize;
178 }
179
180 // apply to DTLS SSLEngine
181 void initHandshaker() {
182 // blank
183 }
184
185 // apply to DTLS SSLEngine
186 void finishHandshake() {
187 // blank
188 }
189
190 // apply to DTLS SSLEngine
191 void launchRetransmission() {
192 // blank
193 }
194
195 @Override
196 public synchronized void close() throws IOException {
197 if (!isClosed) {
198 isClosed = true;
199 writeCipher.dispose();
200 }
201 }
202
203 synchronized boolean isClosed() {
204 return isClosed;
205 }
206
207 //
208 // shared helpers
209 //
210
211 // Encrypt a fragment and wrap up a record.
212 //
213 // To be consistent with the spec of SSLEngine.wrap() methods, the
214 // destination ByteBuffer's position is updated to reflect the amount
215 // of data produced. The limit remains the same.
216 static long encrypt(
217 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
218 int headerOffset, int dstLim, int headerSize,
219 ProtocolVersion protocolVersion) {
220 boolean isDTLS = protocolVersion.isDTLS;
221 if (isDTLS) {
222 if (protocolVersion.useTLS13PlusSpec()) {
223 return d13Encrypt(encCipher,
224 contentType, destination, headerOffset,
225 dstLim, headerSize, protocolVersion);
226 } else {
227 return d10Encrypt(encCipher,
228 contentType, destination, headerOffset,
229 dstLim, headerSize, protocolVersion);
230 }
231 } else {
232 if (protocolVersion.useTLS13PlusSpec()) {
233 return t13Encrypt(encCipher,
234 contentType, destination, headerOffset,
235 dstLim, headerSize, protocolVersion);
236 } else {
237 return t10Encrypt(encCipher,
238 contentType, destination, headerOffset,
239 dstLim, headerSize, protocolVersion);
240 }
241 }
242 }
243
244 static long d13Encrypt(
245 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
246 int headerOffset, int dstLim, int headerSize,
247 ProtocolVersion protocolVersion) {
248 throw new UnsupportedOperationException("Not supported yet.");
249 }
250
251 private static long d10Encrypt(
252 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
253 int headerOffset, int dstLim, int headerSize,
254 ProtocolVersion protocolVersion) {
255 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
256 encCipher.encrypt(contentType, destination);
257
258 // Finish out the record header.
259 int fragLen = destination.limit() - headerOffset - headerSize;
260
261 destination.put(headerOffset, contentType); // content type
262 destination.put(headerOffset + 1, protocolVersion.major);
263 destination.put(headerOffset + 2, protocolVersion.minor);
264
265 // epoch and sequence_number
266 destination.put(headerOffset + 3, sequenceNumber[0]);
267 destination.put(headerOffset + 4, sequenceNumber[1]);
268 destination.put(headerOffset + 5, sequenceNumber[2]);
269 destination.put(headerOffset + 6, sequenceNumber[3]);
270 destination.put(headerOffset + 7, sequenceNumber[4]);
271 destination.put(headerOffset + 8, sequenceNumber[5]);
272 destination.put(headerOffset + 9, sequenceNumber[6]);
273 destination.put(headerOffset + 10, sequenceNumber[7]);
274
275 // fragment length
276 destination.put(headerOffset + 11, (byte)(fragLen >> 8));
277 destination.put(headerOffset + 12, (byte)fragLen);
278
279 // Update destination position to reflect the amount of data produced.
280 destination.position(destination.limit());
281
282 return Authenticator.toLong(sequenceNumber);
283 }
284
285 static long t13Encrypt(
286 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
287 int headerOffset, int dstLim, int headerSize,
288 ProtocolVersion protocolVersion) {
289 if (!encCipher.isNullCipher()) {
290 // inner plaintext, using zero length padding.
291 int pos = destination.position();
292 destination.position(destination.limit());
293 destination.limit(destination.limit() + 1);
294 destination.put(contentType);
295 destination.position(pos);
296 }
297
298 // use the right TLSCiphertext.opaque_type and legacy_record_version
299 ProtocolVersion pv = protocolVersion;
300 if (!encCipher.isNullCipher()) {
301 pv = ProtocolVersion.TLS12;
302 contentType = ContentType.APPLICATION_DATA.id;
303 } else if (protocolVersion.useTLS13PlusSpec()) {
304 pv = ProtocolVersion.TLS12;
305 }
306
307 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
308 encCipher.encrypt(contentType, destination);
309
310 // Finish out the record header.
311 int fragLen = destination.limit() - headerOffset - headerSize;
312 destination.put(headerOffset, contentType);
313 destination.put(headerOffset + 1, pv.major);
314 destination.put(headerOffset + 2, pv.minor);
315
316 // fragment length
317 destination.put(headerOffset + 3, (byte)(fragLen >> 8));
318 destination.put(headerOffset + 4, (byte)fragLen);
319
320 // Update destination position to reflect the amount of data produced.
321 destination.position(destination.limit());
322
323 return Authenticator.toLong(sequenceNumber);
324 }
325
326 static long t10Encrypt(
327 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
328 int headerOffset, int dstLim, int headerSize,
329 ProtocolVersion protocolVersion) {
330 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
331 encCipher.encrypt(contentType, destination);
332
333 // Finish out the record header.
334 int fragLen = destination.limit() - headerOffset - headerSize;
335
336 destination.put(headerOffset, contentType); // content type
337 destination.put(headerOffset + 1, protocolVersion.major);
338 destination.put(headerOffset + 2, protocolVersion.minor);
339
340 // fragment length
341 destination.put(headerOffset + 3, (byte)(fragLen >> 8));
342 destination.put(headerOffset + 4, (byte)fragLen);
343
344 // Update destination position to reflect the amount of data produced.
345 destination.position(destination.limit());
346
347 return Authenticator.toLong(sequenceNumber);
348 }
349
350 // Encrypt a fragment and wrap up a record.
351 //
352 // Uses the internal expandable buf variable and the current
353 // protocolVersion variable.
354 long encrypt(
355 SSLWriteCipher encCipher, byte contentType, int headerSize) {
356 if (protocolVersion.useTLS13PlusSpec()) {
357 return t13Encrypt(encCipher, contentType, headerSize);
358 } else {
359 return t10Encrypt(encCipher, contentType, headerSize);
360 }
361 }
362
363 private static final class T13PaddingHolder {
364 private static final byte[] zeros = new byte[16];
365 }
366
367 long t13Encrypt(
368 SSLWriteCipher encCipher, byte contentType, int headerSize) {
369 if (!encCipher.isNullCipher()) {
370 // inner plaintext
371 write(contentType);
372 write(T13PaddingHolder.zeros, 0, T13PaddingHolder.zeros.length);
373 }
374
375 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
376 int position = headerSize;
377 int contentLen = count - position;
378
379 // ensure the capacity
380 int packetSize = encCipher.calculatePacketSize(contentLen, headerSize);
381 if (packetSize > buf.length) {
382 byte[] newBuf = new byte[packetSize];
383 System.arraycopy(buf, 0, newBuf, 0, count);
384 buf = newBuf;
385 }
386
387 // use the right TLSCiphertext.opaque_type and legacy_record_version
388 ProtocolVersion pv = protocolVersion;
389 if (!encCipher.isNullCipher()) {
390 pv = ProtocolVersion.TLS12;
391 contentType = ContentType.APPLICATION_DATA.id;
392 } else {
393 pv = ProtocolVersion.TLS12;
394 }
395
396 ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
397 count = headerSize + encCipher.encrypt(contentType, destination);
398
399 // Fill out the header, write it and the message.
400 int fragLen = count - headerSize;
401
402 buf[0] = contentType;
403 buf[1] = pv.major;
404 buf[2] = pv.minor;
405 buf[3] = (byte)((fragLen >> 8) & 0xFF);
406 buf[4] = (byte)(fragLen & 0xFF);
407
408 return Authenticator.toLong(sequenceNumber);
409 }
410
411 long t10Encrypt(
412 SSLWriteCipher encCipher, byte contentType, int headerSize) {
413 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
414 int position = headerSize + writeCipher.getExplicitNonceSize();
415 int contentLen = count - position;
416
417 // ensure the capacity
418 int packetSize = encCipher.calculatePacketSize(contentLen, headerSize);
419 if (packetSize > buf.length) {
420 byte[] newBuf = new byte[packetSize];
421 System.arraycopy(buf, 0, newBuf, 0, count);
422 buf = newBuf;
423 }
424 ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
425 count = headerSize + encCipher.encrypt(contentType, destination);
426
427 // Fill out the header, write it and the message.
428 int fragLen = count - headerSize;
429 buf[0] = contentType;
430 buf[1] = protocolVersion.major;
431 buf[2] = protocolVersion.minor;
432 buf[3] = (byte)((fragLen >> 8) & 0xFF);
433 buf[4] = (byte)(fragLen & 0xFF);
434
435 return Authenticator.toLong(sequenceNumber);
436 }
437
438 static ByteBuffer encodeV2ClientHello(
439 byte[] fragment, int offset, int length) throws IOException {
440 int v3SessIdLenOffset = offset + 34; // 2: client_version
441 // 32: random
442
443 int v3SessIdLen = fragment[v3SessIdLenOffset];
444 int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen;
445 int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) +
446 (fragment[v3CSLenOffset + 1] & 0xff);
447 int cipherSpecs = v3CSLen / 2; // 2: cipher spec size
448
449 // Estimate the max V2ClientHello message length
450 //
451 // 11: header size
452 // (cipherSpecs * 6): cipher_specs
453 // 6: one cipher suite may need 6 bytes, see V3toV2CipherSuite.
454 // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
455 // signaling cipher suite
456 // 32: challenge size
457 int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32;
458
459 // Create a ByteBuffer backed by an accessible byte array.
483 }
484 }
485
486 if (!containsRenegoInfoSCSV) {
487 v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF);
488 }
489
490 /*
491 * Copy in the nonce.
492 */
493 dstBuf.put(fragment, (offset + 2), 32);
494
495 /*
496 * Build the first part of the V3 record header from the V2 one
497 * that's now buffered up. (Lengths are fixed up later).
498 */
499 int msgLen = dstBuf.position() - 2; // Exclude the legth field itself
500 dstBuf.position(0);
501 dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF))); // pos: 0
502 dstBuf.put((byte)(msgLen & 0xFF)); // pos: 1
503 dstBuf.put(SSLHandshake.CLIENT_HELLO.id); // pos: 2
504 dstBuf.put(fragment[offset]); // major version, pos: 3
505 dstBuf.put(fragment[offset + 1]); // minor version, pos: 4
506 dstBuf.put((byte)(v2CSLen >>> 8)); // pos: 5
507 dstBuf.put((byte)(v2CSLen & 0xFF)); // pos: 6
508 dstBuf.put((byte)0x00); // session_id_length, pos: 7
509 dstBuf.put((byte)0x00); // pos: 8
510 dstBuf.put((byte)0x00); // challenge_length, pos: 9
511 dstBuf.put((byte)32); // pos: 10
512
513 dstBuf.position(0);
514 dstBuf.limit(msgLen + 2);
515
516 return dstBuf;
517 }
518
519 private static int V3toV2CipherSuite(ByteBuffer dstBuf,
520 byte byte1, byte byte2) {
521 dstBuf.put((byte)0);
522 dstBuf.put(byte1);
523 dstBuf.put(byte2);
|