1 /*
   2  * Copyright (c) 2006, 2012, 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.io.PrintStream;
  30 import java.util.*;
  31 import javax.net.ssl.*;
  32 
  33 /**
  34  * This file contains all the classes relevant to TLS Extensions for the
  35  * ClientHello and ServerHello messages. The extension mechanism and
  36  * several extensions are defined in RFC 3546. Additional extensions are
  37  * defined in the ECC RFC 4492.
  38  *
  39  * Currently, only the two ECC extensions are fully supported.
  40  *
  41  * The classes contained in this file are:
  42  *  . HelloExtensions: a List of extensions as used in the client hello
  43  *      and server hello messages.
  44  *  . ExtensionType: an enum style class for the extension type
  45  *  . HelloExtension: abstract base class for all extensions. All subclasses
  46  *      must be immutable.
  47  *
  48  *  . UnknownExtension: used to represent all parsed extensions that we do not
  49  *      explicitly support.
  50  *  . ServerNameExtension: the server_name extension.
  51  *  . SignatureAlgorithmsExtension: the signature_algorithms extension.
  52  *  . SupportedEllipticCurvesExtension: the ECC supported curves extension.
  53  *  . SupportedEllipticPointFormatsExtension: the ECC supported point formats
  54  *      (compressed/uncompressed) extension.
  55  *
  56  * @since   1.6
  57  * @author  Andreas Sterbenz
  58  */
  59 final class HelloExtensions {
  60 
  61     private List<HelloExtension> extensions;
  62     private int encodedLength;
  63 
  64     HelloExtensions() {
  65         extensions = Collections.emptyList();
  66     }
  67 
  68     HelloExtensions(HandshakeInStream s) throws IOException {
  69         int len = s.getInt16();
  70         extensions = new ArrayList<HelloExtension>();
  71         encodedLength = len + 2;
  72         while (len > 0) {
  73             int type = s.getInt16();
  74             int extlen = s.getInt16();
  75             ExtensionType extType = ExtensionType.get(type);
  76             HelloExtension extension;
  77             if (extType == ExtensionType.EXT_SERVER_NAME) {
  78                 extension = new ServerNameExtension(s, extlen);
  79             } else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) {
  80                 extension = new SignatureAlgorithmsExtension(s, extlen);
  81             } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) {
  82                 extension = new SupportedEllipticCurvesExtension(s, extlen);
  83             } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) {
  84                 extension =
  85                         new SupportedEllipticPointFormatsExtension(s, extlen);
  86             } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) {
  87                 extension = new RenegotiationInfoExtension(s, extlen);
  88             } else if (extType == ExtensionType.EXT_MAX_FRAGMENT_LENGTH) {
  89                 extension = new MaxFragmentLengthExtension(s, extlen);
  90             } else {
  91                 extension = new UnknownExtension(s, extlen, extType);
  92             }
  93             extensions.add(extension);
  94             len -= extlen + 4;
  95         }
  96         if (len != 0) {
  97             throw new SSLProtocolException(
  98                         "Error parsing extensions: extra data");
  99         }
 100     }
 101 
 102     // Return the List of extensions. Must not be modified by the caller.
 103     List<HelloExtension> list() {
 104         return extensions;
 105     }
 106 
 107     void add(HelloExtension ext) {
 108         if (extensions.isEmpty()) {
 109             extensions = new ArrayList<HelloExtension>();
 110         }
 111         extensions.add(ext);
 112         encodedLength = -1;
 113     }
 114 
 115     HelloExtension get(ExtensionType type) {
 116         for (HelloExtension ext : extensions) {
 117             if (ext.type == type) {
 118                 return ext;
 119             }
 120         }
 121         return null;
 122     }
 123 
 124     int length() {
 125         if (encodedLength >= 0) {
 126             return encodedLength;
 127         }
 128         if (extensions.isEmpty()) {
 129             encodedLength = 0;
 130         } else {
 131             encodedLength = 2;
 132             for (HelloExtension ext : extensions) {
 133                 encodedLength += ext.length();
 134             }
 135         }
 136         return encodedLength;
 137     }
 138 
 139     void send(HandshakeOutStream s) throws IOException {
 140         int length = length();
 141         if (length == 0) {
 142             return;
 143         }
 144         s.putInt16(length - 2);
 145         for (HelloExtension ext : extensions) {
 146             ext.send(s);
 147         }
 148     }
 149 
 150     void print(PrintStream s) throws IOException {
 151         for (HelloExtension ext : extensions) {
 152             s.println(ext.toString());
 153         }
 154     }
 155 }