--- a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java Thu Apr 11 14:47:54 2013 -0700
+++ b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java Thu Apr 11 18:57:14 2013 -0700
@@ -29,7 +29,6 @@
import java.io.*;
import java.nio.*;
-
/**
* A OutputRecord class extension which uses external ByteBuffers
* or the internal ByteArrayOutputStream for data manipulations.
@@ -101,51 +100,6 @@
return finishedMsg;
}
-
- /**
- * Calculate the MAC value, storing the result either in
- * the internal buffer, or at the end of the destination
- * ByteBuffer.
- * <P>
- * We assume that the higher levels have assured us enough
- * room, otherwise we'll indirectly throw a
- * BufferOverFlowException runtime exception.
- *
- * position should equal limit, and points to the next
- * free spot.
- */
- private void addMAC(MAC signer, ByteBuffer bb)
- throws IOException {
-
- if (signer.MAClen() != 0) {
- byte[] hash = signer.compute(contentType(), bb, false);
-
- /*
- * position was advanced to limit in compute above.
- *
- * Mark next area as writable (above layers should have
- * established that we have plenty of room), then write
- * out the hash.
- */
- bb.limit(bb.limit() + hash.length);
- bb.put(hash);
- }
- }
-
- /*
- * Encrypt a ByteBuffer.
- *
- * We assume that the higher levels have assured us enough
- * room for the encryption (plus padding), otherwise we'll
- * indirectly throw a BufferOverFlowException runtime exception.
- *
- * position and limit will be the same, and points to the
- * next free spot.
- */
- void encrypt(CipherBox box, ByteBuffer bb) {
- box.encrypt(bb);
- }
-
/*
* Override the actual write below. We do things this way to be
* consistent with InputRecord. InputRecord may try to write out
@@ -160,7 +114,8 @@
* Copy data out of buffer, it's ready to go.
*/
ByteBuffer netBB = (ByteBuffer)
- ByteBuffer.allocate(len).put(buf, 0, len).flip();
+ ByteBuffer.allocate(len).put(buf, off, len).flip();
+
writer.putOutboundData(netBB);
}
@@ -168,17 +123,19 @@
* Main method for writing non-application data.
* We MAC/encrypt, then send down for processing.
*/
- void write(MAC writeMAC, CipherBox writeCipher) throws IOException {
+ void write(Authenticator authenticator, CipherBox writeCipher)
+ throws IOException {
+
/*
* Sanity check.
*/
switch (contentType()) {
- case ct_change_cipher_spec:
- case ct_alert:
- case ct_handshake:
- break;
- default:
- throw new RuntimeException("unexpected byte buffers");
+ case ct_change_cipher_spec:
+ case ct_alert:
+ case ct_handshake:
+ break;
+ default:
+ throw new RuntimeException("unexpected byte buffers");
}
/*
@@ -193,10 +150,10 @@
*/
if (!isEmpty()) {
// compress(); // eventually
- addMAC(writeMAC);
- encrypt(writeCipher);
- write((OutputStream)null, false, // send down for processing
- (ByteArrayOutputStream)null);
+ encrypt(authenticator, writeCipher);
+
+ // send down for processing
+ write((OutputStream)null, false, (ByteArrayOutputStream)null);
}
return;
}
@@ -204,8 +161,8 @@
/**
* Main wrap/write driver.
*/
- void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher)
- throws IOException {
+ void write(EngineArgs ea, Authenticator authenticator,
+ CipherBox writeCipher) throws IOException {
/*
* sanity check to make sure someone didn't inadvertantly
* send us an impossible combination we don't know how
@@ -217,7 +174,7 @@
* Have we set the MAC's yet? If not, we're not ready
* to process application data yet.
*/
- if (writeMAC == MAC.NULL) {
+ if (authenticator == MAC.NULL) {
return;
}
@@ -255,7 +212,7 @@
*/
int length;
if (engine.needToSplitPayload(writeCipher, protocolVersion)) {
- write(ea, writeMAC, writeCipher, 0x01);
+ write(ea, authenticator, writeCipher, 0x01);
ea.resetLim(); // reset application data buffer limit
length = Math.min(ea.getAppRemaining(),
maxDataSizeMinusOneByteRecord);
@@ -265,14 +222,14 @@
// Don't bother to really write empty records.
if (length > 0) {
- write(ea, writeMAC, writeCipher, length);
+ write(ea, authenticator, writeCipher, length);
}
return;
}
- void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher,
- int length) throws IOException {
+ void write(EngineArgs ea, Authenticator authenticator,
+ CipherBox writeCipher, int length) throws IOException {
/*
* Copy out existing buffer values.
*/
@@ -286,39 +243,76 @@
* Don't need to worry about SSLv2 rewrites, if we're here,
* that's long since done.
*/
- int dstData = dstPos + headerSize;
+ int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize();
dstBB.position(dstData);
+ /*
+ * transfer application data into the network data buffer
+ */
ea.gather(length);
+ dstBB.limit(dstBB.position());
+ dstBB.position(dstData);
/*
* "flip" but skip over header again, add MAC & encrypt
- * addMAC will expand the limit to reflect the new
- * data.
*/
- dstBB.limit(dstBB.position());
- dstBB.position(dstData);
- addMAC(writeMAC, dstBB);
+ if (authenticator instanceof MAC) {
+ MAC signer = (MAC)authenticator;
+ if (signer.MAClen() != 0) {
+ byte[] hash = signer.compute(contentType(), dstBB, false);
+
+ /*
+ * position was advanced to limit in compute above.
+ *
+ * Mark next area as writable (above layers should have
+ * established that we have plenty of room), then write
+ * out the hash.
+ */
+ dstBB.limit(dstBB.limit() + hash.length);
+ dstBB.put(hash);
+
+ // reset the position and limit
+ dstBB.limit(dstBB.position());
+ dstBB.position(dstData);
+ }
+ }
- /*
- * Encrypt may pad, so again the limit may have changed.
- */
- dstBB.limit(dstBB.position());
- dstBB.position(dstData);
- encrypt(writeCipher, dstBB);
+ if (!writeCipher.isNullCipher()) {
+ /*
+ * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1
+ * or later.
+ */
+ if (protocolVersion.v >= ProtocolVersion.TLS11.v &&
+ (writeCipher.isCBCMode() || writeCipher.isAEADMode())) {
+ byte[] nonce = writeCipher.createExplicitNonce(
+ authenticator, contentType(), dstBB.remaining());
+ dstBB.position(dstPos + headerSize);
+ dstBB.put(nonce);
+ if (!writeCipher.isAEADMode()) {
+ // The explicit IV in TLS 1.1 and later can be encrypted.
+ dstBB.position(dstPos + headerSize);
+ } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
+ }
- if (debug != null
- && (Debug.isOn("record") || Debug.isOn("handshake"))) {
- if ((debug != null && Debug.isOn("record"))
- || contentType() == ct_change_cipher_spec)
+ /*
+ * Encrypt may pad, so again the limit may have changed.
+ */
+ writeCipher.encrypt(dstBB, dstLim);
+
+ if ((debug != null) && (Debug.isOn("record") ||
+ (Debug.isOn("handshake") &&
+ (contentType() == ct_change_cipher_spec)))) {
System.out.println(Thread.currentThread().getName()
// v3.0/v3.1 ...
+ ", WRITE: " + protocolVersion
+ " " + InputRecord.contentName(contentType())
+ ", length = " + length);
+ }
+ } else {
+ dstBB.position(dstBB.limit());
}
- int packetLength = dstBB.limit() - dstData;
+ int packetLength = dstBB.limit() - dstPos - headerSize;
/*
* Finish out the record header.
@@ -333,7 +327,5 @@
* Position was already set by encrypt() above.
*/
dstBB.limit(dstLim);
-
- return;
}
}