1 /* |
|
2 * Copyright (c) 2003, 2013, 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 |
|
27 package sun.security.ssl; |
|
28 |
|
29 import java.io.*; |
|
30 import java.nio.*; |
|
31 |
|
32 /** |
|
33 * A OutputRecord class extension which uses external ByteBuffers |
|
34 * or the internal ByteArrayOutputStream for data manipulations. |
|
35 * <P> |
|
36 * Instead of rewriting this entire class |
|
37 * to use ByteBuffers, we leave things intact, so handshake, CCS, |
|
38 * and alerts will continue to use the internal buffers, but application |
|
39 * data will use external buffers. |
|
40 * |
|
41 * @author Brad Wetmore |
|
42 */ |
|
43 final class EngineOutputRecord extends OutputRecord { |
|
44 |
|
45 private SSLEngineImpl engine; |
|
46 private EngineWriter writer; |
|
47 |
|
48 private boolean finishedMsg = false; |
|
49 |
|
50 /* |
|
51 * All handshake hashing is done by the superclass |
|
52 */ |
|
53 |
|
54 /* |
|
55 * Default constructor makes a record supporting the maximum |
|
56 * SSL record size. It allocates the header bytes directly. |
|
57 * |
|
58 * @param type the content type for the record |
|
59 */ |
|
60 EngineOutputRecord(byte type, SSLEngineImpl engine) { |
|
61 super(type, recordSize(type)); |
|
62 this.engine = engine; |
|
63 writer = engine.writer; |
|
64 } |
|
65 |
|
66 /** |
|
67 * Get the size of the buffer we need for records of the specified |
|
68 * type. |
|
69 * <P> |
|
70 * Application data buffers will provide their own byte buffers, |
|
71 * and will not use the internal byte caching. |
|
72 */ |
|
73 private static int recordSize(byte type) { |
|
74 switch (type) { |
|
75 |
|
76 case ct_change_cipher_spec: |
|
77 case ct_alert: |
|
78 return maxAlertRecordSize; |
|
79 |
|
80 case ct_handshake: |
|
81 return maxRecordSize; |
|
82 |
|
83 case ct_application_data: |
|
84 return 0; |
|
85 } |
|
86 |
|
87 throw new RuntimeException("Unknown record type: " + type); |
|
88 } |
|
89 |
|
90 void setFinishedMsg() { |
|
91 finishedMsg = true; |
|
92 } |
|
93 |
|
94 @Override |
|
95 public void flush() throws IOException { |
|
96 finishedMsg = false; |
|
97 } |
|
98 |
|
99 boolean isFinishedMsg() { |
|
100 return finishedMsg; |
|
101 } |
|
102 |
|
103 /* |
|
104 * Override the actual write below. We do things this way to be |
|
105 * consistent with InputRecord. InputRecord may try to write out |
|
106 * data to the peer, and *then* throw an Exception. This forces |
|
107 * data to be generated/output before the exception is ever |
|
108 * generated. |
|
109 */ |
|
110 @Override |
|
111 void writeBuffer(OutputStream s, byte [] buf, int off, int len, |
|
112 int debugOffset) throws IOException { |
|
113 /* |
|
114 * Copy data out of buffer, it's ready to go. |
|
115 */ |
|
116 ByteBuffer netBB = ByteBuffer.allocate(len).put(buf, off, len).flip(); |
|
117 writer.putOutboundData(netBB); |
|
118 } |
|
119 |
|
120 /* |
|
121 * Main method for writing non-application data. |
|
122 * We MAC/encrypt, then send down for processing. |
|
123 */ |
|
124 void write(Authenticator authenticator, CipherBox writeCipher) |
|
125 throws IOException { |
|
126 |
|
127 /* |
|
128 * Sanity check. |
|
129 */ |
|
130 switch (contentType()) { |
|
131 case ct_change_cipher_spec: |
|
132 case ct_alert: |
|
133 case ct_handshake: |
|
134 break; |
|
135 default: |
|
136 throw new RuntimeException("unexpected byte buffers"); |
|
137 } |
|
138 |
|
139 /* |
|
140 * Don't bother to really write empty records. We went this |
|
141 * far to drive the handshake machinery, for correctness; not |
|
142 * writing empty records improves performance by cutting CPU |
|
143 * time and network resource usage. Also, some protocol |
|
144 * implementations are fragile and don't like to see empty |
|
145 * records, so this increases robustness. |
|
146 * |
|
147 * (Even change cipher spec messages have a byte of data!) |
|
148 */ |
|
149 if (!isEmpty()) { |
|
150 // compress(); // eventually |
|
151 encrypt(authenticator, writeCipher); |
|
152 |
|
153 // send down for processing |
|
154 write((OutputStream)null, false, (ByteArrayOutputStream)null); |
|
155 } |
|
156 return; |
|
157 } |
|
158 |
|
159 /** |
|
160 * Main wrap/write driver. |
|
161 */ |
|
162 void write(EngineArgs ea, Authenticator authenticator, |
|
163 CipherBox writeCipher) throws IOException { |
|
164 /* |
|
165 * sanity check to make sure someone didn't inadvertantly |
|
166 * send us an impossible combination we don't know how |
|
167 * to process. |
|
168 */ |
|
169 assert(contentType() == ct_application_data); |
|
170 |
|
171 /* |
|
172 * Have we set the MAC's yet? If not, we're not ready |
|
173 * to process application data yet. |
|
174 */ |
|
175 if (authenticator == MAC.NULL) { |
|
176 return; |
|
177 } |
|
178 |
|
179 /* |
|
180 * Don't bother to really write empty records. We went this |
|
181 * far to drive the handshake machinery, for correctness; not |
|
182 * writing empty records improves performance by cutting CPU |
|
183 * time and network resource usage. Also, some protocol |
|
184 * implementations are fragile and don't like to see empty |
|
185 * records, so this increases robustness. |
|
186 */ |
|
187 if (ea.getAppRemaining() == 0) { |
|
188 return; |
|
189 } |
|
190 |
|
191 /* |
|
192 * By default, we counter chosen plaintext issues on CBC mode |
|
193 * ciphersuites in SSLv3/TLS1.0 by sending one byte of application |
|
194 * data in the first record of every payload, and the rest in |
|
195 * subsequent record(s). Note that the issues have been solved in |
|
196 * TLS 1.1 or later. |
|
197 * |
|
198 * It is not necessary to split the very first application record of |
|
199 * a freshly negotiated TLS session, as there is no previous |
|
200 * application data to guess. To improve compatibility, we will not |
|
201 * split such records. |
|
202 * |
|
203 * Because of the compatibility, we'd better produce no more than |
|
204 * SSLSession.getPacketBufferSize() net data for each wrap. As we |
|
205 * need a one-byte record at first, the 2nd record size should be |
|
206 * equal to or less than Record.maxDataSizeMinusOneByteRecord. |
|
207 * |
|
208 * This avoids issues in the outbound direction. For a full fix, |
|
209 * the peer must have similar protections. |
|
210 */ |
|
211 int length; |
|
212 if (engine.needToSplitPayload(writeCipher, protocolVersion)) { |
|
213 write(ea, authenticator, writeCipher, 0x01); |
|
214 ea.resetLim(); // reset application data buffer limit |
|
215 length = Math.min(ea.getAppRemaining(), |
|
216 maxDataSizeMinusOneByteRecord); |
|
217 } else { |
|
218 length = Math.min(ea.getAppRemaining(), maxDataSize); |
|
219 } |
|
220 |
|
221 // Don't bother to really write empty records. |
|
222 if (length > 0) { |
|
223 write(ea, authenticator, writeCipher, length); |
|
224 } |
|
225 |
|
226 return; |
|
227 } |
|
228 |
|
229 void write(EngineArgs ea, Authenticator authenticator, |
|
230 CipherBox writeCipher, int length) throws IOException { |
|
231 /* |
|
232 * Copy out existing buffer values. |
|
233 */ |
|
234 ByteBuffer dstBB = ea.netData; |
|
235 int dstPos = dstBB.position(); |
|
236 int dstLim = dstBB.limit(); |
|
237 |
|
238 /* |
|
239 * Where to put the data. Jump over the header. |
|
240 * |
|
241 * Don't need to worry about SSLv2 rewrites, if we're here, |
|
242 * that's long since done. |
|
243 */ |
|
244 int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize(); |
|
245 dstBB.position(dstData); |
|
246 |
|
247 /* |
|
248 * transfer application data into the network data buffer |
|
249 */ |
|
250 ea.gather(length); |
|
251 dstBB.limit(dstBB.position()); |
|
252 dstBB.position(dstData); |
|
253 |
|
254 /* |
|
255 * "flip" but skip over header again, add MAC & encrypt |
|
256 */ |
|
257 if (authenticator instanceof MAC) { |
|
258 MAC signer = (MAC)authenticator; |
|
259 if (signer.MAClen() != 0) { |
|
260 byte[] hash = signer.compute(contentType(), dstBB, false); |
|
261 |
|
262 /* |
|
263 * position was advanced to limit in compute above. |
|
264 * |
|
265 * Mark next area as writable (above layers should have |
|
266 * established that we have plenty of room), then write |
|
267 * out the hash. |
|
268 */ |
|
269 dstBB.limit(dstBB.limit() + hash.length); |
|
270 dstBB.put(hash); |
|
271 |
|
272 // reset the position and limit |
|
273 dstBB.limit(dstBB.position()); |
|
274 dstBB.position(dstData); |
|
275 } |
|
276 } |
|
277 |
|
278 if (!writeCipher.isNullCipher()) { |
|
279 /* |
|
280 * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1 |
|
281 * or later. |
|
282 */ |
|
283 if (protocolVersion.v >= ProtocolVersion.TLS11.v && |
|
284 (writeCipher.isCBCMode() || writeCipher.isAEADMode())) { |
|
285 byte[] nonce = writeCipher.createExplicitNonce( |
|
286 authenticator, contentType(), dstBB.remaining()); |
|
287 dstBB.position(dstPos + headerSize); |
|
288 dstBB.put(nonce); |
|
289 if (!writeCipher.isAEADMode()) { |
|
290 // The explicit IV in TLS 1.1 and later can be encrypted. |
|
291 dstBB.position(dstPos + headerSize); |
|
292 } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode |
|
293 } |
|
294 |
|
295 /* |
|
296 * Encrypt may pad, so again the limit may have changed. |
|
297 */ |
|
298 writeCipher.encrypt(dstBB, dstLim); |
|
299 |
|
300 if ((debug != null) && (Debug.isOn("record") || |
|
301 (Debug.isOn("handshake") && |
|
302 (contentType() == ct_change_cipher_spec)))) { |
|
303 System.out.println(Thread.currentThread().getName() |
|
304 // v3.0/v3.1 ... |
|
305 + ", WRITE: " + protocolVersion |
|
306 + " " + InputRecord.contentName(contentType()) |
|
307 + ", length = " + length); |
|
308 } |
|
309 } else { |
|
310 dstBB.position(dstBB.limit()); |
|
311 } |
|
312 |
|
313 int packetLength = dstBB.limit() - dstPos - headerSize; |
|
314 |
|
315 /* |
|
316 * Finish out the record header. |
|
317 */ |
|
318 dstBB.put(dstPos, contentType()); |
|
319 dstBB.put(dstPos + 1, protocolVersion.major); |
|
320 dstBB.put(dstPos + 2, protocolVersion.minor); |
|
321 dstBB.put(dstPos + 3, (byte)(packetLength >> 8)); |
|
322 dstBB.put(dstPos + 4, (byte)packetLength); |
|
323 |
|
324 /* |
|
325 * Position was already set by encrypt() above. |
|
326 */ |
|
327 dstBB.limit(dstLim); |
|
328 } |
|
329 } |
|