author | wetmore |
Tue, 12 Mar 2013 15:31:49 -0700 | |
changeset 16067 | 36055e4b5305 |
parent 16045 | 9d08c3b9a6a0 |
child 16126 | aad71cf676d7 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
12428 | 2 |
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
26 |
||
27 |
package sun.security.ssl; |
|
28 |
||
29 |
import java.io.*; |
|
30 |
import java.nio.*; |
|
12428 | 31 |
import java.util.Arrays; |
2 | 32 |
|
33 |
import javax.net.ssl.SSLException; |
|
34 |
import sun.misc.HexDumpEncoder; |
|
35 |
||
36 |
||
37 |
/** |
|
38 |
* SSL 3.0 records, as written to a TCP stream. |
|
39 |
* |
|
40 |
* Each record has a message area that starts out with data supplied by the |
|
41 |
* application. It may grow/shrink due to compression and will be modified |
|
42 |
* in place for mac-ing and encryption. |
|
43 |
* |
|
44 |
* Handshake records have additional needs, notably accumulation of a set |
|
45 |
* of hashes which are used to establish that handshaking was done right. |
|
46 |
* Handshake records usually have several handshake messages each, and we |
|
47 |
* need message-level control over what's hashed. |
|
48 |
* |
|
49 |
* @author David Brownell |
|
50 |
*/ |
|
51 |
class OutputRecord extends ByteArrayOutputStream implements Record { |
|
52 |
||
53 |
private HandshakeHash handshakeHash; |
|
54 |
private int lastHashed; |
|
55 |
private boolean firstMessage; |
|
56 |
final private byte contentType; |
|
57 |
||
58 |
// current protocol version, sent as record version |
|
59 |
ProtocolVersion protocolVersion; |
|
60 |
||
61 |
// version for the ClientHello message. Only relevant if this is a |
|
62 |
// client handshake record. If set to ProtocolVersion.SSL20Hello, |
|
63 |
// the V3 client hello is converted to V2 format. |
|
64 |
private ProtocolVersion helloVersion; |
|
65 |
||
66 |
/* Class and subclass dynamic debugging support */ |
|
67 |
static final Debug debug = Debug.getInstance("ssl"); |
|
68 |
||
69 |
/* |
|
70 |
* Default constructor makes a record supporting the maximum |
|
71 |
* SSL record size. It allocates the header bytes directly. |
|
72 |
* |
|
73 |
* @param type the content type for the record |
|
74 |
*/ |
|
75 |
OutputRecord(byte type, int size) { |
|
76 |
super(size); |
|
77 |
this.protocolVersion = ProtocolVersion.DEFAULT; |
|
78 |
this.helloVersion = ProtocolVersion.DEFAULT_HELLO; |
|
79 |
firstMessage = true; |
|
16067 | 80 |
count = headerSize; |
2 | 81 |
contentType = type; |
82 |
lastHashed = count; |
|
83 |
} |
|
84 |
||
85 |
OutputRecord(byte type) { |
|
86 |
this(type, recordSize(type)); |
|
87 |
} |
|
88 |
||
89 |
/** |
|
90 |
* Get the size of the buffer we need for records of the specified |
|
91 |
* type. |
|
92 |
*/ |
|
93 |
private static int recordSize(byte type) { |
|
94 |
if ((type == ct_change_cipher_spec) || (type == ct_alert)) { |
|
95 |
return maxAlertRecordSize; |
|
96 |
} else { |
|
97 |
return maxRecordSize; |
|
98 |
} |
|
99 |
} |
|
100 |
||
101 |
/* |
|
102 |
* Updates the SSL version of this record. |
|
103 |
*/ |
|
104 |
synchronized void setVersion(ProtocolVersion protocolVersion) { |
|
105 |
this.protocolVersion = protocolVersion; |
|
106 |
} |
|
107 |
||
108 |
/* |
|
109 |
* Updates helloVersion of this record. |
|
110 |
*/ |
|
111 |
synchronized void setHelloVersion(ProtocolVersion helloVersion) { |
|
112 |
this.helloVersion = helloVersion; |
|
113 |
} |
|
114 |
||
115 |
/* |
|
116 |
* Reset the record so that it can be refilled, starting |
|
117 |
* immediately after the header. |
|
118 |
*/ |
|
14664
e71aa0962e70
8003950: Adds missing Override annotations and removes unnecessary imports in sun.security.ssl
xuelei
parents:
12428
diff
changeset
|
119 |
@Override |
2 | 120 |
public synchronized void reset() { |
121 |
super.reset(); |
|
16067 | 122 |
count = headerSize; |
2 | 123 |
lastHashed = count; |
124 |
} |
|
125 |
||
126 |
/* |
|
127 |
* For handshaking, we need to be able to hash every byte above the |
|
128 |
* record marking layer. This is where we're guaranteed to see those |
|
129 |
* bytes, so this is where we can hash them. |
|
130 |
*/ |
|
131 |
void setHandshakeHash(HandshakeHash handshakeHash) { |
|
132 |
assert(contentType == ct_handshake); |
|
133 |
this.handshakeHash = handshakeHash; |
|
134 |
} |
|
135 |
||
136 |
/* |
|
137 |
* We hash (the plaintext) on demand. There is one place where |
|
138 |
* we want to access the hash in the middle of a record: client |
|
139 |
* cert message gets hashed, and part of the same record is the |
|
140 |
* client cert verify message which uses that hash. So we track |
|
141 |
* how much of each record we've hashed so far. |
|
142 |
*/ |
|
143 |
void doHashes() { |
|
144 |
int len = count - lastHashed; |
|
145 |
||
146 |
if (len > 0) { |
|
147 |
hashInternal(buf, lastHashed, len); |
|
148 |
lastHashed = count; |
|
149 |
} |
|
150 |
} |
|
151 |
||
152 |
/* |
|
153 |
* Need a helper function so we can hash the V2 hello correctly |
|
154 |
*/ |
|
155 |
private void hashInternal(byte buf [], int offset, int len) { |
|
156 |
if (debug != null && Debug.isOn("data")) { |
|
157 |
try { |
|
158 |
HexDumpEncoder hd = new HexDumpEncoder(); |
|
159 |
||
160 |
System.out.println("[write] MD5 and SHA1 hashes: len = " |
|
161 |
+ len); |
|
162 |
hd.encodeBuffer(new ByteArrayInputStream(buf, |
|
163 |
lastHashed, len), System.out); |
|
164 |
} catch (IOException e) { } |
|
165 |
} |
|
166 |
||
167 |
handshakeHash.update(buf, lastHashed, len); |
|
168 |
lastHashed = count; |
|
169 |
} |
|
170 |
||
171 |
/* |
|
172 |
* Return true iff the record is empty -- to avoid doing the work |
|
173 |
* of sending empty records over the network. |
|
174 |
*/ |
|
175 |
boolean isEmpty() { |
|
16067 | 176 |
return count == headerSize; |
2 | 177 |
} |
178 |
||
100
01ef29ca378f
6447412: Issue with socket.close() for ssl sockets when poweroff on other system
xuelei
parents:
2
diff
changeset
|
179 |
/* |
16067 | 180 |
* Return true if the record is of a given alert. |
100
01ef29ca378f
6447412: Issue with socket.close() for ssl sockets when poweroff on other system
xuelei
parents:
2
diff
changeset
|
181 |
*/ |
01ef29ca378f
6447412: Issue with socket.close() for ssl sockets when poweroff on other system
xuelei
parents:
2
diff
changeset
|
182 |
boolean isAlert(byte description) { |
16067 | 183 |
// An alert is defined with a two bytes struct, |
184 |
// {byte level, byte description}, following after the header bytes. |
|
185 |
if (count > (headerSize + 1) && contentType == ct_alert) { |
|
186 |
return buf[headerSize + 1] == description; |
|
100
01ef29ca378f
6447412: Issue with socket.close() for ssl sockets when poweroff on other system
xuelei
parents:
2
diff
changeset
|
187 |
} |
01ef29ca378f
6447412: Issue with socket.close() for ssl sockets when poweroff on other system
xuelei
parents:
2
diff
changeset
|
188 |
|
01ef29ca378f
6447412: Issue with socket.close() for ssl sockets when poweroff on other system
xuelei
parents:
2
diff
changeset
|
189 |
return false; |
01ef29ca378f
6447412: Issue with socket.close() for ssl sockets when poweroff on other system
xuelei
parents:
2
diff
changeset
|
190 |
} |
2 | 191 |
|
192 |
/* |
|
16067 | 193 |
* Compute the MAC and append it to this record. In case we |
194 |
* are automatically flushing a handshake stream, make sure we |
|
195 |
* have hashed the message first. |
|
2 | 196 |
*/ |
16067 | 197 |
void addMAC(MAC signer) throws IOException { |
2 | 198 |
// |
199 |
// when we support compression, hashing can't go here |
|
200 |
// since it'll need to be done on the uncompressed data, |
|
201 |
// and the MAC applies to the compressed data. |
|
16067 | 202 |
// |
2 | 203 |
if (contentType == ct_handshake) { |
204 |
doHashes(); |
|
205 |
} |
|
16067 | 206 |
if (signer.MAClen() != 0) { |
207 |
byte[] hash = signer.compute(contentType, buf, |
|
208 |
headerSize, count - headerSize); |
|
209 |
write(hash); |
|
2 | 210 |
} |
211 |
} |
|
212 |
||
213 |
/* |
|
16067 | 214 |
* Encrypt ... length may grow due to block cipher padding |
215 |
*/ |
|
216 |
void encrypt(CipherBox box) { |
|
217 |
int len = count - headerSize; |
|
218 |
count = headerSize + box.encrypt(buf, headerSize, len); |
|
219 |
} |
|
220 |
||
221 |
||
222 |
/* |
|
2 | 223 |
* Tell how full the buffer is ... for filling it with application or |
224 |
* handshake data. |
|
225 |
*/ |
|
226 |
final int availableDataBytes() { |
|
16067 | 227 |
int dataSize = count - headerSize; |
2 | 228 |
return maxDataSize - dataSize; |
229 |
} |
|
230 |
||
231 |
/* |
|
12428 | 232 |
* Increases the capacity if necessary to ensure that it can hold |
233 |
* at least the number of elements specified by the minimum |
|
234 |
* capacity argument. |
|
235 |
* |
|
236 |
* Note that the increased capacity is only can be used for held |
|
237 |
* record buffer. Please DO NOT update the availableDataBytes() |
|
238 |
* according to the expended buffer capacity. |
|
239 |
* |
|
240 |
* @see availableDataBytes() |
|
241 |
*/ |
|
242 |
private void ensureCapacity(int minCapacity) { |
|
243 |
// overflow-conscious code |
|
244 |
if (minCapacity > buf.length) { |
|
245 |
buf = Arrays.copyOf(buf, minCapacity); |
|
246 |
} |
|
247 |
} |
|
248 |
||
249 |
/* |
|
2 | 250 |
* Return the type of SSL record that's buffered here. |
251 |
*/ |
|
252 |
final byte contentType() { |
|
253 |
return contentType; |
|
254 |
} |
|
255 |
||
256 |
/* |
|
257 |
* Write the record out on the stream. Note that you must have (in |
|
258 |
* order) compressed the data, appended the MAC, and encrypted it in |
|
259 |
* order for the record to be understood by the other end. (Some of |
|
260 |
* those steps will be null early in handshaking.) |
|
261 |
* |
|
262 |
* Note that this does no locking for the connection, it's required |
|
263 |
* that synchronization be done elsewhere. Also, this does its work |
|
264 |
* in a single low level write, for efficiency. |
|
265 |
*/ |
|
12428 | 266 |
void write(OutputStream s, boolean holdRecord, |
267 |
ByteArrayOutputStream heldRecordBuffer) throws IOException { |
|
268 |
||
2 | 269 |
/* |
270 |
* Don't emit content-free records. (Even change cipher spec |
|
271 |
* messages have a byte of data!) |
|
272 |
*/ |
|
16067 | 273 |
if (count == headerSize) { |
2 | 274 |
return; |
275 |
} |
|
276 |
||
16067 | 277 |
int length = count - headerSize; |
2 | 278 |
// "should" really never write more than about 14 Kb... |
279 |
if (length < 0) { |
|
280 |
throw new SSLException("output record size too small: " |
|
281 |
+ length); |
|
282 |
} |
|
283 |
||
284 |
if (debug != null |
|
285 |
&& (Debug.isOn("record") || Debug.isOn("handshake"))) { |
|
286 |
if ((debug != null && Debug.isOn("record")) |
|
287 |
|| contentType() == ct_change_cipher_spec) |
|
288 |
System.out.println(Thread.currentThread().getName() |
|
289 |
// v3.0/v3.1 ... |
|
290 |
+ ", WRITE: " + protocolVersion |
|
291 |
+ " " + InputRecord.contentName(contentType()) |
|
292 |
+ ", length = " + length); |
|
293 |
} |
|
294 |
||
295 |
/* |
|
296 |
* If this is the initial ClientHello on this connection and |
|
297 |
* we're not trying to resume a (V3) session then send a V2 |
|
298 |
* ClientHello instead so we can detect V2 servers cleanly. |
|
299 |
*/ |
|
300 |
if (firstMessage && useV2Hello()) { |
|
301 |
byte[] v3Msg = new byte[length - 4]; |
|
16067 | 302 |
System.arraycopy(buf, headerSize + 4, v3Msg, 0, v3Msg.length); |
2 | 303 |
V3toV2ClientHello(v3Msg); |
304 |
handshakeHash.reset(); |
|
305 |
lastHashed = 2; |
|
306 |
doHashes(); |
|
307 |
if (debug != null && Debug.isOn("record")) { |
|
308 |
System.out.println( |
|
309 |
Thread.currentThread().getName() |
|
310 |
+ ", WRITE: SSLv2 client hello message" |
|
311 |
+ ", length = " + (count - 2)); // 2 byte SSLv2 header |
|
312 |
} |
|
313 |
} else { |
|
314 |
/* |
|
315 |
* Fill out the header, write it and the message. |
|
316 |
*/ |
|
16067 | 317 |
buf[0] = contentType; |
318 |
buf[1] = protocolVersion.major; |
|
319 |
buf[2] = protocolVersion.minor; |
|
320 |
buf[3] = (byte)(length >> 8); |
|
321 |
buf[4] = (byte)(length); |
|
2 | 322 |
} |
323 |
firstMessage = false; |
|
324 |
||
12428 | 325 |
/* |
326 |
* The upper levels may want us to delay sending this packet so |
|
327 |
* multiple TLS Records can be sent in one (or more) TCP packets. |
|
328 |
* If so, add this packet to the heldRecordBuffer. |
|
329 |
* |
|
330 |
* NOTE: all writes have been synchronized by upper levels. |
|
331 |
*/ |
|
332 |
int debugOffset = 0; |
|
333 |
if (holdRecord) { |
|
334 |
/* |
|
335 |
* If holdRecord is true, we must have a heldRecordBuffer. |
|
336 |
* |
|
337 |
* Don't worry about the override of writeBuffer(), because |
|
338 |
* when holdRecord is true, the implementation in this class |
|
339 |
* will be used. |
|
340 |
*/ |
|
16067 | 341 |
writeBuffer(heldRecordBuffer, buf, 0, count, debugOffset); |
12428 | 342 |
} else { |
343 |
// It's time to send, do we have buffered data? |
|
344 |
// May or may not have a heldRecordBuffer. |
|
345 |
if (heldRecordBuffer != null && heldRecordBuffer.size() > 0) { |
|
346 |
int heldLen = heldRecordBuffer.size(); |
|
347 |
||
348 |
// Ensure the capacity of this buffer. |
|
16067 | 349 |
ensureCapacity(count + heldLen); |
12428 | 350 |
|
351 |
// Slide everything in the buffer to the right. |
|
16067 | 352 |
System.arraycopy(buf, 0, buf, heldLen, count); |
12428 | 353 |
|
354 |
// Prepend the held record to the buffer. |
|
355 |
System.arraycopy( |
|
356 |
heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen); |
|
16067 | 357 |
count += heldLen; |
12428 | 358 |
|
359 |
// Clear the held buffer. |
|
360 |
heldRecordBuffer.reset(); |
|
361 |
||
362 |
// The held buffer has been dumped, set the debug dump offset. |
|
363 |
debugOffset = heldLen; |
|
364 |
} |
|
16067 | 365 |
writeBuffer(s, buf, 0, count, debugOffset); |
12428 | 366 |
} |
367 |
||
2 | 368 |
reset(); |
369 |
} |
|
370 |
||
371 |
/* |
|
372 |
* Actually do the write here. For SSLEngine's HS data, |
|
373 |
* we'll override this method and let it take the appropriate |
|
374 |
* action. |
|
375 |
*/ |
|
12428 | 376 |
void writeBuffer(OutputStream s, byte [] buf, int off, int len, |
377 |
int debugOffset) throws IOException { |
|
2 | 378 |
s.write(buf, off, len); |
379 |
s.flush(); |
|
380 |
||
12428 | 381 |
// Output only the record from the specified debug offset. |
2 | 382 |
if (debug != null && Debug.isOn("packet")) { |
383 |
try { |
|
384 |
HexDumpEncoder hd = new HexDumpEncoder(); |
|
16067 | 385 |
ByteBuffer bb = ByteBuffer.wrap( |
386 |
buf, off + debugOffset, len - debugOffset); |
|
2 | 387 |
|
388 |
System.out.println("[Raw write]: length = " + |
|
16067 | 389 |
bb.remaining()); |
390 |
hd.encodeBuffer(bb, System.out); |
|
2 | 391 |
} catch (IOException e) { } |
392 |
} |
|
393 |
} |
|
394 |
||
395 |
/* |
|
396 |
* Return whether the buffer contains a ClientHello message that should |
|
397 |
* be converted to V2 format. |
|
398 |
*/ |
|
399 |
private boolean useV2Hello() { |
|
400 |
return firstMessage |
|
401 |
&& (helloVersion == ProtocolVersion.SSL20Hello) |
|
402 |
&& (contentType == ct_handshake) |
|
16067 | 403 |
&& (buf[5] == HandshakeMessage.ht_client_hello) |
404 |
&& (buf[headerSize + 4+2+32] == 0); // V3 session ID is empty |
|
2 | 405 |
} |
406 |
||
407 |
/* |
|
408 |
* Detect "old" servers which are capable of SSL V2.0 protocol ... for |
|
409 |
* example, Netscape Commerce 1.0 servers. The V3 message is in the |
|
410 |
* header and the bytes passed as parameter. This routine translates |
|
411 |
* the V3 message into an equivalent V2 one. |
|
6856 | 412 |
* |
413 |
* Note that the translation will strip off all hello extensions as |
|
414 |
* SSL V2.0 does not support hello extension. |
|
2 | 415 |
*/ |
416 |
private void V3toV2ClientHello(byte v3Msg []) throws SSLException { |
|
417 |
int v3SessionIdLenOffset = 2 + 32; // version + nonce |
|
418 |
int v3SessionIdLen = v3Msg[v3SessionIdLenOffset]; |
|
419 |
int v3CipherSpecLenOffset = v3SessionIdLenOffset + 1 + v3SessionIdLen; |
|
420 |
int v3CipherSpecLen = ((v3Msg[v3CipherSpecLenOffset] & 0xff) << 8) + |
|
421 |
(v3Msg[v3CipherSpecLenOffset + 1] & 0xff); |
|
422 |
int cipherSpecs = v3CipherSpecLen / 2; // 2 bytes each in V3 |
|
423 |
||
424 |
/* |
|
425 |
* Copy over the cipher specs. We don't care about actually translating |
|
426 |
* them for use with an actual V2 server since we only talk V3. |
|
427 |
* Therefore, just copy over the V3 cipher spec values with a leading |
|
428 |
* 0. |
|
429 |
*/ |
|
430 |
int v3CipherSpecOffset = v3CipherSpecLenOffset + 2; // skip length |
|
431 |
int v2CipherSpecLen = 0; |
|
432 |
count = 11; |
|
6856 | 433 |
boolean containsRenegoInfoSCSV = false; |
2 | 434 |
for (int i = 0; i < cipherSpecs; i++) { |
435 |
byte byte1, byte2; |
|
436 |
||
437 |
byte1 = v3Msg[v3CipherSpecOffset++]; |
|
438 |
byte2 = v3Msg[v3CipherSpecOffset++]; |
|
439 |
v2CipherSpecLen += V3toV2CipherSuite(byte1, byte2); |
|
6856 | 440 |
if (!containsRenegoInfoSCSV && |
441 |
byte1 == (byte)0x00 && byte2 == (byte)0xFF) { |
|
442 |
containsRenegoInfoSCSV = true; |
|
443 |
} |
|
444 |
} |
|
445 |
||
446 |
if (!containsRenegoInfoSCSV) { |
|
447 |
v2CipherSpecLen += V3toV2CipherSuite((byte)0x00, (byte)0xFF); |
|
2 | 448 |
} |
449 |
||
450 |
/* |
|
451 |
* Build the first part of the V3 record header from the V2 one |
|
452 |
* that's now buffered up. (Lengths are fixed up later). |
|
453 |
*/ |
|
454 |
buf[2] = HandshakeMessage.ht_client_hello; |
|
455 |
buf[3] = v3Msg[0]; // major version |
|
456 |
buf[4] = v3Msg[1]; // minor version |
|
457 |
buf[5] = (byte)(v2CipherSpecLen >>> 8); |
|
458 |
buf[6] = (byte)v2CipherSpecLen; |
|
459 |
buf[7] = 0; |
|
460 |
buf[8] = 0; // always no session |
|
461 |
buf[9] = 0; |
|
462 |
buf[10] = 32; // nonce length (always 32 in V3) |
|
463 |
||
464 |
/* |
|
465 |
* Copy in the nonce. |
|
466 |
*/ |
|
467 |
System.arraycopy(v3Msg, 2, buf, count, 32); |
|
468 |
count += 32; |
|
469 |
||
470 |
/* |
|
471 |
* Set the length of the message. |
|
472 |
*/ |
|
473 |
count -= 2; // don't include length field itself |
|
474 |
buf[0] = (byte)(count >>> 8); |
|
475 |
buf[0] |= 0x80; |
|
476 |
buf[1] = (byte)(count); |
|
477 |
count += 2; |
|
478 |
} |
|
479 |
||
480 |
/* |
|
481 |
* Mappings from V3 cipher suite encodings to their pure V2 equivalents. |
|
482 |
* This is taken from the SSL V3 specification, Appendix E. |
|
483 |
*/ |
|
484 |
private static int[] V3toV2CipherMap1 = |
|
485 |
{-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07}; |
|
486 |
private static int[] V3toV2CipherMap3 = |
|
487 |
{-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0}; |
|
488 |
||
489 |
/* |
|
490 |
* See which matching pure-V2 cipher specs we need to include. |
|
491 |
* We are including these not because we are actually prepared |
|
492 |
* to talk V2 but because the Oracle Web Server insists on receiving |
|
493 |
* at least 1 "pure V2" cipher suite that it supports and returns an |
|
494 |
* illegal_parameter alert unless one is present. Rather than mindlessly |
|
495 |
* claiming to implement all documented pure V2 cipher suites the code below |
|
496 |
* just claims to implement the V2 cipher suite that is "equivalent" |
|
497 |
* in terms of cipher algorithm & exportability with the actual V3 cipher |
|
498 |
* suite that we do support. |
|
499 |
*/ |
|
500 |
private int V3toV2CipherSuite(byte byte1, byte byte2) { |
|
501 |
buf[count++] = 0; |
|
502 |
buf[count++] = byte1; |
|
503 |
buf[count++] = byte2; |
|
504 |
||
505 |
if (((byte2 & 0xff) > 0xA) || |
|
506 |
(V3toV2CipherMap1[byte2] == -1)) { |
|
507 |
return 3; |
|
508 |
} |
|
509 |
||
510 |
buf[count++] = (byte)V3toV2CipherMap1[byte2]; |
|
511 |
buf[count++] = 0; |
|
512 |
buf[count++] = (byte)V3toV2CipherMap3[byte2]; |
|
513 |
||
514 |
return 6; |
|
515 |
} |
|
516 |
} |