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, used after Handshake.Finished
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     volatile 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     private static final byte[] HANDSHAKE_MESSAGE_KEY_UPDATE =
80         {SSLHandshake.KEY_UPDATE.id, 0x00, 0x00, 0x01, 0x00};
81 
OutputRecord(HandshakeHash handshakeHash, SSLWriteCipher writeCipher)82     OutputRecord(HandshakeHash handshakeHash, SSLWriteCipher writeCipher) {
83         this.writeCipher = writeCipher;
84         this.firstMessage = true;
85         this.fragmentSize = Record.maxDataSize;
86 
87         this.handshakeHash = handshakeHash;
88 
89         // Please set packetSize and protocolVersion in the implementation.
90     }
91 
setVersion(ProtocolVersion protocolVersion)92     synchronized void setVersion(ProtocolVersion protocolVersion) {
93         this.protocolVersion = protocolVersion;
94     }
95 
96     /*
97      * Updates helloVersion of this record.
98      */
setHelloVersion(ProtocolVersion helloVersion)99     synchronized void setHelloVersion(ProtocolVersion helloVersion) {
100         this.helloVersion = helloVersion;
101     }
102 
103     /*
104      * Return true iff the record is empty -- to avoid doing the work
105      * of sending empty records over the network.
106      */
isEmpty()107     boolean isEmpty() {
108         return false;
109     }
110 
seqNumIsHuge()111     synchronized boolean seqNumIsHuge() {
112         return (writeCipher.authenticator != null) &&
113                         writeCipher.authenticator.seqNumIsHuge();
114     }
115 
116     // SSLEngine and SSLSocket
encodeAlert(byte level, byte description)117     abstract void encodeAlert(byte level, byte description) throws IOException;
118 
119     // SSLEngine and SSLSocket
encodeHandshake(byte[] buffer, int offset, int length)120     abstract void encodeHandshake(byte[] buffer,
121             int offset, int length) throws IOException;
122 
123     // SSLEngine and SSLSocket
encodeChangeCipherSpec()124     abstract void encodeChangeCipherSpec() throws IOException;
125 
126     // apply to SSLEngine only
encode( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)127     Ciphertext encode(
128         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
129         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
130 
131         throw new UnsupportedOperationException();
132     }
133 
134     // apply to SSLEngine only
encodeV2NoCipher()135     void encodeV2NoCipher() throws IOException {
136         throw new UnsupportedOperationException();
137     }
138 
139     // apply to SSLSocket only
deliver( byte[] source, int offset, int length)140     void deliver(
141             byte[] source, int offset, int length) throws IOException {
142         throw new UnsupportedOperationException();
143     }
144 
145     // apply to SSLSocket only
setDeliverStream(OutputStream outputStream)146     void setDeliverStream(OutputStream outputStream) {
147         throw new UnsupportedOperationException();
148     }
149 
150     // Change write ciphers, may use change_cipher_spec record.
changeWriteCiphers(SSLWriteCipher writeCipher, boolean useChangeCipherSpec)151     synchronized void changeWriteCiphers(SSLWriteCipher writeCipher,
152             boolean useChangeCipherSpec) throws IOException {
153         if (isClosed()) {
154             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
155                 SSLLogger.warning("outbound has closed, ignore outbound " +
156                     "change_cipher_spec message");
157             }
158             return;
159         }
160 
161         if (useChangeCipherSpec) {
162             encodeChangeCipherSpec();
163         }
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.writeCipher = writeCipher;
176         this.isFirstAppOutputRecord = true;
177     }
178 
179     // Change write ciphers using key_update handshake message.
changeWriteCiphers(SSLWriteCipher writeCipher, byte keyUpdateRequest)180     synchronized void changeWriteCiphers(SSLWriteCipher writeCipher,
181             byte keyUpdateRequest) throws IOException {
182         if (isClosed()) {
183             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
184                 SSLLogger.warning("outbound has closed, ignore outbound " +
185                     "key_update handshake message");
186             }
187             return;
188         }
189 
190         // encode the handshake message, KeyUpdate
191         byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone();
192         hm[hm.length - 1] = keyUpdateRequest;
193         encodeHandshake(hm, 0, hm.length);
194         flush();
195 
196         // Dispose of any intermediate state in the underlying cipher.
197         writeCipher.dispose();
198 
199         this.writeCipher = writeCipher;
200         this.isFirstAppOutputRecord = true;
201     }
202 
changePacketSize(int packetSize)203     synchronized void changePacketSize(int packetSize) {
204         this.packetSize = packetSize;
205     }
206 
changeFragmentSize(int fragmentSize)207     synchronized void changeFragmentSize(int fragmentSize) {
208         this.fragmentSize = fragmentSize;
209     }
210 
getMaxPacketSize()211     synchronized int getMaxPacketSize() {
212         return packetSize;
213     }
214 
215     // apply to DTLS SSLEngine
initHandshaker()216     void initHandshaker() {
217         // blank
218     }
219 
220     // apply to DTLS SSLEngine
finishHandshake()221     void finishHandshake() {
222         // blank
223     }
224 
225     // apply to DTLS SSLEngine
launchRetransmission()226     void launchRetransmission() {
227         // blank
228     }
229 
230     @Override
close()231     public synchronized void close() throws IOException {
232         if (isClosed) {
233             return;
234         }
235 
236         isClosed = true;
237         writeCipher.dispose();
238     }
239 
isClosed()240     boolean isClosed() {
241         return isClosed;
242     }
243 
244     //
245     // shared helpers
246     //
247 
248     // Encrypt a fragment and wrap up a record.
249     //
250     // To be consistent with the spec of SSLEngine.wrap() methods, the
251     // destination ByteBuffer's position is updated to reflect the amount
252     // of data produced.  The limit remains the same.
encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)253     static long encrypt(
254             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
255             int headerOffset, int dstLim, int headerSize,
256             ProtocolVersion protocolVersion) {
257         boolean isDTLS = protocolVersion.isDTLS;
258         if (isDTLS) {
259             if (protocolVersion.useTLS13PlusSpec()) {
260                 return d13Encrypt(encCipher,
261                         contentType, destination, headerOffset,
262                         dstLim, headerSize, protocolVersion);
263             } else {
264                 return d10Encrypt(encCipher,
265                         contentType, destination, headerOffset,
266                         dstLim, headerSize, protocolVersion);
267             }
268         } else {
269             if (protocolVersion.useTLS13PlusSpec()) {
270                 return t13Encrypt(encCipher,
271                         contentType, destination, headerOffset,
272                         dstLim, headerSize, protocolVersion);
273             } else {
274                 return t10Encrypt(encCipher,
275                         contentType, destination, headerOffset,
276                         dstLim, headerSize, protocolVersion);
277             }
278         }
279     }
280 
d13Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)281     private static long d13Encrypt(
282             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
283             int headerOffset, int dstLim, int headerSize,
284             ProtocolVersion protocolVersion) {
285         throw new UnsupportedOperationException("Not supported yet.");
286     }
287 
d10Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)288     private static long d10Encrypt(
289             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
290             int headerOffset, int dstLim, int headerSize,
291             ProtocolVersion protocolVersion) {
292         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
293         encCipher.encrypt(contentType, destination);
294 
295         // Finish out the record header.
296         int fragLen = destination.limit() - headerOffset - headerSize;
297 
298         destination.put(headerOffset, contentType);         // content type
299         destination.put(headerOffset + 1, protocolVersion.major);
300         destination.put(headerOffset + 2, protocolVersion.minor);
301 
302         // epoch and sequence_number
303         destination.put(headerOffset + 3, sequenceNumber[0]);
304         destination.put(headerOffset + 4, sequenceNumber[1]);
305         destination.put(headerOffset + 5, sequenceNumber[2]);
306         destination.put(headerOffset + 6, sequenceNumber[3]);
307         destination.put(headerOffset + 7, sequenceNumber[4]);
308         destination.put(headerOffset + 8, sequenceNumber[5]);
309         destination.put(headerOffset + 9, sequenceNumber[6]);
310         destination.put(headerOffset + 10, sequenceNumber[7]);
311 
312         // fragment length
313         destination.put(headerOffset + 11, (byte)(fragLen >> 8));
314         destination.put(headerOffset + 12, (byte)fragLen);
315 
316         // Update destination position to reflect the amount of data produced.
317         destination.position(destination.limit());
318 
319         return Authenticator.toLong(sequenceNumber);
320     }
321 
t13Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)322     private static long t13Encrypt(
323             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
324             int headerOffset, int dstLim, int headerSize,
325             ProtocolVersion protocolVersion) {
326         if (!encCipher.isNullCipher()) {
327             // inner plaintext, using zero length padding.
328             int endOfPt = destination.limit();
329             destination.limit(endOfPt + 1);
330             destination.put(endOfPt, contentType);
331         }
332 
333         // use the right TLSCiphertext.opaque_type and legacy_record_version
334         ProtocolVersion pv = protocolVersion;
335         if (!encCipher.isNullCipher()) {
336             pv = ProtocolVersion.TLS12;
337             contentType = ContentType.APPLICATION_DATA.id;
338         } else if (protocolVersion.useTLS13PlusSpec()) {
339             pv = ProtocolVersion.TLS12;
340         }
341 
342         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
343         encCipher.encrypt(contentType, destination);
344 
345         // Finish out the record header.
346         int fragLen = destination.limit() - headerOffset - headerSize;
347         destination.put(headerOffset, contentType);
348         destination.put(headerOffset + 1, pv.major);
349         destination.put(headerOffset + 2, pv.minor);
350 
351         // fragment length
352         destination.put(headerOffset + 3, (byte)(fragLen >> 8));
353         destination.put(headerOffset + 4, (byte)fragLen);
354 
355         // Update destination position to reflect the amount of data produced.
356         destination.position(destination.limit());
357 
358         return Authenticator.toLong(sequenceNumber);
359     }
360 
t10Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)361     private static long t10Encrypt(
362             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
363             int headerOffset, int dstLim, int headerSize,
364             ProtocolVersion protocolVersion) {
365         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
366         encCipher.encrypt(contentType, destination);
367 
368         // Finish out the record header.
369         int fragLen = destination.limit() - headerOffset - headerSize;
370 
371         destination.put(headerOffset, contentType);         // content type
372         destination.put(headerOffset + 1, protocolVersion.major);
373         destination.put(headerOffset + 2, protocolVersion.minor);
374 
375         // fragment length
376         destination.put(headerOffset + 3, (byte)(fragLen >> 8));
377         destination.put(headerOffset + 4, (byte)fragLen);
378 
379         // Update destination position to reflect the amount of data produced.
380         destination.position(destination.limit());
381 
382         return Authenticator.toLong(sequenceNumber);
383     }
384 
385     // Encrypt a fragment and wrap up a record.
386     //
387     // Uses the internal expandable buf variable and the current
388     // protocolVersion variable.
encrypt( SSLWriteCipher encCipher, byte contentType, int headerSize)389     long encrypt(
390             SSLWriteCipher encCipher, byte contentType, int headerSize) {
391         if (protocolVersion.useTLS13PlusSpec()) {
392             return t13Encrypt(encCipher, contentType, headerSize);
393         } else {
394             return t10Encrypt(encCipher, contentType, headerSize);
395         }
396     }
397 
398     private static final class T13PaddingHolder {
399         private static final byte[] zeros = new byte[16];
400     }
401 
t13Encrypt( SSLWriteCipher encCipher, byte contentType, int headerSize)402     private long t13Encrypt(
403             SSLWriteCipher encCipher, byte contentType, int headerSize) {
404         if (!encCipher.isNullCipher()) {
405             // inner plaintext
406             write(contentType);
407             write(T13PaddingHolder.zeros, 0, T13PaddingHolder.zeros.length);
408         }
409 
410         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
411         int position = headerSize;
412         int contentLen = count - position;
413 
414         // ensure the capacity
415         int requiredPacketSize =
416                 encCipher.calculatePacketSize(contentLen, headerSize);
417         if (requiredPacketSize > buf.length) {
418             byte[] newBuf = new byte[requiredPacketSize];
419             System.arraycopy(buf, 0, newBuf, 0, count);
420             buf = newBuf;
421         }
422 
423         // use the right TLSCiphertext.opaque_type and legacy_record_version
424         ProtocolVersion pv = protocolVersion;
425         if (!encCipher.isNullCipher()) {
426             pv = ProtocolVersion.TLS12;
427             contentType = ContentType.APPLICATION_DATA.id;
428         } else {
429             pv = ProtocolVersion.TLS12;
430         }
431 
432         ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
433         count = headerSize + encCipher.encrypt(contentType, destination);
434 
435         // Fill out the header, write it and the message.
436         int fragLen = count - headerSize;
437 
438         buf[0] = contentType;
439         buf[1] = pv.major;
440         buf[2] = pv.minor;
441         buf[3] = (byte)((fragLen >> 8) & 0xFF);
442         buf[4] = (byte)(fragLen & 0xFF);
443 
444         return Authenticator.toLong(sequenceNumber);
445     }
446 
t10Encrypt( SSLWriteCipher encCipher, byte contentType, int headerSize)447     private long t10Encrypt(
448             SSLWriteCipher encCipher, byte contentType, int headerSize) {
449         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
450         int position = headerSize + writeCipher.getExplicitNonceSize();
451         int contentLen = count - position;
452 
453         // ensure the capacity
454         int requiredPacketSize =
455                 encCipher.calculatePacketSize(contentLen, headerSize);
456         if (requiredPacketSize > buf.length) {
457             byte[] newBuf = new byte[requiredPacketSize];
458             System.arraycopy(buf, 0, newBuf, 0, count);
459             buf = newBuf;
460         }
461         ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
462         count = headerSize + encCipher.encrypt(contentType, destination);
463 
464         // Fill out the header, write it and the message.
465         int fragLen = count - headerSize;
466         buf[0] = contentType;
467         buf[1] = protocolVersion.major;
468         buf[2] = protocolVersion.minor;
469         buf[3] = (byte)((fragLen >> 8) & 0xFF);
470         buf[4] = (byte)(fragLen & 0xFF);
471 
472         return Authenticator.toLong(sequenceNumber);
473     }
474 
encodeV2ClientHello( byte[] fragment, int offset, int length)475     static ByteBuffer encodeV2ClientHello(
476             byte[] fragment, int offset, int length) throws IOException {
477         int v3SessIdLenOffset = offset + 34;      //  2: client_version
478                                                   // 32: random
479 
480         int v3SessIdLen = fragment[v3SessIdLenOffset];
481         int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen;
482         int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) +
483                        (fragment[v3CSLenOffset + 1] & 0xff);
484         int cipherSpecs = v3CSLen / 2;        // 2: cipher spec size
485 
486         // Estimate the max V2ClientHello message length
487         //
488         // 11: header size
489         // (cipherSpecs * 6): cipher_specs
490         //    6: one cipher suite may need 6 bytes, see V3toV2CipherSuite.
491         // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
492         //    signaling cipher suite
493         // 32: challenge size
494         int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32;
495 
496         // Create a ByteBuffer backed by an accessible byte array.
497         byte[] dstBytes = new byte[v2MaxMsgLen];
498         ByteBuffer dstBuf = ByteBuffer.wrap(dstBytes);
499 
500         /*
501          * Copy over the cipher specs. We don't care about actually
502          * translating them for use with an actual V2 server since
503          * we only talk V3.  Therefore, just copy over the V3 cipher
504          * spec values with a leading 0.
505          */
506         int v3CSOffset = v3CSLenOffset + 2;   // skip length field
507         int v2CSLen = 0;
508 
509         dstBuf.position(11);
510         boolean containsRenegoInfoSCSV = false;
511         for (int i = 0; i < cipherSpecs; i++) {
512             byte byte1, byte2;
513 
514             byte1 = fragment[v3CSOffset++];
515             byte2 = fragment[v3CSOffset++];
516             v2CSLen += V3toV2CipherSuite(dstBuf, byte1, byte2);
517             if (!containsRenegoInfoSCSV &&
518                     byte1 == (byte)0x00 && byte2 == (byte)0xFF) {
519                 containsRenegoInfoSCSV = true;
520             }
521         }
522 
523         if (!containsRenegoInfoSCSV) {
524             v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF);
525         }
526 
527         /*
528          * Copy in the nonce.
529          */
530         dstBuf.put(fragment, (offset + 2), 32);
531 
532         /*
533          * Build the first part of the V3 record header from the V2 one
534          * that's now buffered up.  (Lengths are fixed up later).
535          */
536         int msgLen = dstBuf.position() - 2;   // Exclude the legth field itself
537         dstBuf.position(0);
538         dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF)));  // pos: 0
539         dstBuf.put((byte)(msgLen & 0xFF));                   // pos: 1
540         dstBuf.put(SSLHandshake.CLIENT_HELLO.id);            // pos: 2
541         dstBuf.put(fragment[offset]);         // major version, pos: 3
542         dstBuf.put(fragment[offset + 1]);     // minor version, pos: 4
543         dstBuf.put((byte)(v2CSLen >>> 8));                   // pos: 5
544         dstBuf.put((byte)(v2CSLen & 0xFF));                  // pos: 6
545         dstBuf.put((byte)0x00);           // session_id_length, pos: 7
546         dstBuf.put((byte)0x00);                              // pos: 8
547         dstBuf.put((byte)0x00);           // challenge_length,  pos: 9
548         dstBuf.put((byte)32);                                // pos: 10
549 
550         dstBuf.position(0);
551         dstBuf.limit(msgLen + 2);
552 
553         return dstBuf;
554     }
555 
V3toV2CipherSuite(ByteBuffer dstBuf, byte byte1, byte byte2)556     private static int V3toV2CipherSuite(ByteBuffer dstBuf,
557             byte byte1, byte byte2) {
558         dstBuf.put((byte)0);
559         dstBuf.put(byte1);
560         dstBuf.put(byte2);
561 
562         if (((byte2 & 0xff) > 0xA) || (V3toV2CipherMap1[byte2] == -1)) {
563             return 3;
564         }
565 
566         dstBuf.put((byte)V3toV2CipherMap1[byte2]);
567         dstBuf.put((byte)0);
568         dstBuf.put((byte)V3toV2CipherMap3[byte2]);
569 
570         return 6;
571     }
572 }
573