1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1838375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootpackage org.conscrypt;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLProtocolException;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class performs functionality dedicated to SSL record layer.
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * It unpacks and routes income data to the appropriate
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * client protocol (handshake, alert, application data protocols)
27f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson * and packages outcome data into SSL/TLS records.
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Initially created object has null connection state and does not
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * perform any cryptography computations over the income/outcome data.
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * After handshake protocol agreed upon security parameters they are placed
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * into SSLSessionImpl object and available for record protocol as
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * pending session. The order of setting up of the pending session
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * as an active session differs for client and server modes.
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * So for client mode the parameters are provided by handshake protocol
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * during retrieving of change_cipher_spec message to be sent (by calling of
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * getChangeCipherSpecMesage method).
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * For server side mode record protocol retrieves the parameters from
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * handshake protocol after receiving of client's change_cipher_spec message.
396670318007799f403594f0760382b8c23f7dda0fJesse Wilson * After the pending session has been set up as a current session,
406670318007799f403594f0760382b8c23f7dda0fJesse Wilson * new connection state object is created and used for encryption/decryption
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * of the messages.
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Among with base functionality this class provides the information about
436670318007799f403594f0760382b8c23f7dda0fJesse Wilson * constrains on the data length, and information about correspondence
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * of plain and encrypted data lengths.
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * For more information on TLS v1 see http://www.ietf.org/rfc/rfc2246.txt,
46f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * on SSL v3 see http://wp.netscape.com/eng/ssl3,
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * on SSL v2 see http://wp.netscape.com/eng/security/SSL_2.html.
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class SSLRecordProtocol {
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
52f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Maximum length of allowed plain data fragment
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * as specified by TLS specification.
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
556670318007799f403594f0760382b8c23f7dda0fJesse Wilson    protected static final int MAX_DATA_LENGTH = 16384; // 2^14
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Maximum length of allowed compressed data fragment
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * as specified by TLS specification.
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
606670318007799f403594f0760382b8c23f7dda0fJesse Wilson    protected static final int MAX_COMPRESSED_DATA_LENGTH
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    = MAX_DATA_LENGTH + 1024;
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Maximum length of allowed ciphered data fragment
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * as specified by TLS specification.
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
666670318007799f403594f0760382b8c23f7dda0fJesse Wilson    protected static final int MAX_CIPHERED_DATA_LENGTH
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    = MAX_COMPRESSED_DATA_LENGTH + 1024;
68f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    /**
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Maximum length of ssl record. It is counted as:
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * type(1) + version(2) + length(2) + MAX_CIPHERED_DATA_LENGTH
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
726670318007799f403594f0760382b8c23f7dda0fJesse Wilson    protected static final int MAX_SSL_PACKET_SIZE
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    = MAX_CIPHERED_DATA_LENGTH + 5;
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // the SSL session used for connection
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private SSLSessionImpl session;
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // protocol version of the connection
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private byte[] version;
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // input stream of record protocol
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private SSLInputStream in;
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // handshake protocol object to which handshaking data will be transmitted
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private HandshakeProtocol handshakeProtocol;
826670318007799f403594f0760382b8c23f7dda0fJesse Wilson    // alert protocol to indicate alerts occurred/received
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AlertProtocol alertProtocol;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // application data object to which application data will be transmitted
8538375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Root    private Appendable appData;
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // connection state holding object
87f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private ConnectionState
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        activeReadState, activeWriteState, pendingConnectionState;
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // logger
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Logger.Stream logger = Logger.getStream("record");
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // flag indicating if session object has been changed after
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // handshake phase (to distinguish session pending state)
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean sessionWasChanged = false;
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // change cipher spec message content
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final byte[] change_cipher_spec_byte = new byte[] {1};
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates an instance of record protocol and tunes
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * up the client protocols to use ut.
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   handshakeProtocol:  HandshakeProtocol
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   alertProtocol:  AlertProtocol
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   in: SSLInputStream
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   appData:    Appendable
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected SSLRecordProtocol(HandshakeProtocol handshakeProtocol,
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AlertProtocol alertProtocol,
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            SSLInputStream in,
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Appendable appData) {
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.handshakeProtocol = handshakeProtocol;
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.handshakeProtocol.setRecordProtocol(this);
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.alertProtocol = alertProtocol;
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.alertProtocol.setRecordProtocol(this);
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.in = in;
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.appData = appData;
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the session obtained during the handshake negotiation.
1226670318007799f403594f0760382b8c23f7dda0fJesse Wilson     * If the handshake process was not completed, method returns null.
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the session in effect.
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected SSLSessionImpl getSession() {
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return session;
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the minimum possible length of the SSL record.
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int getMinRecordSize() {
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (activeReadState == null)
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ? 6 // type + version + length + 1 byte of data
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            : 5 + activeReadState.getMinFragmentSize();
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the record length for the specified incoming data length.
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If actual resulting record length is greater than
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * MAX_CIPHERED_DATA_LENGTH, MAX_CIPHERED_DATA_LENGTH is returned.
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int getRecordSize(int data_size) {
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (activeWriteState == null) {
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 5+data_size; // type + version + length + data_size
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int res = 5 + activeWriteState.getFragmentSize(data_size);
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return (res > MAX_CIPHERED_DATA_LENGTH)
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                ? MAX_CIPHERED_DATA_LENGTH // so the source data should be
1516670318007799f403594f0760382b8c23f7dda0fJesse Wilson                                           // split into several packets
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                : res;
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the upper bound of length of data containing in the record with
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified length.
159f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * If the provided record_size is greater or equal to
160f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * MAX_CIPHERED_DATA_LENGTH the returned value will be
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * MAX_DATA_LENGTH
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * counted as for data with
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * MAX_CIPHERED_DATA_LENGTH length.
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int getDataSize(int record_size) {
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        record_size -= 5; // - (type + version + length + data_size)
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (record_size > MAX_CIPHERED_DATA_LENGTH) {
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // the data of such size consists of the several packets
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return MAX_DATA_LENGTH;
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (activeReadState == null) {
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return record_size;
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
174f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson        return activeReadState.getContentSize(record_size);
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Depending on the Connection State (Session) encrypts and compress
179f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson     * the provided data, and packs it into TLSCiphertext structure.
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   content_type: int
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return  ssl packet created over the current connection state
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected byte[] wrap(byte content_type, DataStream dataStream) {
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] fragment = dataStream.getData(MAX_DATA_LENGTH);
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return wrap(content_type, fragment, 0, fragment.length);
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Depending on the Connection State (Session) encrypts and compress
190f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson     * the provided data, and packs it into TLSCiphertext structure.
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   content_type: int
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   fragment: byte[]
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return  ssl packet created over the current connection state
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected byte[] wrap(byte content_type,
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                       byte[] fragment, int offset, int len) {
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("SSLRecordProtocol.wrap: TLSPlaintext.fragment["
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    +len+"]:");
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.print(fragment, offset, len);
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (len > MAX_DATA_LENGTH) {
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new AlertException(
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AlertProtocol.INTERNAL_ERROR,
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                new SSLProtocolException(
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "The provided chunk of data is too big: " + len
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    + " > MAX_DATA_LENGTH == "+MAX_DATA_LENGTH));
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] ciphered_fragment = fragment;
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (activeWriteState != null) {
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ciphered_fragment =
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                activeWriteState.encrypt(content_type, fragment, offset, len);
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (ciphered_fragment.length > MAX_CIPHERED_DATA_LENGTH) {
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new AlertException(
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    AlertProtocol.INTERNAL_ERROR,
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    new SSLProtocolException(
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        "The ciphered data increased more than on 1024 bytes"));
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (logger != null) {
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.println("SSLRecordProtocol.wrap: TLSCiphertext.fragment["
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        +ciphered_fragment.length+"]:");
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.print(ciphered_fragment);
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return packetize(content_type, version, ciphered_fragment);
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private byte[] packetize(byte type, byte[] version, byte[] fragment) {
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] buff = new byte[5+fragment.length];
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buff[0] = type;
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (version != null) {
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buff[1] = version[0];
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buff[2] = version[1];
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buff[1] = 3;
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buff[2] = 1;
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buff[3] = (byte) ((0x00FF00 & fragment.length) >> 8);
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buff[4] = (byte) (0x0000FF & fragment.length);
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(fragment, 0, buff, 5, fragment.length);
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return buff;
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Set the ssl session to be used after sending the changeCipherSpec message
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   session:    SSLSessionImpl
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void setSession(SSLSessionImpl session) {
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!sessionWasChanged) {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // session was not changed for current handshake process
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (logger != null) {
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.println("SSLRecordProtocol.setSession: Set pending session");
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.println("  cipher name: " + session.getCipherSuite());
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.session = session;
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // create new connection state
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pendingConnectionState = ((version == null) || (version[1] == 1))
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                ? (ConnectionState) new ConnectionStateTLS(getSession())
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                : (ConnectionState) new ConnectionStateSSLv3(getSession());
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            sessionWasChanged = true;
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // wait for rehandshaking's session
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            sessionWasChanged = false;
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the change cipher spec message to be sent to another peer.
269f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * The pending connection state will be built on the base of provided
270f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * session object
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The calling of this method triggers pending write connection state to
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * be active.
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return ssl record containing the "change cipher spec" message.
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected byte[] getChangeCipherSpecMesage(SSLSessionImpl session) {
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // make change_cipher_spec_message:
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] change_cipher_spec_message;
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (activeWriteState == null) {
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            change_cipher_spec_message = new byte[] {
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    ContentType.CHANGE_CIPHER_SPEC, version[0],
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        version[1], 0, 1, 1
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                };
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            change_cipher_spec_message =
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                packetize(ContentType.CHANGE_CIPHER_SPEC, version,
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        activeWriteState.encrypt(ContentType.CHANGE_CIPHER_SPEC,
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            change_cipher_spec_byte, 0, 1));
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        setSession(session);
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        activeWriteState = pendingConnectionState;
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("SSLRecordProtocol.getChangeCipherSpecMesage");
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("activeWriteState = pendingConnectionState");
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.print(change_cipher_spec_message);
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return change_cipher_spec_message;
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Retrieves the fragment field of TLSCiphertext, and than
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * depending on the established Connection State
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * decrypts and decompresses it. The following structure is expected
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * on the input at the moment of the call:
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *  struct {
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *      ContentType type;
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *      ProtocolVersion version;
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *      uint16 length;
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *      select (CipherSpec.cipher_type) {
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *          case stream: GenericStreamCipher;
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *          case block: GenericBlockCipher;
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *      } fragment;
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *  } TLSCiphertext;
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * (as specified by RFC 2246, TLS v1 Protocol specification)
316f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * In addition this method can recognize SSLv2 hello message which
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * are often used to establish the SSL/TLS session.
319f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
3206670318007799f403594f0760382b8c23f7dda0fJesse Wilson     * @throws IOException if some io errors have been occurred
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws EndOfSourceException if underlying input stream
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                              has ran out of data.
3236670318007799f403594f0760382b8c23f7dda0fJesse Wilson     * @throws EndOfBufferException if there was not enough data
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                              to build complete ssl packet.
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the type of unwrapped message.
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int unwrap() throws IOException {
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("SSLRecordProtocol.unwrap: BEGIN [");
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int type = in.readUint8();
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((type < ContentType.CHANGE_CIPHER_SPEC)
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                || (type > ContentType.APPLICATION_DATA)) {
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (logger != null) {
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.println("Non v3.1 message type:" + type);
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (type >= 0x80) {
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // it is probably SSL v2 client_hello message
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // (see SSL v2 spec at:
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // http://wp.netscape.com/eng/security/SSL_2.html)
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int length = (type & 0x7f) << 8 | in.read();
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                byte[] fragment = in.read(length);
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeProtocol.unwrapSSLv2(fragment);
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (logger != null) {
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    logger.println(
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            "SSLRecordProtocol:unwrap ] END, SSLv2 type");
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return ContentType.HANDSHAKE;
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new AlertException(AlertProtocol.UNEXPECTED_MESSAGE,
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    new SSLProtocolException(
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        "Unexpected message type has been received: "+type));
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("Got the message of type: " + type);
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (version != null) {
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((in.read() != version[0])
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    || (in.read() != version[1])) {
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new AlertException(AlertProtocol.UNEXPECTED_MESSAGE,
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        new SSLProtocolException(
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            "Unexpected message type has been received: " +
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            type));
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
366f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson            in.skip(2); // just skip the version number
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = in.readUint16();
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("TLSCiphertext.fragment["+length+"]: ...");
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length > MAX_CIPHERED_DATA_LENGTH) {
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new AlertException(AlertProtocol.RECORD_OVERFLOW,
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    new SSLProtocolException(
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        "Received message is too big."));
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] fragment = in.read(length);
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.print(fragment);
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (activeReadState != null) {
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            fragment = activeReadState.decrypt((byte) type, fragment);
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (logger != null) {
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.println("TLSPlaintext.fragment:");
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.print(fragment);
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fragment.length > MAX_DATA_LENGTH) {
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new AlertException(AlertProtocol.DECOMPRESSION_FAILURE,
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    new SSLProtocolException(
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        "Decompressed plain data is too big."));
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        switch (type) {
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ContentType.CHANGE_CIPHER_SPEC:
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // notify handshake protocol:
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeProtocol.receiveChangeCipherSpec();
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                setSession(handshakeProtocol.getSession());
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // change cipher spec message has been received, so:
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (logger != null) {
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    logger.println("activeReadState = pendingConnectionState");
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                activeReadState = pendingConnectionState;
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ContentType.ALERT:
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                alert(fragment[0], fragment[1]);
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ContentType.HANDSHAKE:
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeProtocol.unwrap(fragment);
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ContentType.APPLICATION_DATA:
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (logger != null) {
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    logger.println(
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            "TLSCiphertext.unwrap: APP DATA["+length+"]:");
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    logger.println(new String(fragment));
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                appData.append(fragment);
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            default:
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new AlertException(AlertProtocol.UNEXPECTED_MESSAGE,
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        new SSLProtocolException(
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            "Unexpected message type has been received: " +
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            type));
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("SSLRecordProtocol:unwrap ] END, type: " + type);
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return type;
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Passes the alert information to the alert protocol.
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   level:  byte
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   description:    byte
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void alert(byte level, byte description) {
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (logger != null) {
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            logger.println("SSLRecordProtocol.allert: "+level+" "+description);
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        alertProtocol.alert(level, description);
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets up the SSL version used in this connection.
4446670318007799f403594f0760382b8c23f7dda0fJesse Wilson     * This method is calling from the handshake protocol after
4453e6dd45baa0d7f9b4fa06f4ade76e088b59cc7bfBrian Carlstrom     * it becomes known which protocol version will be used.
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param   ver:    byte[]
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void setVersion(byte[] ver) {
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.version = ver;
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
4546670318007799f403594f0760382b8c23f7dda0fJesse Wilson     * Shuts down the protocol. It will be impossible to use the instance
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * after the calling of this method.
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdown() {
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        session = null;
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        version = null;
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        in = null;
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        handshakeProtocol = null;
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        alertProtocol = null;
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        appData = null;
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pendingConnectionState != null) {
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pendingConnectionState.shutdown();
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        pendingConnectionState = null;
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (activeReadState != null) {
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            activeReadState.shutdown();
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        activeReadState = null;
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (activeReadState != null) {
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            activeReadState.shutdown();
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        activeWriteState = null;
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
478