blob: 82a9b02d7904371fb6c62a0b7154007f529e8bed [file] [log] [blame]
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package sun.security.ssl;
import java.util.Arrays;
/**
* This class represents an SSL/TLS/DTLS message authentication token,
* which encapsulates a sequence number and ensures that attempts to
* delete or reorder messages can be detected.
*
* Each connection state contains a sequence number, which is maintained
* separately for read and write states.
*
* For SSL/TLS protocols, the sequence number MUST be set to zero
* whenever a connection state is made the active state.
*
* DTLS uses an explicit sequence number, rather than an implicit one.
* Sequence numbers are maintained separately for each epoch, with
* each sequence number initially being 0 for each epoch. The sequence
* number used to compute the DTLS MAC is the 64-bit value formed by
* concatenating the epoch and the sequence number.
*
* Sequence numbers do not wrap. If an implementation would need to wrap
* a sequence number, it must renegotiate instead. A sequence number is
* incremented after each record: specifically, the first record transmitted
* under a particular connection state MUST use sequence number 0.
*/
class Authenticator {
// byte array containing the additional authentication information for
// each record
private final byte[] block;
// the block size of SSL v3.0:
// sequence number + record type + + record length
private static final int BLOCK_SIZE_SSL = 8 + 1 + 2;
// the block size of TLS v1.0 and later:
// sequence number + record type + protocol version + record length
private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2;
// the block size of DTLS v1.0 and later:
// epoch + sequence number + record type + protocol version + record length
private static final int BLOCK_SIZE_DTLS = 2 + 6 + 1 + 2 + 2;
private final boolean isDTLS;
/**
* Default construct, no message authentication token is initialized.
*
* Note that this construct can only be called for null MAC
*/
protected Authenticator(boolean isDTLS) {
if (isDTLS) {
// For DTLS protocols, plaintexts use explicit epoch and
// sequence number in each record. The first 8 byte of
// the block is initialized for null MAC so that the
// epoch and sequence number can be acquired to generate
// plaintext records.
block = new byte[8];
} else {
block = new byte[0];
}
this.isDTLS = isDTLS;
}
/**
* Constructs the message authentication token for the specified
* SSL/TLS protocol.
*/
Authenticator(ProtocolVersion protocolVersion) {
if (protocolVersion.isDTLSProtocol()) {
block = new byte[BLOCK_SIZE_DTLS];
block[9] = protocolVersion.major;
block[10] = protocolVersion.minor;
this.isDTLS = true;
} else if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
block = new byte[BLOCK_SIZE_TLS];
block[9] = protocolVersion.major;
block[10] = protocolVersion.minor;
this.isDTLS = false;
} else {
block = new byte[BLOCK_SIZE_SSL];
this.isDTLS = false;
}
}
/**
* Checks whether the sequence number is close to wrap.
*
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
* Sequence numbers do not wrap. When the sequence number is near
* to wrap, we need to close the connection immediately.
*
* @return true if the sequence number is close to wrap
*/
final boolean seqNumOverflow() {
/*
* Conservatively, we don't allow more records to be generated
* when there are only 2^8 sequence numbers left.
*/
if (isDTLS) {
return (block.length != 0 &&
// no epoch bytes, block[0] and block[1]
block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
block[6] == (byte)0xFF);
} else {
return (block.length != 0 &&
block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
block[6] == (byte)0xFF);
}
}
/**
* Checks whether the sequence number close to renew.
*
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
* Sequence numbers do not wrap. If a TLS
* implementation would need to wrap a sequence number, it must
* renegotiate instead.
*
* @return true if the sequence number is huge enough to renew
*/
final boolean seqNumIsHuge() {
/*
* Conservatively, we should ask for renegotiation when there are
* only 2^32 sequence numbers left.
*/
if (isDTLS) {
return (block.length != 0 &&
// no epoch bytes, block[0] and block[1]
block[2] == (byte)0xFF && block[3] == (byte)0xFF);
} else {
return (block.length != 0 &&
block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
block[2] == (byte)0xFF && block[3] == (byte)0xFF);
}
}
/**
* Gets the current sequence number, including the epoch number for
* DTLS protocols.
*
* @return the byte array of the current sequence number
*/
final byte[] sequenceNumber() {
return Arrays.copyOf(block, 8);
}
/**
* Sets the epoch number (only apply to DTLS protocols).
*/
final void setEpochNumber(int epoch) {
if (!isDTLS) {
throw new RuntimeException(
"Epoch numbers apply to DTLS protocols only");
}
block[0] = (byte)((epoch >> 8) & 0xFF);
block[1] = (byte)(epoch & 0xFF);
}
/**
* Increase the sequence number.
*/
final void increaseSequenceNumber() {
/*
* The sequence number in the block array is a 64-bit
* number stored in big-endian format.
*/
int k = 7;
while ((k >= 0) && (++block[k] == 0)) {
k--;
}
}
/**
* Acquires the current message authentication information with the
* specified record type and fragment length, and then increases the
* sequence number.
*
* @param type the record type
* @param length the fragment of the record
* @param sequence the explicit sequence number of the record
*
* @return the byte array of the current message authentication information
*/
final byte[] acquireAuthenticationBytes(
byte type, int length, byte[] sequence) {
byte[] copy = block.clone();
if (sequence != null) {
if (sequence.length != 8) {
throw new RuntimeException(
"Insufficient explicit sequence number bytes");
}
System.arraycopy(sequence, 0, copy, 0, sequence.length);
} // Otherwise, use the implicit sequence number.
if (block.length != 0) {
copy[8] = type;
copy[copy.length - 2] = (byte)(length >> 8);
copy[copy.length - 1] = (byte)(length);
if (sequence == null || sequence.length != 0) {
// Increase the implicit sequence number in the block array.
increaseSequenceNumber();
}
}
return copy;
}
static final long toLong(byte[] recordEnS) {
if (recordEnS != null && recordEnS.length == 8) {
return ((recordEnS[0] & 0xFFL) << 56) |
((recordEnS[1] & 0xFFL) << 48) |
((recordEnS[2] & 0xFFL) << 40) |
((recordEnS[3] & 0xFFL) << 32) |
((recordEnS[4] & 0xFFL) << 24) |
((recordEnS[5] & 0xFFL) << 16) |
((recordEnS[6] & 0xFFL) << 8) |
(recordEnS[7] & 0xFFL);
}
return -1L;
}
}