--- a/jdk/src/share/classes/sun/security/ssl/MAC.java Tue Mar 12 10:35:44 2013 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/MAC.java Tue Mar 12 15:31:49 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, 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
@@ -39,15 +39,19 @@
/**
* This class computes the "Message Authentication Code" (MAC) for each
- * SSL stream and block cipher message. This is essentially a shared-secret
- * signature, used to provide integrity protection for SSL messages. The
- * MAC is actually one of several keyed hashes, as associated with the cipher
- * suite and protocol version. (SSL v3.0 uses one construct, TLS uses another.)
+ * SSL message. This is essentially a shared-secret signature, used to
+ * provide integrity protection for SSL messages. The MAC is actually
+ * one of several keyed hashes, as associated with the cipher suite and
+ * protocol version. (SSL v3.0 uses one construct, TLS uses another.)
+ *
+ * <P>NOTE: MAC computation is the only place in the SSL protocol that the
+ * sequence number is used. It's also reset to zero with each change of
+ * a cipher spec, so this is the only place this state is needed.
*
* @author David Brownell
* @author Andreas Sterbenz
*/
-final class MAC extends Authenticator {
+final class MAC {
final static MAC NULL = new MAC();
@@ -60,9 +64,26 @@
// JCE Mac object
private final Mac mac;
+ // byte array containing the additional information we MAC in each record
+ // (see below)
+ private final byte[] block;
+
+ // sequence number + record type + + record length
+ private static final int BLOCK_SIZE_SSL = 8 + 1 + 2;
+
+ // sequence number + record type + protocol version + record length
+ private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2;
+
+ // offset of record type in block
+ private static final int BLOCK_OFFSET_TYPE = 8;
+
+ // offset of protocol version number in block (TLS only)
+ private static final int BLOCK_OFFSET_VERSION = 8 + 1;
+
private MAC() {
macSize = 0;
mac = null;
+ block = null;
}
/**
@@ -70,8 +91,6 @@
*/
MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key)
throws NoSuchAlgorithmException, InvalidKeyException {
- super(protocolVersion);
-
this.macSize = macAlg.size;
String algorithm;
@@ -91,6 +110,14 @@
mac = JsseJce.getMac(algorithm);
mac.init(key);
+
+ if (tls) {
+ block = new byte[BLOCK_SIZE_TLS];
+ block[BLOCK_OFFSET_VERSION] = protocolVersion.major;
+ block[BLOCK_OFFSET_VERSION+1] = protocolVersion.minor;
+ } else {
+ block = new byte[BLOCK_SIZE_SSL];
+ }
}
/**
@@ -109,15 +136,7 @@
* @param len the size of the compressed record
*/
final byte[] compute(byte type, byte buf[], int offset, int len) {
- if (macSize == 0) {
- return nullMAC;
- }
-
- byte[] additional = acquireAuthenticationBytes(type, len);
- mac.update(additional);
- mac.update(buf, offset, len);
-
- return mac.doFinal();
+ return compute(type, null, buf, offset, len);
}
/**
@@ -132,13 +151,78 @@
* demarcate the data to be MAC'd.
*/
final byte[] compute(byte type, ByteBuffer bb) {
+ return compute(type, bb, null, 0, bb.remaining());
+ }
+
+ /**
+ * Check 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.
+ */
+ final boolean seqNumOverflow() {
+ /*
+ * Conservatively, we don't allow more records to be generated
+ * when there are only 2^8 sequence numbers left.
+ */
+ return (block != null && mac != null &&
+ 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);
+ }
+
+ /*
+ * Check whether to renew the sequence number
+ *
+ * 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.
+ */
+ final boolean seqNumIsHuge() {
+ /*
+ * Conservatively, we should ask for renegotiation when there are
+ * only 2^48 sequence numbers left.
+ */
+ return (block != null && mac != null &&
+ block[0] == (byte)0xFF && block[1] == (byte)0xFF);
+ }
+
+ // increment the sequence number in the block array
+ // it is a 64-bit number stored in big-endian format
+ private void incrementSequenceNumber() {
+ int k = 7;
+ while ((k >= 0) && (++block[k] == 0)) {
+ k--;
+ }
+ }
+
+ /*
+ * Compute based on either buffer type, either bb.position/limit
+ * or buf/offset/len.
+ */
+ private byte[] compute(byte type, ByteBuffer bb, byte[] buf,
+ int offset, int len) {
+
if (macSize == 0) {
return nullMAC;
}
- byte[] additional = acquireAuthenticationBytes(type, bb.remaining());
- mac.update(additional);
- mac.update(bb);
+ block[BLOCK_OFFSET_TYPE] = type;
+ block[block.length - 2] = (byte)(len >> 8);
+ block[block.length - 1] = (byte)(len );
+
+ mac.update(block);
+ incrementSequenceNumber();
+
+ // content
+ if (bb != null) {
+ mac.update(bb);
+ } else {
+ mac.update(buf, offset, len);
+ }
return mac.doFinal();
}