src/java.base/share/classes/sun/security/ssl/OutputRecord.java

Print this page
8167680 DTLS implementation bugs
   1 /*
   2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 177         this.isFirstAppOutputRecord = true;
 178     }
 179 
 180     void changePacketSize(int packetSize) {
 181         this.packetSize = packetSize;
 182     }
 183 
 184     void changeFragmentSize(int fragmentSize) {
 185         this.fragmentSize = fragmentSize;
 186     }
 187 
 188     int getMaxPacketSize() {
 189         return packetSize;
 190     }
 191 
 192     // apply to DTLS SSLEngine
 193     void initHandshaker() {
 194         // blank
 195     }
 196 





 197     @Override
 198     public synchronized void close() throws IOException {
 199         if (!isClosed) {
 200             isClosed = true;
 201             writeCipher.dispose();
 202         }
 203     }
 204 
 205     //
 206     // shared helpers
 207     //
 208 
 209     // Encrypt a fragment and wrap up a record.
 210     //
 211     // To be consistent with the spec of SSLEngine.wrap() methods, the
 212     // destination ByteBuffer's position is updated to reflect the amount
 213     // of data produced.  The limit remains the same.
 214     static long encrypt(Authenticator authenticator,
 215             CipherBox encCipher, byte contentType, ByteBuffer destination,
 216             int headerOffset, int dstLim, int headerSize,
 217             ProtocolVersion protocolVersion, boolean isDTLS) {
 218 
 219         byte[] sequenceNumber = null;
 220         int dstContent = destination.position();
 221 
 222         // Acquire the current sequence number before using.
 223         if (isDTLS) {
 224             sequenceNumber = authenticator.sequenceNumber();
 225         }
 226 



 227         // "flip" but skip over header again, add MAC & encrypt
 228         if (authenticator instanceof MAC) {
 229             MAC signer = (MAC)authenticator;
 230             if (signer.MAClen() != 0) {
 231                 byte[] hash = signer.compute(contentType, destination, false);
 232 
 233                 /*
 234                  * position was advanced to limit in MAC compute above.
 235                  *
 236                  * Mark next area as writable (above layers should have
 237                  * established that we have plenty of room), then write
 238                  * out the hash.
 239                  */
 240                 destination.limit(destination.limit() + hash.length);
 241                 destination.put(hash);
 242 
 243                 // reset the position and limit
 244                 destination.limit(destination.position());
 245                 destination.position(dstContent);




 246             }
 247         }

 248 
 249         if (!encCipher.isNullCipher()) {
 250             if (protocolVersion.useTLS11PlusSpec() &&
 251                     (encCipher.isCBCMode() || encCipher.isAEADMode())) {
 252                 byte[] nonce = encCipher.createExplicitNonce(
 253                         authenticator, contentType, destination.remaining());
 254                 destination.position(headerOffset + headerSize);
 255                 destination.put(nonce);
 256             }
 257             if (!encCipher.isAEADMode()) {
 258                 // The explicit IV in TLS 1.1 and later can be encrypted.
 259                 destination.position(headerOffset + headerSize);
 260             }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
 261 
 262             // Encrypt may pad, so again the limit may be changed.
 263             encCipher.encrypt(destination, dstLim);





 264         } else {
 265             destination.position(destination.limit());
 266         }
 267 
 268         // Finish out the record header.
 269         int fragLen = destination.limit() - headerOffset - headerSize;
 270 
 271         destination.put(headerOffset, contentType);         // content type
 272         destination.put(headerOffset + 1, protocolVersion.major);
 273         destination.put(headerOffset + 2, protocolVersion.minor);
 274         if (!isDTLS) {
 275             // fragment length
 276             destination.put(headerOffset + 3, (byte)(fragLen >> 8));
 277             destination.put(headerOffset + 4, (byte)fragLen);
 278         } else {
 279             // epoch and sequence_number
 280             destination.put(headerOffset + 3, sequenceNumber[0]);
 281             destination.put(headerOffset + 4, sequenceNumber[1]);
 282             destination.put(headerOffset + 5, sequenceNumber[2]);
 283             destination.put(headerOffset + 6, sequenceNumber[3]);
 284             destination.put(headerOffset + 7, sequenceNumber[4]);
 285             destination.put(headerOffset + 8, sequenceNumber[5]);
 286             destination.put(headerOffset + 9, sequenceNumber[6]);
 287             destination.put(headerOffset + 10, sequenceNumber[7]);
 288 
 289             // fragment length
 290             destination.put(headerOffset + 11, (byte)(fragLen >> 8));
 291             destination.put(headerOffset + 12, (byte)fragLen);
 292 
 293             // Increase the sequence number for next use.

 294             authenticator.increaseSequenceNumber();
 295         }

 296 
 297         // Update destination position to reflect the amount of data produced.
 298         destination.position(destination.limit());
 299 
 300         return Authenticator.toLong(sequenceNumber);
 301     }
 302 
 303     // Encrypt a fragment and wrap up a record.
 304     //
 305     // Uses the internal expandable buf variable and the current
 306     // protocolVersion variable.
 307     void encrypt(Authenticator authenticator,
 308             CipherBox encCipher, byte contentType, int headerSize) {
 309 
 310         int position = headerSize + writeCipher.getExplicitNonceSize();
 311 
 312         // "flip" but skip over header again, add MAC & encrypt
 313         int macLen = 0;
 314         if (authenticator instanceof MAC) {
 315             MAC signer = (MAC)authenticator;


   1 /*
   2  * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 177         this.isFirstAppOutputRecord = true;
 178     }
 179 
 180     void changePacketSize(int packetSize) {
 181         this.packetSize = packetSize;
 182     }
 183 
 184     void changeFragmentSize(int fragmentSize) {
 185         this.fragmentSize = fragmentSize;
 186     }
 187 
 188     int getMaxPacketSize() {
 189         return packetSize;
 190     }
 191 
 192     // apply to DTLS SSLEngine
 193     void initHandshaker() {
 194         // blank
 195     }
 196 
 197     // apply to DTLS SSLEngine
 198     void launchRetransmission() {
 199         // blank
 200     }
 201 
 202     @Override
 203     public synchronized void close() throws IOException {
 204         if (!isClosed) {
 205             isClosed = true;
 206             writeCipher.dispose();
 207         }
 208     }
 209 
 210     //
 211     // shared helpers
 212     //
 213 
 214     // Encrypt a fragment and wrap up a record.
 215     //
 216     // To be consistent with the spec of SSLEngine.wrap() methods, the
 217     // destination ByteBuffer's position is updated to reflect the amount
 218     // of data produced.  The limit remains the same.
 219     static long encrypt(Authenticator authenticator,
 220             CipherBox encCipher, byte contentType, ByteBuffer destination,
 221             int headerOffset, int dstLim, int headerSize,
 222             ProtocolVersion protocolVersion, boolean isDTLS) {
 223 
 224         byte[] sequenceNumber = null;
 225         int dstContent = destination.position();
 226 
 227         // Acquire the current sequence number before using.
 228         if (isDTLS) {
 229             sequenceNumber = authenticator.sequenceNumber();
 230         }
 231 
 232         // The sequence number may be shared for different purpose. 
 233         boolean sharedSequenceNumber = false;
 234 
 235         // "flip" but skip over header again, add MAC & encrypt
 236         if (authenticator instanceof MAC) {
 237             MAC signer = (MAC)authenticator;
 238             if (signer.MAClen() != 0) {
 239                 byte[] hash = signer.compute(contentType, destination, false);
 240 
 241                 /*
 242                  * position was advanced to limit in MAC compute above.
 243                  *
 244                  * Mark next area as writable (above layers should have
 245                  * established that we have plenty of room), then write
 246                  * out the hash.
 247                  */
 248                 destination.limit(destination.limit() + hash.length);
 249                 destination.put(hash);
 250 
 251                 // reset the position and limit
 252                 destination.limit(destination.position());
 253                 destination.position(dstContent);
 254 
 255                 // The signer has used and increased the sequence number.
 256                 if (isDTLS) {
 257                     sharedSequenceNumber = true;
 258                 }
 259             }
 260         }
 261 
 262         if (!encCipher.isNullCipher()) {
 263             if (protocolVersion.useTLS11PlusSpec() &&
 264                     (encCipher.isCBCMode() || encCipher.isAEADMode())) {
 265                 byte[] nonce = encCipher.createExplicitNonce(
 266                         authenticator, contentType, destination.remaining());
 267                 destination.position(headerOffset + headerSize);
 268                 destination.put(nonce);
 269             }
 270             if (!encCipher.isAEADMode()) {
 271                 // The explicit IV in TLS 1.1 and later can be encrypted.
 272                 destination.position(headerOffset + headerSize);
 273             }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
 274 
 275             // Encrypt may pad, so again the limit may be changed.
 276             encCipher.encrypt(destination, dstLim);
 277 
 278             // The cipher has used and increased the sequence number.
 279             if (isDTLS && encCipher.isAEADMode()) {
 280                 sharedSequenceNumber = true;
 281             }
 282         } else {
 283             destination.position(destination.limit());
 284         }
 285 
 286         // Finish out the record header.
 287         int fragLen = destination.limit() - headerOffset - headerSize;
 288 
 289         destination.put(headerOffset, contentType);         // content type
 290         destination.put(headerOffset + 1, protocolVersion.major);
 291         destination.put(headerOffset + 2, protocolVersion.minor);
 292         if (!isDTLS) {
 293             // fragment length
 294             destination.put(headerOffset + 3, (byte)(fragLen >> 8));
 295             destination.put(headerOffset + 4, (byte)fragLen);
 296         } else {
 297             // epoch and sequence_number
 298             destination.put(headerOffset + 3, sequenceNumber[0]);
 299             destination.put(headerOffset + 4, sequenceNumber[1]);
 300             destination.put(headerOffset + 5, sequenceNumber[2]);
 301             destination.put(headerOffset + 6, sequenceNumber[3]);
 302             destination.put(headerOffset + 7, sequenceNumber[4]);
 303             destination.put(headerOffset + 8, sequenceNumber[5]);
 304             destination.put(headerOffset + 9, sequenceNumber[6]);
 305             destination.put(headerOffset + 10, sequenceNumber[7]);
 306 
 307             // fragment length
 308             destination.put(headerOffset + 11, (byte)(fragLen >> 8));
 309             destination.put(headerOffset + 12, (byte)fragLen);
 310 
 311             // Increase the sequence number for next use if it is not shared.
 312             if (!sharedSequenceNumber) {
 313                 authenticator.increaseSequenceNumber();
 314             }
 315         }
 316 
 317         // Update destination position to reflect the amount of data produced.
 318         destination.position(destination.limit());
 319 
 320         return Authenticator.toLong(sequenceNumber);
 321     }
 322 
 323     // Encrypt a fragment and wrap up a record.
 324     //
 325     // Uses the internal expandable buf variable and the current
 326     // protocolVersion variable.
 327     void encrypt(Authenticator authenticator,
 328             CipherBox encCipher, byte contentType, int headerSize) {
 329 
 330         int position = headerSize + writeCipher.getExplicitNonceSize();
 331 
 332         // "flip" but skip over header again, add MAC & encrypt
 333         int macLen = 0;
 334         if (authenticator instanceof MAC) {
 335             MAC signer = (MAC)authenticator;