Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/KeyShareExtension.java
38830 views
/*1* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ssl;2627import java.io.IOException;28import java.nio.ByteBuffer;29import java.security.CryptoPrimitive;30import java.security.GeneralSecurityException;31import java.text.MessageFormat;32import java.util.Arrays;33import java.util.Collections;34import java.util.EnumSet;35import java.util.LinkedList;36import java.util.List;37import java.util.Locale;38import java.util.Map;39import javax.net.ssl.SSLProtocolException;40import sun.security.ssl.DHKeyExchange.DHECredentials;41import sun.security.ssl.DHKeyExchange.DHEPossession;42import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;43import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;44import sun.security.ssl.KeyShareExtension.CHKeyShareSpec;45import sun.security.ssl.SSLExtension.ExtensionConsumer;46import sun.security.ssl.SSLExtension.SSLExtensionSpec;47import sun.security.ssl.SSLHandshake.HandshakeMessage;48import sun.security.ssl.SupportedGroupsExtension.NamedGroup;49import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;50import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;51import sun.misc.HexDumpEncoder;5253/**54* Pack of the "key_share" extensions.55*/56final class KeyShareExtension {57static final HandshakeProducer chNetworkProducer =58new CHKeyShareProducer();59static final ExtensionConsumer chOnLoadConsumer =60new CHKeyShareConsumer();61static final SSLStringizer chStringizer =62new CHKeyShareStringizer();6364static final HandshakeProducer shNetworkProducer =65new SHKeyShareProducer();66static final ExtensionConsumer shOnLoadConsumer =67new SHKeyShareConsumer();68static final HandshakeAbsence shOnLoadAbsence =69new SHKeyShareAbsence();70static final SSLStringizer shStringizer =71new SHKeyShareStringizer();7273static final HandshakeProducer hrrNetworkProducer =74new HRRKeyShareProducer();75static final ExtensionConsumer hrrOnLoadConsumer =76new HRRKeyShareConsumer();77static final HandshakeProducer hrrNetworkReproducer =78new HRRKeyShareReproducer();79static final SSLStringizer hrrStringizer =80new HRRKeyShareStringizer();8182/**83* The key share entry used in "key_share" extensions.84*/85private static final class KeyShareEntry {86final int namedGroupId;87final byte[] keyExchange;8889private KeyShareEntry(int namedGroupId, byte[] keyExchange) {90this.namedGroupId = namedGroupId;91this.keyExchange = keyExchange;92}9394private byte[] getEncoded() {95byte[] buffer = new byte[keyExchange.length + 4];96// 2: named group id97// +2: key exchange length98ByteBuffer m = ByteBuffer.wrap(buffer);99try {100Record.putInt16(m, namedGroupId);101Record.putBytes16(m, keyExchange);102} catch (IOException ioe) {103if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {104SSLLogger.warning(105"Unlikely IOException", ioe);106}107}108109return buffer;110}111112private int getEncodedSize() {113return keyExchange.length + 4; // 2: named group id114// +2: key exchange length115}116117@Override118public String toString() {119MessageFormat messageFormat = new MessageFormat(120"\n'{'\n" +121" \"named group\": {0}\n" +122" \"key_exchange\": '{'\n" +123"{1}\n" +124" '}'\n" +125"'}',", Locale.ENGLISH);126127HexDumpEncoder hexEncoder = new HexDumpEncoder();128Object[] messageFields = {129NamedGroup.nameOf(namedGroupId),130Utilities.indent(hexEncoder.encode(keyExchange), " ")131};132133return messageFormat.format(messageFields);134}135}136137/**138* The "key_share" extension in a ClientHello handshake message.139*/140static final class CHKeyShareSpec implements SSLExtensionSpec {141final List<KeyShareEntry> clientShares;142143private CHKeyShareSpec(List<KeyShareEntry> clientShares) {144this.clientShares = clientShares;145}146147private CHKeyShareSpec(ByteBuffer buffer) throws IOException {148// struct {149// KeyShareEntry client_shares<0..2^16-1>;150// } KeyShareClientHello;151if (buffer.remaining() < 2) {152throw new SSLProtocolException(153"Invalid key_share extension: " +154"insufficient data (length=" + buffer.remaining() + ")");155}156157int listLen = Record.getInt16(buffer);158if (listLen != buffer.remaining()) {159throw new SSLProtocolException(160"Invalid key_share extension: " +161"incorrect list length (length=" + listLen + ")");162}163164List<KeyShareEntry> keyShares = new LinkedList<>();165while (buffer.hasRemaining()) {166int namedGroupId = Record.getInt16(buffer);167byte[] keyExchange = Record.getBytes16(buffer);168if (keyExchange.length == 0) {169throw new SSLProtocolException(170"Invalid key_share extension: empty key_exchange");171}172173keyShares.add(new KeyShareEntry(namedGroupId, keyExchange));174}175176this.clientShares = Collections.unmodifiableList(keyShares);177}178179@Override180public String toString() {181MessageFormat messageFormat = new MessageFormat(182"\"client_shares\": '['{0}\n']'", Locale.ENGLISH);183184StringBuilder builder = new StringBuilder(512);185for (KeyShareEntry entry : clientShares) {186builder.append(entry.toString());187}188189Object[] messageFields = {190Utilities.indent(builder.toString())191};192193return messageFormat.format(messageFields);194}195}196197private static final class CHKeyShareStringizer implements SSLStringizer {198@Override199public String toString(ByteBuffer buffer) {200try {201return (new CHKeyShareSpec(buffer)).toString();202} catch (IOException ioe) {203// For debug logging only, so please swallow exceptions.204return ioe.getMessage();205}206}207}208209/**210* Network data producer of the extension in a ClientHello211* handshake message.212*/213private static final214class CHKeyShareProducer implements HandshakeProducer {215// Prevent instantiation of this class.216private CHKeyShareProducer() {217// blank218}219220@Override221public byte[] produce(ConnectionContext context,222HandshakeMessage message) throws IOException {223// The producing happens in client side only.224ClientHandshakeContext chc = (ClientHandshakeContext)context;225226// Is it a supported and enabled extension?227if (!chc.sslConfig.isAvailable(SSLExtension.CH_KEY_SHARE)) {228if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {229SSLLogger.fine(230"Ignore unavailable key_share extension");231}232return null;233}234235List<NamedGroup> namedGroups;236if (chc.serverSelectedNamedGroup != null) {237// Response to HelloRetryRequest238namedGroups = Arrays.asList(chc.serverSelectedNamedGroup);239} else {240namedGroups = chc.clientRequestedNamedGroups;241if (namedGroups == null || namedGroups.isEmpty()) {242// No supported groups.243if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {244SSLLogger.warning(245"Ignore key_share extension, no supported groups");246}247return null;248}249}250251List<KeyShareEntry> keyShares = new LinkedList<>();252for (NamedGroup ng : namedGroups) {253SSLKeyExchange ke = SSLKeyExchange.valueOf(ng);254if (ke == null) {255if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {256SSLLogger.warning(257"No key exchange for named group " + ng.name);258}259continue;260}261262SSLPossession[] poses = ke.createPossessions(chc);263for (SSLPossession pos : poses) {264// update the context265chc.handshakePossessions.add(pos);266if (!(pos instanceof ECDHEPossession) &&267!(pos instanceof DHEPossession)) {268// May need more possesion types in the future.269continue;270}271272keyShares.add(new KeyShareEntry(ng.id, pos.encode()));273}274275// One key share entry only. Too much key share entries makes276// the ClientHello handshake message really big.277if (!keyShares.isEmpty()) {278break;279}280}281282int listLen = 0;283for (KeyShareEntry entry : keyShares) {284listLen += entry.getEncodedSize();285}286byte[] extData = new byte[listLen + 2]; // 2: list length287ByteBuffer m = ByteBuffer.wrap(extData);288Record.putInt16(m, listLen);289for (KeyShareEntry entry : keyShares) {290m.put(entry.getEncoded());291}292293// update the context294chc.handshakeExtensions.put(SSLExtension.CH_KEY_SHARE,295new CHKeyShareSpec(keyShares));296297return extData;298}299}300301/**302* Network data consumer of the extension in a ClientHello303* handshake message.304*/305private static final class CHKeyShareConsumer implements ExtensionConsumer {306// Prevent instantiation of this class.307private CHKeyShareConsumer() {308// blank309}310311@Override312public void consume(ConnectionContext context,313HandshakeMessage message, ByteBuffer buffer) throws IOException {314// The consuming happens in server side only.315ServerHandshakeContext shc = (ServerHandshakeContext)context;316317if (shc.handshakeExtensions.containsKey(SSLExtension.CH_KEY_SHARE)) {318if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {319SSLLogger.fine(320"The key_share extension has been loaded");321}322return;323}324325// Is it a supported and enabled extension?326if (!shc.sslConfig.isAvailable(SSLExtension.CH_KEY_SHARE)) {327if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {328SSLLogger.fine(329"Ignore unavailable key_share extension");330}331return; // ignore the extension332}333334// Parse the extension335CHKeyShareSpec spec;336try {337spec = new CHKeyShareSpec(buffer);338} catch (IOException ioe) {339throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);340}341342List<SSLCredentials> credentials = new LinkedList<>();343for (KeyShareEntry entry : spec.clientShares) {344NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId);345if (ng == null || !SupportedGroups.isActivatable(346shc.algorithmConstraints, ng)) {347if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {348SSLLogger.fine(349"Ignore unsupported named group: " +350NamedGroup.nameOf(entry.namedGroupId));351}352continue;353}354355if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {356try {357ECDHECredentials ecdhec =358ECDHECredentials.valueOf(ng, entry.keyExchange);359if (ecdhec != null) {360if (!shc.algorithmConstraints.permits(361EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),362ecdhec.popPublicKey)) {363SSLLogger.warning(364"ECDHE key share entry does not " +365"comply to algorithm constraints");366} else {367credentials.add(ecdhec);368}369}370} catch (IOException | GeneralSecurityException ex) {371SSLLogger.warning(372"Cannot decode named group: " +373NamedGroup.nameOf(entry.namedGroupId));374}375} else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {376try {377DHECredentials dhec =378DHECredentials.valueOf(ng, entry.keyExchange);379if (dhec != null) {380if (!shc.algorithmConstraints.permits(381EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),382dhec.popPublicKey)) {383SSLLogger.warning(384"DHE key share entry does not " +385"comply to algorithm constraints");386} else {387credentials.add(dhec);388}389}390} catch (IOException | GeneralSecurityException ex) {391SSLLogger.warning(392"Cannot decode named group: " +393NamedGroup.nameOf(entry.namedGroupId));394}395}396}397398if (!credentials.isEmpty()) {399shc.handshakeCredentials.addAll(credentials);400} else {401// New handshake credentials are required from the client side.402shc.handshakeProducers.put(403SSLHandshake.HELLO_RETRY_REQUEST.id,404SSLHandshake.HELLO_RETRY_REQUEST);405}406407// update the context408shc.handshakeExtensions.put(SSLExtension.CH_KEY_SHARE, spec);409}410}411412/**413* The key share entry used in ServerHello "key_share" extensions.414*/415static final class SHKeyShareSpec implements SSLExtensionSpec {416final KeyShareEntry serverShare;417418SHKeyShareSpec(KeyShareEntry serverShare) {419this.serverShare = serverShare;420}421422private SHKeyShareSpec(ByteBuffer buffer) throws IOException {423// struct {424// KeyShareEntry server_share;425// } KeyShareServerHello;426if (buffer.remaining() < 5) { // 5: minimal server_share427throw new SSLProtocolException(428"Invalid key_share extension: " +429"insufficient data (length=" + buffer.remaining() + ")");430}431432int namedGroupId = Record.getInt16(buffer);433byte[] keyExchange = Record.getBytes16(buffer);434435if (buffer.hasRemaining()) {436throw new SSLProtocolException(437"Invalid key_share extension: unknown extra data");438}439440this.serverShare = new KeyShareEntry(namedGroupId, keyExchange);441}442443@Override444public String toString() {445MessageFormat messageFormat = new MessageFormat(446"\"server_share\": '{'\n" +447" \"named group\": {0}\n" +448" \"key_exchange\": '{'\n" +449"{1}\n" +450" '}'\n" +451"'}',", Locale.ENGLISH);452453HexDumpEncoder hexEncoder = new HexDumpEncoder();454Object[] messageFields = {455NamedGroup.nameOf(serverShare.namedGroupId),456Utilities.indent(457hexEncoder.encode(serverShare.keyExchange), " ")458};459460return messageFormat.format(messageFields);461}462}463464private static final class SHKeyShareStringizer implements SSLStringizer {465@Override466public String toString(ByteBuffer buffer) {467try {468return (new SHKeyShareSpec(buffer)).toString();469} catch (IOException ioe) {470// For debug logging only, so please swallow exceptions.471return ioe.getMessage();472}473}474}475476/**477* Network data producer of the extension in a ServerHello478* handshake message.479*/480private static final class SHKeyShareProducer implements HandshakeProducer {481// Prevent instantiation of this class.482private SHKeyShareProducer() {483// blank484}485486@Override487public byte[] produce(ConnectionContext context,488HandshakeMessage message) throws IOException {489// The producing happens in client side only.490ServerHandshakeContext shc = (ServerHandshakeContext)context;491492// In response to key_share request only493CHKeyShareSpec kss =494(CHKeyShareSpec)shc.handshakeExtensions.get(495SSLExtension.CH_KEY_SHARE);496if (kss == null) {497// Unlikely, no key_share extension requested.498if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {499SSLLogger.warning(500"Ignore, no client key_share extension");501}502return null;503}504505// Is it a supported and enabled extension?506if (!shc.sslConfig.isAvailable(SSLExtension.SH_KEY_SHARE)) {507if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {508SSLLogger.warning(509"Ignore, no available server key_share extension");510}511return null;512}513514// use requested key share entries515if ((shc.handshakeCredentials == null) ||516shc.handshakeCredentials.isEmpty()) {517// Unlikely, HelloRetryRequest should be used ealier.518if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {519SSLLogger.warning(520"No available client key share entries");521}522return null;523}524525KeyShareEntry keyShare = null;526for (SSLCredentials cd : shc.handshakeCredentials) {527NamedGroup ng = null;528if (cd instanceof ECDHECredentials) {529ng = ((ECDHECredentials)cd).namedGroup;530} else if (cd instanceof DHECredentials) {531ng = ((DHECredentials)cd).namedGroup;532}533534if (ng == null) {535continue;536}537538SSLKeyExchange ke = SSLKeyExchange.valueOf(ng);539if (ke == null) {540if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {541SSLLogger.warning(542"No key exchange for named group " + ng.name);543}544continue;545}546547SSLPossession[] poses = ke.createPossessions(shc);548for (SSLPossession pos : poses) {549if (!(pos instanceof ECDHEPossession) &&550!(pos instanceof DHEPossession)) {551// May need more possesion types in the future.552continue;553}554555// update the context556shc.handshakeKeyExchange = ke;557shc.handshakePossessions.add(pos);558keyShare = new KeyShareEntry(ng.id, pos.encode());559break;560}561562if (keyShare != null) {563for (Map.Entry<Byte, HandshakeProducer> me :564ke.getHandshakeProducers(shc)) {565shc.handshakeProducers.put(566me.getKey(), me.getValue());567}568569// We have got one! Don't forgor to break.570break;571}572}573574if (keyShare == null) {575// Unlikely, HelloRetryRequest should be used instead ealier.576if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {577SSLLogger.warning(578"No available server key_share extension");579}580return null;581}582583byte[] extData = keyShare.getEncoded();584585// update the context586SHKeyShareSpec spec = new SHKeyShareSpec(keyShare);587shc.handshakeExtensions.put(SSLExtension.SH_KEY_SHARE, spec);588589return extData;590}591}592593/**594* Network data consumer of the extension in a ServerHello595* handshake message.596*/597private static final class SHKeyShareConsumer implements ExtensionConsumer {598// Prevent instantiation of this class.599private SHKeyShareConsumer() {600// blank601}602603@Override604public void consume(ConnectionContext context,605HandshakeMessage message, ByteBuffer buffer) throws IOException {606// Happens in client side only.607ClientHandshakeContext chc = (ClientHandshakeContext)context;608if (chc.clientRequestedNamedGroups == null ||609chc.clientRequestedNamedGroups.isEmpty()) {610// No supported groups.611throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,612"Unexpected key_share extension in ServerHello");613}614615// Is it a supported and enabled extension?616if (!chc.sslConfig.isAvailable(SSLExtension.SH_KEY_SHARE)) {617throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,618"Unsupported key_share extension in ServerHello");619}620621// Parse the extension622SHKeyShareSpec spec;623try {624spec = new SHKeyShareSpec(buffer);625} catch (IOException ioe) {626throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);627}628629KeyShareEntry keyShare = spec.serverShare;630NamedGroup ng = NamedGroup.valueOf(keyShare.namedGroupId);631if (ng == null || !SupportedGroups.isActivatable(632chc.algorithmConstraints, ng)) {633throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,634"Unsupported named group: " +635NamedGroup.nameOf(keyShare.namedGroupId));636}637638SSLKeyExchange ke = SSLKeyExchange.valueOf(ng);639if (ke == null) {640throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,641"No key exchange for named group " + ng.name);642}643644SSLCredentials credentials = null;645if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {646try {647ECDHECredentials ecdhec =648ECDHECredentials.valueOf(ng, keyShare.keyExchange);649if (ecdhec != null) {650if (!chc.algorithmConstraints.permits(651EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),652ecdhec.popPublicKey)) {653throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,654"ECDHE key share entry does not " +655"comply to algorithm constraints");656} else {657credentials = ecdhec;658}659}660} catch (IOException | GeneralSecurityException ex) {661throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,662"Cannot decode named group: " +663NamedGroup.nameOf(keyShare.namedGroupId));664}665} else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {666try {667DHECredentials dhec =668DHECredentials.valueOf(ng, keyShare.keyExchange);669if (dhec != null) {670if (!chc.algorithmConstraints.permits(671EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),672dhec.popPublicKey)) {673throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,674"DHE key share entry does not " +675"comply to algorithm constraints");676} else {677credentials = dhec;678}679}680} catch (IOException | GeneralSecurityException ex) {681throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,682"Cannot decode named group: " +683NamedGroup.nameOf(keyShare.namedGroupId));684}685} else {686throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,687"Unsupported named group: " +688NamedGroup.nameOf(keyShare.namedGroupId));689}690691if (credentials == null) {692throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,693"Unsupported named group: " + ng.name);694}695696// update the context697chc.handshakeKeyExchange = ke;698chc.handshakeCredentials.add(credentials);699chc.handshakeExtensions.put(SSLExtension.SH_KEY_SHARE, spec);700}701}702703/**704* The absence processing if the extension is not present in705* the ServerHello handshake message.706*/707private static final class SHKeyShareAbsence implements HandshakeAbsence {708@Override709public void absent(ConnectionContext context,710HandshakeMessage message) throws IOException {711// The producing happens in client side only.712ClientHandshakeContext chc = (ClientHandshakeContext)context;713714// Cannot use the previous requested key shares any more.715if (SSLLogger.isOn && SSLLogger.isOn("handshake")) {716SSLLogger.fine(717"No key_share extension in ServerHello, " +718"cleanup the key shares if necessary");719}720chc.handshakePossessions.clear();721}722}723724/**725* The key share entry used in HelloRetryRequest "key_share" extensions.726*/727static final class HRRKeyShareSpec implements SSLExtensionSpec {728final int selectedGroup;729730HRRKeyShareSpec(NamedGroup serverGroup) {731this.selectedGroup = serverGroup.id;732}733734private HRRKeyShareSpec(ByteBuffer buffer) throws IOException {735// struct {736// NamedGroup selected_group;737// } KeyShareHelloRetryRequest;738if (buffer.remaining() != 2) {739throw new SSLProtocolException(740"Invalid key_share extension: " +741"improper data (length=" + buffer.remaining() + ")");742}743744this.selectedGroup = Record.getInt16(buffer);745}746747@Override748public String toString() {749MessageFormat messageFormat = new MessageFormat(750"\"selected group\": '['{0}']'", Locale.ENGLISH);751752Object[] messageFields = {753NamedGroup.nameOf(selectedGroup)754};755return messageFormat.format(messageFields);756}757}758759private static final class HRRKeyShareStringizer implements SSLStringizer {760@Override761public String toString(ByteBuffer buffer) {762try {763return (new HRRKeyShareSpec(buffer)).toString();764} catch (IOException ioe) {765// For debug logging only, so please swallow exceptions.766return ioe.getMessage();767}768}769}770771/**772* Network data producer of the extension in a HelloRetryRequest773* handshake message.774*/775private static final776class HRRKeyShareProducer implements HandshakeProducer {777// Prevent instantiation of this class.778private HRRKeyShareProducer() {779// blank780}781782@Override783public byte[] produce(ConnectionContext context,784HandshakeMessage message) throws IOException {785// The producing happens in server side only.786ServerHandshakeContext shc = (ServerHandshakeContext) context;787788// Is it a supported and enabled extension?789if (!shc.sslConfig.isAvailable(SSLExtension.HRR_KEY_SHARE)) {790throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,791"Unsupported key_share extension in HelloRetryRequest");792}793794if (shc.clientRequestedNamedGroups == null ||795shc.clientRequestedNamedGroups.isEmpty()) {796// No supported groups.797throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,798"Unexpected key_share extension in HelloRetryRequest");799}800801NamedGroup selectedGroup = null;802for (NamedGroup ng : shc.clientRequestedNamedGroups) {803if (SupportedGroups.isActivatable(804shc.algorithmConstraints, ng)) {805if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {806SSLLogger.fine(807"HelloRetryRequest selected named group: " +808ng.name);809}810811selectedGroup = ng;812break;813}814}815816if (selectedGroup == null) {817throw shc.conContext.fatal(818Alert.UNEXPECTED_MESSAGE, "No common named group");819}820821byte[] extdata = new byte[] {822(byte)((selectedGroup.id >> 8) & 0xFF),823(byte)(selectedGroup.id & 0xFF)824};825826// update the context827shc.serverSelectedNamedGroup = selectedGroup;828shc.handshakeExtensions.put(SSLExtension.HRR_KEY_SHARE,829new HRRKeyShareSpec(selectedGroup));830831return extdata;832}833}834835/**836* Network data producer of the extension for stateless837* HelloRetryRequest reconstruction.838*/839private static final840class HRRKeyShareReproducer implements HandshakeProducer {841// Prevent instantiation of this class.842private HRRKeyShareReproducer() {843// blank844}845846@Override847public byte[] produce(ConnectionContext context,848HandshakeMessage message) throws IOException {849// The producing happens in server side only.850ServerHandshakeContext shc = (ServerHandshakeContext) context;851852// Is it a supported and enabled extension?853if (!shc.sslConfig.isAvailable(SSLExtension.HRR_KEY_SHARE)) {854throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,855"Unsupported key_share extension in HelloRetryRequest");856}857858CHKeyShareSpec spec = (CHKeyShareSpec)shc.handshakeExtensions.get(859SSLExtension.CH_KEY_SHARE);860if (spec != null && spec.clientShares != null &&861spec.clientShares.size() == 1) {862int namedGroupId = spec.clientShares.get(0).namedGroupId;863864byte[] extdata = new byte[] {865(byte)((namedGroupId >> 8) & 0xFF),866(byte)(namedGroupId & 0xFF)867};868869return extdata;870}871872return null;873}874}875876/**877* Network data consumer of the extension in a HelloRetryRequest878* handshake message.879*/880private static final881class HRRKeyShareConsumer implements ExtensionConsumer {882// Prevent instantiation of this class.883private HRRKeyShareConsumer() {884// blank885}886887@Override888public void consume(ConnectionContext context,889HandshakeMessage message, ByteBuffer buffer) throws IOException {890// The producing happens in client side only.891ClientHandshakeContext chc = (ClientHandshakeContext)context;892893// Is it a supported and enabled extension?894if (!chc.sslConfig.isAvailable(SSLExtension.HRR_KEY_SHARE)) {895throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,896"Unsupported key_share extension in HelloRetryRequest");897}898899if (chc.clientRequestedNamedGroups == null ||900chc.clientRequestedNamedGroups.isEmpty()) {901// No supported groups.902throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,903"Unexpected key_share extension in HelloRetryRequest");904}905906// Parse the extension907HRRKeyShareSpec spec;908try {909spec = new HRRKeyShareSpec(buffer);910} catch (IOException ioe) {911throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);912}913914NamedGroup serverGroup = NamedGroup.valueOf(spec.selectedGroup);915if (serverGroup == null) {916throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,917"Unsupported HelloRetryRequest selected group: " +918NamedGroup.nameOf(spec.selectedGroup));919}920921if (!chc.clientRequestedNamedGroups.contains(serverGroup)) {922throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,923"Unexpected HelloRetryRequest selected group: " +924serverGroup.name);925}926927// update the context928929// When sending the new ClientHello, the client MUST replace the930// original "key_share" extension with one containing only a new931// KeyShareEntry for the group indicated in the selected_group932// field of the triggering HelloRetryRequest.933//934chc.serverSelectedNamedGroup = serverGroup;935chc.handshakeExtensions.put(SSLExtension.HRR_KEY_SHARE, spec);936}937}938}939940941