src/java.base/share/classes/sun/security/ssl/Authenticator.java
Print this page
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,23 +26,30 @@
package sun.security.ssl;
import java.util.Arrays;
/**
- * This class represents an SSL/TLS message authentication token,
+ * 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 SSL/TLS connection state contains a sequence number, which
- * is maintained separately for read and write states. The sequence
- * number MUST be set to zero whenever a connection state is made the
- * active state. Sequence numbers are of type uint64 and may not
- * exceed 2^64-1. Sequence numbers do not wrap. If a SSL/TLS
- * 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.
+ * 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
@@ -54,30 +61,57 @@
// 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
*/
- Authenticator() {
+ 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.v >= ProtocolVersion.TLS10.v) {
+ 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.
@@ -91,16 +125,24 @@
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.
@@ -111,51 +153,109 @@
* @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^48 sequence numbers left.
+ * only 2^32 sequence numbers left.
*/
+ if (isDTLS) {
return (block.length != 0 &&
- block[0] == (byte)0xFF && block[1] == (byte)0xFF);
+ // 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.
+ * 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) {
+ 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);
- /*
- * Increase the sequence number in the block array
- * it is a 64-bit number stored in big-endian format
- */
- int k = 7;
- while ((k >= 0) && (++block[k] == 0)) {
- k--;
+ if (sequence == null || sequence.length != 0) {
+ // Increase the implicit sequence number in the block array.
+ increaseSequenceNumber();
}
}
return copy;
}
+ final static 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;
+ }
}