/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* SSL 3.0 records, as written to a TCP stream.
*
* Each record has a message area that starts out with data supplied by the
* in place for mac-ing and encryption.
*
* Handshake records have additional needs, notably accumulation of a set
* of hashes which are used to establish that handshaking was done right.
* Handshake records usually have several handshake messages each, and we
* need message-level control over what's hashed.
*
* @author David Brownell
*/
private int lastHashed;
private boolean firstMessage;
final private byte contentType;
// current protocol version, sent as record version
// version for the ClientHello message. Only relevant if this is a
// client handshake record. If set to ProtocolVersion.SSL20Hello,
// the V3 client hello is converted to V2 format.
/* Class and subclass dynamic debugging support */
/*
* Default constructor makes a record supporting the maximum
* SSL record size. It allocates the header bytes directly.
*
* @param type the content type for the record
*/
super(size);
firstMessage = true;
count = headerSize;
contentType = type;
lastHashed = count;
}
}
/**
* Get the size of the buffer we need for records of the specified
* type.
*/
return maxAlertRecordSize;
} else {
return maxRecordSize;
}
}
/*
* Updates the SSL version of this record.
*/
this.protocolVersion = protocolVersion;
}
/*
* Updates helloVersion of this record.
*/
this.helloVersion = helloVersion;
}
/*
* Reset the record so that it can be refilled, starting
* immediately after the header.
*/
public synchronized void reset() {
super.reset();
count = headerSize;
lastHashed = count;
}
/*
* For handshaking, we need to be able to hash every byte above the
* record marking layer. This is where we're guaranteed to see those
* bytes, so this is where we can hash them.
*/
assert(contentType == ct_handshake);
this.handshakeHash = handshakeHash;
}
/*
* We hash (the plaintext) on demand. There is one place where
* we want to access the hash in the middle of a record: client
* cert message gets hashed, and part of the same record is the
* client cert verify message which uses that hash. So we track
* how much of each record we've hashed so far.
*/
void doHashes() {
if (len > 0) {
lastHashed = count;
}
}
/*
* Need a helper function so we can hash the V2 hello correctly
*/
try {
+ len);
} catch (IOException e) { }
}
lastHashed = count;
}
/*
* Return true iff the record is empty -- to avoid doing the work
* of sending empty records over the network.
*/
boolean isEmpty() {
return count == headerSize;
}
/*
* Return true if the record is of a given alert.
*/
// An alert is defined with a two bytes struct,
// {byte level, byte description}, following after the header bytes.
}
return false;
}
/*
* Compute the MAC and append it to this record. In case we
* are automatically flushing a handshake stream, make sure we
* have hashed the message first.
*/
//
// when we support compression, hashing can't go here
// since it'll need to be done on the uncompressed data,
// and the MAC applies to the compressed data.
//
if (contentType == ct_handshake) {
doHashes();
}
}
}
/*
* Encrypt ... length may grow due to block cipher padding
*/
}
/*
* Tell how full the buffer is ... for filling it with application or
* handshake data.
*/
final int availableDataBytes() {
return maxDataSize - dataSize;
}
/*
* Increases the capacity if necessary to ensure that it can hold
* at least the number of elements specified by the minimum
* capacity argument.
*
* Note that the increased capacity is only can be used for held
* record buffer. Please DO NOT update the availableDataBytes()
* according to the expended buffer capacity.
*
* @see availableDataBytes()
*/
// overflow-conscious code
}
}
/*
* Return the type of SSL record that's buffered here.
*/
final byte contentType() {
return contentType;
}
/*
* Write the record out on the stream. Note that you must have (in
* order) compressed the data, appended the MAC, and encrypted it in
* order for the record to be understood by the other end. (Some of
* those steps will be null early in handshaking.)
*
* Note that this does no locking for the connection, it's required
* that synchronization be done elsewhere. Also, this does its work
* in a single low level write, for efficiency.
*/
/*
* Don't emit content-free records. (Even change cipher spec
* messages have a byte of data!)
*/
if (count == headerSize) {
return;
}
// "should" really never write more than about 14 Kb...
if (length < 0) {
throw new SSLException("output record size too small: "
+ length);
}
|| contentType() == ct_change_cipher_spec)
+ ", WRITE: " + protocolVersion
+ ", length = " + length);
}
/*
* If this is the initial ClientHello on this connection and
* we're not trying to resume a (V3) session then send a V2
* ClientHello instead so we can detect V2 servers cleanly.
*/
if (firstMessage && useV2Hello()) {
lastHashed = 2;
doHashes();
+ ", WRITE: SSLv2 client hello message"
}
} else {
/*
* Fill out the header, write it and the message.
*/
}
firstMessage = false;
/*
* The upper levels may want us to delay sending this packet so
* multiple TLS Records can be sent in one (or more) TCP packets.
* If so, add this packet to the heldRecordBuffer.
*
* NOTE: all writes have been synchronized by upper levels.
*/
int debugOffset = 0;
if (holdRecord) {
/*
* If holdRecord is true, we must have a heldRecordBuffer.
*
* Don't worry about the override of writeBuffer(), because
* when holdRecord is true, the implementation in this class
* will be used.
*/
} else {
// It's time to send, do we have buffered data?
// May or may not have a heldRecordBuffer.
// Ensure the capacity of this buffer.
// Slide everything in the buffer to the right.
// Prepend the held record to the buffer.
// Clear the held buffer.
// The held buffer has been dumped, set the debug dump offset.
}
}
reset();
}
/*
* Actually do the write here. For SSLEngine's HS data,
* we'll override this method and let it take the appropriate
* action.
*/
int debugOffset) throws IOException {
s.flush();
// Output only the record from the specified debug offset.
try {
} catch (IOException e) { }
}
}
/*
* Return whether the buffer contains a ClientHello message that should
* be converted to V2 format.
*/
private boolean useV2Hello() {
return firstMessage
&& (contentType == ct_handshake)
}
/*
* Detect "old" servers which are capable of SSL V2.0 protocol ... for
* example, Netscape Commerce 1.0 servers. The V3 message is in the
* header and the bytes passed as parameter. This routine translates
* the V3 message into an equivalent V2 one.
*
* Note that the translation will strip off all hello extensions as
* SSL V2.0 does not support hello extension.
*/
/*
* Copy over the cipher specs. We don't care about actually translating
* them for use with an actual V2 server since we only talk V3.
* Therefore, just copy over the V3 cipher spec values with a leading
* 0.
*/
int v2CipherSpecLen = 0;
count = 11;
boolean containsRenegoInfoSCSV = false;
for (int i = 0; i < cipherSpecs; i++) {
if (!containsRenegoInfoSCSV &&
containsRenegoInfoSCSV = true;
}
}
if (!containsRenegoInfoSCSV) {
}
/*
* Build the first part of the V3 record header from the V2 one
* that's now buffered up. (Lengths are fixed up later).
*/
/*
* Copy in the nonce.
*/
count += 32;
/*
* Set the length of the message.
*/
count += 2;
}
/*
* Mappings from V3 cipher suite encodings to their pure V2 equivalents.
* This is taken from the SSL V3 specification, Appendix E.
*/
private static int[] V3toV2CipherMap1 =
{-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
private static int[] V3toV2CipherMap3 =
{-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
/*
* See which matching pure-V2 cipher specs we need to include.
* We are including these not because we are actually prepared
* to talk V2 but because the Oracle Web Server insists on receiving
* at least 1 "pure V2" cipher suite that it supports and returns an
* illegal_parameter alert unless one is present. Rather than mindlessly
* claiming to implement all documented pure V2 cipher suites the code below
* just claims to implement the V2 cipher suite that is "equivalent"
* in terms of cipher algorithm & exportability with the actual V3 cipher
* suite that we do support.
*/
return 3;
}
return 6;
}
}