src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 51407 910f7b56592f
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
     1 /*
     1 /*
     2  * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package sun.security.ssl;
    26 package sun.security.ssl;
    27 
    27 
    28 import java.io.*;
    28 import java.io.IOException;
    29 import java.nio.*;
    29 import java.nio.ByteBuffer;
    30 import java.util.*;
    30 import java.util.LinkedList;
    31 
       
    32 import javax.net.ssl.SSLException;
       
    33 import javax.net.ssl.SSLHandshakeException;
    31 import javax.net.ssl.SSLHandshakeException;
    34 import sun.security.util.HexDumpEncoder;
    32 
    35 import static sun.security.ssl.Ciphertext.RecordType;
    33 import sun.security.ssl.SSLCipher.SSLWriteCipher;
       
    34 import sun.security.ssl.KeyUpdate.KeyUpdateMessage;
       
    35 import sun.security.ssl.KeyUpdate.KeyUpdateRequest;
    36 
    36 
    37 /**
    37 /**
    38  * {@code OutputRecord} implementation for {@code SSLEngine}.
    38  * {@code OutputRecord} implementation for {@code SSLEngine}.
    39  */
    39  */
    40 final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord {
    40 final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord {
    41 
    41 
    42     private HandshakeFragment fragmenter = null;
    42     private HandshakeFragment fragmenter = null;
    43     private LinkedList<RecordMemo> alertMemos = new LinkedList<>();
       
    44     private boolean isTalkingToV2 = false;      // SSLv2Hello
    43     private boolean isTalkingToV2 = false;      // SSLv2Hello
    45     private ByteBuffer v2ClientHello = null;    // SSLv2Hello
    44     private ByteBuffer v2ClientHello = null;    // SSLv2Hello
    46 
    45 
    47     private boolean isCloseWaiting = false;
    46     private boolean isCloseWaiting = false;
    48 
    47 
    49     SSLEngineOutputRecord() {
    48     SSLEngineOutputRecord(HandshakeHash handshakeHash) {
    50         this.writeAuthenticator = MAC.TLS_NULL;
    49         super(handshakeHash, SSLWriteCipher.nullTlsWriteCipher());
    51 
    50 
    52         this.packetSize = SSLRecord.maxRecordSize;
    51         this.packetSize = SSLRecord.maxRecordSize;
    53         this.protocolVersion = ProtocolVersion.DEFAULT_TLS;
    52         this.protocolVersion = ProtocolVersion.NONE;
    54     }
    53     }
    55 
    54 
    56     @Override
    55     @Override
    57     public synchronized void close() throws IOException {
    56     public synchronized void close() throws IOException {
    58         if (!isClosed) {
    57         if (!isClosed) {
    59             if (alertMemos != null && !alertMemos.isEmpty()) {
    58             if (fragmenter != null && fragmenter.hasAlert()) {
    60                 isCloseWaiting = true;
    59                 isCloseWaiting = true;
    61             } else {
    60             } else {
    62                 super.close();
    61                 super.close();
    63             }
    62             }
    64         }
    63         }
    65     }
    64     }
    66 
    65 
    67     @Override
    66     @Override
    68     void encodeAlert(byte level, byte description) throws IOException {
    67     void encodeAlert(byte level, byte description) throws IOException {
    69         RecordMemo memo = new RecordMemo();
    68         if (fragmenter == null) {
    70 
    69            fragmenter = new HandshakeFragment();
    71         memo.contentType = Record.ct_alert;
    70         }
    72         memo.majorVersion = protocolVersion.major;
    71 
    73         memo.minorVersion = protocolVersion.minor;
    72         fragmenter.queueUpAlert(level, description);
    74         memo.encodeCipher = writeCipher;
       
    75         memo.encodeAuthenticator = writeAuthenticator;
       
    76 
       
    77         memo.fragment = new byte[2];
       
    78         memo.fragment[0] = level;
       
    79         memo.fragment[1] = description;
       
    80 
       
    81         alertMemos.add(memo);
       
    82     }
    73     }
    83 
    74 
    84     @Override
    75     @Override
    85     void encodeHandshake(byte[] source,
    76     void encodeHandshake(byte[] source,
    86             int offset, int length) throws IOException {
    77             int offset, int length) throws IOException {
    91 
    82 
    92         if (firstMessage) {
    83         if (firstMessage) {
    93             firstMessage = false;
    84             firstMessage = false;
    94 
    85 
    95             if ((helloVersion == ProtocolVersion.SSL20Hello) &&
    86             if ((helloVersion == ProtocolVersion.SSL20Hello) &&
    96                 (source[offset] == HandshakeMessage.ht_client_hello) &&
    87                 (source[offset] == SSLHandshake.CLIENT_HELLO.id) &&
    97                                             //  5: recode header size
    88                                             //  5: recode header size
    98                 (source[offset + 4 + 2 + 32] == 0)) {
    89                 (source[offset + 4 + 2 + 32] == 0)) {
    99                                             // V3 session ID is empty
    90                                             // V3 session ID is empty
   100                                             //  4: handshake header size
    91                                             //  4: handshake header size
   101                                             //  2: client_version in ClientHello
    92                                             //  2: client_version in ClientHello
   104                 // Double space should be big enough for the converted message.
    95                 // Double space should be big enough for the converted message.
   105                 v2ClientHello = encodeV2ClientHello(
    96                 v2ClientHello = encodeV2ClientHello(
   106                         source, (offset + 4), (length - 4));
    97                         source, (offset + 4), (length - 4));
   107 
    98 
   108                 v2ClientHello.position(2);     // exclude the header
    99                 v2ClientHello.position(2);     // exclude the header
   109                 handshakeHash.update(v2ClientHello);
   100                 handshakeHash.deliver(v2ClientHello);
   110                 v2ClientHello.position(0);
   101                 v2ClientHello.position(0);
   111 
   102 
   112                 return;
   103                 return;
   113             }
   104             }
   114         }
   105         }
   115 
   106 
   116         byte handshakeType = source[offset];
   107         byte handshakeType = source[offset];
   117         if (handshakeType != HandshakeMessage.ht_hello_request) {
   108         if (handshakeHash.isHashable(handshakeType)) {
   118             handshakeHash.update(source, offset, length);
   109             handshakeHash.deliver(source, offset, length);
   119         }
   110         }
   120 
   111 
   121         fragmenter.queueUpFragment(source, offset, length);
   112         fragmenter.queueUpFragment(source, offset, length);
   122     }
   113     }
   123 
   114 
   133     void encodeV2NoCipher() throws IOException {
   124     void encodeV2NoCipher() throws IOException {
   134         isTalkingToV2 = true;
   125         isTalkingToV2 = true;
   135     }
   126     }
   136 
   127 
   137     @Override
   128     @Override
   138     Ciphertext encode(ByteBuffer[] sources, int offset, int length,
   129     Ciphertext encode(
       
   130         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
       
   131         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
       
   132         return encode(srcs, srcsOffset, srcsLength, dsts[0]);
       
   133     }
       
   134 
       
   135     private Ciphertext encode(ByteBuffer[] sources, int offset, int length,
   139             ByteBuffer destination) throws IOException {
   136             ByteBuffer destination) throws IOException {
   140 
   137 
   141         if (writeAuthenticator.seqNumOverflow()) {
   138         if (writeCipher.authenticator.seqNumOverflow()) {
   142             if (debug != null && Debug.isOn("ssl")) {
   139             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
   143                 System.out.println(Thread.currentThread().getName() +
   140                 SSLLogger.fine(
   144                     ", sequence number extremely close to overflow " +
   141                     "sequence number extremely close to overflow " +
   145                     "(2^64-1 packets). Closing connection.");
   142                     "(2^64-1 packets). Closing connection.");
   146             }
   143             }
   147 
   144 
   148             throw new SSLHandshakeException("sequence number overflow");
   145             throw new SSLHandshakeException("sequence number overflow");
   149         }
   146         }
   150 
   147 
   151         int macLen = 0;
   148         // Don't process the incoming record until all of the
   152         if (writeAuthenticator instanceof MAC) {
   149         // buffered records get handled.
   153             macLen = ((MAC)writeAuthenticator).MAClen();
   150         Ciphertext ct = acquireCiphertext(destination);
       
   151         if (ct != null) {
       
   152             return ct;
       
   153         }
       
   154 
       
   155         if (sources == null || sources.length == 0) {
       
   156             return null;
       
   157         }
       
   158 
       
   159         int srcsRemains = 0;
       
   160         for (int i = offset; i < offset + length; i++) {
       
   161             srcsRemains += sources[i].remaining();
       
   162         }
       
   163 
       
   164         if (srcsRemains == 0) {
       
   165             return null;
   154         }
   166         }
   155 
   167 
   156         int dstLim = destination.limit();
   168         int dstLim = destination.limit();
   157         boolean isFirstRecordOfThePayload = true;
   169         boolean isFirstRecordOfThePayload = true;
   158         int packetLeftSize = Math.min(maxRecordSize, packetSize);
   170         int packetLeftSize = Math.min(maxRecordSize, packetSize);
   168             } else {
   180             } else {
   169                 needMorePayload = false;
   181                 needMorePayload = false;
   170 
   182 
   171                 if (packetLeftSize > 0) {
   183                 if (packetLeftSize > 0) {
   172                     fragLen = writeCipher.calculateFragmentSize(
   184                     fragLen = writeCipher.calculateFragmentSize(
   173                             packetLeftSize, macLen, headerSize);
   185                             packetLeftSize, headerSize);
   174 
   186 
   175                     fragLen = Math.min(fragLen, Record.maxDataSize);
   187                     fragLen = Math.min(fragLen, Record.maxDataSize);
   176                 } else {
   188                 } else {
   177                     fragLen = Record.maxDataSize;
   189                     fragLen = Record.maxDataSize;
   178                 }
   190                 }
   206             }
   218             }
   207 
   219 
   208             destination.limit(destination.position());
   220             destination.limit(destination.position());
   209             destination.position(dstContent);
   221             destination.position(dstContent);
   210 
   222 
   211             if ((debug != null) && Debug.isOn("record")) {
   223             if (SSLLogger.isOn && SSLLogger.isOn("record")) {
   212                 System.out.println(Thread.currentThread().getName() +
   224                 SSLLogger.fine(
   213                         ", WRITE: " + protocolVersion + " " +
   225                         "WRITE: " + protocolVersion + " " +
   214                         Record.contentName(Record.ct_application_data) +
   226                         ContentType.APPLICATION_DATA.name +
   215                         ", length = " + destination.remaining());
   227                         ", length = " + destination.remaining());
   216             }
   228             }
   217 
   229 
   218             // Encrypt the fragment and wrap up a record.
   230             // Encrypt the fragment and wrap up a record.
   219             recordSN = encrypt(writeAuthenticator, writeCipher,
   231             recordSN = encrypt(writeCipher,
   220                     Record.ct_application_data, destination,
   232                     ContentType.APPLICATION_DATA.id, destination,
   221                     dstPos, dstLim, headerSize,
   233                     dstPos, dstLim, headerSize,
   222                     protocolVersion, false);
   234                     protocolVersion);
   223 
   235 
   224             if ((debug != null) && Debug.isOn("packet")) {
   236             if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   225                 ByteBuffer temporary = destination.duplicate();
   237                 ByteBuffer temporary = destination.duplicate();
   226                 temporary.limit(temporary.position());
   238                 temporary.limit(temporary.position());
   227                 temporary.position(dstPos);
   239                 temporary.position(dstPos);
   228                 Debug.printHex(
   240                 SSLLogger.fine("Raw write", temporary);
   229                         "[Raw write]: length = " + temporary.remaining(),
       
   230                         temporary);
       
   231             }
   241             }
   232 
   242 
   233             packetLeftSize -= destination.position() - dstPos;
   243             packetLeftSize -= destination.position() - dstPos;
   234 
   244 
   235             // remain the limit unchanged
   245             // remain the limit unchanged
   236             destination.limit(dstLim);
   246             destination.limit(dstLim);
   237 
   247 
   238             if (isFirstAppOutputRecord) {
   248             if (isFirstAppOutputRecord) {
   239                 isFirstAppOutputRecord = false;
   249                 isFirstAppOutputRecord = false;
   240             }
   250             }
   241         }
   251 
   242 
   252             // atKeyLimit() inactive when limits not checked, tc set when limits
   243         return new Ciphertext(RecordType.RECORD_APPLICATION_DATA, recordSN);
   253             // are active.
   244     }
   254             if (writeCipher.atKeyLimit()) {
   245 
   255                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
   246     @Override
   256                     SSLLogger.fine("KeyUpdate: triggered, write side.");
   247     Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException {
   257                 }
       
   258 
       
   259                 PostHandshakeContext p = new PostHandshakeContext(tc);
       
   260                 KeyUpdate.handshakeProducer.produce(p,
       
   261                     new KeyUpdateMessage(p, KeyUpdateRequest.REQUESTED));
       
   262             }
       
   263         }
       
   264 
       
   265         return new Ciphertext(ContentType.APPLICATION_DATA.id,
       
   266                 SSLHandshake.NOT_APPLICABLE.id, recordSN);
       
   267     }
       
   268 
       
   269     private Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException {
   248         if (isTalkingToV2) {              // SSLv2Hello
   270         if (isTalkingToV2) {              // SSLv2Hello
   249             // We don't support SSLv2.  Send an SSLv2 error message
   271             // We don't support SSLv2.  Send an SSLv2 error message
   250             // so that the connection can be closed gracefully.
   272             // so that the connection can be closed gracefully.
   251             //
   273             //
   252             // Please don't change the limit of the destination buffer.
   274             // Please don't change the limit of the destination buffer.
   253             destination.put(SSLRecord.v2NoCipher);
   275             destination.put(SSLRecord.v2NoCipher);
   254             if (debug != null && Debug.isOn("packet")) {
   276             if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   255                 Debug.printHex(
   277                 SSLLogger.fine("Raw write", SSLRecord.v2NoCipher);
   256                         "[Raw write]: length = " + SSLRecord.v2NoCipher.length,
       
   257                         SSLRecord.v2NoCipher);
       
   258             }
   278             }
   259 
   279 
   260             isTalkingToV2 = false;
   280             isTalkingToV2 = false;
   261 
   281 
   262             return new Ciphertext(RecordType.RECORD_ALERT, -1L);
   282             return new Ciphertext(ContentType.ALERT.id,
       
   283                     SSLHandshake.NOT_APPLICABLE.id, -1L);
   263         }
   284         }
   264 
   285 
   265         if (v2ClientHello != null) {
   286         if (v2ClientHello != null) {
   266             // deliver the SSLv2 format ClientHello message
   287             // deliver the SSLv2 format ClientHello message
   267             //
   288             //
   268             // Please don't change the limit of the destination buffer.
   289             // Please don't change the limit of the destination buffer.
   269             if (debug != null) {
   290             if (SSLLogger.isOn) {
   270                 if (Debug.isOn("record")) {
   291                 if (SSLLogger.isOn("record")) {
   271                      System.out.println(Thread.currentThread().getName() +
   292                      SSLLogger.fine(Thread.currentThread().getName() +
   272                             ", WRITE: SSLv2 ClientHello message" +
   293                             ", WRITE: SSLv2 ClientHello message" +
   273                             ", length = " + v2ClientHello.remaining());
   294                             ", length = " + v2ClientHello.remaining());
   274                 }
   295                 }
   275 
   296 
   276                 if (Debug.isOn("packet")) {
   297                 if (SSLLogger.isOn("packet")) {
   277                     Debug.printHex(
   298                     SSLLogger.fine("Raw write", v2ClientHello);
   278                         "[Raw write]: length = " + v2ClientHello.remaining(),
       
   279                         v2ClientHello);
       
   280                 }
   299                 }
   281             }
   300             }
   282 
   301 
   283             destination.put(v2ClientHello);
   302             destination.put(v2ClientHello);
   284             v2ClientHello = null;
   303             v2ClientHello = null;
   285 
   304 
   286             return new Ciphertext(RecordType.RECORD_CLIENT_HELLO, -1L);
   305             return new Ciphertext(ContentType.HANDSHAKE.id,
   287         }
   306                    SSLHandshake.CLIENT_HELLO.id, -1L);
   288 
       
   289         if (alertMemos != null && !alertMemos.isEmpty()) {
       
   290             RecordMemo memo = alertMemos.pop();
       
   291 
       
   292             int macLen = 0;
       
   293             if (memo.encodeAuthenticator instanceof MAC) {
       
   294                 macLen = ((MAC)memo.encodeAuthenticator).MAClen();
       
   295             }
       
   296 
       
   297             int dstPos = destination.position();
       
   298             int dstLim = destination.limit();
       
   299             int dstContent = dstPos + headerSize +
       
   300                                 writeCipher.getExplicitNonceSize();
       
   301             destination.position(dstContent);
       
   302 
       
   303             destination.put(memo.fragment);
       
   304 
       
   305             destination.limit(destination.position());
       
   306             destination.position(dstContent);
       
   307 
       
   308             if ((debug != null) && Debug.isOn("record")) {
       
   309                 System.out.println(Thread.currentThread().getName() +
       
   310                         ", WRITE: " + protocolVersion + " " +
       
   311                         Record.contentName(Record.ct_alert) +
       
   312                         ", length = " + destination.remaining());
       
   313             }
       
   314 
       
   315             // Encrypt the fragment and wrap up a record.
       
   316             long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
       
   317                     Record.ct_alert, destination, dstPos, dstLim, headerSize,
       
   318                     ProtocolVersion.valueOf(memo.majorVersion,
       
   319                             memo.minorVersion), false);
       
   320 
       
   321             if ((debug != null) && Debug.isOn("packet")) {
       
   322                 ByteBuffer temporary = destination.duplicate();
       
   323                 temporary.limit(temporary.position());
       
   324                 temporary.position(dstPos);
       
   325                 Debug.printHex(
       
   326                         "[Raw write]: length = " + temporary.remaining(),
       
   327                         temporary);
       
   328             }
       
   329 
       
   330             // remain the limit unchanged
       
   331             destination.limit(dstLim);
       
   332 
       
   333             if (isCloseWaiting && (memo.contentType == Record.ct_alert)) {
       
   334                 isCloseWaiting = true;
       
   335                 close();
       
   336             }
       
   337             return new Ciphertext(RecordType.RECORD_ALERT, recordSN);
       
   338         }
   307         }
   339 
   308 
   340         if (fragmenter != null) {
   309         if (fragmenter != null) {
   341             return fragmenter.acquireCiphertext(destination);
   310             return fragmenter.acquireCiphertext(destination);
   342         }
   311         }
   345     }
   314     }
   346 
   315 
   347     @Override
   316     @Override
   348     boolean isEmpty() {
   317     boolean isEmpty() {
   349         return (!isTalkingToV2) && (v2ClientHello == null) &&
   318         return (!isTalkingToV2) && (v2ClientHello == null) &&
   350                 ((fragmenter == null) || fragmenter.isEmpty()) &&
   319                 ((fragmenter == null) || fragmenter.isEmpty());
   351                 ((alertMemos == null) || alertMemos.isEmpty());
       
   352     }
   320     }
   353 
   321 
   354     // buffered record fragment
   322     // buffered record fragment
   355     private static class RecordMemo {
   323     private static class RecordMemo {
   356         byte            contentType;
   324         byte            contentType;
   357         byte            majorVersion;
   325         byte            majorVersion;
   358         byte            minorVersion;
   326         byte            minorVersion;
   359         CipherBox       encodeCipher;
   327         SSLWriteCipher  encodeCipher;
   360         Authenticator   encodeAuthenticator;
       
   361 
   328 
   362         byte[]          fragment;
   329         byte[]          fragment;
   363     }
   330     }
   364 
   331 
   365     private static class HandshakeMemo extends RecordMemo {
   332     private static class HandshakeMemo extends RecordMemo {
   370     final class HandshakeFragment {
   337     final class HandshakeFragment {
   371         private LinkedList<RecordMemo> handshakeMemos = new LinkedList<>();
   338         private LinkedList<RecordMemo> handshakeMemos = new LinkedList<>();
   372 
   339 
   373         void queueUpFragment(byte[] source,
   340         void queueUpFragment(byte[] source,
   374                 int offset, int length) throws IOException {
   341                 int offset, int length) throws IOException {
   375 
       
   376             HandshakeMemo memo = new HandshakeMemo();
   342             HandshakeMemo memo = new HandshakeMemo();
   377 
   343 
   378             memo.contentType = Record.ct_handshake;
   344             memo.contentType = ContentType.HANDSHAKE.id;
   379             memo.majorVersion = protocolVersion.major;  // kick start version?
   345             memo.majorVersion = protocolVersion.major;  // kick start version?
   380             memo.minorVersion = protocolVersion.minor;
   346             memo.minorVersion = protocolVersion.minor;
   381             memo.encodeCipher = writeCipher;
   347             memo.encodeCipher = writeCipher;
   382             memo.encodeAuthenticator = writeAuthenticator;
       
   383 
   348 
   384             memo.handshakeType = source[offset];
   349             memo.handshakeType = source[offset];
   385             memo.acquireOffset = 0;
   350             memo.acquireOffset = 0;
   386             memo.fragment = new byte[length - 4];       // 4: header size
   351             memo.fragment = new byte[length - 4];       // 4: header size
   387                                                         //    1: HandshakeType
   352                                                         //    1: HandshakeType
   392         }
   357         }
   393 
   358 
   394         void queueUpChangeCipherSpec() {
   359         void queueUpChangeCipherSpec() {
   395             RecordMemo memo = new RecordMemo();
   360             RecordMemo memo = new RecordMemo();
   396 
   361 
   397             memo.contentType = Record.ct_change_cipher_spec;
   362             memo.contentType = ContentType.CHANGE_CIPHER_SPEC.id;
   398             memo.majorVersion = protocolVersion.major;
   363             memo.majorVersion = protocolVersion.major;
   399             memo.minorVersion = protocolVersion.minor;
   364             memo.minorVersion = protocolVersion.minor;
   400             memo.encodeCipher = writeCipher;
   365             memo.encodeCipher = writeCipher;
   401             memo.encodeAuthenticator = writeAuthenticator;
       
   402 
   366 
   403             memo.fragment = new byte[1];
   367             memo.fragment = new byte[1];
   404             memo.fragment[0] = 1;
   368             memo.fragment[0] = 1;
       
   369 
       
   370             handshakeMemos.add(memo);
       
   371         }
       
   372 
       
   373         void queueUpAlert(byte level, byte description) {
       
   374             RecordMemo memo = new RecordMemo();
       
   375 
       
   376             memo.contentType = ContentType.ALERT.id;
       
   377             memo.majorVersion = protocolVersion.major;
       
   378             memo.minorVersion = protocolVersion.minor;
       
   379             memo.encodeCipher = writeCipher;
       
   380 
       
   381             memo.fragment = new byte[2];
       
   382             memo.fragment[0] = level;
       
   383             memo.fragment[1] = description;
   405 
   384 
   406             handshakeMemos.add(memo);
   385             handshakeMemos.add(memo);
   407         }
   386         }
   408 
   387 
   409         Ciphertext acquireCiphertext(ByteBuffer dstBuf) throws IOException {
   388         Ciphertext acquireCiphertext(ByteBuffer dstBuf) throws IOException {
   411                 return null;
   390                 return null;
   412             }
   391             }
   413 
   392 
   414             RecordMemo memo = handshakeMemos.getFirst();
   393             RecordMemo memo = handshakeMemos.getFirst();
   415             HandshakeMemo hsMemo = null;
   394             HandshakeMemo hsMemo = null;
   416             if (memo.contentType == Record.ct_handshake) {
   395             if (memo.contentType == ContentType.HANDSHAKE.id) {
   417                 hsMemo = (HandshakeMemo)memo;
   396                 hsMemo = (HandshakeMemo)memo;
   418             }
       
   419 
       
   420             int macLen = 0;
       
   421             if (memo.encodeAuthenticator instanceof MAC) {
       
   422                 macLen = ((MAC)memo.encodeAuthenticator).MAClen();
       
   423             }
   397             }
   424 
   398 
   425             // ChangeCipherSpec message is pretty small.  Don't worry about
   399             // ChangeCipherSpec message is pretty small.  Don't worry about
   426             // the fragmentation of ChangeCipherSpec record.
   400             // the fragmentation of ChangeCipherSpec record.
   427             int fragLen;
   401             int fragLen;
   428             if (packetSize > 0) {
   402             if (packetSize > 0) {
   429                 fragLen = Math.min(maxRecordSize, packetSize);
   403                 fragLen = Math.min(maxRecordSize, packetSize);
   430                 fragLen = memo.encodeCipher.calculateFragmentSize(
   404                 fragLen = memo.encodeCipher.calculateFragmentSize(
   431                         fragLen, macLen, headerSize);
   405                         fragLen, headerSize);
   432             } else {
   406             } else {
   433                 fragLen = Record.maxDataSize;
   407                 fragLen = Record.maxDataSize;
   434             }
   408             }
   435 
   409 
   436             if (fragmentSize > 0) {
   410             if (fragmentSize > 0) {
   472                         // still have space for more records?
   446                         // still have space for more records?
   473                         if ((remainingFragLen > chipLen) &&
   447                         if ((remainingFragLen > chipLen) &&
   474                                  !handshakeMemos.isEmpty()) {
   448                                  !handshakeMemos.isEmpty()) {
   475 
   449 
   476                             // look for the next buffered record fragment
   450                             // look for the next buffered record fragment
   477                             RecordMemo reMemo = handshakeMemos.getFirst();
   451                             RecordMemo rm = handshakeMemos.getFirst();
   478                             if (reMemo.contentType == Record.ct_handshake) {
   452                             if (rm.contentType == ContentType.HANDSHAKE.id &&
   479                                 hsMemo = (HandshakeMemo)reMemo;
   453                                     rm.encodeCipher == hsMemo.encodeCipher) {
       
   454                                 hsMemo = (HandshakeMemo)rm;
   480                             } else {
   455                             } else {
   481                                 // not handshake message, break the loop
   456                                 // not of the flight, break the loop
   482                                 break;
   457                                 break;
   483                             }
   458                             }
   484                         }
   459                         }
   485                     }
   460                     }
   486 
   461 
   487                     remainingFragLen -= chipLen;
   462                     remainingFragLen -= chipLen;
   488                 }
   463                 }
   489 
       
   490                 fragLen -= remainingFragLen;
       
   491             } else {
   464             } else {
   492                 fragLen = Math.min(fragLen, memo.fragment.length);
   465                 fragLen = Math.min(fragLen, memo.fragment.length);
   493                 dstBuf.put(memo.fragment, 0, fragLen);
   466                 dstBuf.put(memo.fragment, 0, fragLen);
   494 
   467 
   495                 handshakeMemos.removeFirst();
   468                 handshakeMemos.removeFirst();
   496             }
   469             }
   497 
   470 
   498             dstBuf.limit(dstBuf.position());
   471             dstBuf.limit(dstBuf.position());
   499             dstBuf.position(dstContent);
   472             dstBuf.position(dstContent);
   500 
   473 
   501             if ((debug != null) && Debug.isOn("record")) {
   474             if (SSLLogger.isOn && SSLLogger.isOn("record")) {
   502                 System.out.println(Thread.currentThread().getName() +
   475                 SSLLogger.fine(
   503                         ", WRITE: " + protocolVersion + " " +
   476                         "WRITE: " + protocolVersion + " " +
   504                         Record.contentName(memo.contentType) +
   477                         ContentType.nameOf(memo.contentType) +
   505                         ", length = " + dstBuf.remaining());
   478                         ", length = " + dstBuf.remaining());
   506             }
   479             }
   507 
   480 
   508             // Encrypt the fragment and wrap up a record.
   481             // Encrypt the fragment and wrap up a record.
   509             long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
   482             long recordSN = encrypt(
       
   483                     memo.encodeCipher,
   510                     memo.contentType, dstBuf,
   484                     memo.contentType, dstBuf,
   511                     dstPos, dstLim, headerSize,
   485                     dstPos, dstLim, headerSize,
   512                     ProtocolVersion.valueOf(memo.majorVersion,
   486                     ProtocolVersion.valueOf(memo.majorVersion,
   513                             memo.minorVersion), false);
   487                             memo.minorVersion));
   514 
   488 
   515             if ((debug != null) && Debug.isOn("packet")) {
   489             if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   516                 ByteBuffer temporary = dstBuf.duplicate();
   490                 ByteBuffer temporary = dstBuf.duplicate();
   517                 temporary.limit(temporary.position());
   491                 temporary.limit(temporary.position());
   518                 temporary.position(dstPos);
   492                 temporary.position(dstPos);
   519                 Debug.printHex(
   493                 SSLLogger.fine("Raw write", temporary);
   520                         "[Raw write]: length = " + temporary.remaining(),
       
   521                         temporary);
       
   522             }
   494             }
   523 
   495 
   524             // remain the limit unchanged
   496             // remain the limit unchanged
   525             dstBuf.limit(dstLim);
   497             dstBuf.limit(dstLim);
   526 
   498 
   527             // Reset the fragmentation offset.
   499             // Reset the fragmentation offset.
   528             if (hsMemo != null) {
   500             if (hsMemo != null) {
   529                 return new Ciphertext(RecordType.valueOf(
   501                 return new Ciphertext(hsMemo.contentType,
   530                         hsMemo.contentType, hsMemo.handshakeType), recordSN);
   502                         hsMemo.handshakeType, recordSN);
   531             } else {
   503             } else {
   532                 return new Ciphertext(
   504                 if (isCloseWaiting &&
   533                         RecordType.RECORD_CHANGE_CIPHER_SPEC, recordSN);
   505                         memo.contentType == ContentType.ALERT.id) {
       
   506                     close();
       
   507                 }
       
   508 
       
   509                 return new Ciphertext(memo.contentType,
       
   510                         SSLHandshake.NOT_APPLICABLE.id, recordSN);
   534             }
   511             }
   535         }
   512         }
   536 
   513 
   537         boolean isEmpty() {
   514         boolean isEmpty() {
   538             return handshakeMemos.isEmpty();
   515             return handshakeMemos.isEmpty();
       
   516         }
       
   517 
       
   518         boolean hasAlert() {
       
   519             for (RecordMemo memo : handshakeMemos) {
       
   520                 if (memo.contentType ==  ContentType.ALERT.id) {
       
   521                     return true;
       
   522                 }
       
   523             }
       
   524 
       
   525             return false;
   539         }
   526         }
   540     }
   527     }
   541 
   528 
   542     /*
   529     /*
   543      * Need to split the payload except the following cases:
   530      * Need to split the payload except the following cases: