1 /*
   2  * Copyright (c) 2018, 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
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.security.AccessControlContext;
  30 import java.security.AccessController;
  31 import java.security.PrivilegedAction;
  32 import java.util.HashMap;
  33 import java.util.HashSet;
  34 import java.util.List;
  35 import java.util.Map;
  36 import java.util.Set;
  37 import javax.net.ssl.HandshakeCompletedEvent;
  38 import javax.net.ssl.HandshakeCompletedListener;
  39 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  40 import javax.net.ssl.SSLException;
  41 import javax.net.ssl.SSLSocket;
  42 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
  43 
  44 /**
  45  * SSL/(D)TLS transportation context.
  46  */
  47 class TransportContext implements ConnectionContext {
  48     final SSLTransport              transport;
  49 
  50     // registered plaintext consumers
  51     final Map<Byte, SSLConsumer>    consumers;
  52     final AccessControlContext      acc;
  53 
  54     final SSLContextImpl            sslContext;
  55     final SSLConfiguration          sslConfig;
  56     final InputRecord               inputRecord;
  57     final OutputRecord              outputRecord;
  58 
  59     // connection status
  60     boolean                         isUnsureMode;
  61     boolean                         isNegotiated = false;
  62     boolean                         isBroken = false;
  63     boolean                         isInputCloseNotified = false;
  64     boolean                         peerUserCanceled = false;
  65     Exception                       closeReason = null;
  66     Exception                       delegatedThrown = null;
  67 
  68     // negotiated security parameters
  69     SSLSessionImpl                  conSession;
  70     ProtocolVersion                 protocolVersion;
  71     String                          applicationProtocol= null;
  72 
  73     // handshake context
  74     HandshakeContext                handshakeContext = null;
  75 
  76     // connection reserved status for handshake.
  77     boolean                         secureRenegotiation = false;
  78     byte[]                          clientVerifyData;
  79     byte[]                          serverVerifyData;
  80 
  81     // connection sensitive configuration
  82     List<NamedGroup>                serverRequestedNamedGroups;
  83 
  84     CipherSuite cipherSuite;
  85     private static final byte[] emptyByteArray = new byte[0];
  86 
  87     // Please never use the transport parameter other than storing a
  88     // reference to this object.
  89     //
  90     // Called by SSLEngineImpl
  91     TransportContext(SSLContextImpl sslContext, SSLTransport transport,
  92             InputRecord inputRecord, OutputRecord outputRecord) {
  93         this(sslContext, transport, new SSLConfiguration(sslContext, true),
  94                 inputRecord, outputRecord, true);
  95     }
  96 
  97     // Please never use the transport parameter other than storing a
  98     // reference to this object.
  99     //
 100     // Called by SSLSocketImpl
 101     TransportContext(SSLContextImpl sslContext, SSLTransport transport,
 102             InputRecord inputRecord, OutputRecord outputRecord,
 103             boolean isClientMode) {
 104         this(sslContext, transport,
 105                 new SSLConfiguration(sslContext, isClientMode),
 106                 inputRecord, outputRecord, false);
 107     }
 108 
 109     // Please never use the transport parameter other than storing a
 110     // reference to this object.
 111     //
 112     // Called by SSLSocketImpl with an existing SSLConfig
 113     TransportContext(SSLContextImpl sslContext, SSLTransport transport,
 114             SSLConfiguration sslConfig,
 115             InputRecord inputRecord, OutputRecord outputRecord) {
 116         this(sslContext, transport, (SSLConfiguration)sslConfig.clone(),
 117                 inputRecord, outputRecord, false);
 118     }
 119 
 120     private TransportContext(SSLContextImpl sslContext, SSLTransport transport,
 121             SSLConfiguration sslConfig, InputRecord inputRecord,
 122             OutputRecord outputRecord, boolean isUnsureMode) {
 123         this.transport = transport;
 124         this.sslContext = sslContext;
 125         this.inputRecord = inputRecord;
 126         this.outputRecord = outputRecord;
 127         this.sslConfig = sslConfig;
 128         if (this.sslConfig.maximumPacketSize == 0) {
 129             this.sslConfig.maximumPacketSize = outputRecord.getMaxPacketSize();
 130         }
 131         this.isUnsureMode = isUnsureMode;
 132 
 133         // initial security parameters
 134         this.conSession = SSLSessionImpl.nullSession;
 135         this.protocolVersion = this.sslConfig.maximumProtocolVersion;
 136         this.clientVerifyData = emptyByteArray;
 137         this.serverVerifyData = emptyByteArray;
 138 
 139         this.acc = AccessController.getContext();
 140         this.consumers = new HashMap<>();
 141     }
 142 
 143     // Dispatch plaintext to a specific consumer.
 144     void dispatch(Plaintext plaintext) throws IOException {
 145         if (plaintext == null) {
 146             return;
 147         }
 148 
 149         ContentType ct = ContentType.valueOf(plaintext.contentType);
 150         if (ct == null) {
 151             throw fatal(Alert.UNEXPECTED_MESSAGE,
 152                 "Unknown content type: " + plaintext.contentType);
 153         }
 154 
 155         switch (ct) {
 156             case HANDSHAKE:
 157                 byte type = HandshakeContext.getHandshakeType(this,
 158                         plaintext);
 159                 if (handshakeContext == null) {
 160                     if (type == SSLHandshake.KEY_UPDATE.id ||
 161                             type == SSLHandshake.NEW_SESSION_TICKET.id) {
 162                         if (isNegotiated &&
 163                                 protocolVersion.useTLS13PlusSpec()) {
 164                             handshakeContext = new PostHandshakeContext(this);
 165                         } else {
 166                             throw fatal(Alert.UNEXPECTED_MESSAGE,
 167                                     "Unexpected post-handshake message: " +
 168                                     SSLHandshake.nameOf(type));
 169                         }
 170                     } else {
 171                         handshakeContext = sslConfig.isClientMode ?
 172                                 new ClientHandshakeContext(sslContext, this) :
 173                                 new ServerHandshakeContext(sslContext, this);
 174                         outputRecord.initHandshaker();
 175                     }
 176                 }
 177                 handshakeContext.dispatch(type, plaintext);
 178                 break;
 179             case ALERT:
 180                 Alert.alertConsumer.consume(this, plaintext.fragment);
 181                 break;
 182             default:
 183                 SSLConsumer consumer = consumers.get(plaintext.contentType);
 184                 if (consumer != null) {
 185                     consumer.consume(this, plaintext.fragment);
 186                 } else {
 187                     throw fatal(Alert.UNEXPECTED_MESSAGE,
 188                         "Unexpected content: " + plaintext.contentType);
 189                 }
 190         }
 191     }
 192 
 193     void kickstart() throws IOException {
 194         if (isUnsureMode) {
 195             throw new IllegalStateException("Client/Server mode not yet set.");
 196         }
 197 
 198         if (outputRecord.isClosed() || inputRecord.isClosed() || isBroken) {
 199             if (closeReason != null) {
 200                 throw new SSLException(
 201                         "Cannot kickstart, the connection is broken or closed",
 202                         closeReason);
 203             } else {
 204                 throw new SSLException(
 205                         "Cannot kickstart, the connection is broken or closed");
 206             }
 207         }
 208 
 209         // initialize the handshaker if necessary
 210         if (handshakeContext == null) {
 211             //  TLS1.3 post-handshake
 212             if (isNegotiated && protocolVersion.useTLS13PlusSpec()) {
 213                 handshakeContext = new PostHandshakeContext(this);
 214             } else {
 215                 handshakeContext = sslConfig.isClientMode ?
 216                         new ClientHandshakeContext(sslContext, this) :
 217                         new ServerHandshakeContext(sslContext, this);
 218                 outputRecord.initHandshaker();
 219             }
 220         }
 221 
 222         // kickstart the handshake if needed
 223         //
 224         // Need no kickstart message on server side unless the connection
 225         // has been established.
 226         if(isNegotiated || sslConfig.isClientMode) {
 227            handshakeContext.kickstart();
 228         }
 229     }
 230 
 231     boolean isPostHandshakeContext() {
 232         return handshakeContext != null &&
 233                 (handshakeContext instanceof PostHandshakeContext);
 234     }
 235 
 236     // Note: close_notify is delivered as a warning alert.
 237     void warning(Alert alert) {
 238         // For initial handshaking, don't send a warning alert message to peer
 239         // if handshaker has not started.
 240         if (isNegotiated || handshakeContext != null) {
 241             try {
 242                 outputRecord.encodeAlert(Alert.Level.WARNING.level, alert.id);
 243             } catch (IOException ioe) {
 244                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 245                     SSLLogger.warning(
 246                         "Warning: failed to send warning alert " + alert, ioe);
 247                 }
 248             }
 249         }
 250     }
 251 
 252     SSLException fatal(Alert alert,
 253             String diagnostic) throws SSLException {
 254         return fatal(alert, diagnostic, null);
 255     }
 256 
 257     SSLException fatal(Alert alert, Throwable cause) throws SSLException {
 258         return fatal(alert, null, cause);
 259     }
 260 
 261     SSLException fatal(Alert alert,
 262             String diagnostic, Throwable cause) throws SSLException {
 263         return fatal(alert, diagnostic, false, cause);
 264     }
 265 
 266     // Note: close_notify is not delivered via fatal() methods.
 267     SSLException fatal(Alert alert, String diagnostic,
 268             boolean recvFatalAlert, Throwable cause) throws SSLException {
 269         // If we've already shutdown because of an error, there is nothing we
 270         // can do except rethrow the exception.
 271         //
 272         // Most exceptions seen here will be SSLExceptions. We may find the
 273         // occasional Exception which hasn't been converted to a SSLException,
 274         // so we'll do it here.
 275         if (closeReason != null) {
 276             if (cause == null) {
 277                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 278                     SSLLogger.warning(
 279                             "Closed transport, general or untracked problem");
 280                 }
 281                 throw alert.createSSLException(
 282                         "Closed transport, general or untracked problem");
 283             }
 284 
 285             if (cause instanceof SSLException) {
 286                 throw (SSLException)cause;
 287             } else {    // unlikely, but just in case.
 288                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 289                     SSLLogger.warning(
 290                             "Closed transport, unexpected rethrowing", cause);
 291                 }
 292                 throw alert.createSSLException("Unexpected rethrowing", cause);
 293             }
 294         }
 295 
 296         // If we have no further information, make a general-purpose
 297         // message for folks to see.  We generally have one or the other.
 298         if (diagnostic == null) {
 299             if (cause == null) {
 300                 diagnostic = "General/Untracked problem";
 301             } else {
 302                 diagnostic = cause.getMessage();
 303             }
 304         }
 305 
 306         if (cause == null) {
 307             cause = alert.createSSLException(diagnostic);
 308         }
 309 
 310         // shutdown the transport
 311         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 312             SSLLogger.severe("Fatal (" + alert + "): " + diagnostic, cause);
 313         }
 314 
 315         // remember the close reason
 316         if (cause instanceof SSLException) {
 317             closeReason = (SSLException)cause;
 318         } else {
 319             // Including RuntimeException, but we'll throw those down below.
 320             closeReason = alert.createSSLException(diagnostic, cause);
 321         }
 322 
 323         // close inbound
 324         try {
 325             inputRecord.close();
 326         } catch (IOException ioe) {
 327             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 328                 SSLLogger.warning("Fatal: input record closure failed", ioe);
 329             }
 330 
 331             closeReason.addSuppressed(ioe);
 332         }
 333 
 334         // invalidate the session
 335         if (conSession != null) {
 336             conSession.invalidate();
 337         }
 338 
 339         if (handshakeContext != null &&
 340                 handshakeContext.handshakeSession != null) {
 341             handshakeContext.handshakeSession.invalidate();
 342         }
 343 
 344         // send fatal alert
 345         //
 346         // If we haven't even started handshaking yet, or we are the recipient
 347         // of a fatal alert, no need to generate a fatal close alert.
 348         if (!recvFatalAlert && !isOutboundClosed() && !isBroken &&
 349                 (isNegotiated || handshakeContext != null)) {
 350             try {
 351                 outputRecord.encodeAlert(Alert.Level.FATAL.level, alert.id);
 352             } catch (IOException ioe) {
 353                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 354                     SSLLogger.warning(
 355                         "Fatal: failed to send fatal alert " + alert, ioe);
 356                 }
 357 
 358                 closeReason.addSuppressed(ioe);
 359             }
 360         }
 361 
 362         // close outbound
 363         try {
 364             outputRecord.close();
 365         } catch (IOException ioe) {
 366             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 367                 SSLLogger.warning("Fatal: output record closure failed", ioe);
 368             }
 369 
 370             closeReason.addSuppressed(ioe);
 371         }
 372 
 373         // terminate the handshake context
 374         if (handshakeContext != null) {
 375             handshakeContext = null;
 376         }
 377 
 378         // terminate the transport
 379         try {
 380             transport.shutdown();
 381         } catch (IOException ioe) {
 382             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 383                 SSLLogger.warning("Fatal: transport closure failed", ioe);
 384             }
 385 
 386             closeReason.addSuppressed(ioe);
 387         } finally {
 388             isBroken = true;
 389         }
 390 
 391         if (closeReason instanceof SSLException) {
 392             throw (SSLException)closeReason;
 393         } else {
 394             throw (RuntimeException)closeReason;
 395         }
 396     }
 397 
 398     void setUseClientMode(boolean useClientMode) {
 399         // Once handshaking has begun, the mode can not be reset for the
 400         // life of this engine.
 401         if (handshakeContext != null || isNegotiated) {
 402             throw new IllegalArgumentException(
 403                     "Cannot change mode after SSL traffic has started");
 404         }
 405 
 406         /*
 407          * If we need to change the client mode and the enabled
 408          * protocols and cipher suites haven't specifically been
 409          * set by the user, change them to the corresponding
 410          * default ones.
 411          */
 412         if (sslConfig.isClientMode != useClientMode) {
 413             if (sslContext.isDefaultProtocolVesions(
 414                     sslConfig.enabledProtocols)) {
 415                 sslConfig.enabledProtocols =
 416                         sslContext.getDefaultProtocolVersions(!useClientMode);
 417             }
 418 
 419             if (sslContext.isDefaultCipherSuiteList(
 420                     sslConfig.enabledCipherSuites)) {
 421                 sslConfig.enabledCipherSuites =
 422                         sslContext.getDefaultCipherSuites(!useClientMode);
 423             }
 424 
 425             sslConfig.isClientMode = useClientMode;
 426         }
 427 
 428         isUnsureMode = false;
 429     }
 430 
 431     // The OutputRecord is closed and not buffered output record.
 432     boolean isOutboundDone() {
 433         return outputRecord.isClosed() && outputRecord.isEmpty();
 434     }
 435 
 436     // The OutputRecord is closed, but buffered output record may be still
 437     // waiting for delivery to the underlying connection.
 438     boolean isOutboundClosed() {
 439         return outputRecord.isClosed();
 440     }
 441 
 442     boolean isInboundClosed() {
 443         return inputRecord.isClosed();
 444     }
 445 
 446     // Close inbound, no more data should be delivered to the underlying
 447     // transportation connection.
 448     void closeInbound() throws SSLException {
 449         if (isInboundClosed()) {
 450             return;
 451         }
 452 
 453         try {
 454             // Important note: check if the initial handshake is started at
 455             // first so that the passiveInboundClose() implementation need not
 456             // to consider the case any more.
 457             if (!isInputCloseNotified) {
 458                 // the initial handshake is not started
 459                 initiateInboundClose();
 460             } else {
 461                 passiveInboundClose();
 462             }
 463         } catch (IOException ioe) {
 464             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 465                 SSLLogger.warning("inbound closure failed", ioe);
 466             }
 467         }
 468     }
 469 
 470     // Close the connection passively.  The closure could be kickoff by
 471     // receiving a close_notify alert or reaching end_of_file of the socket.
 472     //
 473     // Note that this method is called only if the initial handshake has
 474     // started or completed.
 475     private void passiveInboundClose() throws IOException {
 476         if (!isInboundClosed()) {
 477             inputRecord.close();
 478         }
 479 
 480         // For TLS 1.2 and prior version, it is required to respond with
 481         // a close_notify alert of its own and close down the connection
 482         // immediately, discarding any pending writes.
 483         if (!isOutboundClosed()) {
 484             boolean needCloseNotify = SSLConfiguration.acknowledgeCloseNotify;
 485             if (!needCloseNotify) {
 486                 if (isNegotiated) {
 487                     if (!protocolVersion.useTLS13PlusSpec()) {
 488                         needCloseNotify = true;
 489                     }
 490                 } else if (handshakeContext != null) {  // initial handshake
 491                     ProtocolVersion pv = handshakeContext.negotiatedProtocol;
 492                     if (pv == null || (!pv.useTLS13PlusSpec())) {
 493                         needCloseNotify = true;
 494                     }
 495                 }
 496             }
 497 
 498             if (needCloseNotify) {
 499                 synchronized (outputRecord) {
 500                     try {
 501                         // send a close_notify alert
 502                         warning(Alert.CLOSE_NOTIFY);
 503                     } finally {
 504                         outputRecord.close();
 505                     }
 506                 }
 507             }
 508         }
 509     }
 510 
 511     // Initiate a inbound close when the handshake is not started.
 512     private void initiateInboundClose() throws IOException {
 513         if (!isInboundClosed()) {
 514             inputRecord.close();
 515         }
 516     }
 517 
 518     // Close outbound, no more data should be received from the underlying
 519     // transportation connection.
 520     void closeOutbound() {
 521         if (isOutboundClosed()) {
 522             return;
 523         }
 524 
 525         try {
 526              initiateOutboundClose();
 527         } catch (IOException ioe) {
 528             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 529                 SSLLogger.warning("outbound closure failed", ioe);
 530             }
 531         }
 532     }
 533 
 534     // Initiate a close by sending a close_notify alert.
 535     private void initiateOutboundClose() throws IOException {
 536         boolean useUserCanceled = false;
 537         if (!isNegotiated && (handshakeContext != null) && !peerUserCanceled) {
 538             // initial handshake
 539             useUserCanceled = true;
 540         }
 541 
 542         // Need a lock here so that the user_canceled alert and the
 543         // close_notify alert can be delivered together.
 544         synchronized (outputRecord) {
 545             try {
 546                 // send a user_canceled alert if needed.
 547                 if (useUserCanceled) {
 548                     warning(Alert.USER_CANCELED);
 549                 }
 550 
 551                 // send a close_notify alert
 552                 warning(Alert.CLOSE_NOTIFY);
 553             } finally {
 554                 outputRecord.close();
 555             }
 556         }
 557     }
 558 
 559     // Note; HandshakeStatus.FINISHED status is retrieved in other places.
 560     HandshakeStatus getHandshakeStatus() {
 561         if (!outputRecord.isEmpty()) {
 562             // If no handshaking, special case to wrap alters or
 563             // post-handshake messages.
 564             return HandshakeStatus.NEED_WRAP;
 565         } else if (isOutboundClosed() && isInboundClosed()) {
 566             return HandshakeStatus.NOT_HANDSHAKING;
 567         } else if (handshakeContext != null) {
 568             if (!handshakeContext.delegatedActions.isEmpty()) {
 569                 return HandshakeStatus.NEED_TASK;
 570             } else if (!isInboundClosed()) {
 571                 if (sslContext.isDTLS() &&
 572                         !inputRecord.isEmpty()) {
 573                     return HandshakeStatus.NEED_UNWRAP_AGAIN;
 574                 } else {
 575                     return HandshakeStatus.NEED_UNWRAP;
 576                 }
 577             } else if (!isOutboundClosed()) {
 578                 // Special case that the inbound was closed, but outbound open.
 579                 return HandshakeStatus.NEED_WRAP;
 580             }   // Otherwise, both inbound and outbound are closed.
 581         }
 582 
 583         return HandshakeStatus.NOT_HANDSHAKING;
 584     }
 585 
 586     HandshakeStatus finishHandshake() {
 587         if (protocolVersion.useTLS13PlusSpec()) {
 588             outputRecord.tc = this;
 589             inputRecord.tc = this;
 590             cipherSuite = handshakeContext.negotiatedCipherSuite;
 591             inputRecord.readCipher.baseSecret =
 592                     handshakeContext.baseReadSecret;
 593             outputRecord.writeCipher.baseSecret =
 594                     handshakeContext.baseWriteSecret;
 595         }
 596 
 597         handshakeContext = null;
 598         outputRecord.handshakeHash.finish();
 599         inputRecord.finishHandshake();
 600         outputRecord.finishHandshake();
 601         isNegotiated = true;
 602 
 603         // Tell folk about handshake completion, but do it in a separate thread.
 604         if (transport instanceof SSLSocket &&
 605                 sslConfig.handshakeListeners != null &&
 606                 !sslConfig.handshakeListeners.isEmpty()) {
 607             HandshakeCompletedEvent hce =
 608                 new HandshakeCompletedEvent((SSLSocket)transport, conSession);
 609             Thread thread = new Thread(
 610                 null,
 611                 new NotifyHandshake(sslConfig.handshakeListeners, hce),
 612                 "HandshakeCompletedNotify-Thread",
 613                 0,
 614                 false);
 615             thread.start();
 616         }
 617 
 618         return HandshakeStatus.FINISHED;
 619     }
 620 
 621     HandshakeStatus finishPostHandshake() {
 622         handshakeContext = null;
 623 
 624         // Note: May need trigger handshake completion even for post-handshake
 625         // authentication in the future.
 626 
 627         return HandshakeStatus.FINISHED;
 628     }
 629 
 630     // A separate thread is allocated to deliver handshake completion
 631     // events.
 632     private static class NotifyHandshake implements Runnable {
 633         private final Set<Map.Entry<HandshakeCompletedListener,
 634                 AccessControlContext>> targets;         // who gets notified
 635         private final HandshakeCompletedEvent event;    // the notification
 636 
 637         NotifyHandshake(
 638                 Map<HandshakeCompletedListener,AccessControlContext> listeners,
 639                 HandshakeCompletedEvent event) {
 640             this.targets = new HashSet<>(listeners.entrySet());     // clone
 641             this.event = event;
 642         }
 643 
 644         @Override
 645         public void run() {
 646             // Don't need to synchronize, as it only runs in one thread.
 647             for (Map.Entry<HandshakeCompletedListener,
 648                     AccessControlContext> entry : targets) {
 649                 final HandshakeCompletedListener listener = entry.getKey();
 650                 AccessControlContext acc = entry.getValue();
 651                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
 652                     @Override
 653                     public Void run() {
 654                         listener.handshakeCompleted(event);
 655                         return null;
 656                     }
 657                 }, acc);
 658             }
 659         }
 660     }
 661 }