/*
* 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.
/**
* 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
/**
* 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.
/**
* 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.
Returns: true if the sequence number is close to wrap
/**
* 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.
Returns: true if the sequence number is huge enough to renew
/**
* 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.
Returns: the byte array of the current sequence number
/**
* 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).
/**
* 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.
/**
* 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.
Params: - type – the record type
- length – the fragment of the record
- sequence – the explicit sequence number of the record
Returns: the byte array of the current message authentication information
/**
* 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;
}
}