< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 2003, 2019, 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.nio.ByteBuffer;
  30 import java.nio.ReadOnlyBufferException;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedActionException;
  33 import java.security.PrivilegedExceptionAction;
  34 import java.util.List;
  35 import java.util.Map;
  36 import java.util.concurrent.locks.ReentrantLock;
  37 import java.util.function.BiFunction;
  38 import javax.net.ssl.SSLEngine;
  39 import javax.net.ssl.SSLEngineResult;
  40 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  41 import javax.net.ssl.SSLEngineResult.Status;
  42 import javax.net.ssl.SSLException;
  43 import javax.net.ssl.SSLHandshakeException;
  44 import javax.net.ssl.SSLKeyException;
  45 import javax.net.ssl.SSLParameters;
  46 import javax.net.ssl.SSLPeerUnverifiedException;
  47 import javax.net.ssl.SSLProtocolException;
  48 import javax.net.ssl.SSLSession;
  49 
  50 /**
  51  * Implementation of an non-blocking SSLEngine.
  52  *
  53  * @author Brad Wetmore
  54  */
  55 final class SSLEngineImpl extends SSLEngine implements SSLTransport {
  56     private final SSLContextImpl        sslContext;
  57     final TransportContext              conContext;
  58     private final ReentrantLock         engineLock = new ReentrantLock();
  59 
  60     /**
  61      * Constructor for an SSLEngine from SSLContext, without
  62      * host/port hints.
  63      *
  64      * This Engine will not be able to cache sessions, but must renegotiate
  65      * everything by hand.
  66      */
  67     SSLEngineImpl(SSLContextImpl sslContext) {
  68         this(sslContext, null, -1);
  69     }
  70 
  71     /**
  72      * Constructor for an SSLEngine from SSLContext.
  73      */
  74     SSLEngineImpl(SSLContextImpl sslContext,
  75             String host, int port) {
  76         super(host, port);
  77         this.sslContext = sslContext;
  78         HandshakeHash handshakeHash = new HandshakeHash();
  79         if (sslContext.isDTLS()) {
  80             this.conContext = new TransportContext(sslContext, this,
  81                     new DTLSInputRecord(handshakeHash),
  82                     new DTLSOutputRecord(handshakeHash));
  83         } else {
  84             this.conContext = new TransportContext(sslContext, this,
  85                     new SSLEngineInputRecord(handshakeHash),
  86                     new SSLEngineOutputRecord(handshakeHash));
  87         }
  88 
  89         // Server name indication is a connection scope extension.
  90         if (host != null) {
  91             this.conContext.sslConfig.serverNames =
  92                     Utilities.addToSNIServerNameList(
  93                             conContext.sslConfig.serverNames, host);
  94         }
  95     }
  96 
  97     @Override
  98     public void beginHandshake() throws SSLException {
  99         engineLock.lock();
 100         try {
 101             if (conContext.isUnsureMode) {
 102                 throw new IllegalStateException(
 103                         "Client/Server mode has not yet been set.");
 104             }
 105 
 106             try {
 107                 conContext.kickstart();
 108             } catch (IOException ioe) {
 109                 throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
 110                     "Couldn't kickstart handshaking", ioe);
 111             } catch (Exception ex) {     // including RuntimeException
 112                 throw conContext.fatal(Alert.INTERNAL_ERROR,
 113                     "Fail to begin handshake", ex);
 114             }
 115         } finally {
 116             engineLock.unlock();
 117         }
 118     }
 119 
 120     @Override
 121     public SSLEngineResult wrap(ByteBuffer[] appData,
 122             int offset, int length, ByteBuffer netData) throws SSLException {
 123         return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1);
 124     }
 125 
 126     // @Override
 127     public SSLEngineResult wrap(
 128         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 129         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 130 
 131         engineLock.lock();
 132         try {
 133             if (conContext.isUnsureMode) {
 134                 throw new IllegalStateException(
 135                         "Client/Server mode has not yet been set.");
 136             }
 137 
 138             // See if the handshaker needs to report back some SSLException.
 139             checkTaskThrown();
 140 
 141             // check parameters
 142             checkParams(srcs, srcsOffset, srcsLength,
 143                     dsts, dstsOffset, dstsLength);
 144 
 145             try {
 146                 return writeRecord(
 147                     srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 148             } catch (SSLProtocolException spe) {
 149                 // may be an unexpected handshake message
 150                 throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
 151             } catch (IOException ioe) {
 152                 throw conContext.fatal(Alert.INTERNAL_ERROR,
 153                     "problem wrapping app data", ioe);
 154             } catch (Exception ex) {     // including RuntimeException
 155                 throw conContext.fatal(Alert.INTERNAL_ERROR,
 156                     "Fail to wrap application data", ex);
 157             }
 158         } finally {
 159             engineLock.unlock();
 160         }
 161     }
 162 
 163     private SSLEngineResult writeRecord(
 164         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 165         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 166 
 167         // May need to deliver cached records.
 168         if (isOutboundDone()) {
 169             return new SSLEngineResult(
 170                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 171         }
 172 
 173         HandshakeContext hc = conContext.handshakeContext;
 174         HandshakeStatus hsStatus = null;
 175         if (!conContext.isNegotiated && !conContext.isBroken &&
 176                 !conContext.isInboundClosed() &&
 177                 !conContext.isOutboundClosed()) {
 178             conContext.kickstart();
 179 


 424                         "destination buffer[" + i + "] == null");
 425             }
 426 
 427             /*
 428              * Make sure the destination bufffers are writable.
 429              */
 430             if (dsts[i].isReadOnly()) {
 431                 throw new ReadOnlyBufferException();
 432             }
 433         }
 434 
 435         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 436             if (srcs[i] == null) {
 437                 throw new IllegalArgumentException(
 438                         "source buffer[" + i + "] == null");
 439             }
 440         }
 441     }
 442 
 443     @Override
 444     public SSLEngineResult unwrap(ByteBuffer src,
 445             ByteBuffer[] dsts, int offset, int length) throws SSLException {
 446         return unwrap(
 447                 new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
 448     }
 449 
 450     // @Override
 451     public SSLEngineResult unwrap(
 452         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 453         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 454 
 455         engineLock.lock();
 456         try {
 457             if (conContext.isUnsureMode) {
 458                 throw new IllegalStateException(
 459                         "Client/Server mode has not yet been set.");
 460             }
 461 
 462             // See if the handshaker needs to report back some SSLException.
 463             checkTaskThrown();
 464 
 465             // check parameters
 466             checkParams(srcs, srcsOffset, srcsLength,
 467                     dsts, dstsOffset, dstsLength);
 468 
 469             try {
 470                 return readRecord(
 471                     srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 472             } catch (SSLProtocolException spe) {
 473                 // may be an unexpected handshake message
 474                 throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 475                         spe.getMessage(), spe);
 476             } catch (IOException ioe) {
 477                 /*
 478                  * Don't reset position so it looks like we didn't
 479                  * consume anything.  We did consume something, and it
 480                  * got us into this situation, so report that much back.
 481                  * Our days of consuming are now over anyway.
 482                  */
 483                 throw conContext.fatal(Alert.INTERNAL_ERROR,
 484                         "problem unwrapping net record", ioe);
 485             } catch (Exception ex) {     // including RuntimeException
 486                 throw conContext.fatal(Alert.INTERNAL_ERROR,
 487                     "Fail to unwrap network record", ex);
 488             }
 489         } finally {
 490             engineLock.unlock();
 491         }
 492     }
 493 
 494     private SSLEngineResult readRecord(
 495         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 496         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 497 
 498         /*
 499          * Check if we are closing/closed.
 500          */
 501         if (isInboundDone()) {
 502             return new SSLEngineResult(
 503                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 504         }
 505 
 506         HandshakeStatus hsStatus = null;
 507         if (!conContext.isNegotiated && !conContext.isBroken &&
 508                 !conContext.isInboundClosed() &&
 509                 !conContext.isOutboundClosed()) {
 510             conContext.kickstart();


 705         if (pt != Plaintext.PLAINTEXT_NULL) {
 706             HandshakeStatus hsStatus = tryToFinishHandshake(pt.contentType);
 707             if (hsStatus == null) {
 708                 pt.handshakeStatus = conContext.getHandshakeStatus();
 709             } else {
 710                 pt.handshakeStatus = hsStatus;
 711             }
 712 
 713             // Is the sequence number is nearly overflow?
 714             if (conContext.inputRecord.seqNumIsHuge() ||
 715                     conContext.inputRecord.readCipher.atKeyLimit()) {
 716                 pt.handshakeStatus =
 717                         tryKeyUpdate(pt.handshakeStatus);
 718             }
 719         }
 720 
 721         return pt;
 722     }
 723 
 724     @Override
 725     public Runnable getDelegatedTask() {
 726         engineLock.lock();
 727         try {
 728             if (conContext.handshakeContext != null && // PRE or POST handshake
 729                     !conContext.handshakeContext.taskDelegated &&
 730                     !conContext.handshakeContext.delegatedActions.isEmpty()) {
 731                 conContext.handshakeContext.taskDelegated = true;
 732                 return new DelegatedTask(this);
 733             }
 734         } finally {
 735             engineLock.unlock();
 736         }
 737 
 738         return null;
 739     }
 740 
 741     @Override
 742     public void closeInbound() throws SSLException {
 743         engineLock.lock();
 744         try {
 745             if (isInboundDone()) {
 746                 return;
 747             }
 748 
 749             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 750                 SSLLogger.finest("Closing inbound of SSLEngine");
 751             }
 752 
 753             // Is it ready to close inbound?
 754             //
 755             // No exception if the initial handshake is not started.
 756             if (!conContext.isInputCloseNotified &&
 757                 (conContext.isNegotiated ||
 758                     conContext.handshakeContext != null)) {
 759 
 760                 throw conContext.fatal(Alert.INTERNAL_ERROR,
 761                         "closing inbound before receiving peer's close_notify");
 762             }


 763 
 764             conContext.closeInbound();
 765         } finally {
 766             engineLock.unlock();
 767         }


 768     }
 769 
 770     @Override
 771     public boolean isInboundDone() {
 772         engineLock.lock();
 773         try {
 774             return conContext.isInboundClosed();
 775         } finally {
 776             engineLock.unlock();
 777         }
 778     }
 779 
 780     @Override
 781     public void closeOutbound() {
 782         engineLock.lock();
 783         try {
 784             if (conContext.isOutboundClosed()) {
 785                 return;
 786             }
 787 
 788             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 789                 SSLLogger.finest("Closing outbound of SSLEngine");
 790             }
 791 
 792             conContext.closeOutbound();
 793         } finally {
 794             engineLock.unlock();
 795         }


 796     }
 797 
 798     @Override
 799     public boolean isOutboundDone() {
 800         engineLock.lock();
 801         try {
 802             return conContext.isOutboundDone();
 803         } finally {
 804             engineLock.unlock();
 805         }
 806     }
 807 
 808     @Override
 809     public String[] getSupportedCipherSuites() {
 810         return CipherSuite.namesOf(sslContext.getSupportedCipherSuites());
 811     }
 812 
 813     @Override
 814     public String[] getEnabledCipherSuites() {
 815         engineLock.lock();
 816         try {
 817             return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
 818         } finally {
 819             engineLock.unlock();
 820         }
 821     }
 822 
 823     @Override
 824     public void setEnabledCipherSuites(String[] suites) {
 825         engineLock.lock();
 826         try {
 827             conContext.sslConfig.enabledCipherSuites =
 828                     CipherSuite.validValuesOf(suites);
 829         } finally {
 830             engineLock.unlock();
 831         }
 832     }
 833 
 834     @Override
 835     public String[] getSupportedProtocols() {
 836         return ProtocolVersion.toStringArray(
 837                 sslContext.getSupportedProtocolVersions());
 838     }
 839 
 840     @Override
 841     public String[] getEnabledProtocols() {
 842         engineLock.lock();
 843         try {
 844             return ProtocolVersion.toStringArray(
 845                     conContext.sslConfig.enabledProtocols);
 846         } finally {
 847             engineLock.unlock();
 848         }
 849     }
 850 
 851     @Override
 852     public void setEnabledProtocols(String[] protocols) {
 853         engineLock.lock();
 854         try {
 855             if (protocols == null) {
 856                 throw new IllegalArgumentException("Protocols cannot be null");
 857             }
 858 
 859             conContext.sslConfig.enabledProtocols =
 860                     ProtocolVersion.namesOf(protocols);
 861         } finally {
 862             engineLock.unlock();
 863         }



 864     }
 865 
 866     @Override
 867     public SSLSession getSession() {
 868         engineLock.lock();
 869         try {
 870             return conContext.conSession;
 871         } finally {
 872             engineLock.unlock();
 873         }
 874     }
 875 
 876     @Override
 877     public SSLSession getHandshakeSession() {
 878         engineLock.lock();
 879         try {
 880             return conContext.handshakeContext == null ?
 881                     null : conContext.handshakeContext.handshakeSession;
 882         } finally {
 883             engineLock.unlock();
 884         }
 885     }
 886 
 887     @Override
 888     public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
 889         engineLock.lock();
 890         try {
 891             return conContext.getHandshakeStatus();
 892         } finally {
 893             engineLock.unlock();
 894         }
 895     }
 896 
 897     @Override
 898     public void setUseClientMode(boolean mode) {
 899         engineLock.lock();
 900         try {
 901             conContext.setUseClientMode(mode);
 902         } finally {
 903             engineLock.unlock();
 904         }
 905     }
 906 
 907     @Override
 908     public boolean getUseClientMode() {
 909         engineLock.lock();
 910         try {
 911             return conContext.sslConfig.isClientMode;
 912         } finally {
 913             engineLock.unlock();
 914         }
 915     }
 916 
 917     @Override
 918     public void setNeedClientAuth(boolean need) {
 919         engineLock.lock();
 920         try {
 921             conContext.sslConfig.clientAuthType =
 922                     (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
 923                             ClientAuthType.CLIENT_AUTH_NONE);
 924         } finally {
 925             engineLock.unlock();
 926         }
 927     }
 928 
 929     @Override
 930     public boolean getNeedClientAuth() {
 931         engineLock.lock();
 932         try {
 933             return (conContext.sslConfig.clientAuthType ==
 934                             ClientAuthType.CLIENT_AUTH_REQUIRED);
 935         } finally {
 936             engineLock.unlock();
 937         }
 938     }
 939 
 940     @Override
 941     public void setWantClientAuth(boolean want) {
 942         engineLock.lock();
 943         try {
 944             conContext.sslConfig.clientAuthType =
 945                     (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
 946                             ClientAuthType.CLIENT_AUTH_NONE);
 947         } finally {
 948             engineLock.unlock();
 949         }
 950     }
 951 
 952     @Override
 953     public boolean getWantClientAuth() {
 954         engineLock.lock();
 955         try {
 956             return (conContext.sslConfig.clientAuthType ==
 957                             ClientAuthType.CLIENT_AUTH_REQUESTED);
 958         } finally {
 959             engineLock.unlock();
 960         }
 961     }
 962 
 963     @Override
 964     public void setEnableSessionCreation(boolean flag) {
 965         engineLock.lock();
 966         try {
 967             conContext.sslConfig.enableSessionCreation = flag;
 968         } finally {
 969             engineLock.unlock();
 970         }
 971     }
 972 
 973     @Override
 974     public boolean getEnableSessionCreation() {
 975         engineLock.lock();
 976         try {
 977             return conContext.sslConfig.enableSessionCreation;
 978         } finally {
 979             engineLock.unlock();
 980         }
 981     }
 982 
 983     @Override
 984     public SSLParameters getSSLParameters() {
 985         engineLock.lock();
 986         try {
 987             return conContext.sslConfig.getSSLParameters();
 988         } finally {
 989             engineLock.unlock();
 990         }
 991    }
 992 
 993     @Override
 994     public void setSSLParameters(SSLParameters params) {
 995         engineLock.lock();
 996         try {
 997             conContext.sslConfig.setSSLParameters(params);
 998 
 999             if (conContext.sslConfig.maximumPacketSize != 0) {
1000                 conContext.outputRecord.changePacketSize(
1001                         conContext.sslConfig.maximumPacketSize);
1002             }
1003         } finally {
1004             engineLock.unlock();
1005         }
1006    }
1007 
1008     @Override
1009     public String getApplicationProtocol() {
1010         engineLock.lock();
1011         try {
1012             return conContext.applicationProtocol;
1013         } finally {
1014             engineLock.unlock();
1015         }
1016     }
1017 
1018     @Override
1019     public String getHandshakeApplicationProtocol() {
1020         engineLock.lock();
1021         try {
1022             return conContext.handshakeContext == null ?
1023                     null : conContext.handshakeContext.applicationProtocol;
1024         } finally {
1025             engineLock.unlock();
1026         }
1027     }
1028 
1029     @Override
1030     public void setHandshakeApplicationProtocolSelector(
1031             BiFunction<SSLEngine, List<String>, String> selector) {
1032         engineLock.lock();
1033         try {
1034             conContext.sslConfig.engineAPSelector = selector;
1035         } finally {
1036             engineLock.unlock();
1037         }
1038     }
1039 
1040     @Override
1041     public BiFunction<SSLEngine, List<String>, String>
1042             getHandshakeApplicationProtocolSelector() {
1043         engineLock.lock();
1044         try {
1045             return conContext.sslConfig.engineAPSelector;
1046         } finally {
1047             engineLock.unlock();
1048         }
1049     }
1050 
1051     @Override
1052     public boolean useDelegatedTask() {
1053         return true;
1054     }
1055 
1056     /*
1057      * Depending on whether the error was just a warning and the
1058      * handshaker wasn't closed, or fatal and the handshaker is now
1059      * null, report back the Exception that happened in the delegated
1060      * task(s).
1061      */
1062     private void checkTaskThrown() throws SSLException {
1063 
1064         Exception exc = null;
1065         engineLock.lock();
1066         try {
1067             // First check the handshake context.
1068             HandshakeContext hc = conContext.handshakeContext;
1069             if ((hc != null) && (hc.delegatedThrown != null)) {
1070                 exc = hc.delegatedThrown;
1071                 hc.delegatedThrown = null;
1072             }
1073 
1074             /*
1075              * hc.delegatedThrown and conContext.delegatedThrown are most
1076              * likely the same, but it's possible we could have had a non-fatal
1077              * exception and thus the new HandshakeContext is still valid
1078              * (alert warning).  If so, then we may have a secondary exception
1079              * waiting to be reported from the TransportContext, so we will
1080              * need to clear that on a successive call. Otherwise, clear it now.
1081              */
1082             if (conContext.delegatedThrown != null) {
1083                 if (exc != null) {
1084                     // hc object comparison
1085                     if (conContext.delegatedThrown == exc) {
1086                         // clear if/only if both are the same
1087                         conContext.delegatedThrown = null;
1088                     } // otherwise report the hc delegatedThrown
1089                 } else {
1090                     // Nothing waiting in HandshakeContext, but one is in the
1091                     // TransportContext.
1092                     exc = conContext.delegatedThrown;

1093                     conContext.delegatedThrown = null;
1094                 }





1095             }
1096         } finally {
1097             engineLock.unlock();
1098         }
1099 
1100         // Anything to report?
1101         if (exc == null) {
1102             return;
1103         }
1104 
1105         // If it wasn't a RuntimeException/SSLException, need to wrap it.
1106         if (exc instanceof SSLException) {
1107             throw (SSLException)exc;
1108         } else if (exc instanceof RuntimeException) {
1109             throw (RuntimeException)exc;
1110         } else {
1111             throw getTaskThrown(exc);
1112         }
1113     }
1114 
1115     private static SSLException getTaskThrown(Exception taskThrown) {
1116         String msg = taskThrown.getMessage();
1117 


1135                 new SSLProtocolException(msg).initCause(taskThrown);
1136         } else if (taskThrown instanceof SSLException) {
1137             return (SSLException)taskThrown;
1138         } else {
1139             return new SSLException(msg, taskThrown);
1140         }
1141     }
1142 
1143     /**
1144      * Implement a simple task delegator.
1145      */
1146     private static class DelegatedTask implements Runnable {
1147         private final SSLEngineImpl engine;
1148 
1149         DelegatedTask(SSLEngineImpl engineInstance) {
1150             this.engine = engineInstance;
1151         }
1152 
1153         @Override
1154         public void run() {
1155             engine.engineLock.lock();
1156             try {
1157                 HandshakeContext hc = engine.conContext.handshakeContext;
1158                 if (hc == null || hc.delegatedActions.isEmpty()) {
1159                     return;
1160                 }
1161 
1162                 try {
1163                     AccessController.doPrivileged(
1164                             new DelegatedAction(hc), engine.conContext.acc);
1165                 } catch (PrivilegedActionException pae) {
1166                     // Get the handshake context again in case the
1167                     // handshaking has completed.
1168                     Exception reportedException = pae.getException();
1169 
1170                     // Report to both the TransportContext...
1171                     if (engine.conContext.delegatedThrown == null) {
1172                         engine.conContext.delegatedThrown = reportedException;
1173                     }
1174 
1175                     // ...and the HandshakeContext in case condition
1176                     // wasn't fatal and the handshakeContext is still


1193                     }
1194 
1195                     // ...and the HandshakeContext in case condition
1196                     // wasn't fatal and the handshakeContext is still
1197                     // around.
1198                     hc = engine.conContext.handshakeContext;
1199                     if (hc != null) {
1200                         hc.delegatedThrown = rte;
1201                     } else if (engine.conContext.closeReason != null) {
1202                         // Update the reason in case there was a previous.
1203                         engine.conContext.closeReason = rte;
1204                     }
1205                 }
1206 
1207                 // Get the handshake context again in case the
1208                 // handshaking has completed.
1209                 hc = engine.conContext.handshakeContext;
1210                 if (hc != null) {
1211                     hc.taskDelegated = false;
1212                 }
1213             } finally {
1214                 engine.engineLock.unlock();
1215             }
1216         }
1217 
1218         private static class DelegatedAction
1219                 implements PrivilegedExceptionAction<Void> {
1220             final HandshakeContext context;
1221             DelegatedAction(HandshakeContext context) {
1222                 this.context = context;
1223             }
1224 
1225             @Override
1226             public Void run() throws Exception {
1227                 while (!context.delegatedActions.isEmpty()) {
1228                     Map.Entry<Byte, ByteBuffer> me =
1229                             context.delegatedActions.poll();
1230                     if (me != null) {
1231                         context.dispatch(me.getKey(), me.getValue());
1232                     }
1233                 }
1234                 return null;
   1 /*
   2  * Copyright (c) 2003, 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.nio.ByteBuffer;
  30 import java.nio.ReadOnlyBufferException;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedActionException;
  33 import java.security.PrivilegedExceptionAction;
  34 import java.util.List;
  35 import java.util.Map;

  36 import java.util.function.BiFunction;
  37 import javax.net.ssl.SSLEngine;
  38 import javax.net.ssl.SSLEngineResult;
  39 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  40 import javax.net.ssl.SSLEngineResult.Status;
  41 import javax.net.ssl.SSLException;
  42 import javax.net.ssl.SSLHandshakeException;
  43 import javax.net.ssl.SSLKeyException;
  44 import javax.net.ssl.SSLParameters;
  45 import javax.net.ssl.SSLPeerUnverifiedException;
  46 import javax.net.ssl.SSLProtocolException;
  47 import javax.net.ssl.SSLSession;
  48 
  49 /**
  50  * Implementation of an non-blocking SSLEngine.
  51  *
  52  * @author Brad Wetmore
  53  */
  54 final class SSLEngineImpl extends SSLEngine implements SSLTransport {
  55     private final SSLContextImpl        sslContext;
  56     final TransportContext              conContext;

  57 
  58     /**
  59      * Constructor for an SSLEngine from SSLContext, without
  60      * host/port hints.
  61      *
  62      * This Engine will not be able to cache sessions, but must renegotiate
  63      * everything by hand.
  64      */
  65     SSLEngineImpl(SSLContextImpl sslContext) {
  66         this(sslContext, null, -1);
  67     }
  68 
  69     /**
  70      * Constructor for an SSLEngine from SSLContext.
  71      */
  72     SSLEngineImpl(SSLContextImpl sslContext,
  73             String host, int port) {
  74         super(host, port);
  75         this.sslContext = sslContext;
  76         HandshakeHash handshakeHash = new HandshakeHash();
  77         if (sslContext.isDTLS()) {
  78             this.conContext = new TransportContext(sslContext, this,
  79                     new DTLSInputRecord(handshakeHash),
  80                     new DTLSOutputRecord(handshakeHash));
  81         } else {
  82             this.conContext = new TransportContext(sslContext, this,
  83                     new SSLEngineInputRecord(handshakeHash),
  84                     new SSLEngineOutputRecord(handshakeHash));
  85         }
  86 
  87         // Server name indication is a connection scope extension.
  88         if (host != null) {
  89             this.conContext.sslConfig.serverNames =
  90                     Utilities.addToSNIServerNameList(
  91                             conContext.sslConfig.serverNames, host);
  92         }
  93     }
  94 
  95     @Override
  96     public synchronized void beginHandshake() throws SSLException {
  97         if (conContext.isUnsureMode) {
  98             throw new IllegalStateException(
  99                     "Client/Server mode has not yet been set.");
 100         }


 101 
 102         try {
 103             conContext.kickstart();
 104         } catch (IOException ioe) {
 105             throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
 106                 "Couldn't kickstart handshaking", ioe);
 107         } catch (Exception ex) {     // including RuntimeException
 108             throw conContext.fatal(Alert.INTERNAL_ERROR,
 109                 "Fail to begin handshake", ex);



 110         }
 111     }
 112 
 113     @Override
 114     public synchronized SSLEngineResult wrap(ByteBuffer[] appData,
 115             int offset, int length, ByteBuffer netData) throws SSLException {
 116         return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1);
 117     }
 118 
 119     // @Override
 120     public synchronized SSLEngineResult wrap(
 121         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 122         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 123 
 124         if (conContext.isUnsureMode) {
 125             throw new IllegalStateException(
 126                     "Client/Server mode has not yet been set.");
 127         }


 128 
 129         // See if the handshaker needs to report back some SSLException.
 130         checkTaskThrown();
 131 
 132         // check parameters
 133         checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);

 134 
 135         try {
 136             return writeRecord(
 137                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 138         } catch (SSLProtocolException spe) {
 139             // may be an unexpected handshake message
 140             throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
 141         } catch (IOException ioe) {
 142             throw conContext.fatal(Alert.INTERNAL_ERROR,
 143                 "problem wrapping app data", ioe);
 144         } catch (Exception ex) {     // including RuntimeException
 145             throw conContext.fatal(Alert.INTERNAL_ERROR,
 146                 "Fail to wrap application data", ex);



 147         }
 148     }
 149 
 150     private SSLEngineResult writeRecord(
 151         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 152         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 153 
 154         // May need to deliver cached records.
 155         if (isOutboundDone()) {
 156             return new SSLEngineResult(
 157                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 158         }
 159 
 160         HandshakeContext hc = conContext.handshakeContext;
 161         HandshakeStatus hsStatus = null;
 162         if (!conContext.isNegotiated && !conContext.isBroken &&
 163                 !conContext.isInboundClosed() &&
 164                 !conContext.isOutboundClosed()) {
 165             conContext.kickstart();
 166 


 411                         "destination buffer[" + i + "] == null");
 412             }
 413 
 414             /*
 415              * Make sure the destination bufffers are writable.
 416              */
 417             if (dsts[i].isReadOnly()) {
 418                 throw new ReadOnlyBufferException();
 419             }
 420         }
 421 
 422         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 423             if (srcs[i] == null) {
 424                 throw new IllegalArgumentException(
 425                         "source buffer[" + i + "] == null");
 426             }
 427         }
 428     }
 429 
 430     @Override
 431     public synchronized SSLEngineResult unwrap(ByteBuffer src,
 432             ByteBuffer[] dsts, int offset, int length) throws SSLException {
 433         return unwrap(
 434                 new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
 435     }
 436 
 437     // @Override
 438     public synchronized SSLEngineResult unwrap(
 439         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 440         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 441 
 442         if (conContext.isUnsureMode) {
 443             throw new IllegalStateException(
 444                     "Client/Server mode has not yet been set.");
 445         }


 446 
 447         // See if the handshaker needs to report back some SSLException.
 448         checkTaskThrown();
 449 
 450         // check parameters
 451         checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);

 452 
 453         try {
 454             return readRecord(
 455                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 456         } catch (SSLProtocolException spe) {
 457             // may be an unexpected handshake message
 458             throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 459                     spe.getMessage(), spe);
 460         } catch (IOException ioe) {
 461             /*
 462              * Don't reset position so it looks like we didn't
 463              * consume anything.  We did consume something, and it
 464              * got us into this situation, so report that much back.
 465              * Our days of consuming are now over anyway.
 466              */
 467             throw conContext.fatal(Alert.INTERNAL_ERROR,
 468                     "problem unwrapping net record", ioe);
 469         } catch (Exception ex) {     // including RuntimeException
 470             throw conContext.fatal(Alert.INTERNAL_ERROR,
 471                 "Fail to unwrap network record", ex);



 472         }
 473     }
 474 
 475     private SSLEngineResult readRecord(
 476         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 477         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 478 
 479         /*
 480          * Check if we are closing/closed.
 481          */
 482         if (isInboundDone()) {
 483             return new SSLEngineResult(
 484                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 485         }
 486 
 487         HandshakeStatus hsStatus = null;
 488         if (!conContext.isNegotiated && !conContext.isBroken &&
 489                 !conContext.isInboundClosed() &&
 490                 !conContext.isOutboundClosed()) {
 491             conContext.kickstart();


 686         if (pt != Plaintext.PLAINTEXT_NULL) {
 687             HandshakeStatus hsStatus = tryToFinishHandshake(pt.contentType);
 688             if (hsStatus == null) {
 689                 pt.handshakeStatus = conContext.getHandshakeStatus();
 690             } else {
 691                 pt.handshakeStatus = hsStatus;
 692             }
 693 
 694             // Is the sequence number is nearly overflow?
 695             if (conContext.inputRecord.seqNumIsHuge() ||
 696                     conContext.inputRecord.readCipher.atKeyLimit()) {
 697                 pt.handshakeStatus =
 698                         tryKeyUpdate(pt.handshakeStatus);
 699             }
 700         }
 701 
 702         return pt;
 703     }
 704 
 705     @Override
 706     public synchronized Runnable getDelegatedTask() {
 707         if (conContext.handshakeContext != null && // PRE or POST handshake
 708                 !conContext.handshakeContext.taskDelegated &&
 709                 !conContext.handshakeContext.delegatedActions.isEmpty()) {
 710             conContext.handshakeContext.taskDelegated = true;
 711             return new DelegatedTask(this);





 712         }
 713 
 714         return null;
 715     }
 716 
 717     @Override
 718     public synchronized void closeInbound() throws SSLException {
 719         if (isInboundDone()) {
 720             return;
 721         }






 722 
 723         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 724             SSLLogger.finest("Closing inbound of SSLEngine");
 725         }



 726 
 727         // Is it ready to close inbound?
 728         //
 729         // No need to throw exception if the initial handshake is not started.
 730         if (!conContext.isInputCloseNotified &&
 731             (conContext.isNegotiated || conContext.handshakeContext != null)) {
 732 
 733             throw conContext.fatal(Alert.INTERNAL_ERROR,
 734                     "closing inbound before receiving peer's close_notify");

 735         }
 736 
 737         conContext.closeInbound();
 738     }
 739 
 740     @Override
 741     public synchronized boolean isInboundDone() {
 742         return conContext.isInboundClosed();





 743     }
 744 
 745     @Override
 746     public synchronized void closeOutbound() {
 747         if (conContext.isOutboundClosed()) {
 748             return;
 749         }






 750 
 751         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 752             SSLLogger.finest("Closing outbound of SSLEngine");

 753         }
 754 
 755         conContext.closeOutbound();
 756     }
 757 
 758     @Override
 759     public synchronized boolean isOutboundDone() {
 760         return conContext.isOutboundDone();





 761     }
 762 
 763     @Override
 764     public String[] getSupportedCipherSuites() {
 765         return CipherSuite.namesOf(sslContext.getSupportedCipherSuites());
 766     }
 767 
 768     @Override
 769     public synchronized String[] getEnabledCipherSuites() {
 770         return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);





 771     }
 772 
 773     @Override
 774     public synchronized void setEnabledCipherSuites(String[] suites) {
 775         conContext.sslConfig.enabledCipherSuites =
 776                 CipherSuite.validValuesOf(suites);





 777     }
 778 
 779     @Override
 780     public String[] getSupportedProtocols() {
 781         return ProtocolVersion.toStringArray(
 782                 sslContext.getSupportedProtocolVersions());
 783     }
 784 
 785     @Override
 786     public synchronized String[] getEnabledProtocols() {
 787         return ProtocolVersion.toStringArray(
 788                 conContext.sslConfig.enabledProtocols);





 789     }
 790 
 791     @Override
 792     public synchronized void setEnabledProtocols(String[] protocols) {
 793         if (protocols == null) {
 794             throw new IllegalArgumentException("Protocols cannot be null");








 795         }
 796 
 797         conContext.sslConfig.enabledProtocols =
 798                 ProtocolVersion.namesOf(protocols);
 799     }
 800 
 801     @Override
 802     public synchronized SSLSession getSession() {
 803         return conContext.conSession;





 804     }
 805 
 806     @Override
 807     public synchronized SSLSession getHandshakeSession() {
 808         return conContext.handshakeContext == null ?
 809                 null : conContext.handshakeContext.handshakeSession;





 810     }
 811 
 812     @Override
 813     public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
 814         return conContext.getHandshakeStatus();





 815     }
 816 
 817     @Override
 818     public synchronized void setUseClientMode(boolean mode) {
 819         conContext.setUseClientMode(mode);





 820     }
 821 
 822     @Override
 823     public synchronized boolean getUseClientMode() {
 824         return conContext.sslConfig.isClientMode;





 825     }
 826 
 827     @Override
 828     public synchronized void setNeedClientAuth(boolean need) {
 829         conContext.sslConfig.clientAuthType =
 830                 (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
 831                         ClientAuthType.CLIENT_AUTH_NONE);





 832     }
 833 
 834     @Override
 835     public synchronized boolean getNeedClientAuth() {
 836         return (conContext.sslConfig.clientAuthType ==
 837                         ClientAuthType.CLIENT_AUTH_REQUIRED);





 838     }
 839 
 840     @Override
 841     public synchronized void setWantClientAuth(boolean want) {
 842         conContext.sslConfig.clientAuthType =
 843                 (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
 844                         ClientAuthType.CLIENT_AUTH_NONE);





 845     }
 846 
 847     @Override
 848     public synchronized boolean getWantClientAuth() {
 849         return (conContext.sslConfig.clientAuthType ==
 850                         ClientAuthType.CLIENT_AUTH_REQUESTED);





 851     }
 852 
 853     @Override
 854     public synchronized void setEnableSessionCreation(boolean flag) {
 855         conContext.sslConfig.enableSessionCreation = flag;





 856     }
 857 
 858     @Override
 859     public synchronized boolean getEnableSessionCreation() {
 860         return conContext.sslConfig.enableSessionCreation;





 861     }
 862 
 863     @Override
 864     public synchronized SSLParameters getSSLParameters() {
 865         return conContext.sslConfig.getSSLParameters();
 866     }





 867 
 868     @Override
 869     public synchronized void setSSLParameters(SSLParameters params) {
 870         conContext.sslConfig.setSSLParameters(params);


 871 
 872         if (conContext.sslConfig.maximumPacketSize != 0) {
 873             conContext.outputRecord.changePacketSize(
 874                     conContext.sslConfig.maximumPacketSize);



 875         }
 876     }
 877 
 878     @Override
 879     public synchronized String getApplicationProtocol() {
 880         return conContext.applicationProtocol;





 881     }
 882 
 883     @Override
 884     public synchronized String getHandshakeApplicationProtocol() {
 885         return conContext.handshakeContext == null ?
 886                 null : conContext.handshakeContext.applicationProtocol;





 887     }
 888 
 889     @Override
 890     public synchronized void setHandshakeApplicationProtocolSelector(
 891             BiFunction<SSLEngine, List<String>, String> selector) {
 892         conContext.sslConfig.engineAPSelector = selector;





 893     }
 894 
 895     @Override
 896     public synchronized BiFunction<SSLEngine, List<String>, String>
 897             getHandshakeApplicationProtocolSelector() {
 898         return conContext.sslConfig.engineAPSelector;





 899     }
 900 
 901     @Override
 902     public boolean useDelegatedTask() {
 903         return true;
 904     }
 905 
 906     /*
 907      * Depending on whether the error was just a warning and the
 908      * handshaker wasn't closed, or fatal and the handshaker is now
 909      * null, report back the Exception that happened in the delegated
 910      * task(s).
 911      */
 912     private synchronized void checkTaskThrown() throws SSLException {
 913 
 914         Exception exc = null;








 915 
 916         // First check the handshake context.
 917         HandshakeContext hc = conContext.handshakeContext;
 918         if ((hc != null) && (hc.delegatedThrown != null)) {
 919             exc = hc.delegatedThrown;
 920             hc.delegatedThrown = null;
 921         }
 922 
 923         /*
 924          * hc.delegatedThrown and conContext.delegatedThrown are most likely
 925          * the same, but it's possible we could have had a non-fatal
 926          * exception and thus the new HandshakeContext is still valid
 927          * (alert warning).  If so, then we may have a secondary exception
 928          * waiting to be reported from the TransportContext, so we will
 929          * need to clear that on a successive call.  Otherwise, clear it now.
 930          */
 931         if (conContext.delegatedThrown != null) {
 932             if (exc != null) {
 933                 // hc object comparison
 934                 if (conContext.delegatedThrown == exc) {
 935                     // clear if/only if both are the same
 936                     conContext.delegatedThrown = null;
 937                 } // otherwise report the hc delegatedThrown
 938             } else {
 939                 // Nothing waiting in HandshakeContext, but one is in the
 940                 // TransportContext.
 941                 exc = conContext.delegatedThrown;
 942                 conContext.delegatedThrown = null;
 943             }


 944         }
 945 
 946         // Anything to report?
 947         if (exc == null) {
 948             return;
 949         }
 950 
 951         // If it wasn't a RuntimeException/SSLException, need to wrap it.
 952         if (exc instanceof SSLException) {
 953             throw (SSLException)exc;
 954         } else if (exc instanceof RuntimeException) {
 955             throw (RuntimeException)exc;
 956         } else {
 957             throw getTaskThrown(exc);
 958         }
 959     }
 960 
 961     private static SSLException getTaskThrown(Exception taskThrown) {
 962         String msg = taskThrown.getMessage();
 963 


 981                 new SSLProtocolException(msg).initCause(taskThrown);
 982         } else if (taskThrown instanceof SSLException) {
 983             return (SSLException)taskThrown;
 984         } else {
 985             return new SSLException(msg, taskThrown);
 986         }
 987     }
 988 
 989     /**
 990      * Implement a simple task delegator.
 991      */
 992     private static class DelegatedTask implements Runnable {
 993         private final SSLEngineImpl engine;
 994 
 995         DelegatedTask(SSLEngineImpl engineInstance) {
 996             this.engine = engineInstance;
 997         }
 998 
 999         @Override
1000         public void run() {
1001             synchronized (engine) {

1002                 HandshakeContext hc = engine.conContext.handshakeContext;
1003                 if (hc == null || hc.delegatedActions.isEmpty()) {
1004                     return;
1005                 }
1006 
1007                 try {
1008                     AccessController.doPrivileged(
1009                             new DelegatedAction(hc), engine.conContext.acc);
1010                 } catch (PrivilegedActionException pae) {
1011                     // Get the handshake context again in case the
1012                     // handshaking has completed.
1013                     Exception reportedException = pae.getException();
1014 
1015                     // Report to both the TransportContext...
1016                     if (engine.conContext.delegatedThrown == null) {
1017                         engine.conContext.delegatedThrown = reportedException;
1018                     }
1019 
1020                     // ...and the HandshakeContext in case condition
1021                     // wasn't fatal and the handshakeContext is still


1038                     }
1039 
1040                     // ...and the HandshakeContext in case condition
1041                     // wasn't fatal and the handshakeContext is still
1042                     // around.
1043                     hc = engine.conContext.handshakeContext;
1044                     if (hc != null) {
1045                         hc.delegatedThrown = rte;
1046                     } else if (engine.conContext.closeReason != null) {
1047                         // Update the reason in case there was a previous.
1048                         engine.conContext.closeReason = rte;
1049                     }
1050                 }
1051 
1052                 // Get the handshake context again in case the
1053                 // handshaking has completed.
1054                 hc = engine.conContext.handshakeContext;
1055                 if (hc != null) {
1056                     hc.taskDelegated = false;
1057                 }


1058             }
1059         }
1060 
1061         private static class DelegatedAction
1062                 implements PrivilegedExceptionAction<Void> {
1063             final HandshakeContext context;
1064             DelegatedAction(HandshakeContext context) {
1065                 this.context = context;
1066             }
1067 
1068             @Override
1069             public Void run() throws Exception {
1070                 while (!context.delegatedActions.isEmpty()) {
1071                     Map.Entry<Byte, ByteBuffer> me =
1072                             context.delegatedActions.poll();
1073                     if (me != null) {
1074                         context.dispatch(me.getKey(), me.getValue());
1075                     }
1076                 }
1077                 return null;
< prev index next >