1/*
2 * Copyright (c) 1996, 2014, 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
26package sun.security.ssl;
27
28import java.io.*;
29import java.nio.*;
30import java.util.*;
31
32import javax.crypto.BadPaddingException;
33
34import javax.net.ssl.*;
35
36import sun.security.util.HexDumpEncoder;
37
38
39/**
40 * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input
41 * records, including buffering, decryption, handshake messages marshal, etc.
42 *
43 * @author David Brownell
44 */
45class InputRecord implements Record, Closeable {
46
47    /* Class and subclass dynamic debugging support */
48    static final Debug debug = Debug.getInstance("ssl");
49
50    Authenticator       readAuthenticator;
51    CipherBox           readCipher;
52
53    HandshakeHash       handshakeHash;
54    boolean             isClosed;
55
56    // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
57    // and the first message we read is a ClientHello in V2 format, we convert
58    // it to V3. Otherwise we throw an exception when encountering a V2 hello.
59    ProtocolVersion     helloVersion;
60
61    // fragment size
62    int                 fragmentSize;
63
64    InputRecord() {
65        this.readCipher = CipherBox.NULL;
66        this.readAuthenticator = null;      // Please override this assignment.
67        this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
68        this.fragmentSize = Record.maxDataSize;
69    }
70
71    void setHelloVersion(ProtocolVersion helloVersion) {
72        this.helloVersion = helloVersion;
73    }
74
75    ProtocolVersion getHelloVersion() {
76        return helloVersion;
77    }
78
79    /*
80     * Set instance for the computation of handshake hashes.
81     *
82     * For handshaking, we need to be able to hash every byte above the
83     * record marking layer.  This is where we're guaranteed to see those
84     * bytes, so this is where we can hash them ... especially in the
85     * case of hashing the initial V2 message!
86     */
87    void setHandshakeHash(HandshakeHash handshakeHash) {
88        if (handshakeHash != null) {
89            byte[] reserved = null;
90            if (this.handshakeHash != null) {
91                reserved = this.handshakeHash.getAllHandshakeMessages();
92            }
93            if ((reserved != null) && (reserved.length != 0)) {
94                handshakeHash.update(reserved, 0, reserved.length);
95
96               if (debug != null && Debug.isOn("data")) {
97                    Debug.printHex(
98                        "[reserved] handshake hash: len = " + reserved.length,
99                        reserved);
100               }
101            }
102        }
103
104        this.handshakeHash = handshakeHash;
105    }
106
107    boolean seqNumIsHuge() {
108        return (readAuthenticator != null) &&
109                        readAuthenticator.seqNumIsHuge();
110    }
111
112    boolean isEmpty() {
113        return false;
114    }
115
116    // apply to DTLS SSLEngine
117    void expectingFinishFlight() {
118        // blank
119    }
120
121    /**
122     * Prevent any more data from being read into this record,
123     * and flag the record as holding no data.
124     */
125    @Override
126    public synchronized void close() throws IOException {
127        if (!isClosed) {
128            isClosed = true;
129            readCipher.dispose();
130        }
131    }
132
133    // apply to SSLSocket and SSLEngine
134    void changeReadCiphers(
135            Authenticator readAuthenticator, CipherBox readCipher) {
136
137        /*
138         * Dispose of any intermediate state in the underlying cipher.
139         * For PKCS11 ciphers, this will release any attached sessions,
140         * and thus make finalization faster.
141         *
142         * Since MAC's doFinal() is called for every SSL/TLS packet, it's
143         * not necessary to do the same with MAC's.
144         */
145        readCipher.dispose();
146
147        this.readAuthenticator = readAuthenticator;
148        this.readCipher = readCipher;
149    }
150
151    // change fragment size
152    void changeFragmentSize(int fragmentSize) {
153        this.fragmentSize = fragmentSize;
154    }
155
156    /*
157     * Check if there is enough inbound data in the ByteBuffer to make
158     * a inbound packet.
159     *
160     * @return -1 if there are not enough bytes to tell (small header),
161     */
162    // apply to SSLEngine only
163    int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
164        throw new UnsupportedOperationException();
165    }
166
167    // apply to SSLSocket only
168    int bytesInCompletePacket(InputStream is) throws IOException {
169        throw new UnsupportedOperationException();
170    }
171
172    /**
173     * Return true if the specified record protocol version is out of the
174     * range of the possible supported versions.
175     */
176    void checkRecordVersion(ProtocolVersion version,
177            boolean allowSSL20Hello) throws SSLException {
178        // blank
179    }
180
181    // apply to DTLS SSLEngine only
182    Plaintext acquirePlaintext()
183            throws IOException, BadPaddingException {
184        throw new UnsupportedOperationException();
185    }
186
187    // read, decrypt and decompress the network record.
188    //
189    // apply to SSLEngine only
190    Plaintext decode(ByteBuffer netData)
191            throws IOException, BadPaddingException {
192        throw new UnsupportedOperationException();
193    }
194
195    // apply to SSLSocket only
196    Plaintext decode(InputStream is, ByteBuffer destination)
197            throws IOException, BadPaddingException {
198        throw new UnsupportedOperationException();
199    }
200
201    // apply to SSLSocket only
202    void setDeliverStream(OutputStream outputStream) {
203        throw new UnsupportedOperationException();
204    }
205
206    // calculate plaintext fragment size
207    //
208    // apply to SSLEngine only
209    int estimateFragmentSize(int packetSize) {
210        throw new UnsupportedOperationException();
211    }
212
213    //
214    // shared helpers
215    //
216
217    // Not apply to DTLS
218    static ByteBuffer convertToClientHello(ByteBuffer packet) {
219
220        int srcPos = packet.position();
221        int srcLim = packet.limit();
222
223        byte firstByte = packet.get();
224        byte secondByte = packet.get();
225        int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
226
227        packet.position(srcPos + 3);        // the V2ClientHello record header
228
229        byte majorVersion = packet.get();
230        byte minorVersion = packet.get();
231
232        int cipherSpecLen = ((packet.get() & 0xFF) << 8) +
233                             (packet.get() & 0xFF);
234        int sessionIdLen  = ((packet.get() & 0xFF) << 8) +
235                             (packet.get() & 0xFF);
236        int nonceLen      = ((packet.get() & 0xFF) << 8) +
237                             (packet.get() & 0xFF);
238
239        // Required space for the target SSLv3 ClientHello message.
240        //  5: record header size
241        //  4: handshake header size
242        //  2: ClientHello.client_version
243        // 32: ClientHello.random
244        //  1: length byte of ClientHello.session_id
245        //  2: length bytes of ClientHello.cipher_suites
246        //  2: empty ClientHello.compression_methods
247        int requiredSize = 48 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 );
248        byte[] converted = new byte[requiredSize];
249
250        /*
251         * Build the first part of the V3 record header from the V2 one
252         * that's now buffered up.  (Lengths are fixed up later).
253         */
254        // Note: need not to set the header actually.
255        converted[0] = ct_handshake;
256        converted[1] = majorVersion;
257        converted[2] = minorVersion;
258        // header [3..4] for handshake message length
259        // required size is 5;
260
261        /*
262         * Store the generic V3 handshake header:  4 bytes
263         */
264        converted[5] = 1;    // HandshakeMessage.ht_client_hello
265        // buf [6..8] for length of ClientHello (int24)
266        // required size += 4;
267
268        /*
269         * ClientHello header starts with SSL version
270         */
271        converted[9] = majorVersion;
272        converted[10] = minorVersion;
273        // required size += 2;
274        int pointer = 11;
275
276        /*
277         * Copy Random value/nonce ... if less than the 32 bytes of
278         * a V3 "Random", right justify and zero pad to the left.  Else
279         * just take the last 32 bytes.
280         */
281        int offset = srcPos + 11 + cipherSpecLen + sessionIdLen;
282
283        if (nonceLen < 32) {
284            for (int i = 0; i < (32 - nonceLen); i++) {
285                converted[pointer++] = 0;
286            }
287            packet.position(offset);
288            packet.get(converted, pointer, nonceLen);
289
290            pointer += nonceLen;
291        } else {
292            packet.position(offset + nonceLen - 32);
293            packet.get(converted, pointer, 32);
294
295            pointer += 32;
296        }
297
298        /*
299         * Copy session ID (only one byte length!)
300         */
301        offset -= sessionIdLen;
302        converted[pointer++] = (byte)(sessionIdLen & 0xFF);
303        packet.position(offset);
304        packet.get(converted, pointer, sessionIdLen);
305
306        /*
307         * Copy and translate cipher suites ... V2 specs with first byte zero
308         * are really V3 specs (in the last 2 bytes), just copy those and drop
309         * the other ones.  Preference order remains unchanged.
310         *
311         * Example:  Netscape Navigator 3.0 (exportable) says:
312         *
313         * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
314         * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
315         *
316         * Microsoft Internet Explorer 3.0 (exportable) supports only
317         *
318         * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
319         */
320        int j;
321
322        offset -= cipherSpecLen;
323        packet.position(offset);
324
325        j = pointer + 2;
326        for (int i = 0; i < cipherSpecLen; i += 3) {
327            if (packet.get() != 0) {
328                // Ignore version 2.0 specifix cipher suite.  Clients
329                // should also include the version 3.0 equivalent in
330                // the V2ClientHello message.
331                packet.get();           // ignore the 2nd byte
332                packet.get();           // ignore the 3rd byte
333                continue;
334            }
335
336            converted[j++] = packet.get();
337            converted[j++] = packet.get();
338        }
339
340        j -= pointer + 2;
341        converted[pointer++] = (byte)((j >>> 8) & 0xFF);
342        converted[pointer++] = (byte)(j & 0xFF);
343        pointer += j;
344
345        /*
346         * Append compression methods (default/null only)
347         */
348        converted[pointer++] = 1;
349        converted[pointer++] = 0;      // Session.compression_null
350
351        /*
352         * Fill in lengths of the messages we synthesized (nested:
353         * V3 handshake message within V3 record).
354         */
355        // Note: need not to set the header actually.
356        int fragLen = pointer - 5;                      // TLSPlaintext.length
357        converted[3] = (byte)((fragLen >>> 8) & 0xFF);
358        converted[4] = (byte)(fragLen & 0xFF);
359
360        /*
361         * Handshake.length, length of ClientHello message
362         */
363        fragLen = pointer - 9;                          // Handshake.length
364        converted[6] = (byte)((fragLen >>> 16) & 0xFF);
365        converted[7] = (byte)((fragLen >>> 8) & 0xFF);
366        converted[8] = (byte)(fragLen & 0xFF);
367
368        // consume the full record
369        packet.position(srcPos + recordLen);
370
371        // Need no header bytes.
372        return ByteBuffer.wrap(converted, 5, pointer - 5);  // 5: header size
373    }
374
375    static ByteBuffer decrypt(Authenticator authenticator, CipherBox box,
376            byte contentType, ByteBuffer bb) throws BadPaddingException {
377
378        return decrypt(authenticator, box, contentType, bb, null);
379    }
380
381    static ByteBuffer decrypt(Authenticator authenticator,
382            CipherBox box, byte contentType, ByteBuffer bb,
383            byte[] sequence) throws BadPaddingException {
384
385        BadPaddingException reservedBPE = null;
386        int tagLen =
387            (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
388        int cipheredLength = bb.remaining();
389        int srcPos = bb.position();
390        if (!box.isNullCipher()) {
391            try {
392                // apply explicit nonce for AEAD/CBC cipher suites if needed
393                int nonceSize = box.applyExplicitNonce(
394                        authenticator, contentType, bb, sequence);
395
396                // decrypt the content
397                if (box.isAEADMode()) {
398                    // DON'T decrypt the nonce_explicit for AEAD mode
399                    bb.position(srcPos + nonceSize);
400                }   // The explicit IV for CBC mode can be decrypted.
401
402                // Note that the CipherBox.decrypt() does not change
403                // the capacity of the buffer.
404                box.decrypt(bb, tagLen);
405                // We don't actually remove the nonce.
406                bb.position(srcPos + nonceSize);
407            } catch (BadPaddingException bpe) {
408                // RFC 2246 states that decryption_failed should be used
409                // for this purpose. However, that allows certain attacks,
410                // so we just send bad record MAC. We also need to make
411                // sure to always check the MAC to avoid a timing attack
412                // for the same issue. See paper by Vaudenay et al and the
413                // update in RFC 4346/5246.
414                //
415                // Failover to message authentication code checking.
416                reservedBPE = bpe;
417            }
418        }
419
420        // Requires message authentication code for null, stream and block
421        // cipher suites.
422        if ((authenticator instanceof MAC) && (tagLen != 0)) {
423            MAC signer = (MAC)authenticator;
424            int contentLen = bb.remaining() - tagLen;
425
426            // Note that although it is not necessary, we run the same MAC
427            // computation and comparison on the payload for both stream
428            // cipher and CBC block cipher.
429            if (contentLen < 0) {
430                // negative data length, something is wrong
431                if (reservedBPE == null) {
432                    reservedBPE = new BadPaddingException("bad record");
433                }
434
435                // set offset of the dummy MAC
436                contentLen = cipheredLength - tagLen;
437                bb.limit(srcPos + cipheredLength);
438            }
439
440            // Run MAC computation and comparison on the payload.
441            //
442            // MAC data would be stripped off during the check.
443            if (checkMacTags(contentType, bb, signer, sequence, false)) {
444                if (reservedBPE == null) {
445                    reservedBPE = new BadPaddingException("bad record MAC");
446                }
447            }
448
449            // Run MAC computation and comparison on the remainder.
450            //
451            // It is only necessary for CBC block cipher.  It is used to get a
452            // constant time of MAC computation and comparison on each record.
453            if (box.isCBCMode()) {
454                int remainingLen = calculateRemainingLen(
455                                        signer, cipheredLength, contentLen);
456
457                // NOTE: remainingLen may be bigger (less than 1 block of the
458                // hash algorithm of the MAC) than the cipheredLength.
459                //
460                // Is it possible to use a static buffer, rather than allocate
461                // it dynamically?
462                remainingLen += signer.MAClen();
463                ByteBuffer temporary = ByteBuffer.allocate(remainingLen);
464
465                // Won't need to worry about the result on the remainder. And
466                // then we won't need to worry about what's actual data to
467                // check MAC tag on.  We start the check from the header of the
468                // buffer so that we don't need to construct a new byte buffer.
469                checkMacTags(contentType, temporary, signer, sequence, true);
470            }
471        }
472
473        // Is it a failover?
474        if (reservedBPE != null) {
475            throw reservedBPE;
476        }
477
478        return bb.slice();
479    }
480
481    /*
482     * Run MAC computation and comparison
483     *
484     */
485    private static boolean checkMacTags(byte contentType, ByteBuffer bb,
486            MAC signer, byte[] sequence, boolean isSimulated) {
487
488        int tagLen = signer.MAClen();
489        int position = bb.position();
490        int lim = bb.limit();
491        int macOffset = lim - tagLen;
492
493        bb.limit(macOffset);
494        byte[] hash = signer.compute(contentType, bb, sequence, isSimulated);
495        if (hash == null || tagLen != hash.length) {
496            // Something is wrong with MAC implementation.
497            throw new RuntimeException("Internal MAC error");
498        }
499
500        bb.position(macOffset);
501        bb.limit(lim);
502        try {
503            int[] results = compareMacTags(bb, hash);
504            return (results[0] != 0);
505        } finally {
506            // reset to the data
507            bb.position(position);
508            bb.limit(macOffset);
509        }
510    }
511
512    /*
513     * A constant-time comparison of the MAC tags.
514     *
515     * Please DON'T change the content of the ByteBuffer parameter!
516     */
517    private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
518
519        // An array of hits is used to prevent Hotspot optimization for
520        // the purpose of a constant-time check.
521        int[] results = {0, 0};     // {missed #, matched #}
522
523        // The caller ensures there are enough bytes available in the buffer.
524        // So we won't need to check the remaining of the buffer.
525        for (int i = 0; i < tag.length; i++) {
526            if (bb.get() != tag[i]) {
527                results[0]++;       // mismatched bytes
528            } else {
529                results[1]++;       // matched bytes
530            }
531        }
532
533        return results;
534    }
535
536    /*
537     * Run MAC computation and comparison
538     *
539     * Please DON'T change the content of the byte buffer parameter!
540     */
541    private static boolean checkMacTags(byte contentType, byte[] buffer,
542            int offset, int contentLen, MAC signer, boolean isSimulated) {
543
544        int tagLen = signer.MAClen();
545        byte[] hash = signer.compute(
546                contentType, buffer, offset, contentLen, isSimulated);
547        if (hash == null || tagLen != hash.length) {
548            // Something is wrong with MAC implementation.
549            throw new RuntimeException("Internal MAC error");
550        }
551
552        int[] results = compareMacTags(buffer, offset + contentLen, hash);
553        return (results[0] != 0);
554    }
555
556    /*
557     * A constant-time comparison of the MAC tags.
558     *
559     * Please DON'T change the content of the byte buffer parameter!
560     */
561    private static int[] compareMacTags(
562            byte[] buffer, int offset, byte[] tag) {
563
564        // An array of hits is used to prevent Hotspot optimization for
565        // the purpose of a constant-time check.
566        int[] results = {0, 0};    // {missed #, matched #}
567
568        // The caller ensures there are enough bytes available in the buffer.
569        // So we won't need to check the length of the buffer.
570        for (int i = 0; i < tag.length; i++) {
571            if (buffer[offset + i] != tag[i]) {
572                results[0]++;       // mismatched bytes
573            } else {
574                results[1]++;       // matched bytes
575            }
576        }
577
578        return results;
579    }
580
581    /*
582     * Calculate the length of a dummy buffer to run MAC computation
583     * and comparison on the remainder.
584     *
585     * The caller MUST ensure that the fullLen is not less than usedLen.
586     */
587    private static int calculateRemainingLen(
588            MAC signer, int fullLen, int usedLen) {
589
590        int blockLen = signer.hashBlockLen();
591        int minimalPaddingLen = signer.minimalPaddingLen();
592
593        // (blockLen - minimalPaddingLen) is the maximum message size of
594        // the last block of hash function operation. See FIPS 180-4, or
595        // MD5 specification.
596        fullLen += 13 - (blockLen - minimalPaddingLen);
597        usedLen += 13 - (blockLen - minimalPaddingLen);
598
599        // Note: fullLen is always not less than usedLen, and blockLen
600        // is always bigger than minimalPaddingLen, so we don't worry
601        // about negative values. 0x01 is added to the result to ensure
602        // that the return value is positive.  The extra one byte does
603        // not impact the overall MAC compression function evaluations.
604        return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
605                Math.ceil(usedLen/(1.0d * blockLen))) * blockLen;
606    }
607}
608
609