History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/ssl/EngineInputRecord.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/ssl/EngineInputRecord.java+360−0
@@ -0,0 +1,360 @@
1+/*
2+ * Copyright (c) 2003, 2007, 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+import javax.net.ssl.*;
32+import javax.crypto.BadPaddingException;
33+import sun.misc.HexDumpEncoder;
34+
35+
36+/**
37+ * Wrapper class around InputRecord.
38+ *
39+ * Application data is kept external to the InputRecord,
40+ * but handshake data (alert/change_cipher_spec/handshake) will
41+ * be kept internally in the ByteArrayInputStream.
42+ *
43+ * @author Brad Wetmore
44+ */
45+final class EngineInputRecord extends InputRecord {
46+
47+ private SSLEngineImpl engine;
48+
49+ /*
50+ * A dummy ByteBuffer we'll pass back even when the data
51+ * is stored internally. It'll never actually be used.
52+ */
53+ static private ByteBuffer tmpBB = ByteBuffer.allocate(0);
54+
55+ /*
56+ * Flag to tell whether the last read/parsed data resides
57+ * internal in the ByteArrayInputStream, or in the external
58+ * buffers.
59+ */
60+ private boolean internalData;
61+
62+ EngineInputRecord(SSLEngineImpl engine) {
63+ super();
64+ this.engine = engine;
65+ }
66+
67+ byte contentType() {
68+ if (internalData) {
69+ return super.contentType();
70+ } else {
71+ return ct_application_data;
72+ }
73+ }
74+
75+ /*
76+ * Check if there is enough inbound data in the ByteBuffer
77+ * to make a inbound packet. Look for both SSLv2 and SSLv3.
78+ *
79+ * @return -1 if there are not enough bytes to tell (small header),
80+ */
81+ int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
82+
83+ /*
84+ * SSLv2 length field is in bytes 0/1
85+ * SSLv3/TLS length field is in bytes 3/4
86+ */
87+ if (buf.remaining() < 5) {
88+ return -1;
89+ }
90+
91+ int pos = buf.position();
92+ byte byteZero = buf.get(pos);
93+
94+ int len = 0;
95+
96+ /*
97+ * If we have already verified previous packets, we can
98+ * ignore the verifications steps, and jump right to the
99+ * determination. Otherwise, try one last hueristic to
100+ * see if it's SSL/TLS.
101+ */
102+ if (formatVerified ||
103+ (byteZero == ct_handshake) ||
104+ (byteZero == ct_alert)) {
105+ /*
106+ * Last sanity check that it's not a wild record
107+ */
108+ ProtocolVersion recordVersion =
109+ ProtocolVersion.valueOf(buf.get(pos + 1), buf.get(pos + 2));
110+
111+ // Check if too old (currently not possible)
112+ // or if the major version does not match.
113+ // The actual version negotiation is in the handshaker classes
114+ if ((recordVersion.v < ProtocolVersion.MIN.v)
115+ || (recordVersion.major > ProtocolVersion.MAX.major)) {
116+ throw new SSLException(
117+ "Unsupported record version " + recordVersion);
118+ }
119+
120+ /*
121+ * Reasonably sure this is a V3, disable further checks.
122+ * We can't do the same in the v2 check below, because
123+ * read still needs to parse/handle the v2 clientHello.
124+ */
125+ formatVerified = true;
126+
127+ /*
128+ * One of the SSLv3/TLS message types.
129+ */
130+ len = ((buf.get(pos + 3) & 0xff) << 8) +
131+ (buf.get(pos + 4) & 0xff) + headerSize;
132+
133+ } else {
134+ /*
135+ * Must be SSLv2 or something unknown.
136+ * Check if it's short (2 bytes) or
137+ * long (3) header.
138+ *
139+ * Internals can warn about unsupported SSLv2
140+ */
141+ boolean isShort = ((byteZero & 0x80) != 0);
142+
143+ if (isShort &&
144+ ((buf.get(pos + 2) == 1) || buf.get(pos + 2) == 4)) {
145+
146+ ProtocolVersion recordVersion =
147+ ProtocolVersion.valueOf(buf.get(pos + 3), buf.get(pos + 4));
148+
149+ // Check if too old (currently not possible)
150+ // or if the major version does not match.
151+ // The actual version negotiation is in the handshaker classes
152+ if ((recordVersion.v < ProtocolVersion.MIN.v)
153+ || (recordVersion.major > ProtocolVersion.MAX.major)) {
154+
155+ // if it's not SSLv2, we're out of here.
156+ if (recordVersion.v != ProtocolVersion.SSL20Hello.v) {
157+ throw new SSLException(
158+ "Unsupported record version " + recordVersion);
159+ }
160+ }
161+
162+ /*
163+ * Client or Server Hello
164+ */
165+ int mask = (isShort ? 0x7f : 0x3f);
166+ len = ((byteZero & mask) << 8) + (buf.get(pos + 1) & 0xff) +
167+ (isShort ? 2 : 3);
168+
169+ } else {
170+ // Gobblygook!
171+ throw new SSLException(
172+ "Unrecognized SSL message, plaintext connection?");
173+ }
174+ }
175+
176+ return len;
177+ }
178+
179+ /*
180+ * Verifies and removes the MAC value. Returns true if
181+ * the MAC checks out OK.
182+ *
183+ * On entry:
184+ * position = beginning of app/MAC data
185+ * limit = end of MAC data.
186+ *
187+ * On return:
188+ * position = beginning of app data
189+ * limit = end of app data
190+ */
191+ boolean checkMAC(MAC signer, ByteBuffer bb) {
192+ if (internalData) {
193+ return checkMAC(signer);
194+ }
195+
196+ int len = signer.MAClen();
197+ if (len == 0) { // no mac
198+ return true;
199+ }
200+
201+ /*
202+ * Grab the original limit
203+ */
204+ int lim = bb.limit();
205+
206+ /*
207+ * Delineate the area to apply a MAC on.
208+ */
209+ int macData = lim - len;
210+ bb.limit(macData);
211+
212+ byte[] mac = signer.compute(contentType(), bb);
213+
214+ if (len != mac.length) {
215+ throw new RuntimeException("Internal MAC error");
216+ }
217+
218+ /*
219+ * Delineate the MAC values, position was already set
220+ * by doing the compute above.
221+ *
222+ * We could zero the MAC area, but not much useful information
223+ * there anyway.
224+ */
225+ bb.position(macData);
226+ bb.limit(lim);
227+
228+ try {
229+ for (int i = 0; i < len; i++) {
230+ if (bb.get() != mac[i]) { // No BB.equals(byte []); !
231+ return false;
232+ }
233+ }
234+ return true;
235+ } finally {
236+ /*
237+ * Position to the data.
238+ */
239+ bb.rewind();
240+ bb.limit(macData);
241+ }
242+ }
243+
244+ /*
245+ * Pass the data down if it's internally cached, otherwise
246+ * do it here.
247+ *
248+ * If internal data, data is decrypted internally.
249+ *
250+ * If external data(app), return a new ByteBuffer with data to
251+ * process.
252+ */
253+ ByteBuffer decrypt(CipherBox box, ByteBuffer bb)
254+ throws BadPaddingException {
255+
256+ if (internalData) {
257+ decrypt(box);
258+ return tmpBB;
259+ }
260+
261+ box.decrypt(bb);
262+ bb.rewind();
263+
264+ return bb.slice();
265+ }
266+
267+ /*
268+ * Override the actual write below. We do things this way to be
269+ * consistent with InputRecord. InputRecord may try to write out
270+ * data to the peer, and *then* throw an Exception. This forces
271+ * data to be generated/output before the exception is ever
272+ * generated.
273+ */
274+ void writeBuffer(OutputStream s, byte [] buf, int off, int len)
275+ throws IOException {
276+ /*
277+ * Copy data out of buffer, it's ready to go.
278+ */
279+ ByteBuffer netBB = (ByteBuffer)
280+ (ByteBuffer.allocate(len).put(buf, 0, len).flip());
281+ engine.writer.putOutboundDataSync(netBB);
282+ }
283+
284+ /*
285+ * Delineate or read a complete packet from src.
286+ *
287+ * If internal data (hs, alert, ccs), the data is read and
288+ * stored internally.
289+ *
290+ * If external data (app), return a new ByteBuffer which points
291+ * to the data to process.
292+ */
293+ ByteBuffer read(ByteBuffer srcBB) throws IOException {
294+ /*
295+ * Could have a src == null/dst == null check here,
296+ * but that was already checked by SSLEngine.unwrap before
297+ * ever attempting to read.
298+ */
299+
300+ /*
301+ * If we have anything besides application data,
302+ * or if we haven't even done the initial v2 verification,
303+ * we send this down to be processed by the underlying
304+ * internal cache.
305+ */
306+ if (!formatVerified ||
307+ (srcBB.get(srcBB.position()) != ct_application_data)) {
308+ internalData = true;
309+ read(new ByteBufferInputStream(srcBB), (OutputStream) null);
310+ return tmpBB;
311+ }
312+
313+ internalData = false;
314+
315+ int srcPos = srcBB.position();
316+ int srcLim = srcBB.limit();
317+
318+ ProtocolVersion recordVersion = ProtocolVersion.valueOf(
319+ srcBB.get(srcPos + 1), srcBB.get(srcPos + 2));
320+ // Check if too old (currently not possible)
321+ // or if the major version does not match.
322+ // The actual version negotiation is in the handshaker classes
323+ if ((recordVersion.v < ProtocolVersion.MIN.v)
324+ || (recordVersion.major > ProtocolVersion.MAX.major)) {
325+ throw new SSLException(
326+ "Unsupported record version " + recordVersion);
327+ }
328+
329+ /*
330+ * It's really application data. How much to consume?
331+ * Jump over the header.
332+ */
333+ int len = bytesInCompletePacket(srcBB);
334+ assert(len > 0);
335+
336+ if (debug != null && Debug.isOn("packet")) {
337+ try {
338+ HexDumpEncoder hd = new HexDumpEncoder();
339+ srcBB.limit(srcPos + len);
340+ ByteBuffer bb = srcBB.duplicate(); // Use copy of BB
341+
342+ System.out.println("[Raw read (bb)]: length = " + len);
343+ hd.encodeBuffer(bb, System.out);
344+ } catch (IOException e) { }
345+ }
346+
347+ // Demarcate past header to end of packet.
348+ srcBB.position(srcPos + headerSize);
349+ srcBB.limit(srcPos + len);
350+
351+ // Protect remainder of buffer, create slice to actually
352+ // operate on.
353+ ByteBuffer bb = srcBB.slice();
354+
355+ srcBB.position(srcBB.limit());
356+ srcBB.limit(srcLim);
357+
358+ return bb;
359+ }
360+}