< prev index next >

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

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 1996, 2016, 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 --- 1,7 ---- /* ! * Copyright (c) 1996, 2018, 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,42 **** package sun.security.ssl; import java.io.*; import java.nio.*; import java.util.*; - - import javax.crypto.BadPaddingException; - import javax.net.ssl.*; ! ! import sun.security.util.HexDumpEncoder; ! import static sun.security.ssl.Ciphertext.RecordType; /** * DTLS {@code OutputRecord} implementation for {@code SSLEngine}. */ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { --- 26,37 ---- package sun.security.ssl; import java.io.*; import java.nio.*; import java.util.*; import javax.net.ssl.*; ! import sun.security.ssl.SSLCipher.SSLWriteCipher; /** * DTLS {@code OutputRecord} implementation for {@code SSLEngine}. */ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord {
*** 45,102 **** int writeEpoch; int prevWriteEpoch; Authenticator prevWriteAuthenticator; ! CipherBox prevWriteCipher; ! private LinkedList<RecordMemo> alertMemos = new LinkedList<>(); ! DTLSOutputRecord() { ! this.writeAuthenticator = new MAC(true); this.writeEpoch = 0; this.prevWriteEpoch = 0; ! this.prevWriteCipher = CipherBox.NULL; ! this.prevWriteAuthenticator = new MAC(true); this.packetSize = DTLSRecord.maxRecordSize; ! this.protocolVersion = ProtocolVersion.DEFAULT_DTLS; } @Override ! void changeWriteCiphers(Authenticator writeAuthenticator, ! CipherBox writeCipher) throws IOException { encodeChangeCipherSpec(); prevWriteCipher.dispose(); - this.prevWriteAuthenticator = this.writeAuthenticator; this.prevWriteCipher = this.writeCipher; this.prevWriteEpoch = this.writeEpoch; - this.writeAuthenticator = writeAuthenticator; this.writeCipher = writeCipher; this.writeEpoch++; this.isFirstAppOutputRecord = true; // set the epoch number ! this.writeAuthenticator.setEpochNumber(this.writeEpoch); } @Override void encodeAlert(byte level, byte description) throws IOException { RecordMemo memo = new RecordMemo(); ! memo.contentType = Record.ct_alert; memo.majorVersion = protocolVersion.major; memo.minorVersion = protocolVersion.minor; memo.encodeEpoch = writeEpoch; memo.encodeCipher = writeCipher; - memo.encodeAuthenticator = writeAuthenticator; memo.fragment = new byte[2]; memo.fragment[0] = level; memo.fragment[1] = description; --- 40,105 ---- int writeEpoch; int prevWriteEpoch; Authenticator prevWriteAuthenticator; ! SSLWriteCipher prevWriteCipher; ! private final LinkedList<RecordMemo> alertMemos = new LinkedList<>(); ! DTLSOutputRecord(HandshakeHash handshakeHash) { ! super(handshakeHash, SSLWriteCipher.nullDTlsWriteCipher()); this.writeEpoch = 0; this.prevWriteEpoch = 0; ! this.prevWriteCipher = SSLWriteCipher.nullDTlsWriteCipher(); this.packetSize = DTLSRecord.maxRecordSize; ! this.protocolVersion = ProtocolVersion.NONE; } @Override ! void initHandshaker() { ! // clean up ! fragmenter = null; ! } + @Override + void finishHandshake() { + // fragmenter = null; + } + + @Override + void changeWriteCiphers(SSLWriteCipher writeCipher, + boolean useChangeCipherSpec) throws IOException { + if (useChangeCipherSpec) { encodeChangeCipherSpec(); + } prevWriteCipher.dispose(); this.prevWriteCipher = this.writeCipher; this.prevWriteEpoch = this.writeEpoch; this.writeCipher = writeCipher; this.writeEpoch++; this.isFirstAppOutputRecord = true; // set the epoch number ! this.writeCipher.authenticator.setEpochNumber(this.writeEpoch); } @Override void encodeAlert(byte level, byte description) throws IOException { RecordMemo memo = new RecordMemo(); ! memo.contentType = ContentType.ALERT.id; memo.majorVersion = protocolVersion.major; memo.minorVersion = protocolVersion.minor; memo.encodeEpoch = writeEpoch; memo.encodeCipher = writeCipher; memo.fragment = new byte[2]; memo.fragment[0] = level; memo.fragment[1] = description;
*** 112,122 **** } @Override void encodeHandshake(byte[] source, int offset, int length) throws IOException { - if (firstMessage) { firstMessage = false; } if (fragmenter == null) { --- 115,124 ----
*** 125,158 **** fragmenter.queueUpHandshake(source, offset, length); } @Override ! Ciphertext encode(ByteBuffer[] sources, int offset, int length, ByteBuffer destination) throws IOException { ! if (writeAuthenticator.seqNumOverflow()) { ! if (debug != null && Debug.isOn("ssl")) { ! System.out.println(Thread.currentThread().getName() + ! ", sequence number extremely close to overflow " + "(2^64-1 packets). Closing connection."); } throw new SSLHandshakeException("sequence number overflow"); } ! // not apply to handshake message ! int macLen = 0; ! if (writeAuthenticator instanceof MAC) { ! macLen = ((MAC)writeAuthenticator).MAClen(); } int fragLen; if (packetSize > 0) { fragLen = Math.min(maxRecordSize, packetSize); fragLen = writeCipher.calculateFragmentSize( ! fragLen, macLen, headerSize); fragLen = Math.min(fragLen, Record.maxDataSize); } else { fragLen = Record.maxDataSize; } --- 127,183 ---- fragmenter.queueUpHandshake(source, offset, length); } @Override ! Ciphertext encode( ! ByteBuffer[] srcs, int srcsOffset, int srcsLength, ! ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException { ! return encode(srcs, srcsOffset, srcsLength, dsts[0]); ! } ! ! private Ciphertext encode(ByteBuffer[] sources, int offset, int length, ByteBuffer destination) throws IOException { ! if (writeCipher.authenticator.seqNumOverflow()) { ! if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { ! SSLLogger.fine( ! "sequence number extremely close to overflow " + "(2^64-1 packets). Closing connection."); } throw new SSLHandshakeException("sequence number overflow"); } ! // Don't process the incoming record until all of the buffered records ! // get handled. May need retransmission if no sources specified. ! if (!isEmpty() || sources == null || sources.length == 0) { ! Ciphertext ct = acquireCiphertext(destination); ! if (ct != null) { ! return ct; ! } ! } ! ! if (sources == null || sources.length == 0) { ! return null; ! } ! ! int srcsRemains = 0; ! for (int i = offset; i < offset + length; i++) { ! srcsRemains += sources[i].remaining(); ! } ! ! if (srcsRemains == 0) { ! return null; } + // not apply to handshake message int fragLen; if (packetSize > 0) { fragLen = Math.min(maxRecordSize, packetSize); fragLen = writeCipher.calculateFragmentSize( ! fragLen, headerSize); fragLen = Math.min(fragLen, Record.maxDataSize); } else { fragLen = Record.maxDataSize; }
*** 181,228 **** } destination.limit(destination.position()); destination.position(dstContent); ! if ((debug != null) && Debug.isOn("record")) { ! System.out.println(Thread.currentThread().getName() + ! ", WRITE: " + protocolVersion + " " + ! Record.contentName(Record.ct_application_data) + ", length = " + destination.remaining()); } // Encrypt the fragment and wrap up a record. ! long recordSN = encrypt(writeAuthenticator, writeCipher, ! Record.ct_application_data, destination, dstPos, dstLim, headerSize, ! protocolVersion, true); ! if ((debug != null) && Debug.isOn("packet")) { ByteBuffer temporary = destination.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); ! Debug.printHex( ! "[Raw write]: length = " + temporary.remaining(), ! temporary); } // remain the limit unchanged destination.limit(dstLim); ! return new Ciphertext(RecordType.RECORD_APPLICATION_DATA, recordSN); } ! @Override ! Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException { if (alertMemos != null && !alertMemos.isEmpty()) { RecordMemo memo = alertMemos.pop(); - int macLen = 0; - if (memo.encodeAuthenticator instanceof MAC) { - macLen = ((MAC)memo.encodeAuthenticator).MAClen(); - } - int dstPos = destination.position(); int dstLim = destination.limit(); int dstContent = dstPos + headerSize + writeCipher.getExplicitNonceSize(); destination.position(dstContent); --- 206,247 ---- } destination.limit(destination.position()); destination.position(dstContent); ! if (SSLLogger.isOn && SSLLogger.isOn("record")) { ! SSLLogger.fine( ! "WRITE: " + protocolVersion + " " + ! ContentType.APPLICATION_DATA.name + ", length = " + destination.remaining()); } // Encrypt the fragment and wrap up a record. ! long recordSN = encrypt(writeCipher, ! ContentType.APPLICATION_DATA.id, destination, dstPos, dstLim, headerSize, ! protocolVersion); ! if (SSLLogger.isOn && SSLLogger.isOn("packet")) { ByteBuffer temporary = destination.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); ! SSLLogger.fine("Raw write", temporary); } // remain the limit unchanged destination.limit(dstLim); ! return new Ciphertext(ContentType.APPLICATION_DATA.id, ! SSLHandshake.NOT_APPLICABLE.id, recordSN); } ! private Ciphertext acquireCiphertext( ! ByteBuffer destination) throws IOException { if (alertMemos != null && !alertMemos.isEmpty()) { RecordMemo memo = alertMemos.pop(); int dstPos = destination.position(); int dstLim = destination.limit(); int dstContent = dstPos + headerSize + writeCipher.getExplicitNonceSize(); destination.position(dstContent);
*** 230,265 **** destination.put(memo.fragment); destination.limit(destination.position()); destination.position(dstContent); ! if ((debug != null) && Debug.isOn("record")) { ! System.out.println(Thread.currentThread().getName() + ! ", WRITE: " + protocolVersion + " " + ! Record.contentName(Record.ct_alert) + ", length = " + destination.remaining()); } // Encrypt the fragment and wrap up a record. ! long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher, ! Record.ct_alert, destination, dstPos, dstLim, headerSize, ProtocolVersion.valueOf(memo.majorVersion, ! memo.minorVersion), true); ! if ((debug != null) && Debug.isOn("packet")) { ByteBuffer temporary = destination.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); ! Debug.printHex( ! "[Raw write]: length = " + temporary.remaining(), ! temporary); } // remain the limit unchanged destination.limit(dstLim); ! return new Ciphertext(RecordType.RECORD_ALERT, recordSN); } if (fragmenter != null) { return fragmenter.acquireCiphertext(destination); } --- 249,284 ---- destination.put(memo.fragment); destination.limit(destination.position()); destination.position(dstContent); ! if (SSLLogger.isOn && SSLLogger.isOn("record")) { ! SSLLogger.fine( ! "WRITE: " + protocolVersion + " " + ! ContentType.ALERT.name + ", length = " + destination.remaining()); } // Encrypt the fragment and wrap up a record. ! long recordSN = encrypt(memo.encodeCipher, ! ContentType.ALERT.id, ! destination, dstPos, dstLim, headerSize, ProtocolVersion.valueOf(memo.majorVersion, ! memo.minorVersion)); ! if (SSLLogger.isOn && SSLLogger.isOn("packet")) { ByteBuffer temporary = destination.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); ! SSLLogger.fine("Raw write", temporary); } // remain the limit unchanged destination.limit(dstLim); ! return new Ciphertext(ContentType.ALERT.id, ! SSLHandshake.NOT_APPLICABLE.id, recordSN); } if (fragmenter != null) { return fragmenter.acquireCiphertext(destination); }
*** 272,287 **** return ((fragmenter == null) || fragmenter.isEmpty()) && ((alertMemos == null) || alertMemos.isEmpty()); } @Override - void initHandshaker() { - // clean up - fragmenter = null; - } - - @Override void launchRetransmission() { // Note: Please don't retransmit if there are handshake messages // or alerts waiting in the queue. if (((alertMemos == null) || alertMemos.isEmpty()) && (fragmenter != null) && fragmenter.isRetransmittable()) { --- 291,300 ----
*** 293,304 **** private static class RecordMemo { byte contentType; byte majorVersion; byte minorVersion; int encodeEpoch; ! CipherBox encodeCipher; ! Authenticator encodeAuthenticator; byte[] fragment; } private static class HandshakeMemo extends RecordMemo { --- 306,316 ---- private static class RecordMemo { byte contentType; byte majorVersion; byte minorVersion; int encodeEpoch; ! SSLWriteCipher encodeCipher; byte[] fragment; } private static class HandshakeMemo extends RecordMemo {
*** 306,316 **** int messageSequence; int acquireOffset; } private final class DTLSFragmenter { ! private LinkedList<RecordMemo> handshakeMemos = new LinkedList<>(); private int acquireIndex = 0; private int messageSequence = 0; private boolean flightIsReady = false; // Per section 4.1.1, RFC 6347: --- 318,329 ---- int messageSequence; int acquireOffset; } private final class DTLSFragmenter { ! private final LinkedList<RecordMemo> handshakeMemos = ! new LinkedList<>(); private int acquireIndex = 0; private int messageSequence = 0; private boolean flightIsReady = false; // Per section 4.1.1, RFC 6347:
*** 334,349 **** flightIsReady = false; } RecordMemo memo = new RecordMemo(); ! memo.contentType = Record.ct_change_cipher_spec; memo.majorVersion = protocolVersion.major; memo.minorVersion = protocolVersion.minor; memo.encodeEpoch = writeEpoch; memo.encodeCipher = writeCipher; - memo.encodeAuthenticator = writeAuthenticator; memo.fragment = new byte[1]; memo.fragment[0] = 1; handshakeMemos.add(memo); --- 347,361 ---- flightIsReady = false; } RecordMemo memo = new RecordMemo(); ! memo.contentType = ContentType.CHANGE_CIPHER_SPEC.id; memo.majorVersion = protocolVersion.major; memo.minorVersion = protocolVersion.minor; memo.encodeEpoch = writeEpoch; memo.encodeCipher = writeCipher; memo.fragment = new byte[1]; memo.fragment[0] = 1; handshakeMemos.add(memo);
*** 359,374 **** flightIsReady = false; } HandshakeMemo memo = new HandshakeMemo(); ! memo.contentType = Record.ct_handshake; memo.majorVersion = protocolVersion.major; memo.minorVersion = protocolVersion.minor; memo.encodeEpoch = writeEpoch; memo.encodeCipher = writeCipher; - memo.encodeAuthenticator = writeAuthenticator; memo.handshakeType = buf[offset]; memo.messageSequence = messageSequence++; memo.acquireOffset = 0; memo.fragment = new byte[length - 4]; // 4: header size --- 371,385 ---- flightIsReady = false; } HandshakeMemo memo = new HandshakeMemo(); ! memo.contentType = ContentType.HANDSHAKE.id; memo.majorVersion = protocolVersion.major; memo.minorVersion = protocolVersion.minor; memo.encodeEpoch = writeEpoch; memo.encodeCipher = writeCipher; memo.handshakeType = buf[offset]; memo.messageSequence = messageSequence++; memo.acquireOffset = 0; memo.fragment = new byte[length - 4]; // 4: header size
*** 377,392 **** System.arraycopy(buf, offset + 4, memo.fragment, 0, length - 4); handshakeHashing(memo, memo.fragment); handshakeMemos.add(memo); ! if ((memo.handshakeType == HandshakeMessage.ht_client_hello) || ! (memo.handshakeType == HandshakeMessage.ht_hello_request) || (memo.handshakeType == ! HandshakeMessage.ht_hello_verify_request) || ! (memo.handshakeType == HandshakeMessage.ht_server_hello_done) || ! (memo.handshakeType == HandshakeMessage.ht_finished)) { flightIsReady = true; } } --- 388,403 ---- System.arraycopy(buf, offset + 4, memo.fragment, 0, length - 4); handshakeHashing(memo, memo.fragment); handshakeMemos.add(memo); ! if ((memo.handshakeType == SSLHandshake.CLIENT_HELLO.id) || ! (memo.handshakeType == SSLHandshake.HELLO_REQUEST.id) || (memo.handshakeType == ! SSLHandshake.HELLO_VERIFY_REQUEST.id) || ! (memo.handshakeType == SSLHandshake.SERVER_HELLO_DONE.id) || ! (memo.handshakeType == SSLHandshake.FINISHED.id)) { flightIsReady = true; } }
*** 399,424 **** } } RecordMemo memo = handshakeMemos.get(acquireIndex); HandshakeMemo hsMemo = null; ! if (memo.contentType == Record.ct_handshake) { hsMemo = (HandshakeMemo)memo; } - int macLen = 0; - if (memo.encodeAuthenticator instanceof MAC) { - macLen = ((MAC)memo.encodeAuthenticator).MAClen(); - } - // ChangeCipherSpec message is pretty small. Don't worry about // the fragmentation of ChangeCipherSpec record. int fragLen; if (packetSize > 0) { fragLen = Math.min(maxRecordSize, packetSize); fragLen = memo.encodeCipher.calculateFragmentSize( ! fragLen, macLen, 25); // 25: header size // 13: DTLS record // 12: DTLS handshake message fragLen = Math.min(fragLen, Record.maxDataSize); } else { fragLen = Record.maxDataSize; --- 410,430 ---- } } RecordMemo memo = handshakeMemos.get(acquireIndex); HandshakeMemo hsMemo = null; ! if (memo.contentType == ContentType.HANDSHAKE.id) { hsMemo = (HandshakeMemo)memo; } // ChangeCipherSpec message is pretty small. Don't worry about // the fragmentation of ChangeCipherSpec record. int fragLen; if (packetSize > 0) { fragLen = Math.min(maxRecordSize, packetSize); fragLen = memo.encodeCipher.calculateFragmentSize( ! fragLen, 25); // 25: header size // 13: DTLS record // 12: DTLS handshake message fragLen = Math.min(fragLen, Record.maxDataSize); } else { fragLen = Record.maxDataSize;
*** 457,487 **** } dstBuf.limit(dstBuf.position()); dstBuf.position(dstContent); ! if ((debug != null) && Debug.isOn("record")) { ! System.out.println(Thread.currentThread().getName() + ! ", WRITE: " + protocolVersion + " " + ! Record.contentName(memo.contentType) + ", length = " + dstBuf.remaining()); } // Encrypt the fragment and wrap up a record. ! long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher, memo.contentType, dstBuf, dstPos, dstLim, headerSize, ProtocolVersion.valueOf(memo.majorVersion, ! memo.minorVersion), true); ! if ((debug != null) && Debug.isOn("packet")) { ByteBuffer temporary = dstBuf.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); ! Debug.printHex( ! "[Raw write]: length = " + temporary.remaining(), ! temporary); } // remain the limit unchanged dstBuf.limit(dstLim); --- 463,492 ---- } dstBuf.limit(dstBuf.position()); dstBuf.position(dstContent); ! if (SSLLogger.isOn && SSLLogger.isOn("record")) { ! SSLLogger.fine( ! "WRITE: " + protocolVersion + " " + ! ContentType.nameOf(memo.contentType) + ", length = " + dstBuf.remaining()); } // Encrypt the fragment and wrap up a record. ! long recordSN = encrypt(memo.encodeCipher, memo.contentType, dstBuf, dstPos, dstLim, headerSize, ProtocolVersion.valueOf(memo.majorVersion, ! memo.minorVersion)); ! if (SSLLogger.isOn && SSLLogger.isOn("packet")) { ByteBuffer temporary = dstBuf.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); ! SSLLogger.fine( ! "Raw write (" + temporary.remaining() + ")", temporary); } // remain the limit unchanged dstBuf.limit(dstLim);
*** 490,532 **** hsMemo.acquireOffset += fragLen; if (hsMemo.acquireOffset == hsMemo.fragment.length) { acquireIndex++; } ! return new Ciphertext(RecordType.valueOf( ! hsMemo.contentType, hsMemo.handshakeType), recordSN); } else { acquireIndex++; ! return new Ciphertext( ! RecordType.RECORD_CHANGE_CIPHER_SPEC, recordSN); } } private void handshakeHashing(HandshakeMemo hsFrag, byte[] hsBody) { byte hsType = hsFrag.handshakeType; ! if ((hsType == HandshakeMessage.ht_hello_request) || ! (hsType == HandshakeMessage.ht_hello_verify_request)) { ! // omitted from handshake hash computation return; } - if ((hsFrag.messageSequence == 0) && - (hsType == HandshakeMessage.ht_client_hello)) { - - // omit initial ClientHello message - // - // 2: ClientHello.client_version - // 32: ClientHello.random - int sidLen = hsBody[34]; - - if (sidLen == 0) { // empty session_id, initial handshake - return; - } - } - // calculate the DTLS header byte[] temporary = new byte[12]; // 12: handshake header size // Handshake.msg_type temporary[0] = hsFrag.handshakeType; --- 495,521 ---- hsMemo.acquireOffset += fragLen; if (hsMemo.acquireOffset == hsMemo.fragment.length) { acquireIndex++; } ! return new Ciphertext(hsMemo.contentType, ! hsMemo.handshakeType, recordSN); } else { acquireIndex++; ! return new Ciphertext(ContentType.CHANGE_CIPHER_SPEC.id, ! SSLHandshake.NOT_APPLICABLE.id, recordSN); } } private void handshakeHashing(HandshakeMemo hsFrag, byte[] hsBody) { byte hsType = hsFrag.handshakeType; ! if (!handshakeHash.isHashable(hsType)) { // omitted from handshake hash computation return; } // calculate the DTLS header byte[] temporary = new byte[12]; // 12: handshake header size // Handshake.msg_type temporary[0] = hsFrag.handshakeType;
*** 548,568 **** // Handshake.fragment_length temporary[9] = temporary[1]; temporary[10] = temporary[2]; temporary[11] = temporary[3]; ! if ((hsType != HandshakeMessage.ht_finished) && ! (hsType != HandshakeMessage.ht_certificate_verify)) { ! ! handshakeHash.update(temporary, 0, 12); ! handshakeHash.update(hsBody, 0, hsBody.length); ! } else { ! // Reserve until this handshake message has been processed. ! handshakeHash.reserve(temporary, 0, 12); ! handshakeHash.reserve(hsBody, 0, hsBody.length); ! } ! } boolean isEmpty() { if (!flightIsReady || handshakeMemos.isEmpty() || acquireIndex >= handshakeMemos.size()) { --- 537,548 ---- // Handshake.fragment_length temporary[9] = temporary[1]; temporary[10] = temporary[2]; temporary[11] = temporary[3]; ! handshakeHash.deliver(temporary, 0, 12); ! handshakeHash.deliver(hsBody, 0, hsBody.length); } boolean isEmpty() { if (!flightIsReady || handshakeMemos.isEmpty() || acquireIndex >= handshakeMemos.size()) {
< prev index next >