< prev index next >

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

Print this page




  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 package sun.security.ssl;
  26 
  27 import java.io.IOException;
  28 import java.nio.ByteBuffer;
  29 import java.security.*;
  30 import java.text.MessageFormat;
  31 import java.util.List;
  32 import java.util.ArrayList;
  33 import java.util.Locale;
  34 import java.util.Arrays;

  35 import java.util.Collection;
  36 import javax.crypto.Mac;
  37 import javax.crypto.SecretKey;
  38 import javax.net.ssl.SSLPeerUnverifiedException;
  39 import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED;
  40 import sun.security.ssl.ClientHello.ClientHelloMessage;
  41 import sun.security.ssl.SSLExtension.ExtensionConsumer;
  42 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
  43 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  44 import sun.security.ssl.SessionTicketExtension.SessionTicketSpec;
  45 import sun.security.util.HexDumpEncoder;
  46 
  47 import static sun.security.ssl.SSLExtension.*;
  48 
  49 /**
  50  * Pack of the "pre_shared_key" extension.
  51  */
  52 final class PreSharedKeyExtension {
  53     static final HandshakeProducer chNetworkProducer =
  54             new CHPreSharedKeyProducer();
  55     static final ExtensionConsumer chOnLoadConsumer =
  56             new CHPreSharedKeyConsumer();
  57     static final HandshakeAbsence chOnLoadAbsence =
  58             new CHPreSharedKeyAbsence();
  59     static final HandshakeConsumer chOnTradeConsumer =
  60             new CHPreSharedKeyUpdate();
  61     static final SSLStringizer chStringizer =
  62             new CHPreSharedKeyStringizer();
  63 
  64     static final HandshakeProducer shNetworkProducer =
  65             new SHPreSharedKeyProducer();
  66     static final ExtensionConsumer shOnLoadConsumer =


  73     private static final class PskIdentity {
  74         final byte[] identity;
  75         final int obfuscatedAge;
  76 
  77         PskIdentity(byte[] identity, int obfuscatedAge) {
  78             this.identity = identity;
  79             this.obfuscatedAge = obfuscatedAge;
  80         }
  81 
  82         int getEncodedLength() {
  83             return 2 + identity.length + 4;
  84         }
  85 
  86         void writeEncoded(ByteBuffer m) throws IOException {
  87             Record.putBytes16(m, identity);
  88             Record.putInt32(m, obfuscatedAge);
  89         }
  90 
  91         @Override
  92         public String toString() {
  93             return "{" + Utilities.toHexString(identity) + ", " +
  94                 obfuscatedAge + "}";
  95         }
  96     }
  97 
  98     private static final
  99             class CHPreSharedKeySpec implements SSLExtensionSpec {
 100         final List<PskIdentity> identities;
 101         final List<byte[]> binders;
 102 
 103         CHPreSharedKeySpec(List<PskIdentity> identities, List<byte[]> binders) {
 104             this.identities = identities;
 105             this.binders = binders;
 106         }
 107 
 108         CHPreSharedKeySpec(HandshakeContext context,
 109                 ByteBuffer m) throws IOException {
 110             // struct {
 111             //     PskIdentity identities<7..2^16-1>;
 112             //     PskBinderEntry binders<33..2^16-1>;
 113             // } OfferedPsks;


 193             int bindersEncodedLength = getBindersEncodedLength();
 194             int encodedLength = 4 + idsEncodedLength + bindersEncodedLength;
 195             byte[] buffer = new byte[encodedLength];
 196             ByteBuffer m = ByteBuffer.wrap(buffer);
 197             Record.putInt16(m, idsEncodedLength);
 198             for (PskIdentity curId : identities) {
 199                 curId.writeEncoded(m);
 200             }
 201             Record.putInt16(m, bindersEncodedLength);
 202             for (byte[] curBinder : binders) {
 203                 Record.putBytes8(m, curBinder);
 204             }
 205 
 206             return buffer;
 207         }
 208 
 209         @Override
 210         public String toString() {
 211             MessageFormat messageFormat = new MessageFormat(
 212                 "\"PreSharedKey\": '{'\n" +
 213                 "  \"identities\": '{'\n" +
 214                 "{0}\n" +
 215                 "  '}'" +
 216                 "  \"binders\": \"{1}\",\n" +
 217                 "'}'",
 218                 Locale.ENGLISH);
 219 
 220             Object[] messageFields = {
 221                 Utilities.indent(identitiesString()),
 222                 Utilities.indent(bindersString())
 223             };
 224 
 225             return messageFormat.format(messageFields);
 226         }
 227 
 228         String identitiesString() {
 229             HexDumpEncoder hexEncoder = new HexDumpEncoder();
 230 
 231             StringBuilder result = new StringBuilder();
 232             for (PskIdentity curId : identities) {
 233                 result.append("  {\n"+ Utilities.indent(
 234                         hexEncoder.encode(curId.identity), "    ") +
 235                         "\n  }\n");
 236             }
 237 
 238             return result.toString();
 239         }
 240 
 241         String bindersString() {
 242             StringBuilder result = new StringBuilder();
 243             for (byte[] curBinder : binders) {
 244                 result.append("{" + Utilities.toHexString(curBinder) + "}\n");
 245             }
 246 
 247             return result.toString();
 248         }
 249     }
 250 
 251     private static final
 252             class CHPreSharedKeyStringizer implements SSLStringizer {
 253         @Override
 254         public String toString(ByteBuffer buffer) {
 255             try {


 269 
 270     private static final
 271             class SHPreSharedKeySpec implements SSLExtensionSpec {
 272         final int selectedIdentity;
 273 
 274         SHPreSharedKeySpec(int selectedIdentity) {
 275             this.selectedIdentity = selectedIdentity;
 276         }
 277 
 278         SHPreSharedKeySpec(HandshakeContext context,
 279                 ByteBuffer m) throws IOException {
 280             if (m.remaining() < 2) {
 281                 throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 282                         "Invalid pre_shared_key extension: " +
 283                         "insufficient selected_identity (length=" +
 284                         m.remaining() + ")");
 285             }
 286             this.selectedIdentity = Record.getInt16(m);
 287         }
 288 
 289         byte[] getEncoded() {
 290             return new byte[] {
 291                 (byte)((selectedIdentity >> 8) & 0xFF),
 292                 (byte)(selectedIdentity & 0xFF)
 293             };
 294         }
 295 
 296         @Override
 297         public String toString() {
 298             MessageFormat messageFormat = new MessageFormat(
 299                 "\"PreSharedKey\": '{'\n" +
 300                 "  \"selected_identity\"      : \"{0}\",\n" +
 301                 "'}'",
 302                 Locale.ENGLISH);
 303 
 304             Object[] messageFields = {
 305                 Utilities.byte16HexString(selectedIdentity)
 306             };
 307 
 308             return messageFormat.format(messageFields);
 309         }


 359             }
 360 
 361             // The "psk_key_exchange_modes" extension should have been loaded.
 362             if (!shc.handshakeExtensions.containsKey(
 363                     SSLExtension.PSK_KEY_EXCHANGE_MODES)) {
 364                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 365                         "Client sent PSK but not PSK modes, or the PSK " +
 366                         "extension is not the last extension");
 367             }
 368 
 369             // error if id and binder lists are not the same length
 370             if (pskSpec.identities.size() != pskSpec.binders.size()) {
 371                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 372                         "PSK extension has incorrect number of binders");
 373             }
 374 
 375             if (shc.isResumption) {     // resumingSession may not be set
 376                 SSLSessionContextImpl sessionCache = (SSLSessionContextImpl)
 377                         shc.sslContext.engineGetServerSessionContext();
 378                 int idIndex = 0;
 379                 SSLSessionImpl s = null;
 380 
 381                 for (PskIdentity requestedId : pskSpec.identities) {
 382                     // If we are keeping state, see if the identity is in the cache
 383                     if (requestedId.identity.length == SessionId.MAX_LENGTH) {
 384                         s = sessionCache.get(requestedId.identity);
 385                     }
 386                     // See if the identity is a stateless ticket
 387                     if (s == null &&
 388                             requestedId.identity.length > SessionId.MAX_LENGTH &&
 389                             sessionCache.statelessEnabled()) {
 390                         ByteBuffer b =
 391                                 new SessionTicketSpec(requestedId.identity).
 392                                         decrypt(shc);
 393                         if (b != null) {
 394                             try {
 395                                 s = new SSLSessionImpl(shc, b);
 396                             } catch (IOException | RuntimeException e) {
 397                                 s = null;
 398                             }
 399                         }
 400                         if (b == null || s == null) {
 401                             if (SSLLogger.isOn &&
 402                                     SSLLogger.isOn("ssl,handshake")) {
 403                                 SSLLogger.fine(
 404                                         "Stateless session ticket invalid");
 405                             }
 406                         }
 407                     }
 408 
 409                     if (s != null && canRejoin(clientHello, shc, s)) {
 410                         if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 411                             SSLLogger.fine("Resuming session: ", s);
 412                         }
 413 
 414                         // binder will be checked later
 415                         shc.resumingSession = s;
 416                         shc.handshakeExtensions.put(SH_PRE_SHARED_KEY,
 417                             new SHPreSharedKeySpec(idIndex));   // for the index
 418                         break;
 419                     }
 420 
 421                     ++idIndex;
 422                 }
 423 
 424                 if (idIndex == pskSpec.identities.size()) {
 425                     // no resumable session
 426                     shc.isResumption = false;
 427                     shc.resumingSession = null;
 428                 }
 429             }

 430             // update the context
 431             shc.handshakeExtensions.put(
 432                 SSLExtension.CH_PRE_SHARED_KEY, pskSpec);
 433         }
 434     }
 435 
 436     private static boolean canRejoin(ClientHelloMessage clientHello,
 437         ServerHandshakeContext shc, SSLSessionImpl s) {
 438 
 439         boolean result = s.isRejoinable() && (s.getPreSharedKey() != null);
 440 
 441         // Check protocol version
 442         if (result && s.getProtocolVersion() != shc.negotiatedProtocol) {
 443             if (SSLLogger.isOn &&
 444                 SSLLogger.isOn("ssl,handshake,verbose")) {
 445 
 446                 SSLLogger.finest("Can't resume, incorrect protocol version");
 447             }
 448             result = false;
 449         }


 726             CHPreSharedKeySpec pskPrototype = createPskPrototype(
 727                 chc.resumingSession.getSuite().hashAlg.hashLength, identities);
 728             HandshakeHash pskBinderHash = chc.handshakeHash.copy();
 729 
 730             byte[] binder = computeBinder(chc, binderKey, pskBinderHash,
 731                     chc.resumingSession, chc, clientHello, pskPrototype);
 732 
 733             List<byte[]> binders = new ArrayList<>();
 734             binders.add(binder);
 735 
 736             CHPreSharedKeySpec pskMessage =
 737                     new CHPreSharedKeySpec(identities, binders);
 738             chc.handshakeExtensions.put(CH_PRE_SHARED_KEY, pskMessage);
 739             return pskMessage.getEncoded();
 740         }
 741 
 742         private CHPreSharedKeySpec createPskPrototype(
 743                 int hashLength, List<PskIdentity> identities) {
 744             List<byte[]> binders = new ArrayList<>();
 745             byte[] binderProto = new byte[hashLength];
 746             int i = identities.size();
 747             while (i-- > 0) {
 748                 binders.add(binderProto);
 749             }
 750 
 751             return new CHPreSharedKeySpec(identities, binders);
 752         }
 753     }
 754 
 755     private static byte[] computeBinder(
 756             HandshakeContext context, SecretKey binderKey,
 757             SSLSessionImpl session,
 758             HandshakeHash pskBinderHash) throws IOException {
 759 
 760         pskBinderHash.determine(
 761                 session.getProtocolVersion(), session.getSuite());
 762         pskBinderHash.update();
 763         byte[] digest = pskBinderHash.digest();
 764 
 765         return computeBinder(context, binderKey, session, digest);
 766     }
 767 




  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 package sun.security.ssl;
  26 
  27 import java.io.IOException;
  28 import java.nio.ByteBuffer;
  29 import java.security.*;
  30 import java.text.MessageFormat;
  31 import java.util.List;
  32 import java.util.ArrayList;
  33 import java.util.Locale;
  34 import java.util.Arrays;
  35 import java.util.Objects;
  36 import java.util.Collection;
  37 import javax.crypto.Mac;
  38 import javax.crypto.SecretKey;
  39 import javax.net.ssl.SSLPeerUnverifiedException;
  40 import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED;
  41 import sun.security.ssl.ClientHello.ClientHelloMessage;
  42 import sun.security.ssl.SSLExtension.ExtensionConsumer;
  43 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
  44 import sun.security.ssl.SSLHandshake.HandshakeMessage;



  45 import static sun.security.ssl.SSLExtension.*;
  46 
  47 /**
  48  * Pack of the "pre_shared_key" extension.
  49  */
  50 final class PreSharedKeyExtension {
  51     static final HandshakeProducer chNetworkProducer =
  52             new CHPreSharedKeyProducer();
  53     static final ExtensionConsumer chOnLoadConsumer =
  54             new CHPreSharedKeyConsumer();
  55     static final HandshakeAbsence chOnLoadAbsence =
  56             new CHPreSharedKeyAbsence();
  57     static final HandshakeConsumer chOnTradeConsumer =
  58             new CHPreSharedKeyUpdate();
  59     static final SSLStringizer chStringizer =
  60             new CHPreSharedKeyStringizer();
  61 
  62     static final HandshakeProducer shNetworkProducer =
  63             new SHPreSharedKeyProducer();
  64     static final ExtensionConsumer shOnLoadConsumer =


  71     private static final class PskIdentity {
  72         final byte[] identity;
  73         final int obfuscatedAge;
  74 
  75         PskIdentity(byte[] identity, int obfuscatedAge) {
  76             this.identity = identity;
  77             this.obfuscatedAge = obfuscatedAge;
  78         }
  79 
  80         int getEncodedLength() {
  81             return 2 + identity.length + 4;
  82         }
  83 
  84         void writeEncoded(ByteBuffer m) throws IOException {
  85             Record.putBytes16(m, identity);
  86             Record.putInt32(m, obfuscatedAge);
  87         }
  88 
  89         @Override
  90         public String toString() {
  91             return "{" + Utilities.toHexString(identity) + "," +
  92                 obfuscatedAge + "}";
  93         }
  94     }
  95 
  96     private static final
  97             class CHPreSharedKeySpec implements SSLExtensionSpec {
  98         final List<PskIdentity> identities;
  99         final List<byte[]> binders;
 100 
 101         CHPreSharedKeySpec(List<PskIdentity> identities, List<byte[]> binders) {
 102             this.identities = identities;
 103             this.binders = binders;
 104         }
 105 
 106         CHPreSharedKeySpec(HandshakeContext context,
 107                 ByteBuffer m) throws IOException {
 108             // struct {
 109             //     PskIdentity identities<7..2^16-1>;
 110             //     PskBinderEntry binders<33..2^16-1>;
 111             // } OfferedPsks;


 191             int bindersEncodedLength = getBindersEncodedLength();
 192             int encodedLength = 4 + idsEncodedLength + bindersEncodedLength;
 193             byte[] buffer = new byte[encodedLength];
 194             ByteBuffer m = ByteBuffer.wrap(buffer);
 195             Record.putInt16(m, idsEncodedLength);
 196             for (PskIdentity curId : identities) {
 197                 curId.writeEncoded(m);
 198             }
 199             Record.putInt16(m, bindersEncodedLength);
 200             for (byte[] curBinder : binders) {
 201                 Record.putBytes8(m, curBinder);
 202             }
 203 
 204             return buffer;
 205         }
 206 
 207         @Override
 208         public String toString() {
 209             MessageFormat messageFormat = new MessageFormat(
 210                 "\"PreSharedKey\": '{'\n" +
 211                 "  \"identities\"    : \"{0}\",\n" +
 212                 "  \"binders\"       : \"{1}\",\n" +


 213                 "'}'",
 214                 Locale.ENGLISH);
 215 
 216             Object[] messageFields = {
 217                 Utilities.indent(identitiesString()),
 218                 Utilities.indent(bindersString())
 219             };
 220 
 221             return messageFormat.format(messageFields);
 222         }
 223 
 224         String identitiesString() {


 225             StringBuilder result = new StringBuilder();
 226             for (PskIdentity curId : identities) {
 227                 result.append(curId.toString() + "\n");


 228             }
 229 
 230             return result.toString();
 231         }
 232 
 233         String bindersString() {
 234             StringBuilder result = new StringBuilder();
 235             for (byte[] curBinder : binders) {
 236                 result.append("{" + Utilities.toHexString(curBinder) + "}\n");
 237             }
 238 
 239             return result.toString();
 240         }
 241     }
 242 
 243     private static final
 244             class CHPreSharedKeyStringizer implements SSLStringizer {
 245         @Override
 246         public String toString(ByteBuffer buffer) {
 247             try {


 261 
 262     private static final
 263             class SHPreSharedKeySpec implements SSLExtensionSpec {
 264         final int selectedIdentity;
 265 
 266         SHPreSharedKeySpec(int selectedIdentity) {
 267             this.selectedIdentity = selectedIdentity;
 268         }
 269 
 270         SHPreSharedKeySpec(HandshakeContext context,
 271                 ByteBuffer m) throws IOException {
 272             if (m.remaining() < 2) {
 273                 throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 274                         "Invalid pre_shared_key extension: " +
 275                         "insufficient selected_identity (length=" +
 276                         m.remaining() + ")");
 277             }
 278             this.selectedIdentity = Record.getInt16(m);
 279         }
 280 
 281         byte[] getEncoded() throws IOException {
 282             return new byte[] {
 283                 (byte)((selectedIdentity >> 8) & 0xFF),
 284                 (byte)(selectedIdentity & 0xFF)
 285             };
 286         }
 287 
 288         @Override
 289         public String toString() {
 290             MessageFormat messageFormat = new MessageFormat(
 291                 "\"PreSharedKey\": '{'\n" +
 292                 "  \"selected_identity\"      : \"{0}\",\n" +
 293                 "'}'",
 294                 Locale.ENGLISH);
 295 
 296             Object[] messageFields = {
 297                 Utilities.byte16HexString(selectedIdentity)
 298             };
 299 
 300             return messageFormat.format(messageFields);
 301         }


 351             }
 352 
 353             // The "psk_key_exchange_modes" extension should have been loaded.
 354             if (!shc.handshakeExtensions.containsKey(
 355                     SSLExtension.PSK_KEY_EXCHANGE_MODES)) {
 356                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 357                         "Client sent PSK but not PSK modes, or the PSK " +
 358                         "extension is not the last extension");
 359             }
 360 
 361             // error if id and binder lists are not the same length
 362             if (pskSpec.identities.size() != pskSpec.binders.size()) {
 363                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 364                         "PSK extension has incorrect number of binders");
 365             }
 366 
 367             if (shc.isResumption) {     // resumingSession may not be set
 368                 SSLSessionContextImpl sessionCache = (SSLSessionContextImpl)
 369                         shc.sslContext.engineGetServerSessionContext();
 370                 int idIndex = 0;


 371                 for (PskIdentity requestedId : pskSpec.identities) {
 372                     SSLSessionImpl s = sessionCache.get(requestedId.identity);


























 373                     if (s != null && canRejoin(clientHello, shc, s)) {
 374                         if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 375                             SSLLogger.fine("Resuming session: ", s);
 376                         }
 377 
 378                         // binder will be checked later
 379                         shc.resumingSession = s;
 380                         shc.handshakeExtensions.put(SH_PRE_SHARED_KEY,
 381                             new SHPreSharedKeySpec(idIndex));   // for the index
 382                         break;
 383                     }
 384 
 385                     ++idIndex;
 386                 }
 387 
 388                 if (idIndex == pskSpec.identities.size()) {
 389                     // no resumable session
 390                     shc.isResumption = false;
 391                     shc.resumingSession = null;
 392                 }
 393             }
 394 
 395             // update the context
 396             shc.handshakeExtensions.put(
 397                 SSLExtension.CH_PRE_SHARED_KEY, pskSpec);
 398         }
 399     }
 400 
 401     private static boolean canRejoin(ClientHelloMessage clientHello,
 402         ServerHandshakeContext shc, SSLSessionImpl s) {
 403 
 404         boolean result = s.isRejoinable() && (s.getPreSharedKey() != null);
 405 
 406         // Check protocol version
 407         if (result && s.getProtocolVersion() != shc.negotiatedProtocol) {
 408             if (SSLLogger.isOn &&
 409                 SSLLogger.isOn("ssl,handshake,verbose")) {
 410 
 411                 SSLLogger.finest("Can't resume, incorrect protocol version");
 412             }
 413             result = false;
 414         }


 691             CHPreSharedKeySpec pskPrototype = createPskPrototype(
 692                 chc.resumingSession.getSuite().hashAlg.hashLength, identities);
 693             HandshakeHash pskBinderHash = chc.handshakeHash.copy();
 694 
 695             byte[] binder = computeBinder(chc, binderKey, pskBinderHash,
 696                     chc.resumingSession, chc, clientHello, pskPrototype);
 697 
 698             List<byte[]> binders = new ArrayList<>();
 699             binders.add(binder);
 700 
 701             CHPreSharedKeySpec pskMessage =
 702                     new CHPreSharedKeySpec(identities, binders);
 703             chc.handshakeExtensions.put(CH_PRE_SHARED_KEY, pskMessage);
 704             return pskMessage.getEncoded();
 705         }
 706 
 707         private CHPreSharedKeySpec createPskPrototype(
 708                 int hashLength, List<PskIdentity> identities) {
 709             List<byte[]> binders = new ArrayList<>();
 710             byte[] binderProto = new byte[hashLength];
 711             for (PskIdentity curId : identities) {

 712                 binders.add(binderProto);
 713             }
 714 
 715             return new CHPreSharedKeySpec(identities, binders);
 716         }
 717     }
 718 
 719     private static byte[] computeBinder(
 720             HandshakeContext context, SecretKey binderKey,
 721             SSLSessionImpl session,
 722             HandshakeHash pskBinderHash) throws IOException {
 723 
 724         pskBinderHash.determine(
 725                 session.getProtocolVersion(), session.getSuite());
 726         pskBinderHash.update();
 727         byte[] digest = pskBinderHash.digest();
 728 
 729         return computeBinder(context, binderKey, session, digest);
 730     }
 731 


< prev index next >