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 package sun.security.ssl; 26 27 import java.io.IOException; 28 import java.nio.ByteBuffer; 29 import java.text.MessageFormat; 30 import java.util.*; 31 import sun.security.ssl.SSLExtension.ExtensionConsumer; 32 33 import sun.security.ssl.SSLExtension.SSLExtensionSpec; 34 import sun.security.ssl.SSLHandshake.HandshakeMessage; 35 36 /** 37 * Pack of the "psk_key_exchange_modes" extensions. 38 */ 39 final class PskKeyExchangeModesExtension { 40 static final HandshakeProducer chNetworkProducer = 41 new PskKeyExchangeModesProducer(); 42 static final ExtensionConsumer chOnLoadConsumer = 43 new PskKeyExchangeModesConsumer(); 44 45 enum PskKeyExchangeMode { 46 PSK_KE(0), 47 PSK_DHE_KE(1); 48 49 private final int v; 50 51 PskKeyExchangeMode(int v) { 52 this.v = v; 53 } 54 55 static PskKeyExchangeMode ofInt(int v) { 56 for(PskKeyExchangeMode mode : values()) { 57 if (mode.v == v) { 58 return mode; 59 } 60 } 61 62 return null; 63 } 64 } 65 66 static final class PskKeyExchangeModesSpec implements SSLExtensionSpec { 67 68 69 final List<PskKeyExchangeMode> modes; 70 71 PskKeyExchangeModesSpec(List<PskKeyExchangeMode> modes) { 72 this.modes = modes; 73 } 74 75 PskKeyExchangeModesSpec(ByteBuffer m) throws IOException { 76 77 modes = new ArrayList<>(); 78 int modesEncodedLength = Record.getInt8(m); 79 int modesReadLength = 0; 80 while (modesReadLength < modesEncodedLength) { 81 int mode = Record.getInt8(m); 82 // TODO: handle incorrect values 83 modes.add(PskKeyExchangeMode.ofInt(mode)); 84 modesReadLength += 1; 85 } 86 } 87 88 byte[] getEncoded() throws IOException { 89 90 int encodedLength = modes.size() + 1; 91 byte[] buffer = new byte[encodedLength]; 92 ByteBuffer m = ByteBuffer.wrap(buffer); 93 Record.putInt8(m, modes.size()); 94 for(PskKeyExchangeMode curMode : modes) { 95 Record.putInt8(m, curMode.v); 96 } 97 98 return buffer; 99 } 100 101 @Override 102 public String toString() { 103 MessageFormat messageFormat = new MessageFormat( 104 "\"PskKeyExchangeModes\": '{'\n" + 105 " \"ke_modes\" : \"{0}\",\n" + 106 "'}'", 107 Locale.ENGLISH); 108 109 Object[] messageFields = { 110 Utilities.indent(modesString()), 111 }; 112 113 return messageFormat.format(messageFields); 114 } 115 116 String modesString() { 117 StringBuilder result = new StringBuilder(); 118 for(PskKeyExchangeMode curMode : modes) { 119 result.append(curMode.toString() + "\n"); 120 } 121 122 return result.toString(); 123 } 124 } 125 126 127 private static final 128 class PskKeyExchangeModesConsumer implements ExtensionConsumer { 129 // Prevent instantiation of this class. 130 private PskKeyExchangeModesConsumer() { 131 // blank 132 } 133 134 @Override 135 public void consume(ConnectionContext context, 136 HandshakeMessage message, ByteBuffer buffer) throws IOException { 137 138 ServerHandshakeContext shc = 139 (ServerHandshakeContext) message.handshakeContext; 140 141 PskKeyExchangeModesSpec modes = new PskKeyExchangeModesSpec(buffer); 142 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 143 SSLLogger.fine( 144 "Received PskKeyExchangeModes extension: ", modes); 145 } 146 147 shc.pskKeyExchangeModes = modes.modes; 148 } 149 150 } 151 152 private static final 153 class PskKeyExchangeModesProducer implements HandshakeProducer { 154 155 static final List<PskKeyExchangeMode> MODES = 156 List.of(PskKeyExchangeMode.PSK_DHE_KE); 157 static final PskKeyExchangeModesSpec MODES_MSG = 158 new PskKeyExchangeModesSpec(MODES); 159 160 // Prevent instantiation of this class. 161 private PskKeyExchangeModesProducer() { 162 // blank 163 } 164 165 @Override 166 public byte[] produce(ConnectionContext context, 167 HandshakeMessage message) throws IOException { 168 169 return MODES_MSG.getEncoded(); 170 } 171 172 } 173 } 174