Path: blob/master/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java
41159 views
/*1* Copyright (c) 2015, 2020, 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.text.MessageFormat;30import java.util.Locale;31import javax.net.ssl.SSLProtocolException;32import static sun.security.ssl.SSLExtension.CH_EC_POINT_FORMATS;33import sun.security.ssl.SSLExtension.ExtensionConsumer;34import sun.security.ssl.SSLExtension.SSLExtensionSpec;35import sun.security.ssl.SSLHandshake.HandshakeMessage;36import sun.security.ssl.NamedGroup.NamedGroupSpec;3738/**39* Pack of the "ec_point_formats" extensions [RFC 4492].40*/41final class ECPointFormatsExtension {42static final HandshakeProducer chNetworkProducer =43new CHECPointFormatsProducer();44static final ExtensionConsumer chOnLoadConsumer =45new CHECPointFormatsConsumer();4647static final ExtensionConsumer shOnLoadConsumer =48new SHECPointFormatsConsumer();4950static final SSLStringizer epfStringizer =51new ECPointFormatsStringizer();5253/**54* The "ec_point_formats" extension.55*/56static class ECPointFormatsSpec implements SSLExtensionSpec {57static final ECPointFormatsSpec DEFAULT =58new ECPointFormatsSpec(new byte[] {ECPointFormat.UNCOMPRESSED.id});5960final byte[] formats;6162ECPointFormatsSpec(byte[] formats) {63this.formats = formats;64}6566private ECPointFormatsSpec(HandshakeContext hc,67ByteBuffer m) throws IOException {68if (!m.hasRemaining()) {69throw hc.conContext.fatal(Alert.DECODE_ERROR,70new SSLProtocolException(71"Invalid ec_point_formats extension: " +72"insufficient data"));73}7475this.formats = Record.getBytes8(m);76}7778private boolean hasUncompressedFormat() {79for (byte format : formats) {80if (format == ECPointFormat.UNCOMPRESSED.id) {81return true;82}83}8485return false;86}8788@Override89public String toString() {90MessageFormat messageFormat = new MessageFormat(91"\"formats\": '['{0}']'", Locale.ENGLISH);92if (formats == null || formats.length == 0) {93Object[] messageFields = {94"<no EC point format specified>"95};96return messageFormat.format(messageFields);97} else {98StringBuilder builder = new StringBuilder(512);99boolean isFirst = true;100for (byte pf : formats) {101if (isFirst) {102isFirst = false;103} else {104builder.append(", ");105}106107builder.append(ECPointFormat.nameOf(pf));108}109110Object[] messageFields = {111builder.toString()112};113114return messageFormat.format(messageFields);115}116}117}118119private static final class ECPointFormatsStringizer implements SSLStringizer {120@Override121public String toString(HandshakeContext hc, ByteBuffer buffer) {122try {123return (new ECPointFormatsSpec(hc, buffer)).toString();124} catch (IOException ioe) {125// For debug logging only, so please swallow exceptions.126return ioe.getMessage();127}128}129}130131private static enum ECPointFormat {132UNCOMPRESSED ((byte)0, "uncompressed"),133ANSIX962_COMPRESSED_PRIME ((byte)1, "ansiX962_compressed_prime"),134FMT_ANSIX962_COMPRESSED_CHAR2 ((byte)2, "ansiX962_compressed_char2");135136final byte id;137final String name;138139private ECPointFormat(byte id, String name) {140this.id = id;141this.name = name;142}143144static String nameOf(int id) {145for (ECPointFormat pf: ECPointFormat.values()) {146if (pf.id == id) {147return pf.name;148}149}150return "UNDEFINED-EC-POINT-FORMAT(" + id + ")";151}152}153154/**155* Network data producer of a "ec_point_formats" extension in156* the ClientHello handshake message.157*/158private static final159class CHECPointFormatsProducer implements HandshakeProducer {160// Prevent instantiation of this class.161private CHECPointFormatsProducer() {162// blank163}164165@Override166public byte[] produce(ConnectionContext context,167HandshakeMessage message) throws IOException {168// The producing happens in client side only.169ClientHandshakeContext chc = (ClientHandshakeContext)context;170171// Is it a supported and enabled extension?172if (!chc.sslConfig.isAvailable(CH_EC_POINT_FORMATS)) {173if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {174SSLLogger.fine(175"Ignore unavailable ec_point_formats extension");176}177return null;178}179180// Produce the extension.181//182// produce the extension only if EC cipher suite is activated.183if (NamedGroupSpec.NAMED_GROUP_ECDHE.isSupported(184chc.activeCipherSuites)) {185// We are using uncompressed ECPointFormat only at present.186byte[] extData = new byte[] {0x01, 0x00};187188// Update the context.189chc.handshakeExtensions.put(190CH_EC_POINT_FORMATS, ECPointFormatsSpec.DEFAULT);191192return extData;193}194195if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {196SSLLogger.fine(197"Need no ec_point_formats extension");198}199return null;200}201}202203/**204* Network data consumer of a "ec_point_formats" extension in205* the ClientHello handshake message.206*/207private static final208class CHECPointFormatsConsumer implements ExtensionConsumer {209// Prevent instantiation of this class.210private CHECPointFormatsConsumer() {211// blank212}213214@Override215public void consume(ConnectionContext context,216HandshakeMessage message, ByteBuffer buffer) throws IOException {217218// The consuming happens in server side only.219ServerHandshakeContext shc = (ServerHandshakeContext)context;220221// Is it a supported and enabled extension?222if (!shc.sslConfig.isAvailable(CH_EC_POINT_FORMATS)) {223if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {224SSLLogger.fine(225"Ignore unavailable ec_point_formats extension");226}227return; // ignore the extension228}229230// Parse the extension.231ECPointFormatsSpec spec = new ECPointFormatsSpec(shc, buffer);232233// per RFC 4492, uncompressed points must always be supported.234if (!spec.hasUncompressedFormat()) {235throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,236"Invalid ec_point_formats extension data: " +237"peer does not support uncompressed points");238}239240// Update the context.241shc.handshakeExtensions.put(CH_EC_POINT_FORMATS, spec);242243// No impact on session resumption, as only uncompressed points244// are supported at present.245}246}247248/**249* Network data consumer of a "ec_point_formats" extension in250* the ServerHello handshake message.251*/252private static final253class SHECPointFormatsConsumer implements ExtensionConsumer {254// Prevent instantiation of this class.255private SHECPointFormatsConsumer() {256// blank257}258259@Override260public void consume(ConnectionContext context,261HandshakeMessage message, ByteBuffer buffer) throws IOException {262263// The consuming happens in client side only.264ClientHandshakeContext chc = (ClientHandshakeContext)context;265266// In response to "ec_point_formats" extension request only267ECPointFormatsSpec requestedSpec = (ECPointFormatsSpec)268chc.handshakeExtensions.get(CH_EC_POINT_FORMATS);269if (requestedSpec == null) {270throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,271"Unexpected ec_point_formats extension in ServerHello");272}273274// Parse the extension.275ECPointFormatsSpec spec = new ECPointFormatsSpec(chc, buffer);276277// per RFC 4492, uncompressed points must always be supported.278if (!spec.hasUncompressedFormat()) {279throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,280"Invalid ec_point_formats extension data: " +281"peer does not support uncompressed points");282}283284// Update the context.285chc.handshakeExtensions.put(CH_EC_POINT_FORMATS, spec);286287// No impact on session resumption, as only uncompressed points288// are supported at present.289}290}291}292293294