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.IOException;
30 import java.nio.ByteBuffer;
31 
32 /**
33  * Output stream for handshake data.  This is used only internally
34  * to the SSL classes.
35  *
36  * MT note:  one thread at a time is presumed be writing handshake
37  * messages, but (after initial connection setup) it's possible to
38  * have other threads reading/writing application data.  It's the
39  * SSLSocketImpl class that synchronizes record writes.
40  *
41  * @author  David Brownell
42  */
43 public class HandshakeOutStream extends ByteArrayOutputStream {
44 
45     OutputRecord outputRecord;      // May be null if not actually used to
46                                     // output handshake message records.
47 
HandshakeOutStream(OutputRecord outputRecord)48     HandshakeOutStream(OutputRecord outputRecord) {
49         super();
50         this.outputRecord = outputRecord;
51     }
52 
53     // Complete a handshaking message write. Called by HandshakeMessage.
complete()54     void complete() throws IOException {
55         if (size() < 4) {       // 4: handshake message header size
56             // internal_error alert will be triggered
57             throw new RuntimeException("handshake message is not available");
58         }
59 
60         if (outputRecord != null) {
61             if (!outputRecord.isClosed()) {
62                 outputRecord.encodeHandshake(buf, 0, count);
63             } else {
64                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
65                     SSLLogger.warning("outbound has closed, ignore outbound " +
66                         "handshake messages", ByteBuffer.wrap(buf, 0, count));
67                 }
68             }
69 
70             // reset the byte array output stream
71             reset();
72         }   // otherwise, the handshake outstream is temporarily used only.
73     }
74 
75     //
76     // overridden ByteArrayOutputStream methods
77     //
78 
79     @Override
write(byte[] b, int off, int len)80     public void write(byte[] b, int off, int len) {
81         // The maximum fragment size is 24 bytes.
82         checkOverflow(len, Record.OVERFLOW_OF_INT24);
83         super.write(b, off, len);
84     }
85 
86     @Override
flush()87     public void flush() throws IOException {
88         if (outputRecord != null) {
89             outputRecord.flush();
90         }
91     }
92 
93     //
94     // handshake output stream management functions
95     //
96 
97     /*
98      * Put integers encoded in standard 8, 16, 24, and 32 bit
99      * big endian formats. Note that OutputStream.write(int) only
100      * writes the least significant 8 bits and ignores the rest.
101      */
putInt8(int i)102     void putInt8(int i) throws IOException {
103         checkOverflow(i, Record.OVERFLOW_OF_INT08);
104         super.write(i);
105     }
106 
putInt16(int i)107     void putInt16(int i) throws IOException {
108         checkOverflow(i, Record.OVERFLOW_OF_INT16);
109         super.write(i >> 8);
110         super.write(i);
111     }
112 
putInt24(int i)113     void putInt24(int i) throws IOException {
114         checkOverflow(i, Record.OVERFLOW_OF_INT24);
115         super.write(i >> 16);
116         super.write(i >> 8);
117         super.write(i);
118     }
119 
putInt32(int i)120     void putInt32(int i) throws IOException {
121         super.write(i >> 24);
122         super.write(i >> 16);
123         super.write(i >> 8);
124         super.write(i);
125     }
126 
127     /*
128      * Put byte arrays with length encoded as 8, 16, 24 bit
129      * integers in big-endian format.
130      */
putBytes8(byte[] b)131     void putBytes8(byte[] b) throws IOException {
132         if (b == null) {
133             putInt8(0);
134         } else {
135             putInt8(b.length);
136             super.write(b, 0, b.length);
137         }
138     }
139 
putBytes16(byte[] b)140     public void putBytes16(byte[] b) throws IOException {
141         if (b == null) {
142             putInt16(0);
143         } else {
144             putInt16(b.length);
145             super.write(b, 0, b.length);
146         }
147     }
148 
putBytes24(byte[] b)149     void putBytes24(byte[] b) throws IOException {
150         if (b == null) {
151             putInt24(0);
152         } else {
153             putInt24(b.length);
154             super.write(b, 0, b.length);
155         }
156     }
157 
158     /*
159      * Does the specified length overflow the limitation?
160      */
checkOverflow(int length, int limit)161     private static void checkOverflow(int length, int limit) {
162         if (length >= limit) {
163             // internal_error alert will be triggered
164             throw new RuntimeException(
165                     "Field length overflow, the field length (" +
166                     length + ") should be less than " + limit);
167         }
168     }
169 }
170