diff -r b9fb0d9c58ec -r 36055e4b5305 jdk/src/share/classes/sun/security/ssl/MAC.java --- 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.) + * + *

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(); }