1 /*
2  * Copyright (c) 1996, 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 import java.net.SocketException;
32 import java.net.SocketTimeoutException;
33 
34 import javax.crypto.BadPaddingException;
35 
36 import javax.net.ssl.*;
37 
38 import sun.misc.HexDumpEncoder;
39 
40 
41 /**
42  * SSL 3.0 records, as pulled off a TCP stream.  Input records are
43  * basically buffers tied to a particular input stream ... a layer
44  * above this must map these records into the model of a continuous
45  * stream of data.
46  *
47  * Since this returns SSL 3.0 records, it's the layer that needs to
48  * map SSL 2.0 style handshake records into SSL 3.0 ones for those
49  * "old" clients that interop with both V2 and V3 servers.  Not as
50  * pretty as might be desired.
51  *
52  * NOTE:  During handshaking, each message must be hashed to support
53  * verification that the handshake process wasn't compromised.
54  *
55  * @author David Brownell
56  */
57 class InputRecord extends ByteArrayInputStream implements Record {
58 
59     private HandshakeHash       handshakeHash;
60     private int                 lastHashed;
61     boolean                     formatVerified = true;  // SSLv2 ruled out?
62     private boolean             isClosed;
63     private boolean             appDataValid;
64 
65     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
66     // and the first message we read is a ClientHello in V2 format, we convert
67     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
68     private ProtocolVersion     helloVersion;
69 
70     /* Class and subclass dynamic debugging support */
71     static final Debug debug = Debug.getInstance("ssl");
72 
73     /* The existing record length */
74     private int exlen;
75 
76     /* V2 handshake message */
77     private byte v2Buf[];
78 
79     /*
80      * Construct the record to hold the maximum sized input record.
81      * Data will be filled in separately.
82      */
InputRecord()83     InputRecord() {
84         super(new byte[maxRecordSize]);
85         setHelloVersion(ProtocolVersion.DEFAULT_HELLO);
86         pos = headerSize;
87         count = headerSize;
88         lastHashed = count;
89         exlen = 0;
90         v2Buf = null;
91     }
92 
setHelloVersion(ProtocolVersion helloVersion)93     void setHelloVersion(ProtocolVersion helloVersion) {
94         this.helloVersion = helloVersion;
95     }
96 
getHelloVersion()97     ProtocolVersion getHelloVersion() {
98         return helloVersion;
99     }
100 
101     /*
102      * Enable format checks if initial handshaking hasn't completed
103      */
enableFormatChecks()104     void enableFormatChecks() {
105         formatVerified = false;
106     }
107 
108     // return whether the data in this record is valid, decrypted data
isAppDataValid()109     boolean isAppDataValid() {
110         return appDataValid;
111     }
112 
setAppDataValid(boolean value)113     void setAppDataValid(boolean value) {
114         appDataValid = value;
115     }
116 
117     /*
118      * Return the content type of the record.
119      */
contentType()120     byte contentType() {
121         return buf[0];
122     }
123 
124     /*
125      * For handshaking, we need to be able to hash every byte above the
126      * record marking layer.  This is where we're guaranteed to see those
127      * bytes, so this is where we can hash them ... especially in the
128      * case of hashing the initial V2 message!
129      */
setHandshakeHash(HandshakeHash handshakeHash)130     void setHandshakeHash(HandshakeHash handshakeHash) {
131         this.handshakeHash = handshakeHash;
132     }
133 
getHandshakeHash()134     HandshakeHash getHandshakeHash() {
135         return handshakeHash;
136     }
137 
decrypt(MAC signer, CipherBox box)138     void decrypt(MAC signer, CipherBox box) throws BadPaddingException {
139 
140         BadPaddingException reservedBPE = null;
141         int tagLen = signer.MAClen();
142         int cipheredLength = count - headerSize;
143 
144         if (!box.isNullCipher()) {
145             // sanity check length of the ciphertext
146             if (!box.sanityCheck(tagLen, cipheredLength)) {
147                 throw new BadPaddingException(
148                     "ciphertext sanity check failed");
149             }
150 
151             try {
152                 // Note that the CipherBox.decrypt() does not change
153                 // the capacity of the buffer.
154                 count = headerSize +
155                         box.decrypt(buf, headerSize, cipheredLength, tagLen);
156             } catch (BadPaddingException bpe) {
157                 // RFC 2246 states that decryption_failed should be used
158                 // for this purpose. However, that allows certain attacks,
159                 // so we just send bad record MAC. We also need to make
160                 // sure to always check the MAC to avoid a timing attack
161                 // for the same issue. See paper by Vaudenay et al and the
162                 // update in RFC 4346/5246.
163                 //
164                 // Failover to message authentication code checking.
165                 reservedBPE = bpe;
166             }
167         }
168 
169         if (tagLen != 0) {
170             int macOffset = count - tagLen;
171             int contentLen = macOffset - headerSize;
172 
173             // Note that although it is not necessary, we run the same MAC
174             // computation and comparison on the payload for both stream
175             // cipher and CBC block cipher.
176             if (contentLen < 0) {
177                 // negative data length, something is wrong
178                 if (reservedBPE == null) {
179                     reservedBPE = new BadPaddingException("bad record");
180                 }
181 
182                 // set offset of the dummy MAC
183                 macOffset = headerSize + cipheredLength - tagLen;
184                 contentLen = macOffset - headerSize;
185             }
186 
187             count -= tagLen;  // Set the count before any MAC checking
188                               // exception occurs, so that the following
189                               // process can read the actual decrypted
190                               // content (minus the MAC) in the fragment
191                               // if necessary.
192 
193             // Run MAC computation and comparison on the payload.
194             if (checkMacTags(contentType(),
195                     buf, headerSize, contentLen, signer, false)) {
196                 if (reservedBPE == null) {
197                     reservedBPE = new BadPaddingException("bad record MAC");
198                 }
199             }
200 
201             // Run MAC computation and comparison on the remainder.
202             //
203             // It is only necessary for CBC block cipher.  It is used to get a
204             // constant time of MAC computation and comparison on each record.
205             if (box.isCBCMode()) {
206                 int remainingLen = calculateRemainingLen(
207                                         signer, cipheredLength, contentLen);
208 
209                 // NOTE: remainingLen may be bigger (less than 1 block of the
210                 // hash algorithm of the MAC) than the cipheredLength. However,
211                 // We won't need to worry about it because we always use a
212                 // maximum buffer for every record.  We need a change here if
213                 // we use small buffer size in the future.
214                 if (remainingLen > buf.length) {
215                     // unlikely to happen, just a placehold
216                     throw new RuntimeException(
217                         "Internal buffer capacity error");
218                 }
219 
220                 // Won't need to worry about the result on the remainder. And
221                 // then we won't need to worry about what's actual data to
222                 // check MAC tag on.  We start the check from the header of the
223                 // buffer so that we don't need to construct a new byte buffer.
224                 checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
225             }
226         }
227 
228         // Is it a failover?
229         if (reservedBPE != null) {
230             throw reservedBPE;
231         }
232     }
233 
234     /*
235      * Run MAC computation and comparison
236      *
237      * Please DON'T change the content of the byte buffer parameter!
238      */
checkMacTags(byte contentType, byte[] buffer, int offset, int contentLen, MAC signer, boolean isSimulated)239     static boolean checkMacTags(byte contentType, byte[] buffer,
240             int offset, int contentLen, MAC signer, boolean isSimulated) {
241 
242         int tagLen = signer.MAClen();
243         byte[] hash = signer.compute(
244                 contentType, buffer, offset, contentLen, isSimulated);
245         if (hash == null || tagLen != hash.length) {
246             // Something is wrong with MAC implementation.
247             throw new RuntimeException("Internal MAC error");
248         }
249 
250         int[] results = compareMacTags(buffer, offset + contentLen, hash);
251         return (results[0] != 0);
252     }
253 
254     /*
255      * A constant-time comparison of the MAC tags.
256      *
257      * Please DON'T change the content of the byte buffer parameter!
258      */
compareMacTags( byte[] buffer, int offset, byte[] tag)259     private static int[] compareMacTags(
260             byte[] buffer, int offset, byte[] tag) {
261 
262         // An array of hits is used to prevent Hotspot optimization for
263         // the purpose of a constant-time check.
264         int[] results = {0, 0};    // {missed #, matched #}
265 
266         // The caller ensures there are enough bytes available in the buffer.
267         // So we won't need to check the length of the buffer.
268         for (int i = 0; i < tag.length; i++) {
269             if (buffer[offset + i] != tag[i]) {
270                 results[0]++;       // mismatched bytes
271             } else {
272                 results[1]++;       // matched bytes
273             }
274         }
275 
276         return results;
277     }
278 
279     /*
280      * Calculate the length of a dummy buffer to run MAC computation
281      * and comparison on the remainder.
282      *
283      * The caller MUST ensure that the fullLen is not less than usedLen.
284      */
calculateRemainingLen( MAC signer, int fullLen, int usedLen)285     static int calculateRemainingLen(
286             MAC signer, int fullLen, int usedLen) {
287 
288         int blockLen = signer.hashBlockLen();
289         int minimalPaddingLen = signer.minimalPaddingLen();
290 
291         // (blockLen - minimalPaddingLen) is the maximum message size of
292         // the last block of hash function operation. See FIPS 180-4, or
293         // MD5 specification.
294         fullLen += 13 - (blockLen - minimalPaddingLen);
295         usedLen += 13 - (blockLen - minimalPaddingLen);
296 
297         // Note: fullLen is always not less than usedLen, and blockLen
298         // is always bigger than minimalPaddingLen, so we don't worry
299         // about negative values. 0x01 is added to the result to ensure
300         // that the return value is positive.  The extra one byte does
301         // not impact the overall MAC compression function evaluations.
302         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
303                 Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen();
304     }
305 
306     /*
307      * Well ... hello_request messages are _never_ hashed since we can't
308      * know when they'd appear in the sequence.
309      */
ignore(int bytes)310     void ignore(int bytes) {
311         if (bytes > 0) {
312             pos += bytes;
313             lastHashed = pos;
314         }
315     }
316 
317     /*
318      * We hash the (plaintext) we've processed, but only on demand.
319      *
320      * There is one place where we want to access the hash in the middle
321      * of a record:  client cert message gets hashed, and part of the
322      * same record is the client cert verify message which uses that hash.
323      * So we track how much we've read and hashed.
324      */
doHashes()325     void doHashes() {
326         int len = pos - lastHashed;
327 
328         if (len > 0) {
329             hashInternal(buf, lastHashed, len);
330             lastHashed = pos;
331         }
332     }
333 
334     /*
335      * Need a helper function so we can hash the V2 hello correctly
336      */
hashInternal(byte databuf [], int offset, int len)337     private void hashInternal(byte databuf [], int offset, int len) {
338         if (debug != null && Debug.isOn("data")) {
339             try {
340                 HexDumpEncoder hd = new HexDumpEncoder();
341 
342                 System.out.println("[read] MD5 and SHA1 hashes:  len = "
343                     + len);
344                 hd.encodeBuffer(new ByteArrayInputStream(databuf, offset, len),
345                     System.out);
346             } catch (IOException e) { }
347         }
348         handshakeHash.update(databuf, offset, len);
349     }
350 
351 
352     /*
353      * Handshake messages may cross record boundaries.  We "queue"
354      * these in big buffers if we need to cope with this problem.
355      * This is not anticipated to be a common case; if this turns
356      * out to be wrong, this can readily be sped up.
357      */
queueHandshake(InputRecord r)358     void queueHandshake(InputRecord r) throws IOException {
359         int len;
360 
361         /*
362          * Hash any data that's read but unhashed.
363          */
364         doHashes();
365 
366         /*
367          * Move any unread data to the front of the buffer,
368          * flagging it all as unhashed.
369          */
370         if (pos > headerSize) {
371             len = count - pos;
372             if (len != 0) {
373                 System.arraycopy(buf, pos, buf, headerSize, len);
374             }
375             pos = headerSize;
376             lastHashed = pos;
377             count = headerSize + len;
378         }
379 
380         /*
381          * Grow "buf" if needed
382          */
383         len = r.available() + count;
384         if (buf.length < len) {
385             byte        newbuf [];
386 
387             newbuf = new byte [len];
388             System.arraycopy(buf, 0, newbuf, 0, count);
389             buf = newbuf;
390         }
391 
392         /*
393          * Append the new buffer to this one.
394          */
395         System.arraycopy(r.buf, r.pos, buf, count, len - count);
396         count = len;
397 
398         /*
399          * Adjust lastHashed; important for now with clients which
400          * send SSL V2 client hellos.  This will go away eventually,
401          * by buffer code cleanup.
402          */
403         len = r.lastHashed - r.pos;
404         if (pos == headerSize) {
405             lastHashed += len;
406         } else {
407             throw new SSLProtocolException("?? confused buffer hashing ??");
408         }
409         // we've read the record, advance the pointers
410         r.pos = r.count;
411     }
412 
413 
414     /**
415      * Prevent any more data from being read into this record,
416      * and flag the record as holding no data.
417      */
close()418     public void close() {
419         appDataValid = false;
420         isClosed = true;
421         mark = 0;
422         pos = 0;
423         count = 0;
424     }
425 
426 
427     /*
428      * We may need to send this SSL v2 "No Cipher" message back, if we
429      * are faced with an SSLv2 "hello" that's not saying "I talk v3".
430      * It's the only one documented in the V2 spec as a fatal error.
431      */
432     private static final byte[] v2NoCipher = {
433         (byte)0x80, (byte)0x03, // unpadded 3 byte record
434         (byte)0x00,             // ... error message
435         (byte)0x00, (byte)0x01  // ... NO_CIPHER error
436     };
437 
readFully(InputStream s, byte b[], int off, int len)438     private int readFully(InputStream s, byte b[], int off, int len)
439             throws IOException {
440         int n = 0;
441         while (n < len) {
442             int readLen = s.read(b, off + n, len - n);
443             if (readLen < 0) {
444                 return readLen;
445             }
446 
447             if (debug != null && Debug.isOn("packet")) {
448                 try {
449                     HexDumpEncoder hd = new HexDumpEncoder();
450                     ByteBuffer bb = ByteBuffer.wrap(b, off + n, readLen);
451 
452                     System.out.println("[Raw read]: length = " +
453                         bb.remaining());
454                     hd.encodeBuffer(bb, System.out);
455                 } catch (IOException e) { }
456             }
457 
458             n += readLen;
459             exlen += readLen;
460         }
461 
462         return n;
463     }
464 
465     /*
466      * Read the SSL V3 record ... first time around, check to see if it
467      * really IS a V3 record.  Handle SSL V2 clients which can talk V3.0,
468      * as well as real V3 record format; otherwise report an error.
469      */
read(InputStream s, OutputStream o)470     void read(InputStream s, OutputStream o) throws IOException {
471         if (isClosed) {
472             return;
473         }
474 
475         /*
476          * For SSL it really _is_ an error if the other end went away
477          * so ungracefully as to not shut down cleanly.
478          */
479         if(exlen < headerSize) {
480             int really = readFully(s, buf, exlen, headerSize - exlen);
481             if (really < 0) {
482                 throw new EOFException("SSL peer shut down incorrectly");
483             }
484 
485             pos = headerSize;
486             count = headerSize;
487             lastHashed = pos;
488         }
489 
490         /*
491          * The first record might use some other record marking convention,
492          * typically SSL v2 header.  (PCT could also be detected here.)
493          * This case is currently common -- Navigator 3.0 usually works
494          * this way, as do IE 3.0 and other products.
495          */
496         if (!formatVerified) {
497             formatVerified = true;
498             /*
499              * The first record must either be a handshake record or an
500              * alert message. If it's not, it is either invalid or an
501              * SSLv2 message.
502              */
503             if (buf[0] != ct_handshake && buf[0] != ct_alert) {
504                 handleUnknownRecord(s, o);
505             } else {
506                 readV3Record(s, o);
507             }
508         } else { // formatVerified == true
509             readV3Record(s, o);
510         }
511     }
512 
513     /**
514      * Read a SSL/TLS record. Throw an IOException if the format is invalid.
515      */
readV3Record(InputStream s, OutputStream o)516     private void readV3Record(InputStream s, OutputStream o)
517             throws IOException {
518         ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]);
519         // Check if too old (currently not possible)
520         // or if the major version does not match.
521         // The actual version negotiation is in the handshaker classes
522         if ((recordVersion.v < ProtocolVersion.MIN.v)
523                 || (recordVersion.major > ProtocolVersion.MAX.major)) {
524             throw new SSLException(
525                 "Unsupported record version " + recordVersion);
526         }
527 
528         /*
529          * Get and check length, then the data.
530          */
531         int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff);
532 
533         /*
534          * Check for upper bound.
535          */
536         if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
537             throw new SSLProtocolException("Bad InputRecord size"
538                 + ", count = " + contentLen
539                 + ", buf.length = " + buf.length);
540         }
541 
542         /*
543          * Grow "buf" if needed. Since buf is maxRecordSize by default,
544          * this only occurs when we receive records which violate the
545          * SSL specification. This is a workaround for a Microsoft SSL bug.
546          */
547         if (contentLen > buf.length - headerSize) {
548             byte[] newbuf = new byte[contentLen + headerSize];
549             System.arraycopy(buf, 0, newbuf, 0, headerSize);
550             buf = newbuf;
551         }
552 
553         if (exlen < contentLen + headerSize) {
554             int really = readFully(
555                 s, buf, exlen, contentLen + headerSize - exlen);
556             if (really < 0) {
557                 throw new SSLException("SSL peer shut down incorrectly");
558             }
559         }
560 
561         // now we've got a complete record.
562         count = contentLen + headerSize;
563         exlen = 0;
564 
565         if (debug != null && Debug.isOn("record")) {
566             if (count < 0 || count > (maxRecordSize - headerSize)) {
567                 System.out.println(Thread.currentThread().getName()
568                     + ", Bad InputRecord size" + ", count = " + count);
569             }
570             System.out.println(Thread.currentThread().getName()
571                 + ", READ: " + recordVersion + " "
572                 + contentName(contentType()) + ", length = " + available());
573         }
574         /*
575          * then caller decrypts, verifies, and uncompresses
576          */
577     }
578 
579     /**
580      * Deal with unknown records. Called if the first data we read on this
581      * connection does not look like an SSL/TLS record. It could a SSLv2
582      * message, or just garbage.
583      */
handleUnknownRecord(InputStream s, OutputStream o)584     private void handleUnknownRecord(InputStream s, OutputStream o)
585             throws IOException {
586         /*
587          * No?  Oh well; does it look like a V2 "ClientHello"?
588          * That'd be an unpadded handshake message; we don't
589          * bother checking length just now.
590          */
591         if (((buf[0] & 0x080) != 0) && buf[2] == 1) {
592             /*
593              * if the user has disabled SSLv2Hello (using
594              * setEnabledProtocol) then throw an
595              * exception
596              */
597             if (helloVersion != ProtocolVersion.SSL20Hello) {
598                 throw new SSLHandshakeException("SSLv2Hello is disabled");
599             }
600 
601             ProtocolVersion recordVersion =
602                                 ProtocolVersion.valueOf(buf[3], buf[4]);
603 
604             if (recordVersion == ProtocolVersion.SSL20Hello) {
605                 /*
606                  * Looks like a V2 client hello, but not one saying
607                  * "let's talk SSLv3".  So we send an SSLv2 error
608                  * message, one that's treated as fatal by clients.
609                  * (Otherwise we'll hang.)
610                  */
611                 try {
612                     writeBuffer(o, v2NoCipher, 0, v2NoCipher.length);
613                 } catch (Exception e) {
614                     /* NOTHING */
615                 }
616                 throw new SSLException("Unsupported SSL v2.0 ClientHello");
617             }
618 
619             /*
620              * If we can map this into a V3 ClientHello, read and
621              * hash the rest of the V2 handshake, turn it into a
622              * V3 ClientHello message, and pass it up.
623              */
624             int len = ((buf[0] & 0x7f) << 8) +
625                 (buf[1] & 0xff) - 3;
626             if (v2Buf == null) {
627                 v2Buf = new byte[len];
628             }
629             if (exlen < len + headerSize) {
630                 int really = readFully(
631                         s, v2Buf, exlen - headerSize, len + headerSize - exlen);
632                 if (really < 0) {
633                     throw new EOFException("SSL peer shut down incorrectly");
634                 }
635             }
636 
637             // now we've got a complete record.
638             exlen = 0;
639 
640             hashInternal(buf, 2, 3);
641             hashInternal(v2Buf, 0, len);
642             V2toV3ClientHello(v2Buf);
643             v2Buf = null;
644             lastHashed = count;
645 
646             if (debug != null && Debug.isOn("record"))  {
647                 System.out.println(
648                     Thread.currentThread().getName()
649                     + ", READ:  SSL v2, contentType = "
650                     + contentName(contentType())
651                     + ", translated length = " + available());
652             }
653             return;
654 
655         } else {
656             /*
657              * Does it look like a V2 "ServerHello"?
658              */
659             if (((buf [0] & 0x080) != 0) && buf [2] == 4) {
660                 throw new SSLException(
661                     "SSL V2.0 servers are not supported.");
662             }
663 
664             /*
665              * If this is a V2 NoCipher message then this means
666              * the other server doesn't support V3. Otherwise, we just
667              * don't understand what it's saying.
668              */
669             for (int i = 0; i < v2NoCipher.length; i++) {
670                 if (buf[i] != v2NoCipher[i]) {
671                     throw new SSLException(
672                         "Unrecognized SSL message, plaintext connection?");
673                 }
674             }
675 
676             throw new SSLException("SSL V2.0 servers are not supported.");
677         }
678     }
679 
680     /*
681      * Actually do the write here.  For SSLEngine's HS data,
682      * we'll override this method and let it take the appropriate
683      * action.
684      */
writeBuffer(OutputStream s, byte [] buf, int off, int len)685     void writeBuffer(OutputStream s, byte [] buf, int off, int len)
686             throws IOException {
687         s.write(buf, 0, len);
688         s.flush();
689     }
690 
691     /*
692      * Support "old" clients which are capable of SSL V3.0 protocol ... for
693      * example, Navigator 3.0 clients.  The V2 message is in the header and
694      * the bytes passed as parameter.  This routine translates the V2 message
695      * into an equivalent V3 one.
696      */
V2toV3ClientHello(byte v2Msg [])697     private void V2toV3ClientHello(byte v2Msg []) throws SSLException
698     {
699         int i;
700 
701         /*
702          * Build the first part of the V3 record header from the V2 one
703          * that's now buffered up.  (Lengths are fixed up later).
704          */
705         buf [0] = ct_handshake;
706         buf [1] = buf [3];      // V3.x
707         buf[2] = buf[4];
708         // header [3..4] for handshake message length
709         // count = 5;
710 
711         /*
712          * Store the generic V3 handshake header:  4 bytes
713          */
714         buf [5] = 1;    // HandshakeMessage.ht_client_hello
715         // buf [6..8] for length of ClientHello (int24)
716         // count += 4;
717 
718         /*
719          * ClientHello header starts with SSL version
720          */
721         buf [9] = buf [1];
722         buf [10] = buf [2];
723         // count += 2;
724         count = 11;
725 
726         /*
727          * Start parsing the V2 message ...
728          */
729         int      cipherSpecLen, sessionIdLen, nonceLen;
730 
731         cipherSpecLen = ((v2Msg [0] & 0xff) << 8) + (v2Msg [1] & 0xff);
732         sessionIdLen  = ((v2Msg [2] & 0xff) << 8) + (v2Msg [3] & 0xff);
733         nonceLen   = ((v2Msg [4] & 0xff) << 8) + (v2Msg [5] & 0xff);
734 
735         /*
736          * Copy Random value/nonce ... if less than the 32 bytes of
737          * a V3 "Random", right justify and zero pad to the left.  Else
738          * just take the last 32 bytes.
739          */
740         int      offset = 6 + cipherSpecLen + sessionIdLen;
741 
742         if (nonceLen < 32) {
743             for (i = 0; i < (32 - nonceLen); i++)
744                 buf [count++] = 0;
745             System.arraycopy(v2Msg, offset, buf, count, nonceLen);
746             count += nonceLen;
747         } else {
748             System.arraycopy(v2Msg, offset + (nonceLen - 32),
749                     buf, count, 32);
750             count += 32;
751         }
752 
753         /*
754          * Copy Session ID (only one byte length!)
755          */
756         offset -= sessionIdLen;
757         buf [count++] = (byte) sessionIdLen;
758 
759         System.arraycopy(v2Msg, offset, buf, count, sessionIdLen);
760         count += sessionIdLen;
761 
762         /*
763          * Copy and translate cipher suites ... V2 specs with first byte zero
764          * are really V3 specs (in the last 2 bytes), just copy those and drop
765          * the other ones.  Preference order remains unchanged.
766          *
767          * Example:  Netscape Navigator 3.0 (exportable) says:
768          *
769          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
770          * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
771          *
772          * Microsoft Internet Explorer 3.0 (exportable) supports only
773          *
774          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
775          */
776         int j;
777 
778         offset -= cipherSpecLen;
779         j = count + 2;
780 
781         for (i = 0; i < cipherSpecLen; i += 3) {
782             if (v2Msg [offset + i] != 0)
783                 continue;
784             buf [j++] = v2Msg [offset + i + 1];
785             buf [j++] = v2Msg [offset + i + 2];
786         }
787 
788         j -= count + 2;
789         buf [count++] = (byte) (j >>> 8);
790         buf [count++] = (byte) j;
791         count += j;
792 
793         /*
794          * Append compression methods (default/null only)
795          */
796         buf [count++] = 1;
797         buf [count++] = 0;      // Session.compression_null
798 
799         /*
800          * Fill in lengths of the messages we synthesized (nested:
801          * V3 handshake message within V3 record) and then return
802          */
803         buf [3] = (byte) (count - headerSize);
804         buf [4] = (byte) ((count - headerSize) >>> 8);
805 
806         buf [headerSize + 1] = 0;
807         buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8);
808         buf [headerSize + 3] = (byte) ((count - headerSize) - 4);
809 
810         pos = headerSize;
811     }
812 
813     /**
814      * Return a description for the given content type. This method should be
815      * in Record, but since that is an interface this is not possible.
816      * Called from InputRecord and OutputRecord.
817      */
contentName(int contentType)818     static String contentName(int contentType) {
819         switch (contentType) {
820         case ct_change_cipher_spec:
821             return "Change Cipher Spec";
822         case ct_alert:
823             return "Alert";
824         case ct_handshake:
825             return "Handshake";
826         case ct_application_data:
827             return "Application Data";
828         default:
829             return "contentType = " + contentType;
830         }
831     }
832 
833 }
834